From ba326bfcfdf356c6ea37aafd434c7402ca7b8955 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 28 Feb 2022 05:43:54 -0500 Subject: [PATCH] Introduce code from Rust monorepo. This is a mess --- future-todo/ControllableTalkNet/Dockerfile | 29 + future-todo/ControllableTalkNet/LICENSE | 121 + future-todo/ControllableTalkNet/README.md | 26 + .../TalkNet_Training_Offline.ipynb | 925 + future-todo/ControllableTalkNet/__init__.py | 0 .../assets/dash_customfont.css | 420 + .../controllable_talknet.py | 1097 ++ .../ControllableTalkNet/diffsvc_gui.py | 368 + .../model_lists/sortanon_models.json | 165 + .../ControllableTalkNet/mycroft_talknet.py | 114 + .../ControllableTalkNet/requirements.txt | 28 + .../ControllableTalkNet/talknet_offline.py | 17 + .../ControllableTalkNet/talknet_singer.py | 225 + future-todo/README.md | 0 future-todo/vocodes_common_talknet.py | 484 + tts/NeMo/.dockerignore | 19 + tts/NeMo/.github/ISSUE_TEMPLATE/bug_report.md | 42 + .../.github/ISSUE_TEMPLATE/feature_request.md | 25 + tts/NeMo/.gitignore | 176 + tts/NeMo/.readthedocs.yml | 31 + tts/NeMo/CONTRIBUTING.md | 68 + tts/NeMo/Dockerfile | 104 + tts/NeMo/Jenkinsfile | 1451 ++ tts/NeMo/LICENSE | 201 + tts/NeMo/README.rst | 174 + tts/NeMo/__init__.py | 0 tts/NeMo/docs/.nojekyll | 0 tts/NeMo/docs/Makefile | 216 + tts/NeMo/docs/source/_static/css/custom.css | 199 + tts/NeMo/docs/source/_static/js/pk_scripts.js | 19 + tts/NeMo/docs/source/asr/api.rst | 203 + tts/NeMo/docs/source/asr/asr_all.bib | 980 + .../docs/source/asr/asr_language_modeling.rst | 292 + tts/NeMo/docs/source/asr/configs.rst | 528 + tts/NeMo/docs/source/asr/data/asr_results.csv | 21 + .../docs/source/asr/data/asrlm_results.csv | 2 + .../docs/source/asr/data/benchmark_ca.csv | 2 + .../docs/source/asr/data/benchmark_de.csv | 3 + .../docs/source/asr/data/benchmark_en.csv | 14 + .../docs/source/asr/data/benchmark_es.csv | 3 + .../docs/source/asr/data/benchmark_fr.csv | 3 + .../docs/source/asr/data/benchmark_it.csv | 3 + .../docs/source/asr/data/benchmark_pl.csv | 2 + .../docs/source/asr/data/benchmark_ru.csv | 3 + .../docs/source/asr/data/benchmark_zh.csv | 3 + tts/NeMo/docs/source/asr/datasets.rst | 268 + .../source/asr/images/citrinet_vertical.png | Bin 0 -> 138615 bytes .../docs/source/asr/images/conformer_ctc.png | Bin 0 -> 105304 bytes tts/NeMo/docs/source/asr/images/ctc_asr.png | Bin 0 -> 54705 bytes .../docs/source/asr/images/jasper_layers.png | Bin 0 -> 25461 bytes .../source/asr/images/jasper_vertical.png | Bin 0 -> 279466 bytes .../source/asr/images/quartz_vertical.png | Bin 0 -> 262776 bytes tts/NeMo/docs/source/asr/intro.rst | 59 + tts/NeMo/docs/source/asr/models.rst | 97 + tts/NeMo/docs/source/asr/results.rst | 181 + .../source/asr/speaker_diarization/api.rst | 17 + .../asr/speaker_diarization/configs.rst | 65 + .../data/diarization_results.csv | 4 + .../asr/speaker_diarization/datasets.rst | 72 + .../images/sd_pipeline.png | Bin 0 -> 55717 bytes .../source/asr/speaker_diarization/intro.rst | 52 + .../source/asr/speaker_diarization/models.rst | 5 + .../asr/speaker_diarization/results.rst | 76 + .../asr/speaker_recognition/configs.rst | 117 + .../data/speaker_results.csv | 4 + .../asr/speaker_recognition/datasets.rst | 57 + .../images/ICASPP_SpeakerNet.png | Bin 0 -> 211990 bytes .../source/asr/speaker_recognition/intro.rst | 48 + .../source/asr/speaker_recognition/models.rst | 52 + .../asr/speaker_recognition/results.rst | 85 + .../asr/speech_classification/configs.rst | 104 + .../data/classification_results.csv | 9 + .../asr/speech_classification/datasets.rst | 131 + .../images/marblenet_vertical.png | Bin 0 -> 393467 bytes .../images/matchboxnet_vertical.png | Bin 0 -> 490256 bytes .../asr/speech_classification/intro.rst | 47 + .../asr/speech_classification/models.rst | 71 + .../asr/speech_classification/results.rst | 105 + tts/NeMo/docs/source/common/intro.rst | 39 + tts/NeMo/docs/source/conf.py | 242 + tts/NeMo/docs/source/core/core.rst | 963 + tts/NeMo/docs/source/core/whyntypes.gif | Bin 0 -> 309073 bytes tts/NeMo/docs/source/favicon.ico | Bin 0 -> 25214 bytes tts/NeMo/docs/source/index.rst | 67 + .../docs/source/nemo_text_processing/api.rst | 35 + .../source/nemo_text_processing/intro.rst | 17 + .../inverse_text_normalization.rst | 90 + .../text_normalization.rst | 78 + .../textprocessing_all.bib | 58 + tts/NeMo/docs/source/nlp/api.rst | 74 + tts/NeMo/docs/source/nlp/bert_pretraining.rst | 133 + tts/NeMo/docs/source/nlp/glue_benchmark.rst | 10 + .../docs/source/nlp/information_retrieval.rst | 10 + tts/NeMo/docs/source/nlp/intro.rst | 15 + .../docs/source/nlp/joint_intent_slot.rst | 244 + .../docs/source/nlp/language_modeling.rst | 6 + .../docs/source/nlp/machine_translation.rst | 466 + .../docs/source/nlp/megatron_finetuning.rst | 216 + tts/NeMo/docs/source/nlp/models.rst | 22 + tts/NeMo/docs/source/nlp/nlp_all.bib | 109 + tts/NeMo/docs/source/nlp/nlp_model.rst | 43 + .../nlp/punctuation_and_capitalization.rst | 300 + .../docs/source/nlp/question_answering.rst | 300 + tts/NeMo/docs/source/nlp/sgd_qa.rst | 17 + .../docs/source/nlp/text_classification.rst | 169 + .../docs/source/nlp/token_classification.rst | 219 + tts/NeMo/docs/source/nv_logo.png | Bin 0 -> 109116 bytes .../docs/source/starthere/best-practices.rst | 312 + tts/NeMo/docs/source/starthere/intro.rst | 157 + tts/NeMo/docs/source/starthere/tutorials.rst | 117 + .../docs/source/tools/ctc_segmentation.rst | 20 + tts/NeMo/docs/source/tools/intro.rst | 14 + .../source/tools/speech_data_explorer.rst | 33 + .../tools/text_processing_deployment.rst | 78 + tts/NeMo/docs/source/tools/tools_all.bib | 49 + tts/NeMo/docs/source/tts/api.rst | 47 + tts/NeMo/docs/source/tts/datasets.rst | 187 + tts/NeMo/docs/source/tts/intro.rst | 153 + tts/NeMo/docs/update_docs_docker.sh | 3 + tts/NeMo/examples/asr/asr_webapp/Dockerfile | 41 + tts/NeMo/examples/asr/asr_webapp/README.rst | 69 + .../examples/asr/asr_webapp/asr_service.py | 374 + .../asr/asr_webapp/docker_container_build.sh | 19 + .../asr/asr_webapp/docker_container_run.sh | 20 + .../examples/asr/asr_webapp/gunicorn.conf.py | 36 + tts/NeMo/examples/asr/asr_webapp/model_api.py | 131 + .../examples/asr/asr_webapp/requirements.txt | 4 + .../asr/asr_webapp/templates/main.html | 150 + .../asr/asr_webapp/templates/toast_msg.html | 28 + .../asr/asr_webapp/templates/transcripts.html | 43 + .../templates/updates/remove_files.html | 22 + .../updates/upload_files_failed.html | 22 + .../updates/upload_files_successful.html | 22 + tts/NeMo/examples/asr/asr_webapp/wsgi.py | 18 + .../asr/conf/citrinet/citrinet_384.yaml | 428 + .../asr/conf/citrinet/citrinet_512.yaml | 428 + .../asr/conf/citrinet/config_bpe.yaml | 183 + tts/NeMo/examples/asr/conf/config.yaml | 183 + .../asr/conf/conformer/conformer_ctc_bpe.yaml | 189 + .../conf/conformer/conformer_ctc_char.yaml | 165 + .../asr/conf/jasper/jasper_10x5dr.yaml | 208 + .../asr/conf/marblenet/marblenet_3x2x64.yaml | 180 + .../matchboxnet/matchboxnet_3x1x64_v1.yaml | 193 + .../matchboxnet/matchboxnet_3x1x64_v2.yaml | 193 + .../asr/conf/quartznet/quartznet_15x5.yaml | 281 + .../asr/conf/quartznet/quartznet_15x5_zh.yaml | 483 + .../conformer/conformer_rnnt_bpe.yaml | 201 + .../contextnet_rnnt/config_rnnt.yaml | 237 + .../contextnet_rnnt/config_rnnt_bpe.yaml | 238 + .../quartznet/quartznet_15x5_aug.yaml | 290 + .../sclite/speech_to_text_sclite.py | 158 + .../structured/conf/quartznet_15x5.yaml | 235 + .../structured/speech_to_text_hybrid.py | 56 + .../structured/speech_to_text_structured.py | 146 + .../speech_to_text_structured_v2.py | 90 + .../wav2vec/configs/wav2vec_pretrain.yaml | 123 + .../configs/wav2vec_pretrain_large.yaml | 123 + .../experimental/wav2vec/wav2vec_pretrain.py | 97 + .../quantization/speech_to_text_calibrate.py | 160 + .../speech_to_text_quant_infer.py | 216 + .../speech_to_text_quant_infer_trt.py | 226 + tts/NeMo/examples/asr/speech_to_label.py | 146 + tts/NeMo/examples/asr/speech_to_text.py | 105 + tts/NeMo/examples/asr/speech_to_text_bpe.py | 101 + tts/NeMo/examples/asr/speech_to_text_infer.py | 114 + tts/NeMo/examples/asr/speech_to_text_rnnt.py | 104 + .../examples/asr/speech_to_text_rnnt_bpe.py | 96 + tts/NeMo/examples/asr/transcribe_speech.py | 167 + tts/NeMo/examples/asr/vad_infer.py | 171 + ...et5_image_classification_pure_lightning.py | 65 + .../conf/sgdqa_config.yaml | 115 + .../nlp/dialogue_state_tracking/sgd_qa.py | 145 + .../nlp/entity_linking/build_index.py | 201 + .../tiny_example_entity_linking_config.yaml | 90 + .../umls_medical_entity_linking_config.yaml | 95 + .../data/umls_dataset_processing.py | 189 + .../nlp/entity_linking/query_index.py | 166 + .../self_alignment_pretraining.py | 49 + .../nlp/glue_benchmark/glue_benchmark.py | 73 + .../glue_benchmark/glue_benchmark_config.yaml | 82 + .../nlp/information_retrieval/bert_dpr.py | 35 + .../information_retrieval/bert_joint_ir.py | 35 + .../conf/bert_ir_config.yaml | 99 + .../construct_random_negatives.py | 49 + .../nlp/information_retrieval/get_msmarco.sh | 22 + .../intent_slot_classification_config.yaml | 111 + .../data/assistant_utils.py | 151 + .../data/import_datasets.py | 265 + .../intent_slot_classification.py | 85 + .../nlp/language_modeling/bert_pretraining.py | 38 + ..._pretraining_from_preprocessed_config.yaml | 80 + .../bert_pretraining_from_text_config.yaml | 109 + .../conf/transformer_lm_config.yaml | 96 + .../convert_weights_to_nemo1.0.py | 61 + .../nlp/language_modeling/get_wkt2.sh | 23 + .../nlp/language_modeling/transformer_lm.py | 35 + .../machine_translation/conf/aayn_base.yaml | 156 + .../machine_translation/conf/huggingface.yaml | 132 + .../create_tarred_monolingual_dataset.py | 68 + .../create_tarred_parallel_dataset.py | 143 + .../nlp/machine_translation/enc_dec_nmt.py | 137 + .../nmt_transformer_infer.py | 122 + .../machine_translation/nmt_webapp/README.rst | 7 + .../nmt_webapp/config.json | 12 + .../machine_translation/nmt_webapp/index.html | 140 + .../nmt_webapp/nmt_service.py | 100 + .../nmt_webapp/requirements.txt | 3 + .../machine_translation/nmt_webapp/style.css | 111 + .../nlp/machine_translation/translate_ddp.py | 122 + .../conf/question_answering_squad_config.yaml | 135 + .../nlp/question_answering/get_squad.py | 68 + .../question_answering_squad.py | 134 + .../text2sparql/conf/text2sparql_config.yaml | 105 + .../nlp/text2sparql/data/import_datasets.py | 134 + .../nlp/text2sparql/evaluate_text2sparql.py | 72 + .../examples/nlp/text2sparql/text2sparql.py | 112 + .../conf/text_classification_config.yaml | 119 + .../data/import_datasets.py | 243 + ...parallel_text_classification_evaluation.py | 41 + .../text_classification_with_bert.py | 154 + .../punctuation_capitalization_config.yaml | 133 + .../conf/token_classification_config.yaml | 119 + .../data/get_tatoeba_data.py | 242 + .../data/import_from_iob_format.py | 124 + ...are_data_for_punctuation_capitalization.py | 99 + .../punctuation_capitalization_evaluate.py | 127 + .../punctuation_capitalization_train.py | 101 + .../token_classification_evaluate.py | 137 + .../token_classification_train.py | 147 + .../examples/speaker_recognition/README.md | 21 + .../conf/SpeakerNet_recognition_3x2x512.yaml | 157 + .../conf/SpeakerNet_verification_3x2x512.yaml | 145 + .../conf/speaker_diarization.yaml | 27 + .../extract_speaker_embeddings.py | 101 + .../speaker_recognition/speaker_diarize.py | 49 + .../speaker_recognition/speaker_reco.py | 73 + .../speaker_reco_finetune.py | 98 + .../speaker_recognition/speaker_reco_infer.py | 139 + .../speaker_recognition/voxceleb_eval.py | 110 + tts/NeMo/examples/tts/aligner.py | 33 + tts/NeMo/examples/tts/conf/aligner.yaml | 123 + tts/NeMo/examples/tts/conf/degli.yaml | 107 + tts/NeMo/examples/tts/conf/ed_mel2spec.yaml | 103 + tts/NeMo/examples/tts/conf/fastpitch.yaml | 144 + .../examples/tts/conf/fastpitch_align.yaml | 185 + .../tts/conf/fastpitch_hifigan_e2e.yaml | 138 + tts/NeMo/examples/tts/conf/fastspeech2.yaml | 144 + .../tts/conf/fastspeech2_hifigan_e2e.yaml | 136 + tts/NeMo/examples/tts/conf/glow_tts.yaml | 143 + .../examples/tts/conf/hifigan/hifigan.yaml | 67 + .../tts/conf/hifigan/model/generator/v1.yaml | 8 + .../tts/conf/hifigan/model/generator/v2.yaml | 8 + .../tts/conf/hifigan/model/generator/v3.yaml | 8 + .../conf/hifigan/model/train_ds/train_ds.yaml | 13 + .../model/train_ds/train_ds_finetune.yaml | 11 + .../hifigan/model/validation_ds/val_ds.yaml | 13 + .../model/validation_ds/val_ds_finetune.yaml | 11 + tts/NeMo/examples/tts/conf/melgan.yaml | 108 + tts/NeMo/examples/tts/conf/squeezewave.yaml | 104 + tts/NeMo/examples/tts/conf/tacotron2.yaml | 140 + tts/NeMo/examples/tts/conf/talknet-durs.yaml | 175 + tts/NeMo/examples/tts/conf/talknet-pitch.yaml | 179 + tts/NeMo/examples/tts/conf/talknet-spect.yaml | 244 + tts/NeMo/examples/tts/conf/uniglow.yaml | 96 + tts/NeMo/examples/tts/conf/waveglow.yaml | 97 + tts/NeMo/examples/tts/degli.py | 36 + tts/NeMo/examples/tts/ed_mel2spec.py | 36 + tts/NeMo/examples/tts/fastpitch.py | 35 + .../examples/tts/fastpitch_hifigan_e2e.py | 36 + tts/NeMo/examples/tts/fastspeech2.py | 35 + .../examples/tts/fastspeech2_hifigan_e2e.py | 35 + tts/NeMo/examples/tts/glow_tts.py | 35 + tts/NeMo/examples/tts/hifigan.py | 31 + tts/NeMo/examples/tts/melgan.py | 35 + tts/NeMo/examples/tts/squeezewave.py | 34 + tts/NeMo/examples/tts/tacotron2.py | 44 + tts/NeMo/examples/tts/talknet_durs.py | 33 + tts/NeMo/examples/tts/talknet_pitch.py | 33 + tts/NeMo/examples/tts/talknet_spect.py | 33 + tts/NeMo/examples/tts/test_tts_infer.py | 153 + tts/NeMo/examples/tts/uniglow.py | 44 + tts/NeMo/examples/tts/waveglow.py | 34 + tts/NeMo/external/get_collections.py | 90 + tts/NeMo/external/get_modules.py | 159 + tts/NeMo/nemo_text_processing/README.md | 8 + tts/NeMo/nemo_text_processing/__init__.py | 13 + .../inverse_text_normalization/README.md | 12 + .../inverse_text_normalization/__init__.py | 32 + .../clean_eval_data.py | 342 + .../data/__init__.py | 13 + .../data/currency.tsv | 35 + .../data/electronic/__init__.py | 13 + .../data/electronic/domain.tsv | 1 + .../data/electronic/server_name.tsv | 2 + .../data/magnitudes.tsv | 4 + .../data/measurements.tsv | 110 + .../data/months.tsv | 12 + .../data/numbers/__init__.py | 13 + .../data/numbers/digit.tsv | 9 + .../data/numbers/hundred.tsv | 1 + .../data/numbers/teen.tsv | 10 + .../data/numbers/thousands.tsv | 22 + .../data/numbers/ties.tsv | 9 + .../data/numbers/zero.tsv | 1 + .../data/ordinals/__init__.py | 13 + .../data/ordinals/digit.tsv | 9 + .../data/ordinals/teen.tsv | 1 + .../data/time/__init__.py | 13 + .../data/time/time_suffix.tsv | 8 + .../data/time/time_to.tsv | 12 + .../data/time/time_zone.tsv | 7 + .../data/whitelist.tsv | 10 + .../inverse_normalize.py | 71 + .../run_evaluate.py | 109 + .../inverse_text_normalization/run_predict.py | 75 + .../taggers/__init__.py | 13 + .../taggers/cardinal.py | 134 + .../taggers/date.py | 163 + .../taggers/decimal.py | 95 + .../taggers/electronic.py | 66 + .../taggers/fraction.py | 26 + .../taggers/measure.py | 103 + .../taggers/money.py | 112 + .../taggers/ordinal.py | 50 + .../taggers/punctuation.py | 41 + .../taggers/telephone.py | 67 + .../taggers/time.py | 124 + .../taggers/tokenize_and_classify.py | 91 + .../taggers/whitelist.py | 40 + .../taggers/word.py | 36 + .../inverse_text_normalization/utils.py | 47 + .../verbalizers/__init__.py | 13 + .../verbalizers/cardinal.py | 55 + .../verbalizers/date.py | 87 + .../verbalizers/decimal.py | 65 + .../verbalizers/electronic.py | 52 + .../verbalizers/fraction.py | 25 + .../verbalizers/measure.py | 69 + .../verbalizers/money.py | 48 + .../verbalizers/ordinal.py | 64 + .../verbalizers/telephone.py | 39 + .../verbalizers/time.py | 87 + .../verbalizers/verbalize.py | 62 + .../verbalizers/verbalize_final.py | 50 + .../verbalizers/whitelist.py | 44 + .../verbalizers/word.py | 39 + tts/NeMo/nemo_text_processing/setup.sh | 2 + .../text_normalization/README.md | 11 + .../text_normalization/__init__.py | 33 + .../text_normalization/clean_eval_data.py | 342 + .../text_normalization/data/__init__.py | 13 + .../data/currency/__init__.py | 13 + .../data/currency/currency.tsv | 35 + .../data/currency/currency_minor.tsv | 2 + .../data/currency/currency_minor_one.tsv | 2 + .../data/electronic/__init__.py | 13 + .../data/electronic/domain.tsv | 1 + .../data/electronic/server_name.tsv | 2 + .../data/electronic/symbols.tsv | 20 + .../data/letter_pronunciation.tsv | 2 + .../text_normalization/data/magnitudes.tsv | 4 + .../text_normalization/data/measurements.tsv | 115 + .../data/months/__init__.py | 13 + .../text_normalization/data/months/abbr.tsv | 12 + .../text_normalization/data/months/names.tsv | 12 + .../data/months/numbers.tsv | 24 + .../data/numbers/__init__.py | 13 + .../data/numbers/cardinal_number_name.far | Bin 0 -> 325078 bytes .../text_normalization/data/numbers/digit.tsv | 9 + .../data/numbers/hundred.tsv | 1 + .../text_normalization/data/numbers/teen.tsv | 10 + .../data/numbers/thousands.tsv | 22 + .../text_normalization/data/numbers/ties.tsv | 8 + .../text_normalization/data/numbers/zero.tsv | 1 + .../data/ordinals/__init__.py | 13 + .../data/ordinals/digit.tsv | 9 + .../text_normalization/data/ordinals/teen.tsv | 1 + .../text_normalization/data/roman/__init__.py | 13 + .../data/roman/digit_teen.tsv | 49 + .../data/roman/hundreds.tsv | 9 + .../text_normalization/data/roman/ties.tsv | 5 + .../text_normalization/data/suppletive.tsv | 37 + .../text_normalization/data/time_suffix.tsv | 6 + .../text_normalization/data/time_zone.tsv | 14 + .../text_normalization/data/whitelist.tsv | 15924 ++++++++++++++++ .../data/whitelist_alternatives.tsv | 17 + .../text_normalization/data_loader_utils.py | 269 + .../text_normalization/graph_utils.py | 216 + .../text_normalization/normalize.py | 246 + .../normalize_with_audio.py | 327 + .../text_normalization/run_evaluate.py | 115 + .../text_normalization/run_predict.py | 78 + .../text_normalization/taggers/__init__.py | 13 + .../text_normalization/taggers/cardinal.py | 115 + .../text_normalization/taggers/date.py | 201 + .../text_normalization/taggers/decimal.py | 101 + .../text_normalization/taggers/electronic.py | 63 + .../text_normalization/taggers/fraction.py | 50 + .../text_normalization/taggers/measure.py | 162 + .../text_normalization/taggers/money.py | 86 + .../text_normalization/taggers/ordinal.py | 49 + .../text_normalization/taggers/punctuation.py | 46 + .../text_normalization/taggers/roman.py | 61 + .../text_normalization/taggers/telephone.py | 91 + .../text_normalization/taggers/time.py | 115 + .../taggers/tokenize_and_classify.py | 107 + .../text_normalization/taggers/whitelist.py | 68 + .../text_normalization/taggers/word.py | 41 + .../text_normalization/token_parser.py | 192 + .../verbalizers/__init__.py | 13 + .../verbalizers/cardinal.py | 56 + .../text_normalization/verbalizers/date.py | 100 + .../text_normalization/verbalizers/decimal.py | 74 + .../verbalizers/electronic.py | 91 + .../verbalizers/fraction.py | 72 + .../text_normalization/verbalizers/measure.py | 76 + .../text_normalization/verbalizers/money.py | 117 + .../text_normalization/verbalizers/ordinal.py | 63 + .../text_normalization/verbalizers/roman.py | 46 + .../verbalizers/telephone.py | 69 + .../text_normalization/verbalizers/time.py | 74 + .../verbalizers/verbalize.py | 79 + .../verbalizers/verbalize_final.py | 54 + .../verbalizers/whitelist.py | 48 + .../text_normalization/verbalizers/word.py | 43 + tts/NeMo/reinstall.sh | 40 + tts/NeMo/requirements/requirements.txt | 19 + tts/NeMo/requirements/requirements_asr.txt | 24 + tts/NeMo/requirements/requirements_cv.txt | 2 + tts/NeMo/requirements/requirements_docs.txt | 6 + tts/NeMo/requirements/requirements_nlp.txt | 13 + tts/NeMo/requirements/requirements_test.txt | 11 + .../requirements_text_processing.txt | 2 + tts/NeMo/requirements/requirements_tts.txt | 7 + .../create_tarred_transformer_lm_dataset.py | 318 + .../neural_rescorer/eval_neural_rescorer.py | 288 + .../ngram_lm/eval_beamsearch_ngram.py | 345 + .../ngram_lm/install_beamsearch_decoders.sh | 6 + .../ngram_lm/kenlm_utils.py | 112 + .../ngram_lm/train_kenlm.py | 154 + tts/NeMo/scripts/average_model_checkpoints.py | 171 + .../get_commonvoice_data.py | 178 + .../dataset_processing/get_hi-mia_data.py | 185 + .../get_librispeech_data.py | 171 + .../get_openslr_rir_data.py | 140 + .../dataset_processing/ljspeech/README | 14 + .../ljspeech/calculate_durs.py | 126 + .../create_manifests_and_textfiles.py | 71 + .../ljspeech/create_token2idx_dict.py | 68 + .../ljspeech/extract_ljspeech_energy_pitch.py | 88 + .../extract_ljspeech_phonemes_and_durs.sh | 150 + .../dataset_processing/process_an4_data.py | 88 + .../dataset_processing/process_degli_data.py | 70 + .../dataset_processing/process_hub5_data.py | 256 + .../process_speech_commands_data.py | 402 + .../dataset_processing/process_vad_data.py | 486 + tts/NeMo/scripts/export/convasr_to_enemo.py | 76 + tts/NeMo/scripts/export/convasr_to_onnx.py | 66 + .../scripts/export/convasr_to_single_onnx.py | 62 + .../download_resample_freesound.sh | 115 + .../freesound_download.py | 585 + .../freesound_requirements.txt | 6 + .../freesound_resample.py | 119 + .../nemo_legacy_import/asr_checkpoint_port.py | 72 + .../filter_langs_nmt.py | 403 + .../speaker_recognition/rttm_to_manifest.py | 40 + .../speaker_recognition/scp_to_manifest.py | 96 + .../convert_to_tarred_audio_dataset.py | 601 + .../tokenizers/process_asr_text_tokenizer.py | 282 + .../vad_overlap_posterior.py | 259 + .../vad_tune_threshold.py | 58 + .../write_long_audio_manifest.py | 173 + tts/NeMo/setup.cfg | 36 + tts/NeMo/setup.py | 238 + tts/NeMo/tests/__init__.py | 13 + .../asr/numba/rnnt_loss/test_rnnt_pytorch.py | 256 + .../rnnt_loss/utils/test_gpu_rnnt_kernel.py | 169 + .../asr/numba/rnnt_loss/utils/test_reduce.py | 86 + .../numba/rnnt_loss/utils/test_rnnt_helper.py | 319 + .../numba/spec_augment/test_spec_aug_numba.py | 252 + .../asr/test_asr_classification_model.py | 208 + .../asr/test_asr_ctc_encoder_model_bpe.py | 313 + .../asr/test_asr_ctcencdec_model.py | 305 + .../collections/asr/test_asr_datasets.py | 127 + .../collections/asr/test_asr_exportables.py | 301 + .../test_asr_filterbankfeatures_seq_len.py | 99 + .../tests/collections/asr/test_asr_metrics.py | 172 + .../tests/collections/asr/test_asr_modules.py | 325 + .../asr/test_asr_regression_model.py | 95 + .../asr/test_asr_rnnt_encdec_model.py | 276 + .../asr/test_asr_rnnt_encoder_model_bpe.py | 246 + .../collections/asr/test_jasper_block.py | 295 + .../collections/asr/test_label_datasets.py | 106 + .../asr/test_speaker_label_models.py | 63 + tts/NeMo/tests/collections/common/__init__.py | 13 + .../tests/collections/common/loss_inputs.py | 69 + .../collections/common/perplexity_inputs.py | 49 + tts/NeMo/tests/collections/common/pl_utils.py | 557 + .../tests/collections/common/test_metrics.py | 150 + .../collections/common/test_spc_tokenizer.py | 267 + .../nlp/test_classification_report.py | 48 + .../nlp/test_entity_linking_model.py | 83 + .../tests/collections/nlp/test_huggingface.py | 86 + .../tests/collections/nlp/test_megatron.py | 76 + .../collections/nlp/test_nlp_exportables.py | 176 + .../tests/collections/nlp/test_nmt_model.py | 144 + .../nlp/test_pretrained_models_performance.py | 110 + .../collections/tts/test_tts_datasets.py | 43 + .../collections/tts/test_tts_exportables.py | 62 + .../tests/collections/tts/test_waveglow.py | 110 + tts/NeMo/tests/conftest.py | 188 + tts/NeMo/tests/core/test_config_utils.py | 125 + tts/NeMo/tests/core/test_exp_manager.py | 357 + tts/NeMo/tests/core/test_fileio.py | 299 + tts/NeMo/tests/core/test_neural_types.py | 224 + .../tests/core/test_optimizers_schedulers.py | 809 + tts/NeMo/tests/core/test_save_restore.py | 443 + tts/NeMo/tests/core/test_serialization.py | 165 + tts/NeMo/tests/core/test_typecheck.py | 1075 ++ tts/NeMo/tests/core_ptl/check_for_ranks.py | 155 + tts/NeMo/tests/hydra/config1.yaml | 1 + tts/NeMo/tests/hydra/config1_invalid.yaml | 2 + .../tests/hydra/config_subdir/config2.yaml | 1 + .../hydra/config_subdir/config2_invalid.yaml | 2 + tts/NeMo/tests/hydra/my_app.py | 44 + tts/NeMo/tests/hydra/test_hydra_runner.py | 95 + tts/NeMo/tests/manualtest_model_downloads.py | 92 + .../test_cases_cardinal.txt | 24 + .../test_cases_date.txt | 34 + .../test_cases_decimal.txt | 63 + .../test_cases_electronic.txt | 7 + .../test_cases_measure.txt | 112 + .../test_cases_money.txt | 48 + .../test_cases_ordinal.txt | 33 + .../test_cases_telephone.txt | 4 + .../test_cases_time.txt | 27 + .../test_cases_whitelist.txt | 8 + .../test_cases_word.txt | 50 + .../test_cases_boundary.txt | 7 + .../test_cases_cardinal.txt | 18 + .../test_cases_date.txt | 32 + .../test_cases_decimal.txt | 8 + .../test_cases_electronic.txt | 10 + .../test_cases_fraction.txt | 11 + .../test_cases_measure.txt | 15 + .../test_cases_money.txt | 38 + .../test_cases_normalize_with_audio.txt | 107 + .../test_cases_ordinal.txt | 6 + .../test_cases_telephone.txt | 9 + .../test_cases_time.txt | 14 + .../test_cases_whitelist.txt | 3 + .../test_cases_word.txt | 23 + .../nemo_text_processing/test_boundary.py | 39 + .../nemo_text_processing/test_cardinal.py | 49 + .../tests/nemo_text_processing/test_date.py | 64 + .../nemo_text_processing/test_decimal.py | 49 + .../nemo_text_processing/test_electronic.py | 51 + .../nemo_text_processing/test_fraction.py | 38 + .../nemo_text_processing/test_measure.py | 50 + .../tests/nemo_text_processing/test_money.py | 50 + .../test_normalization_with_audio.py | 33 + .../nemo_text_processing/test_ordinal.py | 50 + ..._sparrowhawk_inverse_text_normalization.sh | 64 + .../test_sparrowhawk_normalization.sh | 64 + .../nemo_text_processing/test_telephone.py | 50 + .../tests/nemo_text_processing/test_time.py | 49 + .../nemo_text_processing/test_whitelist.py | 65 + .../tests/nemo_text_processing/test_word.py | 52 + tts/NeMo/tests/nemo_text_processing/utils.py | 54 + tts/NeMo/tests/test_data_dir.py | 27 + tts/NeMo/tools/ctc_segmentation/README.md | 31 + .../tools/ctc_segmentation/requirements.txt | 2 + tts/NeMo/tools/ctc_segmentation/run_sample.sh | 124 + .../ctc_segmentation/scripts/cut_audio.py | 313 + .../scripts/normalization_helpers.py | 69 + .../ctc_segmentation/scripts/prepare_data.py | 412 + .../scripts/process_manifests.py | 111 + .../scripts/run_ctc_segmentation.py | 180 + .../tools/ctc_segmentation/scripts/utils.py | 173 + .../scripts/verify_segments.py | 143 + tts/NeMo/tools/speech_data_explorer/README.md | 26 + .../speech_data_explorer/data_explorer.py | 717 + .../speech_data_explorer/requirements.txt | 10 + .../tools/speech_data_explorer/screenshot.png | Bin 0 -> 1135618 bytes .../text_processing_deployment/Dockerfile | 38 + .../text_processing_deployment/README.rst | 10 + .../docker/build.sh | 18 + .../docker/launch.sh | 44 + .../export_grammars.sh | 59 + .../pynini_export.py | 111 + tts/NeMo/tutorials/00_NeMo_Primer.ipynb | 1281 ++ tts/NeMo/tutorials/01_NeMo_Models.ipynb | 2636 +++ .../tutorials/AudioTranslationSample.ipynb | 280 + tts/NeMo/tutorials/VoiceSwapSample.ipynb | 325 + tts/NeMo/tutorials/asr/01_ASR_with_NeMo.ipynb | 1174 ++ .../asr/02_Online_ASR_Microphone_Demo.ipynb | 540 + .../tutorials/asr/03_Speech_Commands.ipynb | 1628 ++ ..._Online_Offline_Speech_Commands_Demo.ipynb | 747 + .../asr/05_Online_Noise_Augmentation.ipynb | 1320 ++ .../asr/06_Voice_Activiy_Detection.ipynb | 1169 ++ ...7_Online_Offline_Microphone_VAD_Demo.ipynb | 830 + .../08_ASR_with_Subword_Tokenization.ipynb | 1445 ++ .../asr/10_ASR_CTC_Language_Finetuning.ipynb | 2163 +++ tts/NeMo/tutorials/asr/Offline_ASR.ipynb | 506 + .../asr/images/alignment_example.png | Bin 0 -> 23938 bytes .../asr/images/vad_post_overlap_diagram.png | Bin 0 -> 20961 bytes ...Language_Models_for_Downstream_Tasks.ipynb | 410 + .../tutorials/nlp/02_NLP_Tokenizers.ipynb | 616 + .../nlp/Entity_Linking_Medical.ipynb | 756 + tts/NeMo/tutorials/nlp/GLUE_Benchmark.ipynb | 565 + ...Joint_Intent_and_Slot_Classification.ipynb | 587 + ...ural_Machine_Translation-Text2Sparql.ipynb | 2260 +++ .../nlp/Punctuation_and_Capitalization.ipynb | 735 + .../nlp/Question_Answering_Squad.ipynb | 724 + .../nlp/Relation_Extraction-BioMegatron.ipynb | 630 + ...xt_Classification_Sentiment_Analysis.ipynb | 828 + .../Token_Classification-BioMegatron.ipynb | 648 + ...ssification_Named_Entity_Recognition.ipynb | 849 + .../ASR_with_SpeakerDiarization.ipynb | 555 + .../Speaker_Diarization_Inference.ipynb | 632 + .../Speaker_Recognition_Verification.ipynb | 1211 ++ .../Inverse_Text_Normalization.ipynb | 514 + .../text_processing/Text_Normalization.ipynb | 394 + .../text_processing/images/deployment.png | Bin 0 -> 154145 bytes .../text_processing/images/pipeline.png | Bin 0 -> 225984 bytes .../tools/CTC_Segmentation_Tutorial.ipynb | 811 + ...edCrowd_x_NeMo_ASR_Training_Tutorial.ipynb | 1853 ++ .../setup-asr-preannotations.ipynb | 249 + tts/NeMo/tutorials/tts/1_TTS_inference.ipynb | 389 + .../tts/2_TTS_Tacotron2_Training.ipynb | 347 + .../tts/3_TTS_TalkNet_Training.ipynb | 499 + tts/__init__.py | 0 tts/hifigan/LICENSE | 21 + tts/hifigan/README.md | 105 + tts/hifigan/__init__.py | 0 tts/hifigan/audio_processing.py | 93 + tts/hifigan/config_32k.json | 37 + tts/hifigan/config_v1.json | 37 + tts/hifigan/config_v1b.json | 37 + tts/hifigan/config_v2.json | 37 + tts/hifigan/config_v3.json | 37 + tts/hifigan/denoiser.py | 36 + tts/hifigan/env.py | 15 + tts/hifigan/hifiutils.py | 58 + tts/hifigan/inference.py | 95 + tts/hifigan/inference_e2e.py | 93 + tts/hifigan/meldataset.py | 168 + tts/hifigan/models.py | 283 + tts/hifigan/requirements.txt | 7 + tts/hifigan/stft.py | 141 + tts/hifigan/train.py | 280 + tts/nemo/README.md | 9 + tts/nemo/__init__.py | 28 + tts/nemo/collections/__init__.py | 13 + tts/nemo/collections/asr/__init__.py | 25 + tts/nemo/collections/asr/data/__init__.py | 13 + .../collections/asr/data/audio_to_label.py | 921 + .../asr/data/audio_to_label_dataset.py | 129 + .../collections/asr/data/audio_to_text.py | 1330 ++ .../asr/data/audio_to_text_dali.py | 444 + .../asr/data/audio_to_text_dataset.py | 247 + .../collections/asr/data/feature_to_label.py | 139 + .../asr/data/feature_to_label_dataset.py | 31 + tts/nemo/collections/asr/data/vocabs.py | 352 + tts/nemo/collections/asr/losses/__init__.py | 16 + .../collections/asr/losses/angularloss.py | 68 + tts/nemo/collections/asr/losses/ctc.py | 70 + tts/nemo/collections/asr/losses/rnnt.py | 288 + .../collections/asr/losses/wav2vecloss.py | 118 + tts/nemo/collections/asr/metrics/__init__.py | 13 + tts/nemo/collections/asr/metrics/rnnt_wer.py | 478 + .../collections/asr/metrics/rnnt_wer_bpe.py | 242 + tts/nemo/collections/asr/metrics/wer.py | 247 + tts/nemo/collections/asr/metrics/wer_bpe.py | 210 + tts/nemo/collections/asr/models/__init__.py | 22 + tts/nemo/collections/asr/models/asr_model.py | 91 + .../asr/models/classification_models.py | 750 + .../asr/models/clustering_diarizer.py | 439 + .../asr/models/configs/__init__.py | 46 + .../configs/classification_models_config.py | 95 + .../asr/models/configs/ctc_models_config.py | 85 + .../asr/models/configs/matchboxnet_config.py | 253 + .../asr/models/configs/quartznet_config.py | 308 + .../collections/asr/models/ctc_bpe_models.py | 304 + tts/nemo/collections/asr/models/ctc_models.py | 649 + .../collections/asr/models/label_models.py | 409 + .../collections/asr/models/rnnt_bpe_models.py | 290 + .../collections/asr/models/rnnt_models.py | 835 + .../asr/models/wav2vec/__init__.py | 14 + .../asr/models/wav2vec/wav2vec_config.py | 180 + .../asr/models/wav2vec/wav2vec_model.py | 504 + tts/nemo/collections/asr/modules/__init__.py | 30 + .../asr/modules/audio_preprocessing.py | 643 + .../asr/modules/beam_search_decoder.py | 103 + .../asr/modules/conformer_encoder.py | 255 + tts/nemo/collections/asr/modules/conv_asr.py | 504 + .../collections/asr/modules/lstm_decoder.py | 95 + tts/nemo/collections/asr/modules/rnnt.py | 958 + .../collections/asr/modules/rnnt_abstract.py | 236 + .../asr/modules/wav2vec_modules.py | 306 + tts/nemo/collections/asr/parts/__init__.py | 13 + tts/nemo/collections/asr/parts/features.py | 39 + .../collections/asr/parts/mixins/__init__.py | 15 + .../collections/asr/parts/mixins/mixins.py | 193 + .../collections/asr/parts/numba/__init__.py | 15 + .../asr/parts/numba/rnnt_loss/__init__.py | 16 + .../asr/parts/numba/rnnt_loss/rnnt.py | 225 + .../asr/parts/numba/rnnt_loss/rnnt_numpy.py | 213 + .../asr/parts/numba/rnnt_loss/rnnt_pytorch.py | 186 + .../parts/numba/rnnt_loss/utils/__init__.py | 13 + .../rnnt_loss/utils/cpu_utils/__init__.py | 27 + .../rnnt_loss/utils/cpu_utils/cpu_rnnt.py | 378 + .../rnnt_loss/utils/cuda_utils/__init__.py | 27 + .../rnnt_loss/utils/cuda_utils/gpu_rnnt.py | 254 + .../utils/cuda_utils/gpu_rnnt_kernel.py | 365 + .../rnnt_loss/utils/cuda_utils/reduce.py | 362 + .../numba/rnnt_loss/utils/global_constants.py | 68 + .../numba/rnnt_loss/utils/rnnt_helper.py | 129 + .../asr/parts/numba/spec_augment/__init__.py | 18 + .../numba/spec_augment/spec_aug_numba.py | 290 + .../asr/parts/preprocessing/__init__.py | 41 + .../asr/parts/preprocessing/feature_loader.py | 69 + .../asr/parts/preprocessing/features.py | 432 + .../asr/parts/preprocessing/perturb.py | 895 + .../asr/parts/preprocessing/segment.py | 270 + .../asr/parts/submodules/__init__.py | 13 + .../asr/parts/submodules/conformer_modules.py | 190 + .../asr/parts/submodules/jasper.py | 960 + .../parts/submodules/multi_head_attention.py | 340 + .../parts/submodules/rnnt_beam_decoding.py | 791 + .../parts/submodules/rnnt_greedy_decoding.py | 731 + .../asr/parts/submodules/spectr_augment.py | 152 + .../asr/parts/submodules/subsampling.py | 138 + .../asr/parts/submodules/wav2vec.py | 222 + .../collections/asr/parts/utils/__init__.py | 13 + .../asr/parts/utils/activations.py | 24 + .../asr/parts/utils/asr_module_utils.py | 82 + .../asr/parts/utils/nmse_clustering.py | 271 + .../asr/parts/utils/numba_utils.py | 88 + .../collections/asr/parts/utils/rnnt_utils.py | 89 + .../asr/parts/utils/speaker_utils.py | 400 + .../collections/asr/parts/utils/vad_utils.py | 544 + tts/nemo/collections/common/__init__.py | 26 + .../collections/common/callbacks/__init__.py | 15 + .../collections/common/callbacks/callbacks.py | 97 + tts/nemo/collections/common/data/__init__.py | 15 + tts/nemo/collections/common/data/dataset.py | 178 + .../collections/common/losses/__init__.py | 20 + .../collections/common/losses/aggregator.py | 67 + .../common/losses/cross_entropy.py | 138 + .../collections/common/losses/mse_loss.py | 57 + .../common/losses/multi_similarity_loss.py | 95 + .../common/losses/smoothed_cross_entropy.py | 103 + .../common/losses/spanning_loss.py | 79 + .../collections/common/metrics/__init__.py | 17 + .../common/metrics/classification_accuracy.py | 152 + .../metrics/global_average_loss_metric.py | 73 + .../collections/common/metrics/perplexity.py | 71 + tts/nemo/collections/common/parts/__init__.py | 17 + .../common/parts/multi_layer_perceptron.py | 61 + .../collections/common/parts/patch_utils.py | 132 + .../common/parts/preprocessing/__init__.py | 13 + .../common/parts/preprocessing/cleaners.py | 259 + .../common/parts/preprocessing/collections.py | 468 + .../common/parts/preprocessing/manifest.py | 120 + .../common/parts/preprocessing/parsers.py | 185 + tts/nemo/collections/common/parts/rnn.py | 553 + .../common/parts/transformer_utils.py | 79 + tts/nemo/collections/common/parts/utils.py | 57 + .../collections/common/tokenizers/__init__.py | 19 + .../common/tokenizers/char_tokenizer.py | 142 + .../common/tokenizers/chinese_tokenizers.py | 63 + .../common/tokenizers/en_ja_tokenizers.py | 57 + .../common/tokenizers/fairseq_tokenizer.py | 126 + .../common/tokenizers/huggingface/__init__.py | 15 + .../tokenizers/huggingface/auto_tokenizer.py | 260 + .../common/tokenizers/moses_tokenizers.py | 47 + .../tokenizers/sentencepiece_tokenizer.py | 353 + .../common/tokenizers/tokenizer_spec.py | 55 + .../common/tokenizers/word_tokenizer.py | 72 + .../tokenizers/youtokentome_tokenizer.py | 70 + tts/nemo/collections/cv/__init__.py | 25 + tts/nemo/collections/cv/datasets/__init__.py | 15 + .../collections/cv/datasets/mnist_dataset.py | 134 + tts/nemo/collections/cv/losses/__init__.py | 15 + tts/nemo/collections/cv/losses/nll_loss.py | 54 + tts/nemo/collections/cv/models/__init__.py | 15 + .../collections/cv/models/mnist_lenet5.py | 157 + tts/nemo/collections/cv/modules/__init__.py | 15 + tts/nemo/collections/cv/modules/lenet5.py | 114 + tts/nemo/collections/nlp/__init__.py | 25 + tts/nemo/collections/nlp/data/__init__.py | 40 + .../nlp/data/data_utils/__init__.py | 15 + .../nlp/data/data_utils/data_preprocessing.py | 479 + .../data/dialogue_state_tracking/__init__.py | 17 + .../dialogue_state_tracking/sgd/__init__.py | 13 + .../sgd/data_processor.py | 676 + .../dialogue_state_tracking/sgd/dataset.py | 85 + .../dialogue_state_tracking/sgd/evaluate.py | 294 + .../sgd/input_example.py | 399 + .../dialogue_state_tracking/sgd/metrics.py | 341 + .../sgd/prediction_utils.py | 251 + .../dialogue_state_tracking/sgd/schema.py | 222 + .../nlp/data/entity_linking/__init__.py | 15 + .../entity_linking/entity_linking_dataset.py | 135 + .../nlp/data/glue_benchmark/__init__.py | 15 + .../data/glue_benchmark/data_processors.py | 323 + .../glue_benchmark/glue_benchmark_dataset.py | 365 + .../data/information_retrieval/__init__.py | 17 + .../information_retrieval_dataset.py | 278 + .../intent_slot_classification/__init__.py | 22 + .../intent_slot_classification_dataset.py | 292 + .../intent_slot_classification_descriptor.py | 163 + .../nlp/data/language_modeling/__init__.py | 20 + .../data/language_modeling/l2r_lm_dataset.py | 240 + .../data/language_modeling/lm_bert_dataset.py | 406 + .../language_modeling/sentence_dataset.py | 273 + .../nlp/data/machine_translation/__init__.py | 18 + .../machine_translation_dataset.py | 445 + .../machine_translation/preproc_mt_data.py | 1020 + .../neural_machine_translation/__init__.py | 18 + .../neural_machine_translation_dataset.py | 146 + .../data/question_answering_squad/__init__.py | 13 + .../question_answering_squad/qa_dataset.py | 443 + .../qa_squad_processing.py | 644 + .../nlp/data/text_classification/__init__.py | 19 + .../text_classification_dataset.py | 297 + .../nlp/data/token_classification/__init__.py | 13 + .../punctuation_capitalization_dataset.py | 466 + .../token_classification_dataset.py | 338 + .../token_classification_utils.py | 118 + tts/nemo/collections/nlp/losses/__init__.py | 15 + tts/nemo/collections/nlp/losses/sgd_loss.py | 218 + tts/nemo/collections/nlp/metrics/__init__.py | 16 + .../nlp/metrics/classification_report.py | 173 + .../nlp/metrics/sequence_perplexity.py | 78 + tts/nemo/collections/nlp/models/__init__.py | 28 + .../dialogue_state_tracking/__init__.py | 15 + .../dialogue_state_tracking/sgdqa_model.py | 580 + .../nlp/models/enc_dec_nlp_model.py | 85 + .../nlp/models/entity_linking/__init__.py | 15 + .../entity_linking/entity_linking_model.py | 193 + .../nlp/models/glue_benchmark/__init__.py | 15 + .../glue_benchmark/glue_benchmark_model.py | 279 + .../models/glue_benchmark/metrics_for_glue.py | 66 + .../models/information_retrieval/__init__.py | 16 + .../information_retrieval/base_ir_model.py | 211 + .../information_retrieval/bert_dpr_model.py | 131 + .../bert_joint_ir_model.py | 84 + .../intent_slot_classification/__init__.py | 17 + .../intent_slot_classification_model.py | 487 + .../nlp/models/language_modeling/__init__.py | 16 + .../models/language_modeling/bert_lm_model.py | 272 + .../language_modeling/transformer_lm_model.py | 276 + .../models/machine_translation/__init__.py | 15 + .../machine_translation/mt_enc_dec_config.py | 134 + .../machine_translation/mt_enc_dec_model.py | 836 + .../neural_machine_translation/__init__.py | 17 + .../neural_machine_translation_model.py | 245 + tts/nemo/collections/nlp/models/nlp_model.py | 463 + .../nlp/models/question_answering/__init__.py | 15 + .../nlp/models/question_answering/qa_model.py | 404 + .../models/text_classification/__init__.py | 15 + .../text_classification_model.py | 324 + .../models/token_classification/__init__.py | 19 + .../punctuation_capitalization_model.py | 490 + .../token_classification_model.py | 522 + tts/nemo/collections/nlp/modules/__init__.py | 33 + .../nlp/modules/common/__init__.py | 34 + .../nlp/modules/common/bert_module.py | 93 + .../nlp/modules/common/classifier.py | 87 + .../nlp/modules/common/decoder_module.py | 58 + .../nlp/modules/common/encoder_module.py | 41 + .../modules/common/huggingface/__init__.py | 22 + .../nlp/modules/common/huggingface/albert.py | 33 + .../nlp/modules/common/huggingface/bert.py | 33 + .../modules/common/huggingface/distilbert.py | 34 + .../common/huggingface/huggingface_decoder.py | 79 + .../common/huggingface/huggingface_encoder.py | 99 + .../common/huggingface/huggingface_utils.py | 126 + .../nlp/modules/common/huggingface/roberta.py | 34 + .../nlp/modules/common/lm_utils.py | 179 + .../nlp/modules/common/megatron/__init__.py | 19 + .../modules/common/megatron/megatron_bert.py | 216 + .../modules/common/megatron/megatron_utils.py | 307 + .../nlp/modules/common/sequence_classifier.py | 72 + .../nlp/modules/common/sequence_regression.py | 69 + .../common/sequence_token_classifier.py | 80 + .../nlp/modules/common/token_classifier.py | 165 + .../nlp/modules/common/tokenizer_utils.py | 144 + .../modules/common/transformer/__init__.py | 18 + .../modules/common/transformer/transformer.py | 248 + .../transformer/transformer_decoders.py | 200 + .../transformer/transformer_encoders.py | 176 + .../transformer/transformer_generators.py | 541 + .../common/transformer/transformer_modules.py | 210 + .../common/transformer/transformer_utils.py | 118 + .../dialogue_state_tracking/__init__.py | 13 + .../dialogue_state_tracking/sgd_decoder.py | 195 + .../dialogue_state_tracking/sgd_encoder.py | 77 + tts/nemo/collections/nlp/parts/__init__.py | 16 + .../collections/nlp/parts/nlp_overrides.py | 233 + tts/nemo/collections/nlp/parts/utils_funcs.py | 130 + tts/nemo/collections/tts/__init__.py | 17 + tts/nemo/collections/tts/data/__init__.py | 15 + tts/nemo/collections/tts/data/datalayers.py | 768 + tts/nemo/collections/tts/helpers/__init__.py | 15 + tts/nemo/collections/tts/helpers/helpers.py | 362 + tts/nemo/collections/tts/losses/__init__.py | 16 + .../collections/tts/losses/aligner_loss.py | 89 + .../collections/tts/losses/fastpitchloss.py | 150 + .../collections/tts/losses/fastspeech2loss.py | 127 + .../collections/tts/losses/glow_tts_loss.py | 81 + .../collections/tts/losses/hifigan_losses.py | 132 + tts/nemo/collections/tts/losses/stftlosses.py | 248 + .../collections/tts/losses/tacotron2loss.py | 84 + .../collections/tts/losses/uniglowloss.py | 58 + .../collections/tts/losses/waveglowloss.py | 51 + tts/nemo/collections/tts/models/__init__.py | 53 + tts/nemo/collections/tts/models/aligner.py | 157 + tts/nemo/collections/tts/models/base.py | 305 + tts/nemo/collections/tts/models/degli.py | 330 + .../collections/tts/models/ed_mel2spec.py | 321 + tts/nemo/collections/tts/models/fastpitch.py | 414 + .../tts/models/fastpitch_hifigan_e2e.py | 432 + .../collections/tts/models/fastspeech2.py | 297 + .../tts/models/fastspeech2_hifigan_e2e.py | 430 + tts/nemo/collections/tts/models/glow_tts.py | 279 + tts/nemo/collections/tts/models/hifigan.py | 357 + tts/nemo/collections/tts/models/melgan.py | 338 + .../collections/tts/models/squeezewave.py | 227 + tts/nemo/collections/tts/models/tacotron2.py | 321 + tts/nemo/collections/tts/models/talknet.py | 413 + tts/nemo/collections/tts/models/two_stages.py | 205 + tts/nemo/collections/tts/models/uniglow.py | 264 + tts/nemo/collections/tts/models/waveglow.py | 260 + tts/nemo/collections/tts/modules/__init__.py | 27 + tts/nemo/collections/tts/modules/aligner.py | 106 + tts/nemo/collections/tts/modules/degli.py | 617 + .../collections/tts/modules/ed_mel2spec.py | 261 + tts/nemo/collections/tts/modules/fastpitch.py | 309 + .../collections/tts/modules/fastspeech2.py | 314 + .../tts/modules/fastspeech2_submodules.py | 160 + tts/nemo/collections/tts/modules/glow_tts.py | 441 + .../tts/modules/glow_tts_parser.py | 364 + .../tts/modules/glow_tts_submodules.py | 645 + .../tts/modules/hifigan_modules.py | 447 + .../collections/tts/modules/melgan_modules.py | 508 + .../collections/tts/modules/squeezewave.py | 212 + .../tts/modules/squeezewave_submodules.py | 151 + .../collections/tts/modules/submodules.py | 297 + tts/nemo/collections/tts/modules/tacotron2.py | 442 + tts/nemo/collections/tts/modules/talknet.py | 136 + .../collections/tts/modules/transformer.py | 262 + tts/nemo/collections/tts/modules/uniglow.py | 177 + tts/nemo/collections/tts/modules/waveglow.py | 263 + tts/nemo/constants.py | 18 + tts/nemo/core/__init__.py | 16 + tts/nemo/core/classes/__init__.py | 29 + tts/nemo/core/classes/common.py | 812 + tts/nemo/core/classes/dataset.py | 109 + tts/nemo/core/classes/exportable.py | 308 + tts/nemo/core/classes/loss.py | 26 + tts/nemo/core/classes/modelPT.py | 1419 ++ tts/nemo/core/classes/module.py | 77 + tts/nemo/core/config/__init__.py | 47 + tts/nemo/core/config/base_config.py | 30 + tts/nemo/core/config/hydra_runner.py | 110 + tts/nemo/core/config/modelPT.py | 181 + tts/nemo/core/config/optimizers.py | 265 + tts/nemo/core/config/pytorch.py | 45 + tts/nemo/core/config/pytorch_lightning.py | 97 + tts/nemo/core/config/schedulers.py | 251 + tts/nemo/core/neural_types/__init__.py | 19 + tts/nemo/core/neural_types/axes.py | 101 + tts/nemo/core/neural_types/comparison.py | 32 + tts/nemo/core/neural_types/elements.py | 324 + tts/nemo/core/neural_types/neural_type.py | 243 + tts/nemo/core/optim/__init__.py | 29 + tts/nemo/core/optim/lr_scheduler.py | 686 + tts/nemo/core/optim/novograd.py | 145 + tts/nemo/core/optim/optimizers.py | 171 + tts/nemo/core/utils/__init__.py | 15 + tts/nemo/core/utils/numba_utils.py | 142 + tts/nemo/package_info.py | 35 + tts/nemo/utils/__init__.py | 22 + tts/nemo/utils/app_state.py | 386 + tts/nemo/utils/arguments.py | 132 + tts/nemo/utils/cloud.py | 82 + tts/nemo/utils/config_utils.py | 258 + tts/nemo/utils/decorators/__init__.py | 18 + tts/nemo/utils/decorators/deprecated.py | 72 + tts/nemo/utils/decorators/experimental.py | 33 + tts/nemo/utils/decorators/port_docs.py | 90 + tts/nemo/utils/env_var_parsing.py | 207 + tts/nemo/utils/exceptions.py | 19 + tts/nemo/utils/exp_manager.py | 715 + tts/nemo/utils/export_utils.py | 225 + tts/nemo/utils/formatters/__init__.py | 13 + tts/nemo/utils/formatters/base.py | 135 + tts/nemo/utils/formatters/colors.py | 121 + tts/nemo/utils/formatters/utils.py | 46 + tts/nemo/utils/get_rank.py | 48 + tts/nemo/utils/lightning_logger_patch.py | 58 + tts/nemo/utils/metaclasses.py | 39 + tts/nemo/utils/model_utils.py | 528 + tts/nemo/utils/nemo_logging.py | 421 + tts/requirements-tacotron-python36.txt | 58 + tts/requirements-talknet-python36-38.txt | 75 + tts/tacotron2/.gitmodules | 4 + tts/tacotron2/Dockerfile | 10 + tts/tacotron2/LICENSE | 29 + tts/tacotron2/README.md | 81 + tts/tacotron2/__init__.py | 0 tts/tacotron2/audio_processing.py | 93 + tts/tacotron2/data_utils.py | 111 + tts/tacotron2/distributed.py | 173 + tts/tacotron2/fp16_optimizer.py | 381 + tts/tacotron2/hparams.py | 95 + tts/tacotron2/inference.ipynb | 266 + tts/tacotron2/inference.py | 151 + tts/tacotron2/layers.py | 80 + tts/tacotron2/logger.py | 48 + tts/tacotron2/loss_function.py | 19 + tts/tacotron2/loss_scaler.py | 131 + tts/tacotron2/model.py | 529 + tts/tacotron2/multiproc.py | 23 + tts/tacotron2/plotting_utils.py | 61 + .../requirements-nvidia-original.txt | 9 + tts/tacotron2/stft.py | 141 + tts/tacotron2/text/LICENSE | 19 + tts/tacotron2/text/__init__.py | 74 + tts/tacotron2/text/cleaners.py | 90 + tts/tacotron2/text/cmudict.py | 65 + tts/tacotron2/text/numbers.py | 71 + tts/tacotron2/text/symbols.py | 18 + tts/tacotron2/train.py | 290 + tts/tacotron2/utils.py | 29 + tts/vocodes_common.py | 335 + tts/vocodes_inference.py | 232 + tts/vocodes_model_check_tacotron.py | 62 + tts/vocodes_model_check_talknet.py | 66 + tts/vocodes_server.py | 271 + tts/vocodes_server_talknet.py | 283 + tts/vocodes_wav_images.py | 49 + tts/waveglow/.gitmodules | 3 + tts/waveglow/LICENSE | 29 + tts/waveglow/README.md | 91 + tts/waveglow/config.json | 41 + tts/waveglow/convert_model.py | 72 + tts/waveglow/denoiser.py | 40 + tts/waveglow/distributed.py | 184 + tts/waveglow/glow.py | 311 + tts/waveglow/glow_old.py | 233 + tts/waveglow/inference.py | 84 + tts/waveglow/mel2samp.py | 142 + tts/waveglow/requirements.txt | 10 + tts/waveglow/train.py | 188 + 1058 files changed, 192192 insertions(+) create mode 100644 future-todo/ControllableTalkNet/Dockerfile create mode 100644 future-todo/ControllableTalkNet/LICENSE create mode 100644 future-todo/ControllableTalkNet/README.md create mode 100644 future-todo/ControllableTalkNet/TalkNet_Training_Offline.ipynb create mode 100644 future-todo/ControllableTalkNet/__init__.py create mode 100644 future-todo/ControllableTalkNet/assets/dash_customfont.css create mode 100644 future-todo/ControllableTalkNet/controllable_talknet.py create mode 100644 future-todo/ControllableTalkNet/diffsvc_gui.py create mode 100644 future-todo/ControllableTalkNet/model_lists/sortanon_models.json create mode 100644 future-todo/ControllableTalkNet/mycroft_talknet.py create mode 100644 future-todo/ControllableTalkNet/requirements.txt create mode 100644 future-todo/ControllableTalkNet/talknet_offline.py create mode 100644 future-todo/ControllableTalkNet/talknet_singer.py create mode 100644 future-todo/README.md create mode 100644 future-todo/vocodes_common_talknet.py create mode 100644 tts/NeMo/.dockerignore create mode 100644 tts/NeMo/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 tts/NeMo/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 tts/NeMo/.gitignore create mode 100644 tts/NeMo/.readthedocs.yml create mode 100644 tts/NeMo/CONTRIBUTING.md create mode 100644 tts/NeMo/Dockerfile create mode 100644 tts/NeMo/Jenkinsfile create mode 100644 tts/NeMo/LICENSE create mode 100644 tts/NeMo/README.rst create mode 100644 tts/NeMo/__init__.py create mode 100644 tts/NeMo/docs/.nojekyll create mode 100644 tts/NeMo/docs/Makefile create mode 100644 tts/NeMo/docs/source/_static/css/custom.css create mode 100644 tts/NeMo/docs/source/_static/js/pk_scripts.js create mode 100644 tts/NeMo/docs/source/asr/api.rst create mode 100644 tts/NeMo/docs/source/asr/asr_all.bib create mode 100644 tts/NeMo/docs/source/asr/asr_language_modeling.rst create mode 100644 tts/NeMo/docs/source/asr/configs.rst create mode 100644 tts/NeMo/docs/source/asr/data/asr_results.csv create mode 100644 tts/NeMo/docs/source/asr/data/asrlm_results.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_ca.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_de.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_en.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_es.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_fr.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_it.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_pl.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_ru.csv create mode 100644 tts/NeMo/docs/source/asr/data/benchmark_zh.csv create mode 100644 tts/NeMo/docs/source/asr/datasets.rst create mode 100644 tts/NeMo/docs/source/asr/images/citrinet_vertical.png create mode 100644 tts/NeMo/docs/source/asr/images/conformer_ctc.png create mode 100644 tts/NeMo/docs/source/asr/images/ctc_asr.png create mode 100644 tts/NeMo/docs/source/asr/images/jasper_layers.png create mode 100644 tts/NeMo/docs/source/asr/images/jasper_vertical.png create mode 100644 tts/NeMo/docs/source/asr/images/quartz_vertical.png create mode 100644 tts/NeMo/docs/source/asr/intro.rst create mode 100644 tts/NeMo/docs/source/asr/models.rst create mode 100644 tts/NeMo/docs/source/asr/results.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/api.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/configs.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/data/diarization_results.csv create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/datasets.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/images/sd_pipeline.png create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/intro.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/models.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_diarization/results.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/configs.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/data/speaker_results.csv create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/datasets.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/images/ICASPP_SpeakerNet.png create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/intro.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/models.rst create mode 100644 tts/NeMo/docs/source/asr/speaker_recognition/results.rst create mode 100644 tts/NeMo/docs/source/asr/speech_classification/configs.rst create mode 100644 tts/NeMo/docs/source/asr/speech_classification/data/classification_results.csv create mode 100644 tts/NeMo/docs/source/asr/speech_classification/datasets.rst create mode 100644 tts/NeMo/docs/source/asr/speech_classification/images/marblenet_vertical.png create mode 100644 tts/NeMo/docs/source/asr/speech_classification/images/matchboxnet_vertical.png create mode 100644 tts/NeMo/docs/source/asr/speech_classification/intro.rst create mode 100644 tts/NeMo/docs/source/asr/speech_classification/models.rst create mode 100644 tts/NeMo/docs/source/asr/speech_classification/results.rst create mode 100644 tts/NeMo/docs/source/common/intro.rst create mode 100644 tts/NeMo/docs/source/conf.py create mode 100644 tts/NeMo/docs/source/core/core.rst create mode 100644 tts/NeMo/docs/source/core/whyntypes.gif create mode 100644 tts/NeMo/docs/source/favicon.ico create mode 100644 tts/NeMo/docs/source/index.rst create mode 100755 tts/NeMo/docs/source/nemo_text_processing/api.rst create mode 100644 tts/NeMo/docs/source/nemo_text_processing/intro.rst create mode 100644 tts/NeMo/docs/source/nemo_text_processing/inverse_text_normalization.rst create mode 100644 tts/NeMo/docs/source/nemo_text_processing/text_normalization.rst create mode 100644 tts/NeMo/docs/source/nemo_text_processing/textprocessing_all.bib create mode 100755 tts/NeMo/docs/source/nlp/api.rst create mode 100755 tts/NeMo/docs/source/nlp/bert_pretraining.rst create mode 100644 tts/NeMo/docs/source/nlp/glue_benchmark.rst create mode 100644 tts/NeMo/docs/source/nlp/information_retrieval.rst create mode 100755 tts/NeMo/docs/source/nlp/intro.rst create mode 100644 tts/NeMo/docs/source/nlp/joint_intent_slot.rst create mode 100644 tts/NeMo/docs/source/nlp/language_modeling.rst create mode 100644 tts/NeMo/docs/source/nlp/machine_translation.rst create mode 100644 tts/NeMo/docs/source/nlp/megatron_finetuning.rst create mode 100755 tts/NeMo/docs/source/nlp/models.rst create mode 100644 tts/NeMo/docs/source/nlp/nlp_all.bib create mode 100755 tts/NeMo/docs/source/nlp/nlp_model.rst create mode 100755 tts/NeMo/docs/source/nlp/punctuation_and_capitalization.rst create mode 100644 tts/NeMo/docs/source/nlp/question_answering.rst create mode 100644 tts/NeMo/docs/source/nlp/sgd_qa.rst create mode 100644 tts/NeMo/docs/source/nlp/text_classification.rst create mode 100755 tts/NeMo/docs/source/nlp/token_classification.rst create mode 100644 tts/NeMo/docs/source/nv_logo.png create mode 100644 tts/NeMo/docs/source/starthere/best-practices.rst create mode 100644 tts/NeMo/docs/source/starthere/intro.rst create mode 100644 tts/NeMo/docs/source/starthere/tutorials.rst create mode 100644 tts/NeMo/docs/source/tools/ctc_segmentation.rst create mode 100644 tts/NeMo/docs/source/tools/intro.rst create mode 100644 tts/NeMo/docs/source/tools/speech_data_explorer.rst create mode 100644 tts/NeMo/docs/source/tools/text_processing_deployment.rst create mode 100644 tts/NeMo/docs/source/tools/tools_all.bib create mode 100644 tts/NeMo/docs/source/tts/api.rst create mode 100644 tts/NeMo/docs/source/tts/datasets.rst create mode 100644 tts/NeMo/docs/source/tts/intro.rst create mode 100755 tts/NeMo/docs/update_docs_docker.sh create mode 100644 tts/NeMo/examples/asr/asr_webapp/Dockerfile create mode 100644 tts/NeMo/examples/asr/asr_webapp/README.rst create mode 100644 tts/NeMo/examples/asr/asr_webapp/asr_service.py create mode 100644 tts/NeMo/examples/asr/asr_webapp/docker_container_build.sh create mode 100644 tts/NeMo/examples/asr/asr_webapp/docker_container_run.sh create mode 100644 tts/NeMo/examples/asr/asr_webapp/gunicorn.conf.py create mode 100644 tts/NeMo/examples/asr/asr_webapp/model_api.py create mode 100644 tts/NeMo/examples/asr/asr_webapp/requirements.txt create mode 100644 tts/NeMo/examples/asr/asr_webapp/templates/main.html create mode 100644 tts/NeMo/examples/asr/asr_webapp/templates/toast_msg.html create mode 100644 tts/NeMo/examples/asr/asr_webapp/templates/transcripts.html create mode 100644 tts/NeMo/examples/asr/asr_webapp/templates/updates/remove_files.html create mode 100644 tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_failed.html create mode 100644 tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_successful.html create mode 100644 tts/NeMo/examples/asr/asr_webapp/wsgi.py create mode 100644 tts/NeMo/examples/asr/conf/citrinet/citrinet_384.yaml create mode 100644 tts/NeMo/examples/asr/conf/citrinet/citrinet_512.yaml create mode 100644 tts/NeMo/examples/asr/conf/citrinet/config_bpe.yaml create mode 100644 tts/NeMo/examples/asr/conf/config.yaml create mode 100644 tts/NeMo/examples/asr/conf/conformer/conformer_ctc_bpe.yaml create mode 100644 tts/NeMo/examples/asr/conf/conformer/conformer_ctc_char.yaml create mode 100644 tts/NeMo/examples/asr/conf/jasper/jasper_10x5dr.yaml create mode 100644 tts/NeMo/examples/asr/conf/marblenet/marblenet_3x2x64.yaml create mode 100644 tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v1.yaml create mode 100644 tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v2.yaml create mode 100644 tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5.yaml create mode 100644 tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5_zh.yaml create mode 100644 tts/NeMo/examples/asr/experimental/conformer/conformer_rnnt_bpe.yaml create mode 100644 tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt.yaml create mode 100644 tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt_bpe.yaml create mode 100644 tts/NeMo/examples/asr/experimental/quartznet/quartznet_15x5_aug.yaml create mode 100644 tts/NeMo/examples/asr/experimental/sclite/speech_to_text_sclite.py create mode 100644 tts/NeMo/examples/asr/experimental/structured/conf/quartznet_15x5.yaml create mode 100644 tts/NeMo/examples/asr/experimental/structured/speech_to_text_hybrid.py create mode 100644 tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured.py create mode 100644 tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured_v2.py create mode 100644 tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain.yaml create mode 100644 tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain_large.yaml create mode 100644 tts/NeMo/examples/asr/experimental/wav2vec/wav2vec_pretrain.py create mode 100644 tts/NeMo/examples/asr/quantization/speech_to_text_calibrate.py create mode 100644 tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer.py create mode 100644 tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer_trt.py create mode 100644 tts/NeMo/examples/asr/speech_to_label.py create mode 100644 tts/NeMo/examples/asr/speech_to_text.py create mode 100644 tts/NeMo/examples/asr/speech_to_text_bpe.py create mode 100644 tts/NeMo/examples/asr/speech_to_text_infer.py create mode 100644 tts/NeMo/examples/asr/speech_to_text_rnnt.py create mode 100644 tts/NeMo/examples/asr/speech_to_text_rnnt_bpe.py create mode 100644 tts/NeMo/examples/asr/transcribe_speech.py create mode 100644 tts/NeMo/examples/asr/vad_infer.py create mode 100644 tts/NeMo/examples/cv/mnist_lenet5_image_classification_pure_lightning.py create mode 100644 tts/NeMo/examples/nlp/dialogue_state_tracking/conf/sgdqa_config.yaml create mode 100644 tts/NeMo/examples/nlp/dialogue_state_tracking/sgd_qa.py create mode 100644 tts/NeMo/examples/nlp/entity_linking/build_index.py create mode 100644 tts/NeMo/examples/nlp/entity_linking/conf/tiny_example_entity_linking_config.yaml create mode 100644 tts/NeMo/examples/nlp/entity_linking/conf/umls_medical_entity_linking_config.yaml create mode 100644 tts/NeMo/examples/nlp/entity_linking/data/umls_dataset_processing.py create mode 100644 tts/NeMo/examples/nlp/entity_linking/query_index.py create mode 100644 tts/NeMo/examples/nlp/entity_linking/self_alignment_pretraining.py create mode 100644 tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark.py create mode 100644 tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark_config.yaml create mode 100644 tts/NeMo/examples/nlp/information_retrieval/bert_dpr.py create mode 100644 tts/NeMo/examples/nlp/information_retrieval/bert_joint_ir.py create mode 100644 tts/NeMo/examples/nlp/information_retrieval/conf/bert_ir_config.yaml create mode 100644 tts/NeMo/examples/nlp/information_retrieval/construct_random_negatives.py create mode 100644 tts/NeMo/examples/nlp/information_retrieval/get_msmarco.sh create mode 100644 tts/NeMo/examples/nlp/intent_slot_classification/conf/intent_slot_classification_config.yaml create mode 100644 tts/NeMo/examples/nlp/intent_slot_classification/data/assistant_utils.py create mode 100755 tts/NeMo/examples/nlp/intent_slot_classification/data/import_datasets.py create mode 100644 tts/NeMo/examples/nlp/intent_slot_classification/intent_slot_classification.py create mode 100644 tts/NeMo/examples/nlp/language_modeling/bert_pretraining.py create mode 100644 tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_preprocessed_config.yaml create mode 100644 tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_text_config.yaml create mode 100644 tts/NeMo/examples/nlp/language_modeling/conf/transformer_lm_config.yaml create mode 100644 tts/NeMo/examples/nlp/language_modeling/convert_weights_to_nemo1.0.py create mode 100644 tts/NeMo/examples/nlp/language_modeling/get_wkt2.sh create mode 100644 tts/NeMo/examples/nlp/language_modeling/transformer_lm.py create mode 100644 tts/NeMo/examples/nlp/machine_translation/conf/aayn_base.yaml create mode 100644 tts/NeMo/examples/nlp/machine_translation/conf/huggingface.yaml create mode 100644 tts/NeMo/examples/nlp/machine_translation/create_tarred_monolingual_dataset.py create mode 100644 tts/NeMo/examples/nlp/machine_translation/create_tarred_parallel_dataset.py create mode 100644 tts/NeMo/examples/nlp/machine_translation/enc_dec_nmt.py create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_transformer_infer.py create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_webapp/README.rst create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_webapp/config.json create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_webapp/index.html create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_webapp/nmt_service.py create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_webapp/requirements.txt create mode 100644 tts/NeMo/examples/nlp/machine_translation/nmt_webapp/style.css create mode 100644 tts/NeMo/examples/nlp/machine_translation/translate_ddp.py create mode 100644 tts/NeMo/examples/nlp/question_answering/conf/question_answering_squad_config.yaml create mode 100755 tts/NeMo/examples/nlp/question_answering/get_squad.py create mode 100644 tts/NeMo/examples/nlp/question_answering/question_answering_squad.py create mode 100644 tts/NeMo/examples/nlp/text2sparql/conf/text2sparql_config.yaml create mode 100644 tts/NeMo/examples/nlp/text2sparql/data/import_datasets.py create mode 100644 tts/NeMo/examples/nlp/text2sparql/evaluate_text2sparql.py create mode 100644 tts/NeMo/examples/nlp/text2sparql/text2sparql.py create mode 100644 tts/NeMo/examples/nlp/text_classification/conf/text_classification_config.yaml create mode 100644 tts/NeMo/examples/nlp/text_classification/data/import_datasets.py create mode 100644 tts/NeMo/examples/nlp/text_classification/model_parallel_text_classification_evaluation.py create mode 100644 tts/NeMo/examples/nlp/text_classification/text_classification_with_bert.py create mode 100644 tts/NeMo/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml create mode 100644 tts/NeMo/examples/nlp/token_classification/conf/token_classification_config.yaml create mode 100644 tts/NeMo/examples/nlp/token_classification/data/get_tatoeba_data.py create mode 100644 tts/NeMo/examples/nlp/token_classification/data/import_from_iob_format.py create mode 100644 tts/NeMo/examples/nlp/token_classification/data/prepare_data_for_punctuation_capitalization.py create mode 100644 tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_evaluate.py create mode 100644 tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_train.py create mode 100644 tts/NeMo/examples/nlp/token_classification/token_classification_evaluate.py create mode 100644 tts/NeMo/examples/nlp/token_classification/token_classification_train.py create mode 100644 tts/NeMo/examples/speaker_recognition/README.md create mode 100644 tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_recognition_3x2x512.yaml create mode 100644 tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_verification_3x2x512.yaml create mode 100644 tts/NeMo/examples/speaker_recognition/conf/speaker_diarization.yaml create mode 100644 tts/NeMo/examples/speaker_recognition/extract_speaker_embeddings.py create mode 100644 tts/NeMo/examples/speaker_recognition/speaker_diarize.py create mode 100644 tts/NeMo/examples/speaker_recognition/speaker_reco.py create mode 100644 tts/NeMo/examples/speaker_recognition/speaker_reco_finetune.py create mode 100644 tts/NeMo/examples/speaker_recognition/speaker_reco_infer.py create mode 100644 tts/NeMo/examples/speaker_recognition/voxceleb_eval.py create mode 100644 tts/NeMo/examples/tts/aligner.py create mode 100644 tts/NeMo/examples/tts/conf/aligner.yaml create mode 100644 tts/NeMo/examples/tts/conf/degli.yaml create mode 100755 tts/NeMo/examples/tts/conf/ed_mel2spec.yaml create mode 100644 tts/NeMo/examples/tts/conf/fastpitch.yaml create mode 100644 tts/NeMo/examples/tts/conf/fastpitch_align.yaml create mode 100644 tts/NeMo/examples/tts/conf/fastpitch_hifigan_e2e.yaml create mode 100644 tts/NeMo/examples/tts/conf/fastspeech2.yaml create mode 100644 tts/NeMo/examples/tts/conf/fastspeech2_hifigan_e2e.yaml create mode 100644 tts/NeMo/examples/tts/conf/glow_tts.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/hifigan.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/generator/v1.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/generator/v2.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/generator/v3.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds_finetune.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds.yaml create mode 100644 tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds_finetune.yaml create mode 100644 tts/NeMo/examples/tts/conf/melgan.yaml create mode 100644 tts/NeMo/examples/tts/conf/squeezewave.yaml create mode 100644 tts/NeMo/examples/tts/conf/tacotron2.yaml create mode 100644 tts/NeMo/examples/tts/conf/talknet-durs.yaml create mode 100644 tts/NeMo/examples/tts/conf/talknet-pitch.yaml create mode 100644 tts/NeMo/examples/tts/conf/talknet-spect.yaml create mode 100644 tts/NeMo/examples/tts/conf/uniglow.yaml create mode 100644 tts/NeMo/examples/tts/conf/waveglow.yaml create mode 100755 tts/NeMo/examples/tts/degli.py create mode 100755 tts/NeMo/examples/tts/ed_mel2spec.py create mode 100644 tts/NeMo/examples/tts/fastpitch.py create mode 100644 tts/NeMo/examples/tts/fastpitch_hifigan_e2e.py create mode 100644 tts/NeMo/examples/tts/fastspeech2.py create mode 100644 tts/NeMo/examples/tts/fastspeech2_hifigan_e2e.py create mode 100644 tts/NeMo/examples/tts/glow_tts.py create mode 100644 tts/NeMo/examples/tts/hifigan.py create mode 100644 tts/NeMo/examples/tts/melgan.py create mode 100755 tts/NeMo/examples/tts/squeezewave.py create mode 100755 tts/NeMo/examples/tts/tacotron2.py create mode 100644 tts/NeMo/examples/tts/talknet_durs.py create mode 100644 tts/NeMo/examples/tts/talknet_pitch.py create mode 100644 tts/NeMo/examples/tts/talknet_spect.py create mode 100644 tts/NeMo/examples/tts/test_tts_infer.py create mode 100755 tts/NeMo/examples/tts/uniglow.py create mode 100755 tts/NeMo/examples/tts/waveglow.py create mode 100644 tts/NeMo/external/get_collections.py create mode 100644 tts/NeMo/external/get_modules.py create mode 100644 tts/NeMo/nemo_text_processing/README.md create mode 100644 tts/NeMo/nemo_text_processing/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/README.md create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/clean_eval_data.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/currency.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/domain.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/server_name.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/magnitudes.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/measurements.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/months.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/digit.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/hundred.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/teen.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/thousands.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/ties.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/zero.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/digit.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/teen.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_suffix.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_to.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_zone.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/data/whitelist.tsv create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/inverse_normalize.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/run_evaluate.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/run_predict.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/cardinal.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/date.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/decimal.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/electronic.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/fraction.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/measure.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/money.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/ordinal.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/punctuation.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/telephone.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/time.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/tokenize_and_classify.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/whitelist.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/word.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/utils.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/cardinal.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/date.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/decimal.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/electronic.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/fraction.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/measure.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/money.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/ordinal.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/telephone.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/time.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize_final.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/whitelist.py create mode 100644 tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/word.py create mode 100644 tts/NeMo/nemo_text_processing/setup.sh create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/README.md create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/clean_eval_data.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/currency/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor_one.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/electronic/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/electronic/domain.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/electronic/server_name.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/electronic/symbols.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/letter_pronunciation.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/magnitudes.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/measurements.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/months/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/months/abbr.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/months/names.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/months/numbers.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/__init__.py create mode 100755 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/cardinal_number_name.far create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/digit.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/hundred.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/teen.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/thousands.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/ties.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/numbers/zero.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/digit.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/teen.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/roman/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/roman/digit_teen.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/roman/hundreds.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/roman/ties.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/suppletive.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/time_suffix.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/time_zone.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/whitelist.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data/whitelist_alternatives.tsv create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/data_loader_utils.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/graph_utils.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/normalize.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/normalize_with_audio.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/run_evaluate.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/run_predict.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/cardinal.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/date.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/decimal.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/electronic.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/fraction.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/measure.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/money.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/ordinal.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/punctuation.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/roman.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/telephone.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/time.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/tokenize_and_classify.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/whitelist.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/taggers/word.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/token_parser.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/__init__.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/cardinal.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/date.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/decimal.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/electronic.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/fraction.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/measure.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/money.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/ordinal.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/roman.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/telephone.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/time.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize_final.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/whitelist.py create mode 100644 tts/NeMo/nemo_text_processing/text_normalization/verbalizers/word.py create mode 100755 tts/NeMo/reinstall.sh create mode 100644 tts/NeMo/requirements/requirements.txt create mode 100644 tts/NeMo/requirements/requirements_asr.txt create mode 100644 tts/NeMo/requirements/requirements_cv.txt create mode 100644 tts/NeMo/requirements/requirements_docs.txt create mode 100644 tts/NeMo/requirements/requirements_nlp.txt create mode 100644 tts/NeMo/requirements/requirements_test.txt create mode 100644 tts/NeMo/requirements/requirements_text_processing.txt create mode 100644 tts/NeMo/requirements/requirements_tts.txt create mode 100644 tts/NeMo/scripts/asr_language_modeling/neural_rescorer/create_tarred_transformer_lm_dataset.py create mode 100644 tts/NeMo/scripts/asr_language_modeling/neural_rescorer/eval_neural_rescorer.py create mode 100644 tts/NeMo/scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py create mode 100644 tts/NeMo/scripts/asr_language_modeling/ngram_lm/install_beamsearch_decoders.sh create mode 100644 tts/NeMo/scripts/asr_language_modeling/ngram_lm/kenlm_utils.py create mode 100644 tts/NeMo/scripts/asr_language_modeling/ngram_lm/train_kenlm.py create mode 100644 tts/NeMo/scripts/average_model_checkpoints.py create mode 100644 tts/NeMo/scripts/dataset_processing/get_commonvoice_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/get_hi-mia_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/get_librispeech_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/get_openslr_rir_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/ljspeech/README create mode 100644 tts/NeMo/scripts/dataset_processing/ljspeech/calculate_durs.py create mode 100644 tts/NeMo/scripts/dataset_processing/ljspeech/create_manifests_and_textfiles.py create mode 100644 tts/NeMo/scripts/dataset_processing/ljspeech/create_token2idx_dict.py create mode 100644 tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_energy_pitch.py create mode 100755 tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_phonemes_and_durs.sh create mode 100644 tts/NeMo/scripts/dataset_processing/process_an4_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/process_degli_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/process_hub5_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/process_speech_commands_data.py create mode 100644 tts/NeMo/scripts/dataset_processing/process_vad_data.py create mode 100644 tts/NeMo/scripts/export/convasr_to_enemo.py create mode 100644 tts/NeMo/scripts/export/convasr_to_onnx.py create mode 100644 tts/NeMo/scripts/export/convasr_to_single_onnx.py create mode 100644 tts/NeMo/scripts/freesound_download_resample/download_resample_freesound.sh create mode 100644 tts/NeMo/scripts/freesound_download_resample/freesound_download.py create mode 100644 tts/NeMo/scripts/freesound_download_resample/freesound_requirements.txt create mode 100644 tts/NeMo/scripts/freesound_download_resample/freesound_resample.py create mode 100644 tts/NeMo/scripts/nemo_legacy_import/asr_checkpoint_port.py create mode 100644 tts/NeMo/scripts/neural_machine_translation/filter_langs_nmt.py create mode 100644 tts/NeMo/scripts/speaker_recognition/rttm_to_manifest.py create mode 100644 tts/NeMo/scripts/speaker_recognition/scp_to_manifest.py create mode 100644 tts/NeMo/scripts/speech_recognition/convert_to_tarred_audio_dataset.py create mode 100644 tts/NeMo/scripts/tokenizers/process_asr_text_tokenizer.py create mode 100644 tts/NeMo/scripts/voice_activity_detection/vad_overlap_posterior.py create mode 100644 tts/NeMo/scripts/voice_activity_detection/vad_tune_threshold.py create mode 100644 tts/NeMo/scripts/voice_activity_detection/write_long_audio_manifest.py create mode 100644 tts/NeMo/setup.cfg create mode 100644 tts/NeMo/setup.py create mode 100644 tts/NeMo/tests/__init__.py create mode 100644 tts/NeMo/tests/collections/asr/numba/rnnt_loss/test_rnnt_pytorch.py create mode 100644 tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_gpu_rnnt_kernel.py create mode 100644 tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_reduce.py create mode 100644 tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_rnnt_helper.py create mode 100644 tts/NeMo/tests/collections/asr/numba/spec_augment/test_spec_aug_numba.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_classification_model.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_ctc_encoder_model_bpe.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_ctcencdec_model.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_datasets.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_exportables.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_filterbankfeatures_seq_len.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_metrics.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_modules.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_regression_model.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_rnnt_encdec_model.py create mode 100644 tts/NeMo/tests/collections/asr/test_asr_rnnt_encoder_model_bpe.py create mode 100644 tts/NeMo/tests/collections/asr/test_jasper_block.py create mode 100644 tts/NeMo/tests/collections/asr/test_label_datasets.py create mode 100644 tts/NeMo/tests/collections/asr/test_speaker_label_models.py create mode 100644 tts/NeMo/tests/collections/common/__init__.py create mode 100644 tts/NeMo/tests/collections/common/loss_inputs.py create mode 100644 tts/NeMo/tests/collections/common/perplexity_inputs.py create mode 100644 tts/NeMo/tests/collections/common/pl_utils.py create mode 100644 tts/NeMo/tests/collections/common/test_metrics.py create mode 100644 tts/NeMo/tests/collections/common/test_spc_tokenizer.py create mode 100644 tts/NeMo/tests/collections/nlp/test_classification_report.py create mode 100644 tts/NeMo/tests/collections/nlp/test_entity_linking_model.py create mode 100644 tts/NeMo/tests/collections/nlp/test_huggingface.py create mode 100644 tts/NeMo/tests/collections/nlp/test_megatron.py create mode 100644 tts/NeMo/tests/collections/nlp/test_nlp_exportables.py create mode 100644 tts/NeMo/tests/collections/nlp/test_nmt_model.py create mode 100644 tts/NeMo/tests/collections/nlp/test_pretrained_models_performance.py create mode 100644 tts/NeMo/tests/collections/tts/test_tts_datasets.py create mode 100644 tts/NeMo/tests/collections/tts/test_tts_exportables.py create mode 100644 tts/NeMo/tests/collections/tts/test_waveglow.py create mode 100644 tts/NeMo/tests/conftest.py create mode 100644 tts/NeMo/tests/core/test_config_utils.py create mode 100644 tts/NeMo/tests/core/test_exp_manager.py create mode 100644 tts/NeMo/tests/core/test_fileio.py create mode 100644 tts/NeMo/tests/core/test_neural_types.py create mode 100644 tts/NeMo/tests/core/test_optimizers_schedulers.py create mode 100644 tts/NeMo/tests/core/test_save_restore.py create mode 100644 tts/NeMo/tests/core/test_serialization.py create mode 100644 tts/NeMo/tests/core/test_typecheck.py create mode 100644 tts/NeMo/tests/core_ptl/check_for_ranks.py create mode 100644 tts/NeMo/tests/hydra/config1.yaml create mode 100644 tts/NeMo/tests/hydra/config1_invalid.yaml create mode 100644 tts/NeMo/tests/hydra/config_subdir/config2.yaml create mode 100644 tts/NeMo/tests/hydra/config_subdir/config2_invalid.yaml create mode 100644 tts/NeMo/tests/hydra/my_app.py create mode 100644 tts/NeMo/tests/hydra/test_hydra_runner.py create mode 100644 tts/NeMo/tests/manualtest_model_downloads.py create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_cardinal.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_date.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_decimal.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_electronic.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_measure.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_money.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_ordinal.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_telephone.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_time.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_whitelist.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_word.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_boundary.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_cardinal.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_date.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_decimal.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_electronic.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_fraction.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_measure.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_money.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_normalize_with_audio.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_ordinal.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_telephone.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_time.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_whitelist.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_word.txt create mode 100644 tts/NeMo/tests/nemo_text_processing/test_boundary.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_cardinal.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_date.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_decimal.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_electronic.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_fraction.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_measure.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_money.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_normalization_with_audio.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_ordinal.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_inverse_text_normalization.sh create mode 100644 tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_normalization.sh create mode 100644 tts/NeMo/tests/nemo_text_processing/test_telephone.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_time.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_whitelist.py create mode 100644 tts/NeMo/tests/nemo_text_processing/test_word.py create mode 100644 tts/NeMo/tests/nemo_text_processing/utils.py create mode 100644 tts/NeMo/tests/test_data_dir.py create mode 100644 tts/NeMo/tools/ctc_segmentation/README.md create mode 100644 tts/NeMo/tools/ctc_segmentation/requirements.txt create mode 100644 tts/NeMo/tools/ctc_segmentation/run_sample.sh create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/cut_audio.py create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/normalization_helpers.py create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/prepare_data.py create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/process_manifests.py create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/run_ctc_segmentation.py create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/utils.py create mode 100644 tts/NeMo/tools/ctc_segmentation/scripts/verify_segments.py create mode 100644 tts/NeMo/tools/speech_data_explorer/README.md create mode 100755 tts/NeMo/tools/speech_data_explorer/data_explorer.py create mode 100644 tts/NeMo/tools/speech_data_explorer/requirements.txt create mode 100755 tts/NeMo/tools/speech_data_explorer/screenshot.png create mode 100644 tts/NeMo/tools/text_processing_deployment/Dockerfile create mode 100644 tts/NeMo/tools/text_processing_deployment/README.rst create mode 100644 tts/NeMo/tools/text_processing_deployment/docker/build.sh create mode 100644 tts/NeMo/tools/text_processing_deployment/docker/launch.sh create mode 100644 tts/NeMo/tools/text_processing_deployment/export_grammars.sh create mode 100644 tts/NeMo/tools/text_processing_deployment/pynini_export.py create mode 100644 tts/NeMo/tutorials/00_NeMo_Primer.ipynb create mode 100644 tts/NeMo/tutorials/01_NeMo_Models.ipynb create mode 100644 tts/NeMo/tutorials/AudioTranslationSample.ipynb create mode 100644 tts/NeMo/tutorials/VoiceSwapSample.ipynb create mode 100644 tts/NeMo/tutorials/asr/01_ASR_with_NeMo.ipynb create mode 100644 tts/NeMo/tutorials/asr/02_Online_ASR_Microphone_Demo.ipynb create mode 100644 tts/NeMo/tutorials/asr/03_Speech_Commands.ipynb create mode 100644 tts/NeMo/tutorials/asr/04_Online_Offline_Speech_Commands_Demo.ipynb create mode 100644 tts/NeMo/tutorials/asr/05_Online_Noise_Augmentation.ipynb create mode 100644 tts/NeMo/tutorials/asr/06_Voice_Activiy_Detection.ipynb create mode 100644 tts/NeMo/tutorials/asr/07_Online_Offline_Microphone_VAD_Demo.ipynb create mode 100644 tts/NeMo/tutorials/asr/08_ASR_with_Subword_Tokenization.ipynb create mode 100644 tts/NeMo/tutorials/asr/10_ASR_CTC_Language_Finetuning.ipynb create mode 100644 tts/NeMo/tutorials/asr/Offline_ASR.ipynb create mode 100644 tts/NeMo/tutorials/asr/images/alignment_example.png create mode 100644 tts/NeMo/tutorials/asr/images/vad_post_overlap_diagram.png create mode 100644 tts/NeMo/tutorials/nlp/01_Pretrained_Language_Models_for_Downstream_Tasks.ipynb create mode 100644 tts/NeMo/tutorials/nlp/02_NLP_Tokenizers.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Entity_Linking_Medical.ipynb create mode 100644 tts/NeMo/tutorials/nlp/GLUE_Benchmark.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Joint_Intent_and_Slot_Classification.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Neural_Machine_Translation-Text2Sparql.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Punctuation_and_Capitalization.ipynb create mode 100755 tts/NeMo/tutorials/nlp/Question_Answering_Squad.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Relation_Extraction-BioMegatron.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Text_Classification_Sentiment_Analysis.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Token_Classification-BioMegatron.ipynb create mode 100644 tts/NeMo/tutorials/nlp/Token_Classification_Named_Entity_Recognition.ipynb create mode 100644 tts/NeMo/tutorials/speaker_recognition/ASR_with_SpeakerDiarization.ipynb create mode 100644 tts/NeMo/tutorials/speaker_recognition/Speaker_Diarization_Inference.ipynb create mode 100644 tts/NeMo/tutorials/speaker_recognition/Speaker_Recognition_Verification.ipynb create mode 100755 tts/NeMo/tutorials/text_processing/Inverse_Text_Normalization.ipynb create mode 100755 tts/NeMo/tutorials/text_processing/Text_Normalization.ipynb create mode 100644 tts/NeMo/tutorials/text_processing/images/deployment.png create mode 100644 tts/NeMo/tutorials/text_processing/images/pipeline.png create mode 100644 tts/NeMo/tutorials/tools/CTC_Segmentation_Tutorial.ipynb create mode 100644 tts/NeMo/tutorials/tools/DefinedCrowd_x_NeMo_ASR_Training_Tutorial.ipynb create mode 100644 tts/NeMo/tutorials/tools/label-studio/setup-asr-preannotations.ipynb create mode 100644 tts/NeMo/tutorials/tts/1_TTS_inference.ipynb create mode 100644 tts/NeMo/tutorials/tts/2_TTS_Tacotron2_Training.ipynb create mode 100644 tts/NeMo/tutorials/tts/3_TTS_TalkNet_Training.ipynb create mode 100644 tts/__init__.py create mode 100644 tts/hifigan/LICENSE create mode 100644 tts/hifigan/README.md create mode 100644 tts/hifigan/__init__.py create mode 100644 tts/hifigan/audio_processing.py create mode 100644 tts/hifigan/config_32k.json create mode 100644 tts/hifigan/config_v1.json create mode 100644 tts/hifigan/config_v1b.json create mode 100644 tts/hifigan/config_v2.json create mode 100644 tts/hifigan/config_v3.json create mode 100644 tts/hifigan/denoiser.py create mode 100644 tts/hifigan/env.py create mode 100644 tts/hifigan/hifiutils.py create mode 100644 tts/hifigan/inference.py create mode 100644 tts/hifigan/inference_e2e.py create mode 100644 tts/hifigan/meldataset.py create mode 100644 tts/hifigan/models.py create mode 100644 tts/hifigan/requirements.txt create mode 100644 tts/hifigan/stft.py create mode 100644 tts/hifigan/train.py create mode 100644 tts/nemo/README.md create mode 100644 tts/nemo/__init__.py create mode 100644 tts/nemo/collections/__init__.py create mode 100644 tts/nemo/collections/asr/__init__.py create mode 100644 tts/nemo/collections/asr/data/__init__.py create mode 100644 tts/nemo/collections/asr/data/audio_to_label.py create mode 100644 tts/nemo/collections/asr/data/audio_to_label_dataset.py create mode 100644 tts/nemo/collections/asr/data/audio_to_text.py create mode 100644 tts/nemo/collections/asr/data/audio_to_text_dali.py create mode 100644 tts/nemo/collections/asr/data/audio_to_text_dataset.py create mode 100644 tts/nemo/collections/asr/data/feature_to_label.py create mode 100644 tts/nemo/collections/asr/data/feature_to_label_dataset.py create mode 100644 tts/nemo/collections/asr/data/vocabs.py create mode 100644 tts/nemo/collections/asr/losses/__init__.py create mode 100644 tts/nemo/collections/asr/losses/angularloss.py create mode 100644 tts/nemo/collections/asr/losses/ctc.py create mode 100644 tts/nemo/collections/asr/losses/rnnt.py create mode 100644 tts/nemo/collections/asr/losses/wav2vecloss.py create mode 100644 tts/nemo/collections/asr/metrics/__init__.py create mode 100644 tts/nemo/collections/asr/metrics/rnnt_wer.py create mode 100644 tts/nemo/collections/asr/metrics/rnnt_wer_bpe.py create mode 100644 tts/nemo/collections/asr/metrics/wer.py create mode 100644 tts/nemo/collections/asr/metrics/wer_bpe.py create mode 100644 tts/nemo/collections/asr/models/__init__.py create mode 100644 tts/nemo/collections/asr/models/asr_model.py create mode 100644 tts/nemo/collections/asr/models/classification_models.py create mode 100644 tts/nemo/collections/asr/models/clustering_diarizer.py create mode 100644 tts/nemo/collections/asr/models/configs/__init__.py create mode 100644 tts/nemo/collections/asr/models/configs/classification_models_config.py create mode 100644 tts/nemo/collections/asr/models/configs/ctc_models_config.py create mode 100644 tts/nemo/collections/asr/models/configs/matchboxnet_config.py create mode 100644 tts/nemo/collections/asr/models/configs/quartznet_config.py create mode 100644 tts/nemo/collections/asr/models/ctc_bpe_models.py create mode 100644 tts/nemo/collections/asr/models/ctc_models.py create mode 100644 tts/nemo/collections/asr/models/label_models.py create mode 100644 tts/nemo/collections/asr/models/rnnt_bpe_models.py create mode 100644 tts/nemo/collections/asr/models/rnnt_models.py create mode 100644 tts/nemo/collections/asr/models/wav2vec/__init__.py create mode 100644 tts/nemo/collections/asr/models/wav2vec/wav2vec_config.py create mode 100644 tts/nemo/collections/asr/models/wav2vec/wav2vec_model.py create mode 100644 tts/nemo/collections/asr/modules/__init__.py create mode 100644 tts/nemo/collections/asr/modules/audio_preprocessing.py create mode 100644 tts/nemo/collections/asr/modules/beam_search_decoder.py create mode 100644 tts/nemo/collections/asr/modules/conformer_encoder.py create mode 100644 tts/nemo/collections/asr/modules/conv_asr.py create mode 100644 tts/nemo/collections/asr/modules/lstm_decoder.py create mode 100644 tts/nemo/collections/asr/modules/rnnt.py create mode 100644 tts/nemo/collections/asr/modules/rnnt_abstract.py create mode 100644 tts/nemo/collections/asr/modules/wav2vec_modules.py create mode 100644 tts/nemo/collections/asr/parts/__init__.py create mode 100644 tts/nemo/collections/asr/parts/features.py create mode 100644 tts/nemo/collections/asr/parts/mixins/__init__.py create mode 100644 tts/nemo/collections/asr/parts/mixins/mixins.py create mode 100644 tts/nemo/collections/asr/parts/numba/__init__.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/__init__.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/rnnt.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/rnnt_numpy.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/rnnt_pytorch.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/__init__.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/cpu_utils/__init__.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/cpu_utils/cpu_rnnt.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/cuda_utils/__init__.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/cuda_utils/gpu_rnnt.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/cuda_utils/gpu_rnnt_kernel.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/cuda_utils/reduce.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/global_constants.py create mode 100644 tts/nemo/collections/asr/parts/numba/rnnt_loss/utils/rnnt_helper.py create mode 100644 tts/nemo/collections/asr/parts/numba/spec_augment/__init__.py create mode 100644 tts/nemo/collections/asr/parts/numba/spec_augment/spec_aug_numba.py create mode 100644 tts/nemo/collections/asr/parts/preprocessing/__init__.py create mode 100644 tts/nemo/collections/asr/parts/preprocessing/feature_loader.py create mode 100644 tts/nemo/collections/asr/parts/preprocessing/features.py create mode 100644 tts/nemo/collections/asr/parts/preprocessing/perturb.py create mode 100644 tts/nemo/collections/asr/parts/preprocessing/segment.py create mode 100644 tts/nemo/collections/asr/parts/submodules/__init__.py create mode 100644 tts/nemo/collections/asr/parts/submodules/conformer_modules.py create mode 100644 tts/nemo/collections/asr/parts/submodules/jasper.py create mode 100644 tts/nemo/collections/asr/parts/submodules/multi_head_attention.py create mode 100644 tts/nemo/collections/asr/parts/submodules/rnnt_beam_decoding.py create mode 100644 tts/nemo/collections/asr/parts/submodules/rnnt_greedy_decoding.py create mode 100644 tts/nemo/collections/asr/parts/submodules/spectr_augment.py create mode 100644 tts/nemo/collections/asr/parts/submodules/subsampling.py create mode 100644 tts/nemo/collections/asr/parts/submodules/wav2vec.py create mode 100644 tts/nemo/collections/asr/parts/utils/__init__.py create mode 100644 tts/nemo/collections/asr/parts/utils/activations.py create mode 100644 tts/nemo/collections/asr/parts/utils/asr_module_utils.py create mode 100644 tts/nemo/collections/asr/parts/utils/nmse_clustering.py create mode 100644 tts/nemo/collections/asr/parts/utils/numba_utils.py create mode 100644 tts/nemo/collections/asr/parts/utils/rnnt_utils.py create mode 100644 tts/nemo/collections/asr/parts/utils/speaker_utils.py create mode 100644 tts/nemo/collections/asr/parts/utils/vad_utils.py create mode 100644 tts/nemo/collections/common/__init__.py create mode 100644 tts/nemo/collections/common/callbacks/__init__.py create mode 100644 tts/nemo/collections/common/callbacks/callbacks.py create mode 100644 tts/nemo/collections/common/data/__init__.py create mode 100644 tts/nemo/collections/common/data/dataset.py create mode 100644 tts/nemo/collections/common/losses/__init__.py create mode 100644 tts/nemo/collections/common/losses/aggregator.py create mode 100644 tts/nemo/collections/common/losses/cross_entropy.py create mode 100644 tts/nemo/collections/common/losses/mse_loss.py create mode 100644 tts/nemo/collections/common/losses/multi_similarity_loss.py create mode 100644 tts/nemo/collections/common/losses/smoothed_cross_entropy.py create mode 100644 tts/nemo/collections/common/losses/spanning_loss.py create mode 100644 tts/nemo/collections/common/metrics/__init__.py create mode 100644 tts/nemo/collections/common/metrics/classification_accuracy.py create mode 100644 tts/nemo/collections/common/metrics/global_average_loss_metric.py create mode 100644 tts/nemo/collections/common/metrics/perplexity.py create mode 100644 tts/nemo/collections/common/parts/__init__.py create mode 100644 tts/nemo/collections/common/parts/multi_layer_perceptron.py create mode 100644 tts/nemo/collections/common/parts/patch_utils.py create mode 100644 tts/nemo/collections/common/parts/preprocessing/__init__.py create mode 100644 tts/nemo/collections/common/parts/preprocessing/cleaners.py create mode 100644 tts/nemo/collections/common/parts/preprocessing/collections.py create mode 100644 tts/nemo/collections/common/parts/preprocessing/manifest.py create mode 100644 tts/nemo/collections/common/parts/preprocessing/parsers.py create mode 100644 tts/nemo/collections/common/parts/rnn.py create mode 100644 tts/nemo/collections/common/parts/transformer_utils.py create mode 100644 tts/nemo/collections/common/parts/utils.py create mode 100644 tts/nemo/collections/common/tokenizers/__init__.py create mode 100644 tts/nemo/collections/common/tokenizers/char_tokenizer.py create mode 100644 tts/nemo/collections/common/tokenizers/chinese_tokenizers.py create mode 100644 tts/nemo/collections/common/tokenizers/en_ja_tokenizers.py create mode 100644 tts/nemo/collections/common/tokenizers/fairseq_tokenizer.py create mode 100644 tts/nemo/collections/common/tokenizers/huggingface/__init__.py create mode 100644 tts/nemo/collections/common/tokenizers/huggingface/auto_tokenizer.py create mode 100644 tts/nemo/collections/common/tokenizers/moses_tokenizers.py create mode 100644 tts/nemo/collections/common/tokenizers/sentencepiece_tokenizer.py create mode 100644 tts/nemo/collections/common/tokenizers/tokenizer_spec.py create mode 100644 tts/nemo/collections/common/tokenizers/word_tokenizer.py create mode 100644 tts/nemo/collections/common/tokenizers/youtokentome_tokenizer.py create mode 100644 tts/nemo/collections/cv/__init__.py create mode 100644 tts/nemo/collections/cv/datasets/__init__.py create mode 100644 tts/nemo/collections/cv/datasets/mnist_dataset.py create mode 100644 tts/nemo/collections/cv/losses/__init__.py create mode 100644 tts/nemo/collections/cv/losses/nll_loss.py create mode 100644 tts/nemo/collections/cv/models/__init__.py create mode 100644 tts/nemo/collections/cv/models/mnist_lenet5.py create mode 100644 tts/nemo/collections/cv/modules/__init__.py create mode 100644 tts/nemo/collections/cv/modules/lenet5.py create mode 100644 tts/nemo/collections/nlp/__init__.py create mode 100644 tts/nemo/collections/nlp/data/__init__.py create mode 100644 tts/nemo/collections/nlp/data/data_utils/__init__.py create mode 100644 tts/nemo/collections/nlp/data/data_utils/data_preprocessing.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/__init__.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/__init__.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/data_processor.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/dataset.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/evaluate.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/input_example.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/metrics.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/prediction_utils.py create mode 100644 tts/nemo/collections/nlp/data/dialogue_state_tracking/sgd/schema.py create mode 100644 tts/nemo/collections/nlp/data/entity_linking/__init__.py create mode 100644 tts/nemo/collections/nlp/data/entity_linking/entity_linking_dataset.py create mode 100644 tts/nemo/collections/nlp/data/glue_benchmark/__init__.py create mode 100644 tts/nemo/collections/nlp/data/glue_benchmark/data_processors.py create mode 100644 tts/nemo/collections/nlp/data/glue_benchmark/glue_benchmark_dataset.py create mode 100644 tts/nemo/collections/nlp/data/information_retrieval/__init__.py create mode 100644 tts/nemo/collections/nlp/data/information_retrieval/information_retrieval_dataset.py create mode 100644 tts/nemo/collections/nlp/data/intent_slot_classification/__init__.py create mode 100644 tts/nemo/collections/nlp/data/intent_slot_classification/intent_slot_classification_dataset.py create mode 100644 tts/nemo/collections/nlp/data/intent_slot_classification/intent_slot_classification_descriptor.py create mode 100644 tts/nemo/collections/nlp/data/language_modeling/__init__.py create mode 100644 tts/nemo/collections/nlp/data/language_modeling/l2r_lm_dataset.py create mode 100644 tts/nemo/collections/nlp/data/language_modeling/lm_bert_dataset.py create mode 100644 tts/nemo/collections/nlp/data/language_modeling/sentence_dataset.py create mode 100644 tts/nemo/collections/nlp/data/machine_translation/__init__.py create mode 100644 tts/nemo/collections/nlp/data/machine_translation/machine_translation_dataset.py create mode 100644 tts/nemo/collections/nlp/data/machine_translation/preproc_mt_data.py create mode 100644 tts/nemo/collections/nlp/data/neural_machine_translation/__init__.py create mode 100644 tts/nemo/collections/nlp/data/neural_machine_translation/neural_machine_translation_dataset.py create mode 100644 tts/nemo/collections/nlp/data/question_answering_squad/__init__.py create mode 100644 tts/nemo/collections/nlp/data/question_answering_squad/qa_dataset.py create mode 100644 tts/nemo/collections/nlp/data/question_answering_squad/qa_squad_processing.py create mode 100644 tts/nemo/collections/nlp/data/text_classification/__init__.py create mode 100644 tts/nemo/collections/nlp/data/text_classification/text_classification_dataset.py create mode 100644 tts/nemo/collections/nlp/data/token_classification/__init__.py create mode 100644 tts/nemo/collections/nlp/data/token_classification/punctuation_capitalization_dataset.py create mode 100644 tts/nemo/collections/nlp/data/token_classification/token_classification_dataset.py create mode 100644 tts/nemo/collections/nlp/data/token_classification/token_classification_utils.py create mode 100644 tts/nemo/collections/nlp/losses/__init__.py create mode 100644 tts/nemo/collections/nlp/losses/sgd_loss.py create mode 100644 tts/nemo/collections/nlp/metrics/__init__.py create mode 100644 tts/nemo/collections/nlp/metrics/classification_report.py create mode 100644 tts/nemo/collections/nlp/metrics/sequence_perplexity.py create mode 100644 tts/nemo/collections/nlp/models/__init__.py create mode 100644 tts/nemo/collections/nlp/models/dialogue_state_tracking/__init__.py create mode 100644 tts/nemo/collections/nlp/models/dialogue_state_tracking/sgdqa_model.py create mode 100644 tts/nemo/collections/nlp/models/enc_dec_nlp_model.py create mode 100644 tts/nemo/collections/nlp/models/entity_linking/__init__.py create mode 100644 tts/nemo/collections/nlp/models/entity_linking/entity_linking_model.py create mode 100644 tts/nemo/collections/nlp/models/glue_benchmark/__init__.py create mode 100644 tts/nemo/collections/nlp/models/glue_benchmark/glue_benchmark_model.py create mode 100644 tts/nemo/collections/nlp/models/glue_benchmark/metrics_for_glue.py create mode 100644 tts/nemo/collections/nlp/models/information_retrieval/__init__.py create mode 100644 tts/nemo/collections/nlp/models/information_retrieval/base_ir_model.py create mode 100644 tts/nemo/collections/nlp/models/information_retrieval/bert_dpr_model.py create mode 100644 tts/nemo/collections/nlp/models/information_retrieval/bert_joint_ir_model.py create mode 100644 tts/nemo/collections/nlp/models/intent_slot_classification/__init__.py create mode 100644 tts/nemo/collections/nlp/models/intent_slot_classification/intent_slot_classification_model.py create mode 100644 tts/nemo/collections/nlp/models/language_modeling/__init__.py create mode 100644 tts/nemo/collections/nlp/models/language_modeling/bert_lm_model.py create mode 100644 tts/nemo/collections/nlp/models/language_modeling/transformer_lm_model.py create mode 100644 tts/nemo/collections/nlp/models/machine_translation/__init__.py create mode 100644 tts/nemo/collections/nlp/models/machine_translation/mt_enc_dec_config.py create mode 100644 tts/nemo/collections/nlp/models/machine_translation/mt_enc_dec_model.py create mode 100644 tts/nemo/collections/nlp/models/neural_machine_translation/__init__.py create mode 100644 tts/nemo/collections/nlp/models/neural_machine_translation/neural_machine_translation_model.py create mode 100644 tts/nemo/collections/nlp/models/nlp_model.py create mode 100644 tts/nemo/collections/nlp/models/question_answering/__init__.py create mode 100644 tts/nemo/collections/nlp/models/question_answering/qa_model.py create mode 100644 tts/nemo/collections/nlp/models/text_classification/__init__.py create mode 100644 tts/nemo/collections/nlp/models/text_classification/text_classification_model.py create mode 100644 tts/nemo/collections/nlp/models/token_classification/__init__.py create mode 100644 tts/nemo/collections/nlp/models/token_classification/punctuation_capitalization_model.py create mode 100644 tts/nemo/collections/nlp/models/token_classification/token_classification_model.py create mode 100644 tts/nemo/collections/nlp/modules/__init__.py create mode 100644 tts/nemo/collections/nlp/modules/common/__init__.py create mode 100644 tts/nemo/collections/nlp/modules/common/bert_module.py create mode 100644 tts/nemo/collections/nlp/modules/common/classifier.py create mode 100644 tts/nemo/collections/nlp/modules/common/decoder_module.py create mode 100644 tts/nemo/collections/nlp/modules/common/encoder_module.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/__init__.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/albert.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/bert.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/distilbert.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/huggingface_decoder.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/huggingface_encoder.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/huggingface_utils.py create mode 100644 tts/nemo/collections/nlp/modules/common/huggingface/roberta.py create mode 100644 tts/nemo/collections/nlp/modules/common/lm_utils.py create mode 100644 tts/nemo/collections/nlp/modules/common/megatron/__init__.py create mode 100644 tts/nemo/collections/nlp/modules/common/megatron/megatron_bert.py create mode 100644 tts/nemo/collections/nlp/modules/common/megatron/megatron_utils.py create mode 100644 tts/nemo/collections/nlp/modules/common/sequence_classifier.py create mode 100644 tts/nemo/collections/nlp/modules/common/sequence_regression.py create mode 100644 tts/nemo/collections/nlp/modules/common/sequence_token_classifier.py create mode 100644 tts/nemo/collections/nlp/modules/common/token_classifier.py create mode 100644 tts/nemo/collections/nlp/modules/common/tokenizer_utils.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/__init__.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/transformer.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/transformer_decoders.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/transformer_encoders.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/transformer_generators.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/transformer_modules.py create mode 100644 tts/nemo/collections/nlp/modules/common/transformer/transformer_utils.py create mode 100644 tts/nemo/collections/nlp/modules/dialogue_state_tracking/__init__.py create mode 100644 tts/nemo/collections/nlp/modules/dialogue_state_tracking/sgd_decoder.py create mode 100644 tts/nemo/collections/nlp/modules/dialogue_state_tracking/sgd_encoder.py create mode 100644 tts/nemo/collections/nlp/parts/__init__.py create mode 100644 tts/nemo/collections/nlp/parts/nlp_overrides.py create mode 100644 tts/nemo/collections/nlp/parts/utils_funcs.py create mode 100644 tts/nemo/collections/tts/__init__.py create mode 100644 tts/nemo/collections/tts/data/__init__.py create mode 100644 tts/nemo/collections/tts/data/datalayers.py create mode 100644 tts/nemo/collections/tts/helpers/__init__.py create mode 100644 tts/nemo/collections/tts/helpers/helpers.py create mode 100644 tts/nemo/collections/tts/losses/__init__.py create mode 100644 tts/nemo/collections/tts/losses/aligner_loss.py create mode 100644 tts/nemo/collections/tts/losses/fastpitchloss.py create mode 100644 tts/nemo/collections/tts/losses/fastspeech2loss.py create mode 100644 tts/nemo/collections/tts/losses/glow_tts_loss.py create mode 100644 tts/nemo/collections/tts/losses/hifigan_losses.py create mode 100644 tts/nemo/collections/tts/losses/stftlosses.py create mode 100644 tts/nemo/collections/tts/losses/tacotron2loss.py create mode 100644 tts/nemo/collections/tts/losses/uniglowloss.py create mode 100644 tts/nemo/collections/tts/losses/waveglowloss.py create mode 100644 tts/nemo/collections/tts/models/__init__.py create mode 100644 tts/nemo/collections/tts/models/aligner.py create mode 100644 tts/nemo/collections/tts/models/base.py create mode 100755 tts/nemo/collections/tts/models/degli.py create mode 100755 tts/nemo/collections/tts/models/ed_mel2spec.py create mode 100644 tts/nemo/collections/tts/models/fastpitch.py create mode 100644 tts/nemo/collections/tts/models/fastpitch_hifigan_e2e.py create mode 100644 tts/nemo/collections/tts/models/fastspeech2.py create mode 100644 tts/nemo/collections/tts/models/fastspeech2_hifigan_e2e.py create mode 100644 tts/nemo/collections/tts/models/glow_tts.py create mode 100644 tts/nemo/collections/tts/models/hifigan.py create mode 100644 tts/nemo/collections/tts/models/melgan.py create mode 100644 tts/nemo/collections/tts/models/squeezewave.py create mode 100644 tts/nemo/collections/tts/models/tacotron2.py create mode 100644 tts/nemo/collections/tts/models/talknet.py create mode 100644 tts/nemo/collections/tts/models/two_stages.py create mode 100644 tts/nemo/collections/tts/models/uniglow.py create mode 100644 tts/nemo/collections/tts/models/waveglow.py create mode 100644 tts/nemo/collections/tts/modules/__init__.py create mode 100644 tts/nemo/collections/tts/modules/aligner.py create mode 100755 tts/nemo/collections/tts/modules/degli.py create mode 100755 tts/nemo/collections/tts/modules/ed_mel2spec.py create mode 100644 tts/nemo/collections/tts/modules/fastpitch.py create mode 100644 tts/nemo/collections/tts/modules/fastspeech2.py create mode 100644 tts/nemo/collections/tts/modules/fastspeech2_submodules.py create mode 100644 tts/nemo/collections/tts/modules/glow_tts.py create mode 100644 tts/nemo/collections/tts/modules/glow_tts_parser.py create mode 100644 tts/nemo/collections/tts/modules/glow_tts_submodules.py create mode 100644 tts/nemo/collections/tts/modules/hifigan_modules.py create mode 100644 tts/nemo/collections/tts/modules/melgan_modules.py create mode 100644 tts/nemo/collections/tts/modules/squeezewave.py create mode 100644 tts/nemo/collections/tts/modules/squeezewave_submodules.py create mode 100644 tts/nemo/collections/tts/modules/submodules.py create mode 100644 tts/nemo/collections/tts/modules/tacotron2.py create mode 100644 tts/nemo/collections/tts/modules/talknet.py create mode 100644 tts/nemo/collections/tts/modules/transformer.py create mode 100644 tts/nemo/collections/tts/modules/uniglow.py create mode 100644 tts/nemo/collections/tts/modules/waveglow.py create mode 100644 tts/nemo/constants.py create mode 100644 tts/nemo/core/__init__.py create mode 100644 tts/nemo/core/classes/__init__.py create mode 100644 tts/nemo/core/classes/common.py create mode 100644 tts/nemo/core/classes/dataset.py create mode 100644 tts/nemo/core/classes/exportable.py create mode 100644 tts/nemo/core/classes/loss.py create mode 100644 tts/nemo/core/classes/modelPT.py create mode 100644 tts/nemo/core/classes/module.py create mode 100644 tts/nemo/core/config/__init__.py create mode 100644 tts/nemo/core/config/base_config.py create mode 100644 tts/nemo/core/config/hydra_runner.py create mode 100644 tts/nemo/core/config/modelPT.py create mode 100644 tts/nemo/core/config/optimizers.py create mode 100644 tts/nemo/core/config/pytorch.py create mode 100644 tts/nemo/core/config/pytorch_lightning.py create mode 100644 tts/nemo/core/config/schedulers.py create mode 100644 tts/nemo/core/neural_types/__init__.py create mode 100644 tts/nemo/core/neural_types/axes.py create mode 100644 tts/nemo/core/neural_types/comparison.py create mode 100644 tts/nemo/core/neural_types/elements.py create mode 100644 tts/nemo/core/neural_types/neural_type.py create mode 100644 tts/nemo/core/optim/__init__.py create mode 100644 tts/nemo/core/optim/lr_scheduler.py create mode 100644 tts/nemo/core/optim/novograd.py create mode 100644 tts/nemo/core/optim/optimizers.py create mode 100644 tts/nemo/core/utils/__init__.py create mode 100644 tts/nemo/core/utils/numba_utils.py create mode 100644 tts/nemo/package_info.py create mode 100644 tts/nemo/utils/__init__.py create mode 100644 tts/nemo/utils/app_state.py create mode 100644 tts/nemo/utils/arguments.py create mode 100644 tts/nemo/utils/cloud.py create mode 100644 tts/nemo/utils/config_utils.py create mode 100644 tts/nemo/utils/decorators/__init__.py create mode 100644 tts/nemo/utils/decorators/deprecated.py create mode 100644 tts/nemo/utils/decorators/experimental.py create mode 100644 tts/nemo/utils/decorators/port_docs.py create mode 100644 tts/nemo/utils/env_var_parsing.py create mode 100644 tts/nemo/utils/exceptions.py create mode 100644 tts/nemo/utils/exp_manager.py create mode 100644 tts/nemo/utils/export_utils.py create mode 100644 tts/nemo/utils/formatters/__init__.py create mode 100644 tts/nemo/utils/formatters/base.py create mode 100644 tts/nemo/utils/formatters/colors.py create mode 100644 tts/nemo/utils/formatters/utils.py create mode 100644 tts/nemo/utils/get_rank.py create mode 100644 tts/nemo/utils/lightning_logger_patch.py create mode 100644 tts/nemo/utils/metaclasses.py create mode 100644 tts/nemo/utils/model_utils.py create mode 100644 tts/nemo/utils/nemo_logging.py create mode 100644 tts/requirements-tacotron-python36.txt create mode 100644 tts/requirements-talknet-python36-38.txt create mode 100644 tts/tacotron2/.gitmodules create mode 100644 tts/tacotron2/Dockerfile create mode 100644 tts/tacotron2/LICENSE create mode 100755 tts/tacotron2/README.md create mode 100644 tts/tacotron2/__init__.py create mode 100644 tts/tacotron2/audio_processing.py create mode 100644 tts/tacotron2/data_utils.py create mode 100644 tts/tacotron2/distributed.py create mode 100644 tts/tacotron2/fp16_optimizer.py create mode 100644 tts/tacotron2/hparams.py create mode 100644 tts/tacotron2/inference.ipynb create mode 100755 tts/tacotron2/inference.py create mode 100644 tts/tacotron2/layers.py create mode 100644 tts/tacotron2/logger.py create mode 100644 tts/tacotron2/loss_function.py create mode 100644 tts/tacotron2/loss_scaler.py create mode 100644 tts/tacotron2/model.py create mode 100644 tts/tacotron2/multiproc.py create mode 100644 tts/tacotron2/plotting_utils.py create mode 100644 tts/tacotron2/requirements-nvidia-original.txt create mode 100644 tts/tacotron2/stft.py create mode 100644 tts/tacotron2/text/LICENSE create mode 100644 tts/tacotron2/text/__init__.py create mode 100644 tts/tacotron2/text/cleaners.py create mode 100644 tts/tacotron2/text/cmudict.py create mode 100644 tts/tacotron2/text/numbers.py create mode 100644 tts/tacotron2/text/symbols.py create mode 100644 tts/tacotron2/train.py create mode 100644 tts/tacotron2/utils.py create mode 100644 tts/vocodes_common.py create mode 100755 tts/vocodes_inference.py create mode 100755 tts/vocodes_model_check_tacotron.py create mode 100755 tts/vocodes_model_check_talknet.py create mode 100755 tts/vocodes_server.py create mode 100755 tts/vocodes_server_talknet.py create mode 100644 tts/vocodes_wav_images.py create mode 100644 tts/waveglow/.gitmodules create mode 100644 tts/waveglow/LICENSE create mode 100755 tts/waveglow/README.md create mode 100755 tts/waveglow/config.json create mode 100644 tts/waveglow/convert_model.py create mode 100644 tts/waveglow/denoiser.py create mode 100644 tts/waveglow/distributed.py create mode 100644 tts/waveglow/glow.py create mode 100644 tts/waveglow/glow_old.py create mode 100644 tts/waveglow/inference.py create mode 100644 tts/waveglow/mel2samp.py create mode 100644 tts/waveglow/requirements.txt create mode 100644 tts/waveglow/train.py diff --git a/future-todo/ControllableTalkNet/Dockerfile b/future-todo/ControllableTalkNet/Dockerfile new file mode 100644 index 0000000..be6e6b1 --- /dev/null +++ b/future-todo/ControllableTalkNet/Dockerfile @@ -0,0 +1,29 @@ +FROM nvidia/cuda:11.0.3-base-ubuntu20.04 +ENV TZ=Etc/GMT +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +RUN apt-get update && apt-get install -y git ffmpeg python3.8 python3-pip curl +RUN git clone -q https://github.com/SortAnon/ControllableTalkNet /talknet +RUN git clone -q https://github.com/SortAnon/hifi-gan /talknet/hifi-gan +RUN python3.8 -m pip --no-cache-dir install -r "/talknet/requirements.txt" -f https://download.pytorch.org/whl/torch_stable.html +RUN python3.8 -m pip --no-cache-dir install git+https://github.com/SortAnon/NeMo.git +RUN python3.8 -m pip uninstall -y pesq +RUN python3.8 -m pip install pesq==0.0.2 +RUN touch /talknet/is_docker +WORKDIR /talknet +EXPOSE 8050 + +RUN printf "#!/bin/bash \ + \necho Updating TalkNet... \ + \ngit -C /talknet reset --hard origin/main -q \ + \ngit -C /talknet pull origin main -q \ + \necho Updating HiFi-GAN... \ + \ngit -C /talknet reset --hard origin/main -q \ + \ngit -C /talknet pull origin main -q \ + \necho Updating Python dependencies... \ + \npython3.8 -m pip --quiet --no-cache-dir install -r /talknet/requirements.txt -f https://download.pytorch.org/whl/torch_stable.html \ + \npython3.8 -m pip --quiet --no-cache-dir install git+https://github.com/SortAnon/NeMo.git \ + \necho Launching TalkNet... \ + \npython3.8 talknet_offline.py\n" > /talknet/docker_launch.sh + +RUN chmod +x /talknet/docker_launch.sh +CMD ["./docker_launch.sh"] diff --git a/future-todo/ControllableTalkNet/LICENSE b/future-todo/ControllableTalkNet/LICENSE new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/future-todo/ControllableTalkNet/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/future-todo/ControllableTalkNet/README.md b/future-todo/ControllableTalkNet/README.md new file mode 100644 index 0000000..20f0d04 --- /dev/null +++ b/future-todo/ControllableTalkNet/README.md @@ -0,0 +1,26 @@ +# Controllable TalkNet +Controllable TalkNet is a web application that lets you synthesize speech, +which mimics the pitch and pacing of an existing audio clip. It's based on [NVIDIA's implementation](https://github.com/NVIDIA/NeMo) +of TalkNet 2, with some changes to support singing synthesis and higher audio quality. + +## Requirements +* A Google account to run Colab, or... +* An NVIDIA GPU with 4+ GB of VRAM +* 10 GB of free space + +## How to run +### Google Colab +* [Go to the Colab notebook](https://colab.research.google.com/drive/1aj6Jk8cpRw7SsN3JSYCv57CrR6s0gYPB) and follow the instructions. + +### TalkNet Offline (Windows) +* [Download the setup script](https://github.com/SortAnon/ControllableTalkNet/releases/latest/download/TalkNetOffline.zip) +and extract it to a folder. +* Run setup.bat. The initial setup will take about 20 minutes. +* When it's done, run talknet.bat to start TalkNet on http://127.0.0.1:8050/. To download updates, run update.bat. + +### Docker (Linux) +* Install Docker and NVIDIA Container Toolkit. +* [Download the Dockerfile.](https://raw.githubusercontent.com/SortAnon/ControllableTalkNet/main/Dockerfile) +Open a terminal, and navigate to the directory where you saved it. +* Run ```docker build -t talknet-offline .``` to build the image. Add ```sudo``` if you're not using rootless Docker. +* Run ```docker run -it --gpus all -p 8050:8050 talknet-offline``` to start TalkNet on http://127.0.0.1:8050/. diff --git a/future-todo/ControllableTalkNet/TalkNet_Training_Offline.ipynb b/future-todo/ControllableTalkNet/TalkNet_Training_Offline.ipynb new file mode 100644 index 0000000..44b8cda --- /dev/null +++ b/future-todo/ControllableTalkNet/TalkNet_Training_Offline.ipynb @@ -0,0 +1,925 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# TalkNet Training (offline)\n", + "\n", + "To train a 22KHz TalkNet, run the cells below and follow the instructions.\n", + "\n", + "The notebook will automatically resume training any models from the last saved checkpoint. If you're resuming from a new session, always re-run step 1 first." + ], + "metadata": { + "id": "Gss5Ox_RNiba" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 1:** Configure training data paths. Create the following and change the paths below:\n", + "* A dataset of .wav files, packaged as a .zip or .tar file\n", + "* Training and validation filelists, in LJSpeech format with relative paths (note: ARPABET transcripts are not supported)\n", + "* An output path for checkpoints" + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "### CHANGE THESE ###\n", + "\n", + "dataset = \"/absolute/path_to_dataset.zip\"\n", + "train_filelist = \"/absolute/train_filelist.txt\"\n", + "val_filelist = \"/absolute/val_filelist.txt\"\n", + "output_dir = \"/absolute/name_of_character\"\n", + "\n", + "### ------------ ###\n", + "\n", + "import os\n", + "import gdown\n", + "import platform\n", + "\n", + "assert os.path.exists(dataset), \"Cannot find dataset\"\n", + "assert os.path.exists(train_filelist), \"Cannot find training filelist\"\n", + "assert os.path.exists(val_filelist), \"Cannot find validation filelist\"\n", + "if not os.path.exists(output_dir):\n", + " os.makedirs(output_dir)\n", + "\n", + "if os.getcwd() != output_dir:\n", + " cwd = os.getcwd()\n", + "else:\n", + " os.chdir(cwd)\n", + " \n", + "# Download pre-trained models\n", + "if not os.path.exists(\"talknet_spect.nemo\"):\n", + " print(\"Downloading pre-trained models...\")\n", + " zip_path = \"TalkNet_Pretrained.zip\"\n", + " if not os.path.exists(zip_path) or os.stat(zip_path).st_size < 100:\n", + " d = 'https://drive.google.com/uc?id='\n", + " gdown.download(d+\"19wSym9mNEnmzLS9XdPlfNAW9_u-mP1hR\", zip_path, quiet=False)\n", + " print(platform.system())\n", + " if \"Windows\" in platform.system():\n", + " !tar -xf {zip_path}\n", + " else:\n", + " !unzip -qo {zip_path}\n", + " os.remove(zip_path)\n", + "\n", + "print(\"OK\")" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "nfSawDUD5tqv" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 2:** Dataset processing, part 1.\n", + "\n", + "If this step fails, try the following:\n", + "* Make sure your filelists are correct. They should have relative \n", + "paths that match the contents of the archive." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import os\n", + "import shutil\n", + "import sys\n", + "import json\n", + "import nemo\n", + "import torch\n", + "import torchaudio\n", + "import numpy as np\n", + "#from pysptk import sptk\n", + "from pathlib import Path\n", + "from tqdm.notebook import tqdm\n", + "import ffmpeg\n", + "\n", + "def fix_transcripts(inpath):\n", + " found_arpabet = False\n", + " found_grapheme = False\n", + " with open(inpath, \"r\", encoding=\"utf8\") as f:\n", + " lines = f.readlines()\n", + " with open(inpath, \"w\", encoding=\"utf8\") as f:\n", + " for l in lines:\n", + " if l.strip() == \"\":\n", + " continue\n", + " if \"{\" in l:\n", + " if not found_arpabet:\n", + " print(\"Warning: Skipping ARPABET lines (not supported).\")\n", + " found_arpabet = True\n", + " else:\n", + " f.write(l)\n", + " found_grapheme = True\n", + " assert found_grapheme, \"No non-ARPABET lines found in \" + inpath\n", + "\n", + "def generate_json(inpath, outpath):\n", + " output = \"\"\n", + " sample_rate = 22050\n", + " with open(inpath, \"r\", encoding=\"utf8\") as f:\n", + " for l in f.readlines():\n", + " lpath = l.split(\"|\")[0].strip()\n", + " if lpath[:5] != \"wavs/\":\n", + " lpath = \"wavs/\" + lpath\n", + " lpath = os.path.join(output_dir, \"_training_data\", lpath)\n", + " size = os.stat(lpath).st_size\n", + " x = {\n", + " \"audio_filepath\": lpath,\n", + " \"duration\": size / (sample_rate * 2),\n", + " \"text\": l.split(\"|\")[1].strip(),\n", + " }\n", + " output += json.dumps(x) + \"\\n\"\n", + " with open(outpath, \"w\", encoding=\"utf8\") as w:\n", + " w.write(output)\n", + "\n", + "def convert_to_22k(inpath):\n", + " if inpath.strip()[-4:].lower() != \".wav\":\n", + " print(\"Warning: \" + inpath.strip() + \" is not a .wav file!\")\n", + " return\n", + " ffmpeg.input(inpath).output(\n", + " inpath + \"_22k.wav\",\n", + " ar=\"22050\",\n", + " ac=\"1\",\n", + " acodec=\"pcm_s16le\",\n", + " map_metadata=\"-1\",\n", + " fflags=\"+bitexact\",\n", + " ).overwrite_output().run(quiet=True)\n", + " os.remove(inpath)\n", + " os.rename(inpath + \"_22k.wav\", inpath)\n", + "\n", + "# Extract dataset\n", + "os.chdir(output_dir)\n", + "\n", + "if os.path.exists(\"_training_data\"):\n", + " shutil.rmtree(\"_training_data\")\n", + "os.mkdir(\"_training_data\")\n", + "os.chdir(\"_training_data\")\n", + "os.mkdir(\"wavs\")\n", + "os.chdir(\"wavs\")\n", + "if dataset[-4:] == \".zip\":\n", + " if \"Windows\" in platform.system():\n", + " !tar -xf \"{dataset}\"\n", + " else:\n", + " !unzip -qo \"{dataset}\"\n", + "elif dataset[-4:] == \".tar\":\n", + " !tar -xf \"{dataset}\"\n", + "else:\n", + " raise Exception(\"Unknown extension for dataset\")\n", + "if os.path.exists(os.path.join(output_dir, \"_training_data\", \"wavs\", \"wavs\")):\n", + " shutil.move(\n", + " os.path.join(output_dir, \"_training_data\", \"wavs\", \"wavs\"), \n", + " os.path.join(output_dir, \"_training_data\", \"tempwavs\")\n", + " )\n", + " shutil.rmtree(os.path.join(output_dir, \"_training_data\", \"wavs\"))\n", + " shutil.move(\n", + " os.path.join(output_dir, \"_training_data\", \"tempwavs\"), \n", + " os.path.join(output_dir, \"_training_data\", \"wavs\")\n", + " )\n", + "# Filelist for preprocessing\n", + "os.chdir(output_dir)\n", + "shutil.copy(train_filelist, \"trainfiles.txt\")\n", + "shutil.copy(val_filelist, \"valfiles.txt\")\n", + "fix_transcripts(\"trainfiles.txt\")\n", + "fix_transcripts(\"valfiles.txt\")\n", + "seen_files = []\n", + "with open(\"trainfiles.txt\") as f:\n", + " t = f.read().split(\"\\n\")\n", + "with open(\"valfiles.txt\") as f:\n", + " v = f.read().split(\"\\n\")\n", + " all_filelist = t[:] + v[:]\n", + "with open(\"allfiles.txt\", \"w\") as f:\n", + " for x in all_filelist:\n", + " if x.strip() == \"\":\n", + " continue\n", + " if x.split(\"|\")[0] not in seen_files:\n", + " seen_files.append(x.split(\"|\")[0])\n", + " f.write(x.strip() + \"\\n\")\n", + "\n", + "# Ensure audio is 22k\n", + "print(\"Converting audio...\")\n", + "for r, _, f in os.walk(os.path.join(\"_training_data\", \"wavs\")):\n", + " for name in tqdm(f):\n", + " convert_to_22k(os.path.join(r, name))\n", + "\n", + "# Convert to JSON\n", + "generate_json(\"trainfiles.txt\", \"trainfiles.json\")\n", + "generate_json(\"valfiles.txt\", \"valfiles.json\")\n", + "generate_json(\"allfiles.txt\", \"allfiles.json\")\n", + "\n", + "print(\"OK\")" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "bxFr3Fdi_kOC" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 3:** Dataset processing, part 2. This takes a while, but\n", + "you only have to run this once per dataset (results are saved to Drive).\n", + "\n", + "If this step fails, try the following:\n", + "* Make sure your dataset only contains WAV files." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "# Extract phoneme duration\n", + "\n", + "import json\n", + "from nemo.collections.asr.models import EncDecCTCModel\n", + "asr_model = EncDecCTCModel.from_pretrained(model_name=\"asr_talknet_aligner\").cpu().eval()\n", + "\n", + "def forward_extractor(tokens, log_probs, blank):\n", + " \"\"\"Computes states f and p.\"\"\"\n", + " n, m = len(tokens), log_probs.shape[0]\n", + " # `f[s, t]` -- max sum of log probs for `s` first codes\n", + " # with `t` first timesteps with ending in `tokens[s]`.\n", + " f = np.empty((n + 1, m + 1), dtype=float)\n", + " f.fill(-(10 ** 9))\n", + " p = np.empty((n + 1, m + 1), dtype=int)\n", + " f[0, 0] = 0.0 # Start\n", + " for s in range(1, n + 1):\n", + " c = tokens[s - 1]\n", + " for t in range((s + 1) // 2, m + 1):\n", + " f[s, t] = log_probs[t - 1, c]\n", + " # Option #1: prev char is equal to current one.\n", + " if s == 1 or c == blank or c == tokens[s - 3]:\n", + " options = f[s : (s - 2 if s > 1 else None) : -1, t - 1]\n", + " else: # Is not equal to current one.\n", + " options = f[s : (s - 3 if s > 2 else None) : -1, t - 1]\n", + " f[s, t] += np.max(options)\n", + " p[s, t] = np.argmax(options)\n", + " return f, p\n", + "\n", + "\n", + "def backward_extractor(f, p):\n", + " \"\"\"Computes durs from f and p.\"\"\"\n", + " n, m = f.shape\n", + " n -= 1\n", + " m -= 1\n", + " durs = np.zeros(n, dtype=int)\n", + " if f[-1, -1] >= f[-2, -1]:\n", + " s, t = n, m\n", + " else:\n", + " s, t = n - 1, m\n", + " while s > 0:\n", + " durs[s - 1] += 1\n", + " s -= p[s, t]\n", + " t -= 1\n", + " assert durs.shape[0] == n\n", + " assert np.sum(durs) == m\n", + " assert np.all(durs[1::2] > 0)\n", + " return durs\n", + "\n", + "def preprocess_tokens(tokens, blank):\n", + " new_tokens = [blank]\n", + " for c in tokens:\n", + " new_tokens.extend([c, blank])\n", + " tokens = new_tokens\n", + " return tokens\n", + "\n", + "data_config = {\n", + " 'manifest_filepath': \"allfiles.json\",\n", + " 'sample_rate': 22050,\n", + " 'labels': asr_model.decoder.vocabulary,\n", + " 'batch_size': 1,\n", + "}\n", + "\n", + "parser = nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset.make_vocab(\n", + " notation='phonemes', punct=True, spaces=True, stresses=False, add_blank_at=\"last\"\n", + ")\n", + "\n", + "dataset = nemo.collections.asr.data.audio_to_text._AudioTextDataset(\n", + " manifest_filepath=data_config['manifest_filepath'], sample_rate=data_config['sample_rate'], parser=parser,\n", + ")\n", + "\n", + "dl = torch.utils.data.DataLoader(\n", + " dataset=dataset, batch_size=data_config['batch_size'], collate_fn=dataset.collate_fn, shuffle=False,\n", + ")\n", + "\n", + "blank_id = asr_model.decoder.num_classes_with_blank - 1\n", + "\n", + "if os.path.exists(os.path.join(output_dir, \"durations.pt\")):\n", + " print(\"durations.pt already exists; skipping\")\n", + "else:\n", + " dur_data = {}\n", + " for sample_idx, test_sample in tqdm(enumerate(dl), total=len(dl)):\n", + " log_probs, _, greedy_predictions = asr_model(\n", + " input_signal=test_sample[0], input_signal_length=test_sample[1]\n", + " )\n", + "\n", + " log_probs = log_probs[0].cpu().detach().numpy()\n", + " seq_ids = test_sample[2][0].cpu().detach().numpy()\n", + "\n", + " target_tokens = preprocess_tokens(seq_ids, blank_id)\n", + "\n", + " f, p = forward_extractor(target_tokens, log_probs, blank_id)\n", + " durs = backward_extractor(f, p)\n", + "\n", + " dur_key = Path(dl.dataset.collection[sample_idx].audio_file).stem\n", + " dur_data[dur_key] = {\n", + " 'blanks': torch.tensor(durs[::2], dtype=torch.long).cpu().detach(), \n", + " 'tokens': torch.tensor(durs[1::2], dtype=torch.long).cpu().detach()\n", + " }\n", + "\n", + " del test_sample\n", + "\n", + " torch.save(dur_data, os.path.join(output_dir, \"durations.pt\"))\n", + "\n", + "#Extract F0 (pitch)\n", + "import crepe\n", + "from scipy.io import wavfile\n", + "\n", + "def crepe_f0(audio_file, hop_length=256):\n", + " sr, audio = wavfile.read(audio_file)\n", + " audio_x = np.arange(0, len(audio)) / 22050.0\n", + " time, frequency, confidence, activation = crepe.predict(audio, sr, viterbi=True)\n", + "\n", + " x = np.arange(0, len(audio), hop_length) / 22050.0\n", + " freq_interp = np.interp(x, time, frequency)\n", + " conf_interp = np.interp(x, time, confidence)\n", + " audio_interp = np.interp(x, audio_x, np.absolute(audio)) / 32768.0\n", + " weights = [0.5, 0.25, 0.25]\n", + " audio_smooth = np.convolve(audio_interp, np.array(weights)[::-1], \"same\")\n", + "\n", + " conf_threshold = 0.25\n", + " audio_threshold = 0.0005\n", + " for i in range(len(freq_interp)):\n", + " if conf_interp[i] < conf_threshold:\n", + " freq_interp[i] = 0.0\n", + " if audio_smooth[i] < audio_threshold:\n", + " freq_interp[i] = 0.0\n", + "\n", + " # Hack to make f0 and mel lengths equal\n", + " if len(audio) % hop_length == 0:\n", + " freq_interp = np.pad(freq_interp, pad_width=[0, 1])\n", + " return torch.from_numpy(freq_interp.astype(np.float32))\n", + "\n", + "if os.path.exists(os.path.join(output_dir, \"f0s.pt\")):\n", + " print(\"f0s.pt already exists; skipping\")\n", + "else:\n", + " f0_data = {}\n", + " with open(\"allfiles.json\") as f:\n", + " for i, l in enumerate(f.readlines()):\n", + " print(str(i))\n", + " audio_path = json.loads(l)[\"audio_filepath\"]\n", + " f0_data[Path(audio_path).stem] = crepe_f0(audio_path)\n", + "\n", + " # calculate f0 stats (mean & std) only for train set\n", + " with open(\"trainfiles.json\") as f:\n", + " train_ids = {Path(json.loads(l)[\"audio_filepath\"]).stem for l in f}\n", + " all_f0 = torch.cat([f0[f0 >= 1e-5] for f0_id, f0 in f0_data.items() if f0_id in train_ids])\n", + "\n", + " F0_MEAN, F0_STD = all_f0.mean().item(), all_f0.std().item() \n", + " print(\"F0_MEAN: \" + str(F0_MEAN) + \", F0_STD: \" + str(F0_STD))\n", + " torch.save(f0_data, os.path.join(output_dir, \"f0s.pt\"))\n", + " with open(os.path.join(output_dir, \"f0_info.json\"), \"w\") as f:\n", + " f.write(json.dumps({\"FO_MEAN\": F0_MEAN, \"F0_STD\": F0_STD}))\n", + "\n", + "print(\"OK\")" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "sos9vsxPkIN7" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 4:** Train duration predictor.\n", + "\n", + "If CUDA runs out of memory, try the following:\n", + "* Click on Kernel -> Restart, re-run step 1, and try again.\n", + "* If that doesn't help, reduce the batch size (default 64)." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "batch_size = 64\n", + "\n", + "import os\n", + "from hydra.experimental import compose, initialize\n", + "from hydra.core.global_hydra import GlobalHydra\n", + "from omegaconf import OmegaConf\n", + "import pytorch_lightning as pl\n", + "from nemo.collections.common.callbacks import LogEpochTimeCallback\n", + "from nemo.collections.tts.models import TalkNetDursModel\n", + "from nemo.core.config import hydra_runner\n", + "from nemo.utils.exp_manager import exp_manager\n", + "\n", + "epochs = 20\n", + "learning_rate = 1e-3\n", + "min_learning_rate = 3e-6\n", + "load_checkpoints = True\n", + "\n", + "def train(cfg):\n", + " cfg.sample_rate = 22050\n", + " cfg.train_dataset = os.path.join(output_dir, \"trainfiles.json\")\n", + " cfg.validation_datasets = os.path.join(output_dir, \"valfiles.json\")\n", + " cfg.durs_file = os.path.join(output_dir, \"durations.pt\")\n", + " cfg.f0_file = os.path.join(output_dir, \"f0s.pt\")\n", + " cfg.trainer.accelerator = \"dp\"\n", + " cfg.trainer.max_epochs = epochs\n", + " cfg.trainer.check_val_every_n_epoch = 5\n", + " cfg.model.train_ds.dataloader_params.batch_size = batch_size\n", + " cfg.model.validation_ds.dataloader_params.batch_size = batch_size\n", + " cfg.model.optim.lr = learning_rate\n", + " cfg.model.optim.sched.min_lr = min_learning_rate\n", + " cfg.exp_manager.exp_dir = output_dir\n", + "\n", + " # Find checkpoints\n", + " ckpt_path = \"\"\n", + " if load_checkpoints:\n", + " path0 = os.path.join(output_dir, \"TalkNetDurs\")\n", + " if os.path.exists(path0):\n", + " path1 = sorted(os.listdir(path0))\n", + " for i in range(len(path1)):\n", + " path2 = os.path.join(path0, path1[-(1+i)], \"checkpoints\")\n", + " if os.path.exists(path2):\n", + " match = [x for x in os.listdir(path2) if \"last.ckpt\" in x]\n", + " if len(match) > 0:\n", + " ckpt_path = os.path.join(path2, match[0])\n", + " print(\"Resuming training from \" + match[0])\n", + " break\n", + " \n", + " if ckpt_path != \"\":\n", + " trainer = pl.Trainer(**cfg.trainer, resume_from_checkpoint = ckpt_path)\n", + " model = TalkNetDursModel(cfg=cfg.model, trainer=trainer)\n", + " else:\n", + " warmstart_path = os.path.join(cwd, \"talknet_durs.nemo\")\n", + " trainer = pl.Trainer(**cfg.trainer)\n", + " model = TalkNetDursModel.restore_from(warmstart_path, override_config_path=cfg)\n", + " model.set_trainer(trainer)\n", + " model.setup_training_data(cfg.model.train_ds)\n", + " model.setup_validation_data(cfg.model.validation_ds)\n", + " model.setup_optimization(cfg.model.optim)\n", + " print(\"Warm-starting from \" + warmstart_path)\n", + " exp_manager(trainer, cfg.get('exp_manager', None))\n", + " trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa\n", + " trainer.fit(model)\n", + "\n", + "os.chdir(cwd)\n", + "GlobalHydra().clear()\n", + "initialize(config_path=\"conf\")\n", + "cfg = compose(config_name=\"talknet-durs\")\n", + "train(cfg)\n" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "nM7-bMpKO7U2" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 5:** Train pitch predictor.\n", + "\n", + "If CUDA runs out of memory, try the following:\n", + "* Click on Kernel -> Restart, re-run step 1, and try again.\n", + "* If that doesn't help, reduce the batch size (default 64)." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "batch_size = 64\n", + "epochs = 50\n", + "\n", + "import json\n", + "\n", + "with open(os.path.join(output_dir, \"f0_info.json\"), \"r\") as f:\n", + " f0_info = json.load(f)\n", + " f0_mean = f0_info[\"FO_MEAN\"]\n", + " f0_std = f0_info[\"F0_STD\"]\n", + "\n", + "learning_rate = 1e-3\n", + "min_learning_rate = 3e-6\n", + "load_checkpoints = True\n", + "\n", + "import os\n", + "from hydra.experimental import compose, initialize\n", + "from hydra.core.global_hydra import GlobalHydra\n", + "from omegaconf import OmegaConf\n", + "import pytorch_lightning as pl\n", + "from nemo.collections.common.callbacks import LogEpochTimeCallback\n", + "from nemo.collections.tts.models import TalkNetPitchModel\n", + "from nemo.core.config import hydra_runner\n", + "from nemo.utils.exp_manager import exp_manager\n", + "\n", + "def train(cfg):\n", + " cfg.sample_rate = 22050\n", + " cfg.train_dataset = os.path.join(output_dir, \"trainfiles.json\")\n", + " cfg.validation_datasets = os.path.join(output_dir, \"valfiles.json\")\n", + " cfg.durs_file = os.path.join(output_dir, \"durations.pt\")\n", + " cfg.f0_file = os.path.join(output_dir, \"f0s.pt\")\n", + " cfg.trainer.accelerator = \"dp\"\n", + " cfg.trainer.max_epochs = epochs\n", + " cfg.trainer.check_val_every_n_epoch = 5\n", + " cfg.model.f0_mean=f0_mean\n", + " cfg.model.f0_std=f0_std\n", + " cfg.model.train_ds.dataloader_params.batch_size = batch_size\n", + " cfg.model.validation_ds.dataloader_params.batch_size = batch_size\n", + " cfg.model.optim.lr = learning_rate\n", + " cfg.model.optim.sched.min_lr = min_learning_rate\n", + " cfg.exp_manager.exp_dir = output_dir\n", + "\n", + " # Find checkpoints\n", + " ckpt_path = \"\"\n", + " if load_checkpoints:\n", + " path0 = os.path.join(output_dir, \"TalkNetPitch\")\n", + " if os.path.exists(path0):\n", + " path1 = sorted(os.listdir(path0))\n", + " for i in range(len(path1)):\n", + " path2 = os.path.join(path0, path1[-(1+i)], \"checkpoints\")\n", + " if os.path.exists(path2):\n", + " match = [x for x in os.listdir(path2) if \"last.ckpt\" in x]\n", + " if len(match) > 0:\n", + " ckpt_path = os.path.join(path2, match[0])\n", + " print(\"Resuming training from \" + match[0])\n", + " break\n", + " \n", + " if ckpt_path != \"\":\n", + " trainer = pl.Trainer(**cfg.trainer, resume_from_checkpoint = ckpt_path)\n", + " model = TalkNetPitchModel(cfg=cfg.model, trainer=trainer)\n", + " else:\n", + " warmstart_path = os.path.join(cwd, \"talknet_pitch.nemo\")\n", + " trainer = pl.Trainer(**cfg.trainer)\n", + " model = TalkNetPitchModel.restore_from(warmstart_path, override_config_path=cfg)\n", + " model.set_trainer(trainer)\n", + " model.setup_training_data(cfg.model.train_ds)\n", + " model.setup_validation_data(cfg.model.validation_ds)\n", + " model.setup_optimization(cfg.model.optim)\n", + " print(\"Warm-starting from \" + warmstart_path)\n", + " exp_manager(trainer, cfg.get('exp_manager', None))\n", + " trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa\n", + " trainer.fit(model)\n", + "\n", + "os.chdir(cwd)\n", + "GlobalHydra().clear()\n", + "initialize(config_path=\"conf\")\n", + "cfg = compose(config_name=\"talknet-pitch\")\n", + "train(cfg)" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "JLfm00NuJfon" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 6:** Train spectrogram generator. 200+ epochs are recommended. \n", + "\n", + "This is the slowest of the three models to train, and the hardest to\n", + "get good results from. If your character sounds noisy or robotic,\n", + "try improving the dataset, or adjusting the epochs and learning rate.\n", + "\n", + "If CUDA runs out of memory, try the following:\n", + "* Click on Kernel -> Restart, re-run step 1, and try again.\n", + "* If that doesn't help, reduce the batch size (default 32)." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "epochs = 200\n", + "batch_size = 32\n", + "\n", + "# Advanced settings. You can probably leave these at their defaults (1e-3, 3e-6, empty, checked).\n", + "learning_rate = 1e-3\n", + "min_learning_rate = 3e-6\n", + "pretrained_path = \"\"\n", + "load_checkpoints = True\n", + "\n", + "import os\n", + "from hydra.experimental import compose, initialize\n", + "from hydra.core.global_hydra import GlobalHydra\n", + "from omegaconf import OmegaConf\n", + "import pytorch_lightning as pl\n", + "from nemo.collections.common.callbacks import LogEpochTimeCallback\n", + "from nemo.collections.tts.models import TalkNetSpectModel\n", + "from nemo.core.config import hydra_runner\n", + "from nemo.utils.exp_manager import exp_manager\n", + "\n", + "def train(cfg):\n", + " cfg.sample_rate = 22050\n", + " cfg.train_dataset = os.path.join(output_dir, \"trainfiles.json\")\n", + " cfg.validation_datasets = os.path.join(output_dir, \"valfiles.json\")\n", + " cfg.durs_file = os.path.join(output_dir, \"durations.pt\")\n", + " cfg.f0_file = os.path.join(output_dir, \"f0s.pt\")\n", + " cfg.trainer.accelerator = \"dp\"\n", + " cfg.trainer.max_epochs = epochs\n", + " cfg.trainer.check_val_every_n_epoch = 5\n", + " cfg.model.train_ds.dataloader_params.batch_size = batch_size\n", + " cfg.model.validation_ds.dataloader_params.batch_size = batch_size\n", + " cfg.model.optim.lr = learning_rate\n", + " cfg.model.optim.sched.min_lr = min_learning_rate\n", + " cfg.exp_manager.exp_dir = output_dir\n", + "\n", + " # Find checkpoints\n", + " ckpt_path = \"\"\n", + " if load_checkpoints:\n", + " path0 = os.path.join(output_dir, \"TalkNetSpect\")\n", + " if os.path.exists(path0):\n", + " path1 = sorted(os.listdir(path0))\n", + " for i in range(len(path1)):\n", + " path2 = os.path.join(path0, path1[-(1+i)], \"checkpoints\")\n", + " if os.path.exists(path2):\n", + " match = [x for x in os.listdir(path2) if \"last.ckpt\" in x]\n", + " if len(match) > 0:\n", + " ckpt_path = os.path.join(path2, match[0])\n", + " print(\"Resuming training from \" + match[0])\n", + " break\n", + " \n", + " if ckpt_path != \"\":\n", + " trainer = pl.Trainer(**cfg.trainer, resume_from_checkpoint = ckpt_path)\n", + " model = TalkNetSpectModel(cfg=cfg.model, trainer=trainer)\n", + " else:\n", + " if pretrained_path != \"\":\n", + " warmstart_path = pretrained_path\n", + " else:\n", + " warmstart_path = os.path.join(cwd, \"talknet_spect.nemo\")\n", + " trainer = pl.Trainer(**cfg.trainer)\n", + " model = TalkNetSpectModel.restore_from(warmstart_path, override_config_path=cfg)\n", + " model.set_trainer(trainer)\n", + " model.setup_training_data(cfg.model.train_ds)\n", + " model.setup_validation_data(cfg.model.validation_ds)\n", + " model.setup_optimization(cfg.model.optim)\n", + " print(\"Warm-starting from \" + warmstart_path)\n", + " exp_manager(trainer, cfg.get('exp_manager', None))\n", + " trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa\n", + " trainer.fit(model)\n", + "\n", + "os.chdir(cwd)\n", + "GlobalHydra().clear()\n", + "initialize(config_path=\"conf\")\n", + "cfg = compose(config_name=\"talknet-spect\")\n", + "train(cfg)" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "N9hh4WPHbCcn" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 7:** Generate GTA spectrograms. This will help HiFi-GAN learn what your TalkNet model sounds like.\n", + "\n", + "If this step fails, make sure you've finished training the spectrogram generator." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import sys\n", + "import os\n", + "import torch\n", + "import numpy as np\n", + "from tqdm import tqdm\n", + "from nemo.collections.tts.models import TalkNetSpectModel\n", + "import shutil\n", + "\n", + "def fix_paths(inpath):\n", + " output = \"\"\n", + " with open(inpath, \"r\", encoding=\"utf8\") as f:\n", + " for l in f.readlines():\n", + " if l[:5].lower() != \"wavs/\":\n", + " output += \"wavs/\" + l\n", + " else:\n", + " output += l\n", + " with open(inpath, \"w\", encoding=\"utf8\") as w:\n", + " w.write(output)\n", + "\n", + "shutil.copyfile(train_filelist, os.path.join(cwd, \"hifi-gan\", \"training.txt\"))\n", + "shutil.copyfile(val_filelist, os.path.join(cwd, \"hifi-gan\", \"validation.txt\"))\n", + "fix_paths(os.path.join(cwd, \"hifi-gan\", \"training.txt\"))\n", + "fix_paths(os.path.join(cwd, \"hifi-gan\", \"validation.txt\"))\n", + "fix_paths(os.path.join(output_dir, \"allfiles.txt\"))\n", + "\n", + "os.chdir(cwd)\n", + "outdir = os.path.join(output_dir, \"_training_data\", \"wavs\")\n", + "if not os.path.exists(outdir):\n", + " os.mkdir(outdir)\n", + "\n", + "model_path = \"\"\n", + "path0 = os.path.join(output_dir, \"TalkNetSpect\")\n", + "if os.path.exists(path0):\n", + " path1 = sorted(os.listdir(path0))\n", + " for i in range(len(path1)):\n", + " path2 = os.path.join(path0, path1[-(1+i)], \"checkpoints\")\n", + " if os.path.exists(path2):\n", + " match = [x for x in os.listdir(path2) if \"TalkNetSpect.nemo\" in x]\n", + " if len(match) > 0:\n", + " model_path = os.path.join(path2, match[0])\n", + " break\n", + "assert model_path != \"\", \"TalkNetSpect.nemo not found\"\n", + "\n", + "dur_path = os.path.join(output_dir, \"durations.pt\")\n", + "f0_path = os.path.join(output_dir, \"f0s.pt\")\n", + "\n", + "model = TalkNetSpectModel.restore_from(model_path)\n", + "model.eval()\n", + "with open(os.path.join(output_dir, \"allfiles.txt\"), \"r\", encoding=\"utf-8\") as f:\n", + " dataset = f.readlines()\n", + "durs = torch.load(dur_path)\n", + "f0s = torch.load(f0_path)\n", + "\n", + "for x in tqdm(dataset):\n", + " x_name = os.path.splitext(os.path.basename(x.split(\"|\")[0].strip()))[0]\n", + " x_tokens = model.parse(text=x.split(\"|\")[1].strip())\n", + " x_durs = (\n", + " torch.stack(\n", + " (\n", + " durs[x_name][\"blanks\"],\n", + " torch.cat((durs[x_name][\"tokens\"], torch.zeros(1).int())),\n", + " ),\n", + " dim=1,\n", + " )\n", + " .view(-1)[:-1]\n", + " .view(1, -1)\n", + " .to(\"cuda:0\")\n", + " )\n", + " x_f0s = f0s[x_name].view(1, -1).to(\"cuda:0\")\n", + " x_spect = model.force_spectrogram(tokens=x_tokens, durs=x_durs, f0=x_f0s)\n", + " rel_path = os.path.splitext(x.split(\"|\")[0].strip())[0][5:]\n", + " abs_dir = os.path.join(outdir, os.path.dirname(rel_path))\n", + " if abs_dir != \"\" and not os.path.exists(abs_dir):\n", + " os.makedirs(abs_dir, exist_ok=True)\n", + " np.save(os.path.join(outdir, rel_path + \".npy\"), x_spect.detach().cpu().numpy())\n" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "Ajfyfz2p9Ior" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 8:** Train HiFi-GAN. 2,000+ steps are recommended.\n", + "Stop this cell to finish training the model.\n", + "\n", + "* Click on Kernel -> Restart, re-run step 1, and try again.\n", + "If this step still fails to start, make sure step 7 finished successfully.\n", + "\n", + "Note: If the training process starts at step 2500000, delete the HiFiGAN folder and try again." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import gdown\n", + "d = 'https://drive.google.com/uc?id='\n", + "\n", + "os.chdir(os.path.join(cwd, \"hifi-gan\"))\n", + "\n", + "if not os.path.exists(os.path.join(output_dir, \"HiFiGAN\")):\n", + " os.makedirs(os.path.join(output_dir, \"HiFiGAN\"))\n", + "if not os.path.exists(os.path.join(output_dir, \"HiFiGAN\", \"do_00000000\")):\n", + " print(\"Downloading universal model...\")\n", + " gdown.download(d+\"1qpgI41wNXFcH-iKq1Y42JlBC9j0je8PW\", os.path.join(output_dir, \"HiFiGAN\", \"g_00000000\"), quiet=False)\n", + " gdown.download(d+\"1O63eHZR9t1haCdRHQcEgMfMNxiOciSru\", os.path.join(output_dir, \"HiFiGAN\", \"do_00000000\"), quiet=False)\n", + " start_from_universal = \"--warm_start True \"\n", + "else:\n", + " start_from_universal = \"\"\n", + "\n", + "hifi_train = os.path.join(cwd, \"hifi-gan\", \"training.txt\")\n", + "hifi_val = os.path.join(cwd, \"hifi-gan\", \"validation.txt\")\n", + "hifi_wavs = os.path.join(output_dir, \"_training_data\")\n", + "\n", + "!python train.py --fine_tuning True --config config_v1b.json \\\n", + "{start_from_universal} \\\n", + "--checkpoint_interval 250 --checkpoint_path \"{os.path.join(output_dir, 'HiFiGAN')}\" \\\n", + "--input_training_file \"{hifi_train}\" \\\n", + "--input_validation_file \"{hifi_val}\" \\\n", + "--input_wavs_dir \"{hifi_wavs}\"\n" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "yVBjGhRB9hUJ" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 9:** Package the models. They'll be saved to the output directory as [character_name]_TalkNet.zip.\n", + "\n", + "When done, upload it to Google Drive, with permissions set to \"Anyone with the link\". \n", + "You can then use it with TalkNet by selecting \"Custom model\" as your character. \n", + "\n", + "This cell will also delete the training checkpoints and logs.\n", + "That should free up roughly 2 GB of space.\n", + "If you wish to keep them, set delete_checkpoints to False." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "character_name = \"Character\"\n", + "delete_checkpoints = True\n", + "\n", + "import shutil\n", + "from zipfile import ZipFile\n", + "\n", + "def find_talknet(model_dir):\n", + " ckpt_path = \"\"\n", + " path0 = os.path.join(output_dir, model_dir)\n", + " if os.path.exists(path0):\n", + " path1 = sorted(os.listdir(path0))\n", + " for i in range(len(path1)):\n", + " path2 = os.path.join(path0, path1[-(1+i)], \"checkpoints\")\n", + " if os.path.exists(path2):\n", + " match = [x for x in os.listdir(path2) if \".nemo\" in x]\n", + " if len(match) > 0:\n", + " ckpt_path = os.path.join(path2, match[0])\n", + " break\n", + " assert ckpt_path != \"\", \"Couldn't find \" + model_dir\n", + " return ckpt_path\n", + "\n", + "durs_path = find_talknet(\"TalkNetDurs\")\n", + "pitch_path = find_talknet(\"TalkNetPitch\")\n", + "spect_path = find_talknet(\"TalkNetSpect\")\n", + "assert os.path.exists(os.path.join(output_dir, \"HiFiGAN\", \"g_00000000\")), \"Couldn't find HiFi-GAN\"\n", + "\n", + "zip = ZipFile(os.path.join(output_dir, character_name + \"_TalkNet.zip\"), 'w')\n", + "zip.write(durs_path, \"TalkNetDurs.nemo\")\n", + "zip.write(pitch_path, \"TalkNetPitch.nemo\")\n", + "zip.write(spect_path, \"TalkNetSpect.nemo\")\n", + "zip.write(os.path.join(output_dir, \"HiFiGAN\", \"g_00000000\"), \"hifiganmodel\")\n", + "zip.write(os.path.join(output_dir, \"HiFiGAN\", \"config.json\"), \"config.json\")\n", + "zip.write(os.path.join(output_dir, \"f0_info.json\"), \"f0_info.json\")\n", + "zip.close()\n", + "print(\"Archived model to \" + os.path.join(output_dir, character_name + \"_TalkNet.zip\"))\n", + "\n", + "if delete_checkpoints:\n", + " shutil.rmtree((os.path.join(output_dir, \"TalkNetDurs\")))\n", + " shutil.rmtree((os.path.join(output_dir, \"TalkNetPitch\")))\n", + " shutil.rmtree((os.path.join(output_dir, \"TalkNetSpect\")))\n", + " shutil.rmtree((os.path.join(output_dir, \"HiFiGAN\")))\n" + ], + "outputs": [], + "metadata": { + "cellView": "form", + "id": "5OtwfrTT-blU" + } + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [], + "name": "TalkNet_Training_Offline.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/future-todo/ControllableTalkNet/__init__.py b/future-todo/ControllableTalkNet/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/future-todo/ControllableTalkNet/assets/dash_customfont.css b/future-todo/ControllableTalkNet/assets/dash_customfont.css new file mode 100644 index 0000000..c9855c1 --- /dev/null +++ b/future-todo/ControllableTalkNet/assets/dash_customfont.css @@ -0,0 +1,420 @@ +@font-face { + font-family: 'EquestriaWebfont'; + src: url('Equestria.woff') format('woff'); +} + +/* Table of contents +–––––––––––––––––––––––––––––––––––––––––––––––––– +- Plotly.js +- Grid +- Base Styles +- Typography +- Links +- Buttons +- Forms +- Lists +- Code +- Tables +- Spacing +- Utilities +- Clearing +- Media Queries +*/ + +/* PLotly.js +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* plotly.js's modebar's z-index is 1001 by default + * https://github.com/plotly/plotly.js/blob/7e4d8ab164258f6bd48be56589dacd9bdd7fded2/src/css/_modebar.scss#L5 + * In case a dropdown is above the graph, the dropdown's options + * will be rendered below the modebar + * Increase the select option's z-index + */ + +/* This was actually not quite right - + dropdowns were overlapping each other (edited October 26) + +.Select { + z-index: 1002; +}*/ + + +/* Grid +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.container { + position: relative; + width: 100%; + max-width: 960px; + margin: 0 auto; + padding: 0 20px; + box-sizing: border-box; } +.column, +.columns { + width: 100%; + float: left; + box-sizing: border-box; } + +/* For devices larger than 400px */ +@media (min-width: 400px) { + .container { + width: 85%; + padding: 0; } +} + +/* For devices larger than 550px */ +@media (min-width: 550px) { + .container { + width: 80%; } + .column, + .columns { + margin-left: 4%; } + .column:first-child, + .columns:first-child { + margin-left: 0; } + + .one.column, + .one.columns { width: 4.66666666667%; } + .two.columns { width: 13.3333333333%; } + .three.columns { width: 22%; } + .four.columns { width: 30.6666666667%; } + .five.columns { width: 39.3333333333%; } + .six.columns { width: 48%; } + .seven.columns { width: 56.6666666667%; } + .eight.columns { width: 65.3333333333%; } + .nine.columns { width: 74.0%; } + .ten.columns { width: 82.6666666667%; } + .eleven.columns { width: 91.3333333333%; } + .twelve.columns { width: 100%; margin-left: 0; } + + .one-third.column { width: 30.6666666667%; } + .two-thirds.column { width: 65.3333333333%; } + + .one-half.column { width: 48%; } + + /* Offsets */ + .offset-by-one.column, + .offset-by-one.columns { margin-left: 8.66666666667%; } + .offset-by-two.column, + .offset-by-two.columns { margin-left: 17.3333333333%; } + .offset-by-three.column, + .offset-by-three.columns { margin-left: 26%; } + .offset-by-four.column, + .offset-by-four.columns { margin-left: 34.6666666667%; } + .offset-by-five.column, + .offset-by-five.columns { margin-left: 43.3333333333%; } + .offset-by-six.column, + .offset-by-six.columns { margin-left: 52%; } + .offset-by-seven.column, + .offset-by-seven.columns { margin-left: 60.6666666667%; } + .offset-by-eight.column, + .offset-by-eight.columns { margin-left: 69.3333333333%; } + .offset-by-nine.column, + .offset-by-nine.columns { margin-left: 78.0%; } + .offset-by-ten.column, + .offset-by-ten.columns { margin-left: 86.6666666667%; } + .offset-by-eleven.column, + .offset-by-eleven.columns { margin-left: 95.3333333333%; } + + .offset-by-one-third.column, + .offset-by-one-third.columns { margin-left: 34.6666666667%; } + .offset-by-two-thirds.column, + .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } + + .offset-by-one-half.column, + .offset-by-one-half.columns { margin-left: 52%; } + +} + + +/* Base Styles +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* NOTE +html is set to 62.5% so that all the REM measurements throughout Skeleton +are based on 10px sizing. So basically 1.5rem = 15px :) */ +html { + font-size: 62.5%; } +body { + font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ + line-height: 1.6; + font-weight: 400; + font-family: "Open Sans", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: rgb(50, 50, 50); } + + +/* Typography +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 0; + font-weight: 300; } +h1 { font-size: 4.5rem; line-height: 1.2; letter-spacing: -.1rem; margin-bottom: 2rem; } +h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; margin-bottom: 1.8rem; margin-top: 1.8rem;} +h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; margin-bottom: 1.5rem; margin-top: 1.5rem;} +h4 { font-size: 2.6rem; line-height: 1.35; letter-spacing: -.08rem; margin-bottom: 1.2rem; margin-top: 1.2rem;} +h5 { font-size: 2.2rem; line-height: 1.5; letter-spacing: -.05rem; margin-bottom: 0.6rem; margin-top: 0.6rem;} +h6 { font-size: 2.0rem; line-height: 1.6; letter-spacing: 0; margin-bottom: 0.75rem; margin-top: 0.75rem;} + +p { + margin-top: 0; } + + +/* Blockquotes +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +blockquote { + border-left: 4px lightgrey solid; + padding-left: 1rem; + margin-top: 2rem; + margin-bottom: 2rem; + margin-left: 0rem; +} + + +/* Links +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +a { + color: #1EAEDB; + text-decoration: underline; + cursor: pointer;} +a:hover { + color: #0FA0CE; } + + +/* Buttons +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.button, +button, +input[type="submit"], +input[type="reset"], +input[type="button"] { + display: inline-block; + height: 38px; + padding: 0 30px; + color: #555; + text-align: center; + font-size: 11px; + font-weight: 600; + line-height: 38px; + letter-spacing: .1rem; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border-radius: 4px; + border: 1px solid #bbb; + cursor: pointer; + box-sizing: border-box; } +.button:hover, +button:hover, +input[type="submit"]:hover, +input[type="reset"]:hover, +input[type="button"]:hover, +.button:focus, +button:focus, +input[type="submit"]:focus, +input[type="reset"]:focus, +input[type="button"]:focus { + color: #333; + border-color: #888; + outline: 0; } +.button.button-primary, +button.button-primary, +input[type="submit"].button-primary, +input[type="reset"].button-primary, +input[type="button"].button-primary { + color: #FFF; + background-color: #33C3F0; + border-color: #33C3F0; } +.button.button-primary:hover, +button.button-primary:hover, +input[type="submit"].button-primary:hover, +input[type="reset"].button-primary:hover, +input[type="button"].button-primary:hover, +.button.button-primary:focus, +button.button-primary:focus, +input[type="submit"].button-primary:focus, +input[type="reset"].button-primary:focus, +input[type="button"].button-primary:focus { + color: #FFF; + background-color: #1EAEDB; + border-color: #1EAEDB; } + + +/* Forms +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea, +select { + height: 38px; + padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ + background-color: #fff; + border: 1px solid #D1D1D1; + border-radius: 4px; + box-shadow: none; + box-sizing: border-box; + font-family: inherit; + font-size: inherit; /*https://stackoverflow.com/questions/6080413/why-doesnt-input-inherit-the-font-from-body*/} +/* Removes awkward default styles on some inputs for iOS */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } +textarea { + min-height: 65px; + padding-top: 6px; + padding-bottom: 6px; } +input[type="email"]:focus, +input[type="number"]:focus, +input[type="search"]:focus, +input[type="text"]:focus, +input[type="tel"]:focus, +input[type="url"]:focus, +input[type="password"]:focus, +textarea:focus, +select:focus { + border: 1px solid #33C3F0; + outline: 0; } +label, +legend { + display: block; + margin-bottom: 0px; } +fieldset { + padding: 0; + border-width: 0; } +input[type="checkbox"], +input[type="radio"] { + display: inline; } +label > .label-body { + display: inline-block; + margin-left: .5rem; + font-weight: normal; } + + +/* Lists +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +ul { + list-style: circle inside; } +ol { + list-style: decimal inside; } +ol, ul { + padding-left: 0; + margin-top: 0; } +ul ul, +ul ol, +ol ol, +ol ul { + margin: 1.5rem 0 1.5rem 3rem; + font-size: 90%; } +li { + margin-bottom: 1rem; } + + +/* Tables +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +table { + border-collapse: collapse; +} +th:not(.CalendarDay), +td:not(.CalendarDay) { + padding: 12px 15px; + text-align: left; + border-bottom: 1px solid #E1E1E1; } +th:first-child:not(.CalendarDay), +td:first-child:not(.CalendarDay) { + padding-left: 0; } +th:last-child:not(.CalendarDay), +td:last-child:not(.CalendarDay) { + padding-right: 0; } + + +/* Spacing +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +button, +.button { + margin-bottom: 0rem; } +input, +textarea, +select, +fieldset { + margin-bottom: 0rem; } +pre, +dl, +figure, +table, +form { + margin-bottom: 0rem; } +p, +ul, +ol { + margin-bottom: 0.75rem; } + +/* Utilities +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.u-full-width { + width: 100%; + box-sizing: border-box; } +.u-max-full-width { + max-width: 100%; + box-sizing: border-box; } +.u-pull-right { + float: right; } +.u-pull-left { + float: left; } + + +/* Misc +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +hr { + margin-top: 3rem; + margin-bottom: 3.5rem; + border-width: 0; + border-top: 1px solid #E1E1E1; } + + +/* Clearing +–––––––––––––––––––––––––––––––––––––––––––––––––– */ + +/* Self Clearing Goodness */ +.container:after, +.row:after, +.u-cf { + content: ""; + display: table; + clear: both; } + + +/* Media Queries +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* +Note: The best way to structure the use of media queries is to create the queries +near the relevant code. For example, if you wanted to change the styles for buttons +on small devices, paste the mobile query code up in the buttons section and style it +there. +*/ + + +/* Larger than mobile */ +@media (min-width: 400px) {} + +/* Larger than phablet (also point when grid becomes active) */ +@media (min-width: 550px) {} + +/* Larger than tablet */ +@media (min-width: 750px) {} + +/* Larger than desktop */ +@media (min-width: 1000px) {} + +/* Larger than Desktop HD */ +@media (min-width: 1200px) {} \ No newline at end of file diff --git a/future-todo/ControllableTalkNet/controllable_talknet.py b/future-todo/ControllableTalkNet/controllable_talknet.py new file mode 100644 index 0000000..f258054 --- /dev/null +++ b/future-todo/ControllableTalkNet/controllable_talknet.py @@ -0,0 +1,1097 @@ +import sys +import os +import base64 +import dash +from jupyter_dash import JupyterDash +import dash_core_components as dcc +import dash_html_components as html +import dash_bootstrap_components as dbc +from dash.exceptions import PreventUpdate +import torch +import numpy as np +import tensorflow as tf +import crepe +import scipy +from scipy.io import wavfile +import psola +import io +import nemo +from nemo.collections.asr.models import EncDecCTCModel +from nemo.collections.tts.models import TalkNetSpectModel +from nemo.collections.tts.models import TalkNetPitchModel +from nemo.collections.tts.models import TalkNetDursModel +from ControllableTalkNet.talknet_singer import TalkNetSingerModel +import json +from tqdm import tqdm +import gdown +import zipfile +import resampy +import traceback +import ffmpeg +import time +import uuid + +sys.path.append("hifi-gan") +from hifigan.env import AttrDict +from hifigan.meldataset import mel_spectrogram, MAX_WAV_VALUE +from hifigan.models import Generator +from hifigan.denoiser import Denoiser + +app = JupyterDash(__name__) +DEVICE = "cuda:0" +CPU_PITCH = False +RUN_PATH = os.path.dirname(os.path.realpath(__file__)) +if RUN_PATH == "/content": + UI_MODE = "colab" +elif os.path.exists("/talknet/is_docker"): + UI_MODE = "docker" +else: + UI_MODE = "offline" +torch.set_grad_enabled(False) +if CPU_PITCH: + tf.config.set_visible_devices([], "GPU") + +app.title = "Controllable TalkNet" +app.layout = html.Div( + children=[ + html.H1( + id="header", + children="Controllable TalkNet", + style={ + "font-family": "EquestriaWebfont", + "color": "#ed3c96", + "font-size": "4em", + "text-align": "center", + "margin-top": "0em", + "margin-bottom": "0em", + }, + ), + html.Label("Character selection", htmlFor="model-dropdown"), + dbc.Select( + id="model-dropdown", + options=[ + { + "label": "Custom model", + "value": "Custom", + }, + { + "label": "--- ERROR LOADING MODEL LISTS ---", + "value": "", + "disabled": True, + }, + ], + value=None, + style={ + "max-width": "90vw", + "width": "35em", + "margin-bottom": "0.7em", + }, + ), + html.Div( + children=[ + dcc.Input( + id="drive-id", + type="text", + placeholder="Drive ID for custom model", + style={"width": "22em"}, + ), + ], + id="custom-model", + style={ + "display": "none", + }, + ), + html.Label( + "Upload reference audio to " + RUN_PATH, + htmlFor="reference-dropdown", + id="upload-label", + ), + dcc.Upload( + id="upload-audio", + children=html.Div(["Drag and drop or click to select a file to upload."]), + style={ + "display": "none", + }, + multiple=True, + ), + dcc.Store(id="current-f0s"), + dcc.Store(id="current-f0s-nosilence"), + dcc.Store(id="current-filename"), + dcc.Loading( + id="audio-loading", + children=[ + html.Div( + [ + html.Button( + "Update file list", + id="update-button", + style={ + "margin-right": "10px", + }, + ), + dbc.Select( + id="reference-dropdown", + options=[], + value=None, + style={ + "max-width": "80vw", + "width": "30em", + }, + disabled=False, + ), + dcc.Store(id="pitch-clicks"), + html.Button( + "Debug pitch", + id="pitch-button", + style={ + "margin-left": "10px", + }, + disabled=False, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "row", + "margin-left": "50px", + "vertical-align": "middle", + }, + ), + html.Audio( + id="pitch-out", + controls=True, + style={"display": "none"}, + ), + html.Div( + id="audio-loading-output", + style={ + "font-style": "italic", + "margin-bottom": "0.7em", + "text-align": "center", + }, + ), + ], + type="default", + ), + html.Div( + [ + dcc.Checklist( + id="pitch-options", + options=[ + {"label": "Change input pitch", "value": "pf"}, + {"label": "Auto-tune output", "value": "pc"}, + {"label": "Disable reference audio", "value": "dra"}, + ], + value=[], + ), + html.Div( + [ + html.Label("Semitones", htmlFor="pitch-factor"), + dcc.Input( + id="pitch-factor", + type="number", + value="0", + style={"width": "7em"}, + min=-11, + max=11, + step=1, + disabled=True, + ), + ], + style={ + "flex-direction": "column", + "margin-left": "10px", + "margin-bottom": "0.7em", + }, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "row", + "margin-left": "50px", + "margin-bottom": "0.7em", + }, + ), + html.Label("Transcript", htmlFor="transcript-input"), + dcc.Textarea( + id="transcript-input", + value="", + style={ + "max-width": "90vw", + "width": "50em", + "height": "8em", + "margin-bottom": "0.7em", + }, + ), + dcc.Loading( + html.Div( + [ + html.Button( + "Generate", + id="gen-button", + ), + html.Audio( + id="audio-out", + controls=True, + style={ + "display": "none", + }, + ), + html.Div( + id="generated-info", + style={ + "font-style": "italic", + }, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "column", + }, + ) + ), + html.Footer( + children=""" + Presented by the Pony Preservation Project. + """, + style={"margin-top": "2em", "font-size": "0.7em"}, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "column", + "background-color": "#FFF", + }, +) + +upload_display = { + "width": "100%", + "height": "60px", + "lineHeight": "60px", + "borderWidth": "1px", + "borderStyle": "dashed", + "borderRadius": "5px", + "textAlign": "center", + "margin": "10px", +} + +playback_style = { + "margin-top": "0.3em", + "margin-bottom": "0.3em", + "display": "block", + "width": "600px", + "max-width": "90vw", +} + +playback_hide = { + "display": "none", +} + + +@app.callback( + [ + dash.dependencies.Output("model-dropdown", "options"), + dash.dependencies.Output("upload-audio", "style"), + ], + dash.dependencies.Input("header", "children"), +) +def init_dropdown(value): + if UI_MODE == "docker": + upload_style = upload_display + else: + upload_style = playback_hide + + dropdown = [ + { + "label": "Custom model", + "value": "Custom|default", + } + ] + prev_values = ["Custom|default"] + + def add_to_dropdown(entry): + if entry["value"] in prev_values: + return + dropdown.append(entry) + prev_values.append(entry["value"]) + + all_dict = {} + for filename in os.listdir("model_lists"): + if len(filename) < 5 or filename[-5:].lower() != ".json": + continue + with open(os.path.join("model_lists", filename)) as f: + j = json.load(f) + for s in j: + for c in s["characters"]: + c["source_file"] = filename[:-5] + if s["source"] not in all_dict: + all_dict[s["source"]] = s["characters"] + else: + all_dict[s["source"]].extend(s["characters"]) + for k in sorted(all_dict): + seen_chars = [] + seen_ids = [] + characters = {} + characters_sing = {} + has_singers = False + for c in all_dict[k]: + if c["drive_id"] in seen_ids: + continue + seen_ids.append(c["drive_id"]) + # Handle duplicate names + if c["name"] in seen_chars: + if c["name"] in characters: + rename = ( + c["name"] + " [" + characters[c["name"]]["source_file"] + "]" + ) + characters[rename] = characters[c["name"]] + del characters[c["name"]] + c["name"] = c["name"] + " [" + c["source_file"] + "]" + else: + seen_chars.append(c["name"]) + + characters[c["name"]] = { + "drive_id": c["drive_id"], + "is_singing": c["is_singing"], + "source_file": c["source_file"], + } + if c["is_singing"]: + has_singers = True + if has_singers: + for ck in sorted(characters): + if characters[ck]["is_singing"]: + characters_sing[ck] = characters[ck] + del characters[ck] + separator = "--- " + k.strip().upper() + " MODELS (TALKING) ---" + else: + separator = "--- " + k.strip().upper() + " MODELS ---" + if len(characters) > 0: + add_to_dropdown( + { + "label": separator, + "value": str(uuid.uuid4()) + "|default", + "disabled": True, + } + ) + for ck in sorted(characters): + add_to_dropdown( + { + "label": ck, + "value": characters[ck]["drive_id"] + "|default", + } + ) + if has_singers: + separator = "--- " + k.strip().upper() + " MODELS (SINGING) ---" + add_to_dropdown( + { + "label": separator, + "value": str(uuid.uuid4()) + "|default", + "disabled": True, + } + ) + for ck in sorted(characters_sing): + add_to_dropdown( + { + "label": ck, + "value": characters_sing[ck]["drive_id"] + "|singing", + } + ) + if len(all_dict) == 0: + add_to_dropdown( + { + "label": "--- NO MODEL LISTS FOUND ---", + "value": str(uuid.uuid4()) + "|default", + "disabled": True, + } + ) + return [dropdown, upload_style] + + +def load_hifigan(model_name, conf_name): + # Load HiFi-GAN + conf = os.path.join("hifi-gan", conf_name + ".json") + with open(conf) as f: + json_config = json.loads(f.read()) + h = AttrDict(json_config) + torch.manual_seed(h.seed) + hifigan = Generator(h).to(torch.device(DEVICE)) + state_dict_g = torch.load(model_name, map_location=torch.device(DEVICE)) + hifigan.load_state_dict(state_dict_g["generator"]) + hifigan.eval() + hifigan.remove_weight_norm() + denoiser = Denoiser(hifigan, mode="normal") + return hifigan, h, denoiser + + +def generate_json(input, outpath): + output = "" + sample_rate = 22050 + lpath = input.split("|")[0].strip() + size = os.stat(lpath).st_size + x = { + "audio_filepath": lpath, + "duration": size / (sample_rate * 2), + "text": input.split("|")[1].strip(), + } + output += json.dumps(x) + "\n" + with open(outpath, "w", encoding="utf8") as w: + w.write(output) + + +asr_model = ( + EncDecCTCModel.from_pretrained(model_name="asr_talknet_aligner").cpu().eval() +) + + +def forward_extractor(tokens, log_probs, blank): + """Computes states f and p.""" + n, m = len(tokens), log_probs.shape[0] + # `f[s, t]` -- max sum of log probs for `s` first codes + # with `t` first timesteps with ending in `tokens[s]`. + f = np.empty((n + 1, m + 1), dtype=float) + f.fill(-(10 ** 9)) + p = np.empty((n + 1, m + 1), dtype=int) + f[0, 0] = 0.0 # Start + for s in range(1, n + 1): + c = tokens[s - 1] + for t in range((s + 1) // 2, m + 1): + f[s, t] = log_probs[t - 1, c] + # Option #1: prev char is equal to current one. + if s == 1 or c == blank or c == tokens[s - 3]: + options = f[s : (s - 2 if s > 1 else None) : -1, t - 1] + else: # Is not equal to current one. + options = f[s : (s - 3 if s > 2 else None) : -1, t - 1] + f[s, t] += np.max(options) + p[s, t] = np.argmax(options) + return f, p + + +def backward_extractor(f, p): + """Computes durs from f and p.""" + n, m = f.shape + n -= 1 + m -= 1 + durs = np.zeros(n, dtype=int) + if f[-1, -1] >= f[-2, -1]: + s, t = n, m + else: + s, t = n - 1, m + while s > 0: + durs[s - 1] += 1 + s -= p[s, t] + t -= 1 + assert durs.shape[0] == n + assert np.sum(durs) == m + assert np.all(durs[1::2] > 0) + return durs + + +def preprocess_tokens(tokens, blank): + new_tokens = [blank] + for c in tokens: + new_tokens.extend([c, blank]) + tokens = new_tokens + return tokens + + +parser = ( + nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset.make_vocab( + notation="phonemes", + punct=True, + spaces=True, + stresses=False, + add_blank_at="last", + ) +) + + +def arpa_parse(input, model): + z = [] + space = parser.labels.index(" ") + while "{" in input: + if "}" not in input: + input.replace("{", "") + else: + pre = input[: input.find("{")] + if pre.strip() != "": + x = model.parse(text=pre.strip()) + seq_ids = x.squeeze(0).cpu().detach().numpy() + z.extend(seq_ids) + z.append(space) + + arpaword = input[input.find("{") + 1 : input.find("}")] + arpaword = ( + arpaword.replace("0", "") + .replace("1", "") + .replace("2", "") + .strip() + .split(" ") + ) + + seq_ids = [] + for x in arpaword: + if x == "": + continue + if x.replace("_", " ") not in parser.labels: + continue + seq_ids.append(parser.labels.index(x.replace("_", " "))) + seq_ids.append(space) + z.extend(seq_ids) + input = input[input.find("}") + 1 :] + if input != "": + x = model.parse(text=input.strip()) + seq_ids = x.squeeze(0).cpu().detach().numpy() + z.extend(seq_ids) + if z[-1] == space: + z = z[:-1] + if z[0] == space: + z = z[1:] + return [ + z[i] for i in range(len(z)) if (i == 0) or (z[i] != z[i - 1]) or (z[i] != space) + ] + + +def to_arpa(input): + arpa = "" + z = [] + space = parser.labels.index(" ") + while space in input: + z.append(input[: input.index(space)]) + input = input[input.index(space) + 1 :] + z.append(input) + for y in z: + if len(y) == 0: + continue + + arpaword = " {" + for s in y: + if parser.labels[s] == " ": + arpaword += "_ " + else: + arpaword += parser.labels[s] + " " + arpaword += "} " + if not arpaword.replace("{", "").replace("}", "").replace(" ", "").isalnum(): + arpaword = arpaword.replace("{", "").replace(" }", "") + arpa += arpaword + return arpa.replace(" ", " ").replace(" }", "}").strip() + + +def get_duration(wav_name, transcript, tokens): + if not os.path.exists(os.path.join(RUN_PATH, "temp")): + os.mkdir(os.path.join(RUN_PATH, "temp")) + if "_" not in transcript: + generate_json( + os.path.join(RUN_PATH, "temp", wav_name + "_conv.wav") + + "|" + + transcript.strip(), + os.path.join(RUN_PATH, "temp", wav_name + ".json"), + ) + else: + generate_json( + os.path.join(RUN_PATH, "temp", wav_name + "_conv.wav") + "|" + "dummy", + os.path.join(RUN_PATH, "temp", wav_name + ".json"), + ) + + data_config = { + "manifest_filepath": os.path.join(RUN_PATH, "temp", wav_name + ".json"), + "sample_rate": 22050, + "batch_size": 1, + } + + dataset = nemo.collections.asr.data.audio_to_text._AudioTextDataset( + manifest_filepath=data_config["manifest_filepath"], + sample_rate=data_config["sample_rate"], + parser=parser, + ) + + dl = torch.utils.data.DataLoader( + dataset=dataset, + batch_size=data_config["batch_size"], + collate_fn=dataset.collate_fn, + shuffle=False, + ) + + blank_id = asr_model.decoder.num_classes_with_blank - 1 + + for sample_idx, test_sample in tqdm(enumerate(dl), total=len(dl)): + log_probs, _, greedy_predictions = asr_model( + input_signal=test_sample[0], input_signal_length=test_sample[1] + ) + + log_probs = log_probs[0].cpu().detach().numpy() + target_tokens = preprocess_tokens(tokens, blank_id) + + f, p = forward_extractor(target_tokens, log_probs, blank_id) + durs = backward_extractor(f, p) + + del test_sample + return durs + return None + + +def crepe_f0(wav_path, hop_length=256): + # sr, audio = wavfile.read(io.BytesIO(wav_data)) + sr, audio = wavfile.read(wav_path) + audio_x = np.arange(0, len(audio)) / 22050.0 + f0time, frequency, confidence, activation = crepe.predict(audio, sr, viterbi=True) + + x = np.arange(0, len(audio), hop_length) / 22050.0 + freq_interp = np.interp(x, f0time, frequency) + conf_interp = np.interp(x, f0time, confidence) + audio_interp = np.interp(x, audio_x, np.absolute(audio)) / 32768.0 + weights = [0.5, 0.25, 0.25] + audio_smooth = np.convolve(audio_interp, np.array(weights)[::-1], "same") + + conf_threshold = 0.25 + audio_threshold = 0.0005 + for i in range(len(freq_interp)): + if conf_interp[i] < conf_threshold: + freq_interp[i] = 0.0 + if audio_smooth[i] < audio_threshold: + freq_interp[i] = 0.0 + + # Hack to make f0 and mel lengths equal + if len(audio) % hop_length == 0: + freq_interp = np.pad(freq_interp, pad_width=[0, 1]) + return ( + torch.from_numpy(freq_interp.astype(np.float32)), + torch.from_numpy(frequency.astype(np.float32)), + ) + + +def f0_to_audio(f0s): + volume = 0.2 + sr = 22050 + freq = 440.0 + base_audio = ( + np.sin(2 * np.pi * np.arange(256.0 * len(f0s)) * freq / sr) * volume + ).astype(np.float32) + shifted_audio = psola.vocode(base_audio, sr, target_pitch=f0s) + for i in range(len(f0s)): + if f0s[i] == 0.0: + shifted_audio[i * 256 : (i + 1) * 256] = 0.0 + print(type(shifted_audio[0])) + buffer = io.BytesIO() + wavfile.write(buffer, sr, shifted_audio.astype(np.float32)) + b64 = base64.b64encode(buffer.getvalue()) + sound = "data:audio/x-wav;base64," + b64.decode("ascii") + return sound + + +@app.callback( + dash.dependencies.Output("custom-model", "style"), + dash.dependencies.Input("model-dropdown", "value"), +) +def update_model(model): + if model is not None and model.split("|")[0] == "Custom": + style = {"margin-bottom": "0.7em", "display": "block"} + else: + style = {"display": "none"} + return style + + +@app.callback( + [ + dash.dependencies.Output("pitch-factor", "disabled"), + dash.dependencies.Output("reference-dropdown", "disabled"), + dash.dependencies.Output("pitch-button", "disabled"), + ], + [ + dash.dependencies.Input("pitch-options", "value"), + ], +) +def update_pitch_options(value): + return ["pf" not in value, "dra" in value, "dra" in value] + + +@app.callback( + dash.dependencies.Output("upload-label", "children"), + [ + dash.dependencies.Input("upload-audio", "filename"), + dash.dependencies.Input("upload-audio", "contents"), + ], +) +def save_upload(uploaded_filenames, uploaded_file_contents): + try: + if uploaded_filenames is not None and uploaded_file_contents is not None: + for name, content in zip(uploaded_filenames, uploaded_file_contents): + if name.strip() == "": + continue + data = content.encode("utf8").split(b";base64,")[1] + with open(os.path.join(RUN_PATH, name), "wb") as fp: + fp.write(base64.decodebytes(data)) + except Exception as e: + return str(e) + return "Uploaded " + str(len(uploaded_filenames)) + " file(s)" + + +@app.callback( + dash.dependencies.Output("reference-dropdown", "options"), + [ + dash.dependencies.Input("update-button", "n_clicks"), + ], +) +def update_filelist(n_clicks): + filelist = [] + supported_formats = [".wav", ".ogg", ".mp3", "flac", ".aac"] + for x in sorted(os.listdir(RUN_PATH)): + if x[-4:].lower() in supported_formats: + filelist.append({"label": x, "value": x}) + return filelist + + +@app.callback( + [ + dash.dependencies.Output("audio-loading-output", "children"), + dash.dependencies.Output("current-f0s", "data"), + dash.dependencies.Output("current-f0s-nosilence", "data"), + dash.dependencies.Output("current-filename", "data"), + ], + [ + dash.dependencies.Input("reference-dropdown", "value"), + ], +) +def select_file(dropdown_value): + if dropdown_value is not None: + if not os.path.exists(os.path.join(RUN_PATH, "temp")): + os.mkdir(os.path.join(RUN_PATH, "temp")) + ffmpeg.input(os.path.join(RUN_PATH, dropdown_value)).output( + os.path.join(RUN_PATH, "temp", dropdown_value + "_conv.wav"), + ar="22050", + ac="1", + acodec="pcm_s16le", + map_metadata="-1", + fflags="+bitexact", + ).overwrite_output().run(quiet=True) + fo_with_silence, f0_wo_silence = crepe_f0( + os.path.join(RUN_PATH, "temp", dropdown_value + "_conv.wav") + ) + return [ + "Analyzed " + dropdown_value, + fo_with_silence, + f0_wo_silence, + dropdown_value, + ] + else: + return ["No audio analyzed", None, None] + + +@app.callback( + [ + dash.dependencies.Output("pitch-out", "src"), + dash.dependencies.Output("pitch-out", "style"), + dash.dependencies.Output("pitch-clicks", "data"), + ], + [ + dash.dependencies.Input("pitch-button", "n_clicks"), + dash.dependencies.Input("pitch-clicks", "data"), + dash.dependencies.Input("current-f0s", "data"), + ], +) +def debug_pitch(n_clicks, pitch_clicks, current_f0s): + if not n_clicks or current_f0s is None or n_clicks <= pitch_clicks: + if n_clicks is not None: + pitch_clicks = n_clicks + else: + pitch_clicks = 0 + return [ + None, + playback_hide, + pitch_clicks, + ] + pitch_clicks = n_clicks + return [f0_to_audio(current_f0s), playback_style, pitch_clicks] + + +hifigan_sr = None + + +def download_model(model, custom_model): + try: + global hifigan_sr, h2, denoiser_sr + d = "https://drive.google.com/uc?id=" + if model == "Custom": + drive_id = custom_model + else: + drive_id = model + if drive_id == "" or drive_id is None: + return ("Missing Drive ID", None, None) + if not os.path.exists(os.path.join(RUN_PATH, "models")): + os.mkdir(os.path.join(RUN_PATH, "models")) + if not os.path.exists(os.path.join(RUN_PATH, "models", drive_id)): + os.mkdir(os.path.join(RUN_PATH, "models", drive_id)) + zip_path = os.path.join(RUN_PATH, "models", drive_id, "model.zip") + gdown.download( + d + drive_id, + zip_path, + quiet=False, + ) + if not os.path.exists(zip_path): + os.rmdir(os.path.join(RUN_PATH, "models", drive_id)) + return ("Model download failed", None, None) + if os.stat(zip_path).st_size < 16: + os.remove(zip_path) + os.rmdir(os.path.join(RUN_PATH, "models", drive_id)) + return ("Model zip is empty", None, None) + with zipfile.ZipFile(zip_path, "r") as zip_ref: + zip_ref.extractall(os.path.join(RUN_PATH, "models", drive_id)) + os.remove(zip_path) + + # Download super-resolution HiFi-GAN + sr_path = "hifi-gan/hifisr" + if not os.path.exists(sr_path): + gdown.download( + d + "14fOprFAIlCQkVRxsfInhEPG0n-xN4QOa", sr_path, quiet=False + ) + if not os.path.exists(sr_path): + raise Exception("HiFI-GAN model failed to download!") + if hifigan_sr is None: + hifigan_sr, h2, denoiser_sr = load_hifigan(sr_path, "config_32k") + + return ( + None, + os.path.join(RUN_PATH, "models", drive_id, "TalkNetSpect.nemo"), + os.path.join(RUN_PATH, "models", drive_id, "hifiganmodel"), + ) + except Exception as e: + return (str(e), None, None) + + +tnmodel, tnpath, tndurs, tnpitch = None, None, None, None +hifigan, h, denoiser, hifipath = None, None, None, None + + +@app.callback( + [ + dash.dependencies.Output("audio-out", "src"), + dash.dependencies.Output("generated-info", "children"), + dash.dependencies.Output("audio-out", "style"), + dash.dependencies.Output("audio-out", "title"), + ], + [dash.dependencies.Input("gen-button", "n_clicks")], + [ + dash.dependencies.State("model-dropdown", "value"), + dash.dependencies.State("drive-id", "value"), + dash.dependencies.State("transcript-input", "value"), + dash.dependencies.State("pitch-options", "value"), + dash.dependencies.State("pitch-factor", "value"), + dash.dependencies.State("current-filename", "data"), + dash.dependencies.State("current-f0s", "data"), + dash.dependencies.State("current-f0s-nosilence", "data"), + ], +) +def generate_audio( + n_clicks, + model, + custom_model, + transcript, + pitch_options, + pitch_factor, + wav_name, + f0s, + f0s_wo_silence, +): + global tnmodel, tnpath, tndurs, tnpitch, hifigan, h, denoiser, hifipath + + if n_clicks is None: + raise PreventUpdate + if model is None: + return [None, "No character selected", playback_hide, None] + if transcript is None or transcript.strip() == "": + return [ + None, + "No transcript entered", + playback_hide, + None, + ] + if wav_name is None and "dra" not in pitch_options: + return [ + None, + "No reference audio selected", + playback_hide, + None, + ] + load_error, talknet_path, hifigan_path = download_model( + model.split("|")[0], custom_model + ) + if load_error is not None: + return [ + None, + load_error, + playback_hide, + None, + ] + + try: + with torch.no_grad(): + if tnpath != talknet_path: + singer_path = os.path.join( + os.path.dirname(talknet_path), "TalkNetSinger.nemo" + ) + if os.path.exists(singer_path): + tnmodel = TalkNetSingerModel.restore_from(singer_path) + else: + tnmodel = TalkNetSpectModel.restore_from(talknet_path) + durs_path = os.path.join( + os.path.dirname(talknet_path), "TalkNetDurs.nemo" + ) + pitch_path = os.path.join( + os.path.dirname(talknet_path), "TalkNetPitch.nemo" + ) + if os.path.exists(durs_path): + tndurs = TalkNetDursModel.restore_from(durs_path) + tnmodel.add_module("_durs_model", tndurs) + tnpitch = TalkNetPitchModel.restore_from(pitch_path) + tnmodel.add_module("_pitch_model", tnpitch) + else: + tndurs = None + tnpitch = None + tnmodel.eval() + tnpath = talknet_path + + token_list = arpa_parse(transcript, tnmodel) + tokens = torch.IntTensor(token_list).view(1, -1).to(DEVICE) + arpa = to_arpa(token_list) + + if "dra" in pitch_options: + if tndurs is None or tnpitch is None: + return [ + None, + "Model doesn't support pitch prediction", + playback_hide, + None, + ] + spect = tnmodel.generate_spectrogram(tokens=tokens) + else: + durs = get_duration(wav_name, transcript, token_list) + + # Change pitch + if "pf" in pitch_options: + f0_factor = np.power(np.e, (0.0577623 * float(pitch_factor))) + f0s = [x * f0_factor for x in f0s] + f0s_wo_silence = [x * f0_factor for x in f0s_wo_silence] + + spect = tnmodel.force_spectrogram( + tokens=tokens, + durs=torch.from_numpy(durs) + .view(1, -1) + .type(torch.LongTensor) + .to(DEVICE), + f0=torch.FloatTensor(f0s).view(1, -1).to(DEVICE), + ) + + if hifipath != hifigan_path: + hifigan, h, denoiser = load_hifigan(hifigan_path, "config_v1") + hifipath = hifigan_path + + y_g_hat = hifigan(spect.float()) + audio = y_g_hat.squeeze() + audio = audio * MAX_WAV_VALUE + audio_denoised = denoiser(audio.view(1, -1), strength=35)[:, 0] + audio_np = ( + audio_denoised.detach().cpu().numpy().reshape(-1).astype(np.int16) + ) + + # Auto-tuning + if "pc" in pitch_options and "dra" not in pitch_options: + _, output_freq, _, _ = crepe.predict(audio_np, 22050, viterbi=True) + output_pitch = torch.from_numpy(output_freq.astype(np.float32)) + target_pitch = torch.FloatTensor(f0s_wo_silence) + factor = torch.mean(output_pitch) / torch.mean(target_pitch) + + octaves = [0.125, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0] + nearest_octave = min(octaves, key=lambda x: abs(x - factor)) + target_pitch *= nearest_octave + if len(target_pitch) < len(output_pitch): + target_pitch = torch.nn.functional.pad( + target_pitch, + (0, list(output_pitch.shape)[0] - list(target_pitch.shape)[0]), + "constant", + 0, + ) + if len(target_pitch) > len(output_pitch): + target_pitch = target_pitch[0 : list(output_pitch.shape)[0]] + + audio_np = psola.vocode( + audio_np, 22050, target_pitch=target_pitch + ).astype(np.float32) + normalize = (1.0 / np.max(np.abs(audio_np))) ** 0.9 + audio_np = audio_np * normalize * MAX_WAV_VALUE + audio_np = audio_np.astype(np.int16) + + # Resample to 32k + wave = resampy.resample( + audio_np, + h.sampling_rate, + h2.sampling_rate, + filter="sinc_window", + window=scipy.signal.windows.hann, + num_zeros=8, + ) + wave_out = wave.astype(np.int16) + + # HiFi-GAN super-resolution + wave = wave / MAX_WAV_VALUE + wave = torch.FloatTensor(wave).to(torch.device(DEVICE)) + new_mel = mel_spectrogram( + wave.unsqueeze(0), + h2.n_fft, + h2.num_mels, + h2.sampling_rate, + h2.hop_size, + h2.win_size, + h2.fmin, + h2.fmax, + ) + y_g_hat2 = hifigan_sr(new_mel) + audio2 = y_g_hat2.squeeze() + audio2 = audio2 * MAX_WAV_VALUE + audio2_denoised = denoiser(audio2.view(1, -1), strength=35)[:, 0] + + # High-pass filter, mixing and denormalizing + audio2_denoised = audio2_denoised.detach().cpu().numpy().reshape(-1) + b = scipy.signal.firwin( + 101, cutoff=10500, fs=h2.sampling_rate, pass_zero=False + ) + y = scipy.signal.lfilter(b, [1.0], audio2_denoised) + y *= 4.0 # superres strength + y_out = y.astype(np.int16) + y_padded = np.zeros(wave_out.shape) + y_padded[: y_out.shape[0]] = y_out + sr_mix = wave_out + y_padded + + buffer = io.BytesIO() + wavfile.write(buffer, 32000, sr_mix.astype(np.int16)) + b64 = base64.b64encode(buffer.getvalue()) + sound = "data:audio/x-wav;base64," + b64.decode("ascii") + + output_name = "TalkNet_" + str(int(time.time())) + return [sound, arpa, playback_style, output_name] + except Exception: + return [ + None, + str(traceback.format_exc()), + playback_hide, + None, + ] + + +if __name__ == "__main__": + app.run_server( + mode="external", + debug=True, + dev_tools_ui=True, + dev_tools_hot_reload=True, + threaded=True, + ) diff --git a/future-todo/ControllableTalkNet/diffsvc_gui.py b/future-todo/ControllableTalkNet/diffsvc_gui.py new file mode 100644 index 0000000..837bd4e --- /dev/null +++ b/future-todo/ControllableTalkNet/diffsvc_gui.py @@ -0,0 +1,368 @@ +import sys +import os +import io +import base64 +import dash +from jupyter_dash import JupyterDash +import dash_core_components as dcc +import dash_html_components as html +from dash.exceptions import PreventUpdate +import gdown +import traceback +from scipy.io import wavfile +import numpy as np +import torch + +sys.path.append("DiffSVC_inference_only") +from end2end import load_e2e_diffsvc, endtoend_from_path, write_to_file + +app = JupyterDash(__name__) +UPLOAD_DIRECTORY = "/content" +DEVICE = "cuda" if torch.cuda.is_available() else "cpu" + +app.layout = html.Div( + children=[ + html.H1( + children="DiffSVC", + style={ + "font-family": "EquestriaWebfont", + "color": "#280e5f", + "font-size": "4em", + "text-align": "center", + "margin-top": "0em", + "margin-bottom": "0em", + }, + ), + html.Label("Character selection", htmlFor="speaker-dropdown"), + dcc.Dropdown( + id="speaker-dropdown", + options=[ + { + "label": "Twilight Sparkle", + "value": "Twilight", + }, + { + "label": "Discord", + "value": "Discord", + }, + { + "label": "Pinkie Pie", + "value": "Pinkie", + }, + {"label": "Nancy", "value": "Nancy"}, + ], + value=None, + style={ + "max-width": "90vw", + "width": "20em", + "margin-bottom": "0.7em", + }, + ), + html.Label( + "Upload reference audio to " + UPLOAD_DIRECTORY, + htmlFor="reference-dropdown", + ), + dcc.Store(id="current-f0s"), + dcc.Store(id="current-filename"), + dcc.Loading( + id="audio-loading", + children=[ + html.Div( + [ + html.Button( + "Update file list", + id="update-button", + style={ + "margin-right": "10px", + }, + ), + dcc.Dropdown( + id="reference-dropdown", + options=[], + value=None, + style={ + "max-width": "80vw", + "width": "30em", + }, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "row", + "margin-left": "50px", + "vertical-align": "middle", + }, + ), + html.Div( + id="audio-loading-output", + style={ + "font-style": "italic", + "margin-bottom": "0.7em", + "text-align": "center", + }, + ), + ], + type="default", + ), + html.Div( + [ + dcc.Checklist( + id="svc-options", + options=[ + {"label": "Singing mode", "value": "no_pc"}, + ], + value=[], + ) + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "row", + "margin-left": "50px", + "margin-bottom": "0.7em", + }, + ), + html.Div( + [ + html.Label("Steps", htmlFor="linsteps-input"), + dcc.Input( + id="linsteps-input", + type="number", + value="1000", + style={"width": "7em", "margin-left": "10px"}, + min=1, + max=1000, + step=1, + ), + html.Label("Step strength", htmlFor="linend-input"), + dcc.Input( + id="linend-input", + type="number", + value="0.06", + style={"width": "7em", "margin-left": "10px"}, + min=0.01, + max=0.3, + step=0.01, + ), + ], + style={ + "display": "grid", + "grid-template-columns": "auto 100px", + "margin-bottom": "0.7em", + }, + ), + dcc.Loading( + html.Div( + [ + html.Button( + "Generate", + id="gen-button", + ), + html.Audio( + id="audio-out", + controls=True, + style={ + "display": "none", + }, + ), + html.Div( + id="generated-info", + style={ + "font-style": "italic", + }, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "column", + }, + ) + ), + html.Footer( + children=""" + Presented by the Pony Preservation Project. Models by Cookie. + """, + style={"margin-top": "2em", "font-size": "0.7em"}, + ), + ], + style={ + "width": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "flex-direction": "column", + "background-color": "#FFF", + }, +) + + +playback_style = { + "margin-top": "0.3em", + "margin-bottom": "0.3em", + "display": "block", + "width": "600px", + "max-width": "90vw", +} + +playback_hide = { + "display": "none", +} + + +@app.callback( + dash.dependencies.Output("reference-dropdown", "options"), + [ + dash.dependencies.Input("update-button", "n_clicks"), + ], +) +def update_filelist(n_clicks): + filelist = [] + supported_formats = [".wav", ".ogg", ".mp3", "flac"] + for x in os.listdir(UPLOAD_DIRECTORY): + if x[-4:].lower() in supported_formats: + filelist.append({"label": x, "value": x}) + return filelist + + +@app.callback( + [ + dash.dependencies.Output("audio-loading-output", "children"), + dash.dependencies.Output("current-filename", "data"), + ], + [ + dash.dependencies.Input("reference-dropdown", "value"), + ], +) +def select_file(dropdown_value): + if dropdown_value is not None: + return [ + "Selected " + dropdown_value, + dropdown_value, + ] + else: + return ["No audio selected", None] + + +def download_model(drive_id, outname): + d = "https://drive.google.com/uc?id=" + model_dir = os.path.join(UPLOAD_DIRECTORY, "models") + out_fullpath = os.path.join(model_dir, outname) + out_dir = os.path.dirname(out_fullpath) + + if not os.path.exists(model_dir): + os.mkdir(model_dir) + if not os.path.exists(out_fullpath): + os.makedirs(out_dir, exist_ok=True) + gdown.download( + d + drive_id, + out_fullpath, + quiet=False, + ) + return out_fullpath + + +svc_model, svc_name, last_end, last_step = None, None, None, None + + +@app.callback( + [ + dash.dependencies.Output("audio-out", "src"), + dash.dependencies.Output("generated-info", "children"), + dash.dependencies.Output("audio-out", "style"), + ], + [dash.dependencies.Input("gen-button", "n_clicks")], + [ + dash.dependencies.State("speaker-dropdown", "value"), + dash.dependencies.State("svc-options", "value"), + dash.dependencies.State("current-filename", "data"), + dash.dependencies.State("linend-input", "value"), + dash.dependencies.State("linsteps-input", "value"), + ], +) +def generate_audio(n_clicks, speaker, svc_options, wav_name, lin_end, lin_n_steps): + global svc_model, svc_name, last_end, last_step + + if n_clicks is None: + raise PreventUpdate + if speaker is None: + return [None, "No character selected", playback_hide] + if wav_name is None: + return [None, "No reference audio selected", playback_hide] + + try: + diffsvc_id = "1Uh17L1JtynFDgX9X6jKLPtD_t4IcTEp9" + asr_id = "1qt0pGhCbH0TltFFwSP2Oy3NClthcpr7N" + hifigan_id = "1QQT0HjMhGgDuPhyesZYbvck2lEY7GHAB" + hifigan_config_id = "1mi_O54zi6nW2eU6VuAO_Y4gv_Df-H9Yv" + + diffsvc_path = download_model( + diffsvc_id, + os.path.join(diffsvc_id, "diffsvc_model"), + ) + asr_path = download_model( + asr_id, + os.path.join(asr_id, "asr_model"), + ) + hifigan_path = download_model( + hifigan_id, + os.path.join(hifigan_id, "hifigan_model"), + ) + download_model( + hifigan_config_id, + os.path.join(hifigan_id, "config.json"), + ) + if svc_name != diffsvc_id: + svc_model = load_e2e_diffsvc( + diffsvc_path=diffsvc_path, + dilated_asr_path=asr_path, + hifigan_path=hifigan_path, + device=DEVICE, + ) + svc_name = diffsvc_id + if last_end != lin_end or last_step != lin_n_steps: + svc_model[0].generator.diffusion.set_noise_schedule( + 1e-4, float(lin_end), int(lin_n_steps), device=DEVICE + ) + last_end = lin_end + last_step = lin_n_steps + + pred_audio = endtoend_from_path( + *svc_model, + os.path.join(UPLOAD_DIRECTORY, wav_name), + speaker, + "no_pc" not in svc_options, + "no_pc" not in svc_options, + "no_pc" not in svc_options, + t_max_step=int(lin_n_steps), + ) + pred_audio *= 32768.0 + + buffer = io.BytesIO() + wavfile.write( + buffer, + svc_model[4].sampling_rate, + pred_audio.squeeze().cpu().numpy().astype(np.int16), + ) + b64 = base64.b64encode(buffer.getvalue()) + sound = "data:audio/x-wav;base64," + b64.decode("ascii") + return [sound, "Conversion complete", playback_style] + except Exception: + return [None, str(traceback.format_exc()), playback_hide] + + +if __name__ == "__main__": + app.run_server( + mode="external", + debug=True, + dev_tools_ui=True, + dev_tools_hot_reload=True, + threaded=True, + ) diff --git a/future-todo/ControllableTalkNet/model_lists/sortanon_models.json b/future-todo/ControllableTalkNet/model_lists/sortanon_models.json new file mode 100644 index 0000000..3d7033c --- /dev/null +++ b/future-todo/ControllableTalkNet/model_lists/sortanon_models.json @@ -0,0 +1,165 @@ +[ + {"source": "MLP", + "characters": [ + { + "name": "Applejack", + "drive_id": "1kpEjZ3YqMN3chKSXODOqayEm581rxj4r", + "is_singing": false + }, + { + "name": "Celestia", + "drive_id": "1whXXcnXu9XPcI60xIkTEofpaDYDOw5yB", + "is_singing": false + }, + { + "name": "Chrysalis", + "drive_id": "1bb5jKAcQcEQbx1feVwT1UmAEgocINh-E", + "is_singing": false + }, + { + "name": "Discord", + "drive_id": "1Cg9Oc_K9UDe5WgVDAcaCSbbBoo-Npj1E", + "is_singing": false + }, + { + "name": "Fluttershy", + "drive_id": "1KgVnjrnxZTXgjnI56ilkq5G4UJCbbwZZ", + "is_singing": false + }, + { + "name": "Luna", + "drive_id": "1_ztAbe5YArCMwyyQ_G9lUiz74ym5xJKC", + "is_singing": false + }, + { + "name": "Maud Pie", + "drive_id": "132G6oD0HHPPn4t1H6IkYv18_F0UVLWgi", + "is_singing": false + }, + { + "name": "Pinkie Pie", + "drive_id": "1CdYZ2r52mtgJsFs88U0ZViMSnzpQ_HRp", + "is_singing": false + }, + { + "name": "Rainbow Dash", + "drive_id": "1k3EMXxLC0fLvfxzGbeP6B6plgu9hqCSx", + "is_singing": false + }, + { + "name": "Rarity", + "drive_id": "1QWBvQSso4guc1LRUD40WRJ8DY2CfqHGK", + "is_singing": false + }, + { + "name": "Spike", + "drive_id": "1TKFdmFLttjjzByj2fZW8J70ZHjR-RTwc", + "is_singing": false + }, + { + "name": "Starlight Glimmer", + "drive_id": "1M1AMBq_xjwGTNzRUCXtSLIDJHbcSs3zR", + "is_singing": false + }, + { + "name": "Sunset Shimmer", + "drive_id": "1x1aJt06lBvzUWRlxJ9CEKcFHxQxZPpST", + "is_singing": false + }, + { + "name": "Trixie", + "drive_id": "1a3CYt0-oTTSFjxtZvAVMpClTmQteYua5", + "is_singing": false + }, + { + "name": "Twilight Sparkle", + "drive_id": "1QnOliOAmerMUNuo2wXoH-YoainoSjZen", + "is_singing": false + }, + { + "name": "Twilight Sparkle (whispering)", + "drive_id": "14_TUQVirITdyBh9etfNV8KFFhi_PUs30", + "is_singing": false + }, + { + "name": "Zecora", + "drive_id": "1gL0hqqB7952Q1S185moQd_DRCFfIa3_g", + "is_singing": false + }, + { + "name": "Twilight Sparkle (singing)", + "drive_id": "10CENYWV5ugTXZbnsldN6OKR7wkDEe7V7", + "is_singing": true + }, + { + "name": "Pinkie Pie (singing)", + "drive_id": "1lo-8wI8iB3GArrzIDlaNTA1If8WX0OEf", + "is_singing": true + }, + { + "name": "Applejack (singing)", + "drive_id": "1kegd0J2G4nogaX4IOB2O_vd8msaqMx8M", + "is_singing": true + }, + { + "name": "Fluttershy (singing)", + "drive_id": "1BBdTHis91MwnHTt7tD_xtZ-nQ9SgvqD6", + "is_singing": true + }, + { + "name": "Rarity (singing)", + "drive_id": "1EI7npfQeQYuP6b_Gy8iwA5zAg9Yj5MJA", + "is_singing": true + }, + { + "name": "Rainbow Dash (singing)", + "drive_id": "1q4RgCEVJCSaR_1Dh0rxs6JVRJt30hQRK", + "is_singing": true + }, + { + "name": "Apple Bloom", + "drive_id": "1Wm-7gqws0B3j8mtSQa77Tdk3RZwHEwT5", + "is_singing": false + }, + { + "name": "Scootaloo", + "drive_id": "1YkV1VtP1w5XOx3jYYarrCKSzXCB_FLCy", + "is_singing": false + }, + { + "name": "Sweetie Belle", + "drive_id": "1jLX0Py6j8uY93Fjf2l0HOZQYXiShfWUO", + "is_singing": false + }, + { + "name": "Cozy Glow", + "drive_id": "1cUQQ_4KXTXbmH3MqwwyZu77SpMr20HAL", + "is_singing": false + }, + { + "name": "Big McIntosh", + "drive_id": "1UzL5vo_ykmRdbi-5JOlsQzNKkoV4tJBP", + "is_singing": false + }, + { + "name": "Cadance", + "drive_id": "1w98tMJPfGhWvl797gImMfErPXDz_hA-6", + "is_singing": false + }, + { + "name": "Granny Smith", + "drive_id": "1FJuxLB6MhcHLtmEnOIxhN-yxJ85kmacu", + "is_singing": false + }, + { + "name": "Shining Armor", + "drive_id": "1PUUS71w2ik0uuycNB30nXFze8C7O8OzY", + "is_singing": false + }, + { + "name": "Tirek", + "drive_id": "1rcPDqgDeCIHGDdvfOo-fxfA1XeM4g3CB", + "is_singing": false + } + ]} +] diff --git a/future-todo/ControllableTalkNet/mycroft_talknet.py b/future-todo/ControllableTalkNet/mycroft_talknet.py new file mode 100644 index 0000000..d94eb8e --- /dev/null +++ b/future-todo/ControllableTalkNet/mycroft_talknet.py @@ -0,0 +1,114 @@ +import os +from flask import Flask, request, send_file +import sys +import torch +import numpy as np +from scipy.io import wavfile +import io +from nemo.collections.tts.models import TalkNetSpectModel +from nemo.collections.tts.models import TalkNetPitchModel +from nemo.collections.tts.models import TalkNetDursModel +import json + +sys.path.append("hifi-gan") +from env import AttrDict +from meldataset import MAX_WAV_VALUE +from models import Generator +from denoiser import Denoiser + + +app = Flask(__name__) +RUN_PATH = os.path.dirname(os.path.realpath(__file__)) +DEVICE = "cuda:0" + + +def load_hifigan(model_name, conf_name): + # Load HiFi-GAN + conf = os.path.join("hifi-gan", conf_name + ".json") + with open(conf) as f: + json_config = json.loads(f.read()) + h = AttrDict(json_config) + torch.manual_seed(h.seed) + hifigan = Generator(h).to(torch.device(DEVICE)) + state_dict_g = torch.load(model_name, map_location=torch.device(DEVICE)) + hifigan.load_state_dict(state_dict_g["generator"]) + hifigan.eval() + hifigan.remove_weight_norm() + denoiser = Denoiser(hifigan, mode="normal") + return hifigan, h, denoiser + + +def generate_json(input, outpath): + output = "" + sample_rate = 22050 + lpath = input.split("|")[0].strip() + size = os.stat(lpath).st_size + x = { + "audio_filepath": lpath, + "duration": size / (sample_rate * 2), + "text": input.split("|")[1].strip(), + } + output += json.dumps(x) + "\n" + with open(outpath, "w", encoding="utf8") as w: + w.write(output) + + +def load_talknet(talknet_path): + with torch.no_grad(): + tnmodel = TalkNetSpectModel.restore_from(talknet_path) + durs_path = os.path.join(os.path.dirname(talknet_path), "TalkNetDurs.nemo") + tndurs = TalkNetDursModel.restore_from(durs_path) + tnmodel.add_module("_durs_model", tndurs) + pitch_path = os.path.join(os.path.dirname(talknet_path), "TalkNetPitch.nemo") + tnpitch = TalkNetPitchModel.restore_from(pitch_path) + tnmodel.add_module("_pitch_model", tnpitch) + tnmodel.eval() + return tnmodel + + +def generate_audio(transcript, tnmodel, hifigan, denoiser): + with torch.no_grad(): + tokens = tnmodel.parse(text=transcript.strip()) + spect = tnmodel.generate_spectrogram(tokens=tokens) + + y_g_hat = hifigan(spect.float()) + audio = y_g_hat.squeeze() + audio = audio * MAX_WAV_VALUE + audio_denoised = denoiser(audio.view(1, -1), strength=35)[:, 0] + audio_np = audio_denoised.detach().cpu().numpy().reshape(-1).astype(np.int16) + + buffer = io.BytesIO() + wavfile.write(buffer, 22050, audio_np) + return buffer + + +@app.route("/", methods=["GET"]) +def get_check(): + return "TalkNet server online" + + +@app.route("/api/tts", methods=["GET"]) +def get_tts(): + if "text" not in request.args: + return "" + transcript = request.args.get("text") + return send_file( + generate_audio(transcript, tnmodel, hifigan, denoiser), + attachment_filename="audio.wav", + mimetype="audio/x-wav", + ) + + +if __name__ == "__main__": + hifigan, h, denoiser = load_hifigan( + os.path.join( + RUN_PATH, "models", "1QnOliOAmerMUNuo2wXoH-YoainoSjZen", "hifiganmodel" + ), + "config_v1", + ) + tnmodel = load_talknet( + os.path.join( + RUN_PATH, "models", "1QnOliOAmerMUNuo2wXoH-YoainoSjZen", "TalkNetSpect.nemo" + ) + ) + app.run(debug=False) diff --git a/future-todo/ControllableTalkNet/requirements.txt b/future-todo/ControllableTalkNet/requirements.txt new file mode 100644 index 0000000..f7270b6 --- /dev/null +++ b/future-todo/ControllableTalkNet/requirements.txt @@ -0,0 +1,28 @@ +tensorflow==2.4.1 +tensorboard==2.4.1 +dash==1.21.0 +dash-bootstrap-components==0.13.0 +jupyter-dash==0.4.0 +psola==0.0.1 +wget==3.2 +unidecode==1.2.0 +pysptk==0.1.18 +frozendict==2.0.3 +torch==1.8.1+cu111 +torchvision==0.9.1+cu111 +torchaudio==0.8.1 +torchtext==0.9.1 +torch_stft==0.1.4 +kaldiio==2.17.2 +pydub==0.25.1 +pyannote.audio==1.1.2 +g2p_en==2.1.0 +pesq==0.0.2 +pystoi==0.3.3 +crepe==0.0.12 +resampy==0.2.2 +ffmpeg-python==0.2.0 +tqdm +gdown==3.13.0 +editdistance==0.5.3 +ipywidgets==7.6.3 diff --git a/future-todo/ControllableTalkNet/talknet_offline.py b/future-todo/ControllableTalkNet/talknet_offline.py new file mode 100644 index 0000000..b2b37a6 --- /dev/null +++ b/future-todo/ControllableTalkNet/talknet_offline.py @@ -0,0 +1,17 @@ +if __name__ == "__main__": + import os + from controllable_talknet import * + + if os.path.exists("/talknet/is_docker"): + app.run_server( + host="0.0.0.0", + mode="external", + debug=False, + threaded=True, + ) + else: + app.run_server( + mode="external", + debug=False, + threaded=True, + ) diff --git a/future-todo/ControllableTalkNet/talknet_singer.py b/future-todo/ControllableTalkNet/talknet_singer.py new file mode 100644 index 0000000..34f573d --- /dev/null +++ b/future-todo/ControllableTalkNet/talknet_singer.py @@ -0,0 +1,225 @@ +from collections import OrderedDict +from typing import List + +import torch +from hydra.utils import instantiate +from omegaconf import DictConfig +from pytorch_lightning import Trainer +from torch import nn +from torch.nn import functional as F +import numpy as np + +from nemo.collections.asr.data.audio_to_text import AudioToCharWithDursF0Dataset +from nemo.collections.tts.helpers.helpers import get_mask_from_lengths +from nemo.collections.tts.models.base import SpectrogramGenerator +from nemo.collections.tts.modules.talknet import ( + GaussianEmbedding, + MaskedInstanceNorm1d, + StyleResidual, +) +from nemo.core import Exportable +from nemo.core.classes import ModelPT, PretrainedModelInfo, typecheck +from nemo.core.neural_types import MelSpectrogramType, NeuralType + + +class TalkNetSingerModel(SpectrogramGenerator, Exportable): + """TalkNet's mel spectrogram prediction pipeline.""" + + @property + def output_types(self): + return OrderedDict( + {"mel-spectrogram": NeuralType(("B", "D", "T"), MelSpectrogramType())} + ) + + def __init__(self, cfg: DictConfig, trainer: "Trainer" = None): + super().__init__(cfg=cfg, trainer=trainer) + typecheck.set_typecheck_enabled(enabled=False) + + cfg = self._cfg + self.vocab = AudioToCharWithDursF0Dataset.make_vocab( + **cfg.train_ds.dataset.vocab + ) + self.blanking = cfg.train_ds.dataset.blanking + self.preprocessor = instantiate(cfg.preprocessor) + self.embed = GaussianEmbedding(self.vocab, cfg.d_char) + self.norm_f0 = MaskedInstanceNorm1d(1) + self.res_f0 = StyleResidual(cfg.d_char, 1, kernel_size=3) + self.model = instantiate(cfg.model) + d_out = cfg.model.jasper[-1].filters + self.proj = nn.Conv1d(d_out, cfg.n_mels, kernel_size=1) + + def forward(self, text, text_len, durs, f0): + x, x_len = self.embed(text, durs).transpose(1, 2), durs.sum(-1) + f0_sin = np.nan_to_num(np.sin(9.06472 * np.log(0.0363636 * f0.cpu()))) + f0_cos = np.nan_to_num(np.cos(9.06472 * np.log(0.0363636 * f0.cpu()))) + f0_note = torch.stack( + (torch.from_numpy(f0_sin), torch.from_numpy(f0_cos)), 1 + ).to(self.device) + f0, f0_mask = f0.clone(), f0 > 0.0 + f0 = self.norm_f0(f0.unsqueeze(1), f0_mask) + f0[~f0_mask.unsqueeze(1)] = 0.0 + x = self.res_f0(x, f0) + x = torch.cat((x, f0_note), 1) + y, _ = self.model(x, x_len) + mel = self.proj(y) + return mel + + @staticmethod + def _metrics(true_mel, true_mel_len, pred_mel): + loss = F.mse_loss(pred_mel, true_mel, reduction="none").mean(dim=-2) + mask = get_mask_from_lengths(true_mel_len) + loss *= mask.float() + loss = loss.sum() / mask.sum() + return loss + + def training_step(self, batch, batch_idx): + audio, audio_len, text, text_len, durs, f0, f0_mask = batch + mel, mel_len = self.preprocessor(audio, audio_len) + pred_mel = self(text=text, text_len=text_len, durs=durs, f0=f0) + loss = self._metrics(true_mel=mel, true_mel_len=mel_len, pred_mel=pred_mel) + train_log = {"train_loss": loss} + return {"loss": loss, "progress_bar": train_log, "log": train_log} + + def validation_step(self, batch, batch_idx): + audio, audio_len, text, text_len, durs, f0, f0_mask = batch + mel, mel_len = self.preprocessor(audio, audio_len) + pred_mel = self(text=text, text_len=text_len, durs=durs, f0=f0) + loss = self._metrics(true_mel=mel, true_mel_len=mel_len, pred_mel=pred_mel) + val_log = {"val_loss": loss} + self.log_dict( + val_log, prog_bar=False, on_epoch=True, logger=True, sync_dist=True + ) + + @staticmethod + def _loader(cfg): + dataset = instantiate(cfg.dataset) + return torch.utils.data.DataLoader( # noqa + dataset=dataset, + collate_fn=dataset.collate_fn, + **cfg.dataloader_params, + ) + + def setup_training_data(self, cfg): + self._train_dl = self._loader(cfg) + + def setup_validation_data(self, cfg): + self._validation_dl = self._loader(cfg) + + def setup_test_data(self, cfg): + """Omitted.""" + pass + + def parse(self, text: str, **kwargs) -> torch.Tensor: + return torch.tensor(self.vocab.encode(text)).long().unsqueeze(0).to(self.device) + + def generate_spectrogram(self, tokens: torch.Tensor, **kwargs) -> torch.Tensor: + assert hasattr(self, "_durs_model") and hasattr(self, "_pitch_model") + + if self.blanking: + tokens = [ + AudioToCharWithDursF0Dataset.interleave( + x=torch.empty(len(t) + 1, dtype=torch.long, device=t.device).fill_( + self.vocab.blank + ), + y=t, + ) + for t in tokens + ] + tokens = AudioToCharWithDursF0Dataset.merge( + tokens, value=self.vocab.pad, dtype=torch.long + ) + + text_len = torch.tensor(tokens.shape[-1], dtype=torch.long).unsqueeze(0) + durs = self._durs_model(tokens, text_len) + durs = durs.exp() - 1 + durs[durs < 0.0] = 0.0 + durs = durs.round().long() + + # Pitch + f0_sil, f0_body = self._pitch_model(tokens, text_len, durs) + sil_mask = f0_sil.sigmoid() > 0.5 + f0 = f0_body * self._pitch_model.f0_std + self._pitch_model.f0_mean + f0 = (~sil_mask * f0).float() + + # Spect + mel = self(tokens, text_len, durs, f0) + + return mel + + def forward_for_export(self, tokens: torch.Tensor, text_len: torch.Tensor): + durs = self._durs_model(tokens, text_len) + durs = durs.exp() - 1 + durs[durs < 0.0] = 0.0 + durs = durs.round().long() + + # Pitch + f0_sil, f0_body = self._pitch_model(tokens, text_len, durs) + sil_mask = f0_sil.sigmoid() > 0.5 + f0 = f0_body * self._pitch_model.f0_std + self._pitch_model.f0_mean + f0 = (~sil_mask * f0).float() + + # Spect + x, x_len = self.embed(tokens, durs).transpose(1, 2), durs.sum(-1) + f0_sin = np.nan_to_num(np.sin(9.06472 * np.log(0.0363636 * f0.cpu()))) + f0_cos = np.nan_to_num(np.cos(9.06472 * np.log(0.0363636 * f0.cpu()))) + f0_note = torch.stack( + (torch.from_numpy(f0_sin), torch.from_numpy(f0_cos)), 1 + ).to(self.device) + f0, f0_mask = f0.clone(), f0 > 0.0 + f0 = self.norm_f0(f0.unsqueeze(1), f0_mask) + f0[~f0_mask.unsqueeze(1)] = 0.0 + x = self.res_f0(x, f0) + x = torch.cat((x, f0_note), 1) + y, _ = self.model(x, x_len) + mel = self.proj(y) + + return mel + + def force_spectrogram( + self, tokens: torch.Tensor, durs: torch.Tensor, f0: torch.Tensor, **kwargs + ) -> torch.Tensor: + if self.blanking: + tokens = [ + AudioToCharWithDursF0Dataset.interleave( + x=torch.empty(len(t) + 1, dtype=torch.long, device=t.device).fill_( + self.vocab.blank + ), + y=t, + ) + for t in tokens + ] + tokens = AudioToCharWithDursF0Dataset.merge( + tokens, value=self.vocab.pad, dtype=torch.long + ) + + text_len = torch.tensor(tokens.shape[-1], dtype=torch.long).unsqueeze(0) + durs_len = torch.tensor(durs.shape[-1], dtype=torch.long).unsqueeze(0) + assert text_len == durs_len + + # Spect + mel = self(tokens, text_len, durs, f0) + return mel + + @classmethod + def list_available_models(cls) -> "List[PretrainedModelInfo]": + """ + This method returns a list of pre-trained model which can be instantiated directly from NVIDIA's NGC cloud. + Returns: + List of available pre-trained models. + """ + list_of_models = [] + model = PretrainedModelInfo( + pretrained_model_name="tts_en_talknet", + location=( + "https://api.ngc.nvidia.com/v2/models/nvidia/nemo/tts_en_talknet/versions/1.0.0rc1/files" + "/talknet_spect.nemo" + ), + description=( + "This model is trained on LJSpeech sampled at 22050Hz, and can be used to generate female " + "English voices with an American accent." + ), + class_=cls, # noqa + aliases=["TalkNet-22050Hz"], + ) + list_of_models.append(model) + return list_of_models diff --git a/future-todo/README.md b/future-todo/README.md new file mode 100644 index 0000000..e69de29 diff --git a/future-todo/vocodes_common_talknet.py b/future-todo/vocodes_common_talknet.py new file mode 100644 index 0000000..eb0f961 --- /dev/null +++ b/future-todo/vocodes_common_talknet.py @@ -0,0 +1,484 @@ +import sys +sys.path.append('waveglow/') +import shutil +import json + +import numpy as np +import torch + +#from tacotron2.hparams import create_hparams +#from tacotron2.model import Tacotron2 +#from tacotron2.layers import TacotronSTFT +#from tacotron2.audio_processing import griffin_lim +#from tacotron2.text import text_to_sequence + +#from waveglow.denoiser import Denoiser + +from scipy.io.wavfile import write as write_wav + +# Hifi-Gan +#from hifigan.env import AttrDict +#from hifigan.models import Generator +#from hifigan.denoiser import Denoiser as HifiDenoiser +#from hifigan.meldataset import mel_spectrogram +import resampy +import scipy + +# For metadata +import subprocess +import magic +import os + +# For talknet +from ControllableTalkNet.controllable_talknet import arpa_parse +from ControllableTalkNet.controllable_talknet import to_arpa +from nemo.collections.tts.models import TalkNetSpectModel +from nemo.collections.tts.models import TalkNetDursModel +from nemo.collections.tts.models import TalkNetPitchModel +from ControllableTalkNet.controllable_talknet import load_hifigan +from hifigan.meldataset import MAX_WAV_VALUE +from hifigan.meldataset import mel_spectrogram + +def print_gpu_info(): + print('========================================') + print('Python interpreter', sys.executable) + print('PyTorch version', torch.__version__) + print('CUDA Available?', torch.cuda.is_available()) + print('CUDA Device count', torch.cuda.device_count()) + #try: + # from tensorflow.python.client import device_lib + # print('local devices', str(device_lib.list_local_devices()).replace("\n", "\n ")) + #except ImportError: + # print('no tensorflow - cannot list devices') + # pass + print('========================================', flush=True) + +def load_tacotron_model(checkpoint_path): + hparams = create_hparams() + hparams.sampling_rate = 22050 # Don't change this + hparams.max_decoder_steps = 1000 # How long the audio will be before it cuts off (1000 is about 11 seconds) + hparams.gate_threshold = 0.1 # Model must be 90% sure the clip is over before ending generation (the higher this number is, the more likely that the AI will keep generating until it reaches the Max Decoder Steps) + model = Tacotron2(hparams) + print('Loading synthesizer at path: {}'.format(checkpoint_path)) + model.load_state_dict(torch.load(checkpoint_path)['state_dict']) + _ = model.cuda().eval().half() + # NB(bt, 2021-05-31): Trying to get everything on the same device + device = "cuda:0" + model = model.to(device) + return model + +def load_waveglow_model(checkpoint_path): + waveglow = torch.load(checkpoint_path)['model'] + waveglow.cuda().eval().half() + for k in waveglow.convinv: + k.float() + denoiser = Denoiser(waveglow) + return waveglow + +def load_hifigan_model(checkpoint_path, super_resolution = False): + conf_name = 'config_32k' if super_resolution else 'config_v1' + conf = os.path.join("hifigan", conf_name + ".json") + with open(conf) as f: + json_config = json.loads(f.read()) + h = AttrDict(json_config) + torch.manual_seed(h.seed) + hifigan = Generator(h).to(torch.device("cuda")) + state_dict_g = torch.load(checkpoint_path, map_location=torch.device("cuda")) + hifigan.load_state_dict(state_dict_g["generator"]) + hifigan.eval() + hifigan.remove_weight_norm() + denoiser = HifiDenoiser(hifigan, mode="normal") + return hifigan, h, denoiser + +def preprocess_text(text, raw_input=True): + # TODO: Handle ARPAbet + pre_sequence = "" + for line in text.split("\n"): + if len(line) < 1: + continue + if raw_input: + if line[-1] != ";": + line = line + ";" + else: + #line = ARPA(line) + pass + pre_sequence += line + + with torch.no_grad(): + # save VRAM by not including gradients + sequence = np.array(text_to_sequence(pre_sequence, ['english_cleaners']))[None, :] + sequence = torch.autograd.Variable(torch.from_numpy(sequence)).cuda().long() + return sequence + +class NumpyEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, np.ndarray): + return obj.tolist() + return json.JSONEncoder.default(self, obj) + +def save_spectorgram_json_file(mel_outputs_postnet, output_spectrogram_filename): + # squeeze(0) -> 3D to 2D (by removing the singular 1-length "wrapper" dimension) + # transpose() -> originally 80x{N}, we turn to {N}x80 + mel_for_json = mel_outputs_postnet.cpu().numpy().squeeze(0).transpose() + mel_for_scaling = mel_for_json.copy() + + max_value = np.amax(mel_for_scaling) + min_value = np.amin(mel_for_scaling) + mel_range = max_value - min_value + + mel_for_scaling -= min_value + mel_for_scaling *= (255.0 / mel_range) + mel_for_scaling = mel_for_scaling.astype('int32') + + json_data = { + 'mel': mel_for_json, + 'mel_scaled': mel_for_scaling, + } + + with open(output_spectrogram_filename, 'w') as outfile: + json.dump(json_data, outfile, cls=NumpyEncoder) + +def save_wav_audio_file(audio, output_audio_filename, sampling_rate=22050): + output_audio = audio[0].data.cpu().numpy().astype(np.float32) + write_wav(output_audio_filename, sampling_rate, output_audio) + +def generate_metadata_file(output_audio_filename, output_metadata_filename): + # ==== METADATA (1) ==== + command = [ + "ffprobe", + "-loglevel", "quiet", + "-print_format", "json", + "-show_format", + "-show_streams", + output_audio_filename + ] + + pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, err = pipe.communicate() + ffmpeg_metadata = json.loads(out) + + print(ffmpeg_metadata) + + # ==== METADATA (2) ==== + mime_type = magic.from_file(output_audio_filename, mime=True) + file_size_bytes = os.path.getsize(output_audio_filename) + + duration_millis = int(float(ffmpeg_metadata['format']['duration']) * 1000) + + metadata = { + 'duration_millis': duration_millis, + 'mimetype': mime_type, + 'file_size_bytes': file_size_bytes, + } + + with open(output_metadata_filename, 'w') as json_file: + json.dump(metadata, json_file) + + +class TacotronWaveglowPipeline: + + def __init__(self): + # Cache of "path" => loaded model + #self.tacotron_model_cache = {} + #self.waveglow = None + #self.waveglow_filename = None + #self.hifigan = None + #self.hifigan_denoiser = None + #self.hifigan_h = None + #self.hifigan_filename = None + #self.hifigan_super_resolution = None + #self.hifigan_super_resolution_denoiser = None + #self.hifigan_super_resolution_h = None + #self.hifigan_super_resolution_filename = None + pass + + def maybe_load_hifigan(self, checkpoint_path): + if self.hifigan_filename == checkpoint_path: + print('Hifi-gan model already loaded into memory: {}'.format(checkpoint_path)) + return + print('Dumping previous Hifi-gan model from memory: {}'.format(self.hifigan_filename)) + print('Loading Hifi-gan model into memory: {}'.format(checkpoint_path), flush=True) + hifigan, h, denoiser = load_hifigan_model(checkpoint_path, False) + self.hifigan = hifigan + self.hifigan_denoiser = denoiser + self.hifigan_h = h + self.hifigan_filename = checkpoint_path + + def maybe_load_hifigan_super_resolution(self, checkpoint_path): + if self.hifigan_super_resolution_filename == checkpoint_path: + print('Hifi-gan (SuperRes) model already loaded into memory: {}'.format(checkpoint_path)) + return + print('Dumping previous Hifi-gan (SuperRes) model from memory: {}'.format(self.hifigan_super_resolution_filename)) + print('Loading Hifi-gan (SuperRes) model into memory: {}'.format(checkpoint_path), flush=True) + hifigan, h, denoiser = load_hifigan_model(checkpoint_path, True) + self.hifigan_super_resolution = hifigan + self.hifigan_super_resolution_denoiser = denoiser + self.hifigan_super_resolution_h = h + self.hifigan_super_resolution_filename = checkpoint_path + + def maybe_load_waveglow_model(self, checkpoint_path): + if self.waveglow_filename == checkpoint_path: + print('Waveglow model already loaded into memory: {}'.format(checkpoint_path)) + return + print('Dumping previous waveglow model from memory: {}'.format(self.waveglow_filename)) + print('Loading waveglow model into memory: {}'.format(checkpoint_path), flush=True) + self.waveglow = load_waveglow_model(checkpoint_path) + self.waveglow_filename = checkpoint_path + + def maybe_load_tacotron_model_to_cache(self, checkpoint_path): + if checkpoint_path in self.tacotron_model_cache: + print('Tacotron model already loaded into memory: {}'.format(checkpoint_path)) + return + print('Loading tacotron model into memory: {}'.format(checkpoint_path), flush=True) + model = load_tacotron_model(checkpoint_path) + self.tacotron_model_cache[checkpoint_path] = model + print('Now {} synthesizer models in memory'.format(len(self.tacotron_model_cache))) + + def uncache_tacotron_model(self, checkpoint_path): + print('Currently {} synthesizer models in memory'.format( + len(self.tacotron_model_cache))) + print('Clearing synthesizer from memory: {}'.format(checkpoint_path)) + self.tacotron_model_cache.pop(checkpoint_path, None) + print('Now reduced to {} synthesizer models in memory'.format( + len(self.tacotron_model_cache))) + + def infer(self, args): + assert('synthesizer_checkpoint_path' in args) + assert('vocoder_type' in args) + assert('raw_text' in args) + assert('output_audio_filename' in args) + assert('output_spectrogram_filename' in args) + assert('output_metadata_filename' in args) + + # ======================= BEGIN TALKNET EXPERIMENT ======================== + + print('load models') + + with torch.no_grad(): + + # TODO: Singer model? + # tnmodel = TalkNetSingerModel.restore_from(singer_path + talknet_path = "/home/bt/models/talknet/david-attenborough/TalkNetSpect.nemo" + tnmodel = TalkNetSpectModel.restore_from(talknet_path) + + durs_path = "/home/bt/models/talknet/david-attenborough/TalkNetDurs.nemo" + pitch_path = "/home/bt/models/talknet/david-attenborough/TalkNetPitch.nemo" + + if os.path.exists(durs_path): + print('loading duration and pitch models') + tndurs = TalkNetDursModel.restore_from(durs_path) + tnmodel.add_module("_durs_model", tndurs) + tnpitch = TalkNetPitchModel.restore_from(pitch_path) + tnmodel.add_module("_pitch_model", tnpitch) + + tnmodel.eval() + + print('done loading model?') + + # ==== ARPABET ==== + + print('Raw text: {}'.format(args['raw_text'])) + + text = args['raw_text'] + + token_list = arpa_parse(text, tnmodel) + print('token_list', token_list) + + DEVICE = "cuda:0" + tokens = torch.IntTensor(token_list).view(1, -1).to(DEVICE) + print('tokens', tokens) + + arpa = to_arpa(token_list) + + print('arpa', arpa) + print('done with arpabet') + + # ==== END ARPABET ==== + + # TODO: Either pitch prediction (if model given), or use a source audio file (TODO) + + print("spectrogram estimation") + spect = tnmodel.generate_spectrogram(tokens=tokens) + + + # ==== HIFIGAN ==== + + print("load hifigan") + + hifigan_path = "/home/bt/models/talknet/david-attenborough/hifiganmodel" + + hifigan, h, denoiser = load_hifigan(hifigan_path, "config_v1") + hifipath = hifigan_path + + y_g_hat = hifigan(spect.float()) + audio = y_g_hat.squeeze() + audio = audio * MAX_WAV_VALUE + audio_denoised = denoiser(audio.view(1, -1), strength=35)[:, 0] + audio_np = ( + audio_denoised.detach().cpu().numpy().reshape(-1).astype(np.int16) + ) + + # ==== HIFIGAN SR ==== + + print("load hifigan SR") + + sr_path = "/home/bt/models/hifigan/Superres_Twilight_33000" + hifigan_sr, h2, denoiser_sr = load_hifigan(sr_path, "config_32k") + + # TODO + # TODO + # TODO -- Auto-tuning + # TODO + # TODO + + print("resample 32k") + + # Resample to 32k + wave = resampy.resample( + audio_np, + h.sampling_rate, + h2.sampling_rate, + filter="sinc_window", + window=scipy.signal.windows.hann, + num_zeros=8, + ) + wave_out = wave.astype(np.int16) + + print("hifi SR") + + # HiFi-GAN super-resolution + wave = wave / MAX_WAV_VALUE + wave = torch.FloatTensor(wave).to(torch.device(DEVICE)) + new_mel = mel_spectrogram( + wave.unsqueeze(0), + h2.n_fft, + h2.num_mels, + h2.sampling_rate, + h2.hop_size, + h2.win_size, + h2.fmin, + h2.fmax, + ) + y_g_hat2 = hifigan_sr(new_mel) + audio2 = y_g_hat2.squeeze() + audio2 = audio2 * MAX_WAV_VALUE + audio2_denoised = denoiser(audio2.view(1, -1), strength=35)[:, 0] + + # High-pass filter, mixing and denormalizing + audio2_denoised = audio2_denoised.detach().cpu().numpy().reshape(-1) + b = scipy.signal.firwin( + 101, cutoff=10500, fs=h2.sampling_rate, pass_zero=False + ) + y = scipy.signal.lfilter(b, [1.0], audio2_denoised) + y *= 4.0 # superres strength + y_out = y.astype(np.int16) + y_padded = np.zeros(wave_out.shape) + y_padded[: y_out.shape[0]] = y_out + sr_mix = wave_out + y_padded + + #buffer = io.BytesIO() + #wavfile.write(buffer, 32000, sr_mix.astype(np.int16)) + #b64 = base64.b64encode(buffer.getvalue()) + #sound = "data:audio/x-wav;base64," + b64.decode("ascii") + + print("done!") + + + output_audio = sr_mix.astype(np.int16) + #rate = self.hifigan_super_resolution_h.sampling_rate + rate = h2.sampling_rate + write_wav(args['output_audio_filename'], rate, output_audio) + + print('Saving spectrogram as JSON...') + save_spectorgram_json_file(spect, args['output_spectrogram_filename']) + + print('Generating metadata file...') + generate_metadata_file(args['output_audio_filename'], args['output_metadata_filename']) + + + # ======================= END TALKNET EXPERIMENT ======================== + + #tacotron = self.tacotron_model_cache[args['synthesizer_checkpoint_path']] + + #with torch.no_grad(): + # mel_outputs, mel_outputs_postnet, _, alignments = tacotron.inference(sequence) + + #if args['vocoder_type'] == 'hifigan-superres': + # self.vocode_hifigan_superres(args, mel_outputs_postnet) + #elif args['vocoder_type'] == 'waveglow': + # self.vocode_waveglow(args, mel_outputs_postnet) + #else: + # raise Exception('Wrong vocoder type: {}'.format(args['vocoder_type'])) + + + def vocode_waveglow(self, args, mel_outputs_postnet): + print('Running waveglow...') + with torch.no_grad(): + sigma = 0.8 + audio = self.waveglow.infer(mel_outputs_postnet, sigma=sigma) + + print('Encoding and saving audio...') + save_wav_audio_file(audio, args['output_audio_filename']) + + def vocode_hifigan_superres(self, args, mel_outputs_postnet): + print('Running hifigan...') + with torch.no_grad(): + y_g_hat = self.hifigan(mel_outputs_postnet.float()) + + MAX_WAV_VALUE = 32768.0 + audio = y_g_hat.squeeze() + audio = audio * MAX_WAV_VALUE + audio_denoised = self.hifigan_denoiser(audio.view(1, -1), strength=35)[:, 0] + + # Resample to 32k + audio_denoised = audio_denoised.cpu().numpy().reshape(-1) + + normalize = (MAX_WAV_VALUE / np.max(np.abs(audio_denoised))) ** 0.9 + audio_denoised = audio_denoised * normalize + wave = resampy.resample( + audio_denoised, + self.hifigan_h.sampling_rate, + self.hifigan_super_resolution_h.sampling_rate, + filter="sinc_window", + window=scipy.signal.windows.hann, + num_zeros=8, + ) + wave_out = wave.astype(np.int16) + + # HiFi-GAN super-resolution + print('Running hifigan super resolution...') + wave = wave / MAX_WAV_VALUE + wave = torch.FloatTensor(wave).to(torch.device("cuda")) + new_mel = mel_spectrogram( + wave.unsqueeze(0), + self.hifigan_super_resolution_h.n_fft, + self.hifigan_super_resolution_h.num_mels, + self.hifigan_super_resolution_h.sampling_rate, + self.hifigan_super_resolution_h.hop_size, + self.hifigan_super_resolution_h.win_size, + self.hifigan_super_resolution_h.fmin, + self.hifigan_super_resolution_h.fmax, + ) + y_g_hat2 = self.hifigan_super_resolution(new_mel) + audio2 = y_g_hat2.squeeze() + audio2 = audio2 * MAX_WAV_VALUE + audio2_denoised = self.hifigan_denoiser(audio2.view(1, -1), strength=35)[:, 0] + + # High-pass filter, mixing and denormalizing + audio2_denoised = audio2_denoised.cpu().numpy().reshape(-1) + b = scipy.signal.firwin( + 101, cutoff=10500, fs=self.hifigan_super_resolution_h.sampling_rate, pass_zero=False + ) + y = scipy.signal.lfilter(b, [1.0], audio2_denoised) + superres_strength = 4.0 + y *= superres_strength + y_out = y.astype(np.int16) + y_padded = np.zeros(wave_out.shape) + y_padded[: y_out.shape[0]] = y_out + sr_mix = wave_out + y_padded + sr_mix = sr_mix / normalize + + print('Encoding and saving audio...') + rate = self.hifigan_super_resolution_h.sampling_rate + output_audio = sr_mix.astype(np.int16) + write_wav(args['output_audio_filename'], rate, output_audio) diff --git a/tts/NeMo/.dockerignore b/tts/NeMo/.dockerignore new file mode 100644 index 0000000..14f5114 --- /dev/null +++ b/tts/NeMo/.dockerignore @@ -0,0 +1,19 @@ +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +env +pip-log.txt +pip-delete-this-directory.txt +.tox +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +*.log +.git +**/*.nemo +**/*.ckpt diff --git a/tts/NeMo/.github/ISSUE_TEMPLATE/bug_report.md b/tts/NeMo/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..5aedacf --- /dev/null +++ b/tts/NeMo/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,42 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** + +A clear and concise description of what the bug is. + +**Steps/Code to reproduce bug** + +Please list *minimal* steps or code snippet for us to be able to reproduce the bug. + +A helpful guide on on how to craft a minimal bug report http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports. + + +**Expected behavior** + +A clear and concise description of what you expected to happen. + +**Environment overview (please complete the following information)** + + - Environment location: [Bare-metal, Docker, Cloud(specify cloud provider - AWS, Azure, GCP, Collab)] + - Method of NeMo install: [pip install or from source]. Please specify exact commands you used to install. + - If method of install is [Docker], provide `docker pull` & `docker run` commands used + +**Environment details** + +If NVIDIA docker image is used you don't need to specify these. +Otherwise, please provide: +- OS version +- PyTorch version +- Python version + +**Additional context** + +Add any other context about the problem here. +Example: GPU model diff --git a/tts/NeMo/.github/ISSUE_TEMPLATE/feature_request.md b/tts/NeMo/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..e56d0d0 --- /dev/null +++ b/tts/NeMo/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,25 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: feature request +assignees: okuchaiev + +--- + +**Is your feature request related to a problem? Please describe.** + +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** + +A clear and concise description of what you want to happen. +Provide a code snippet on how new APIs/changes would be used by others. + +**Describe alternatives you've considered** + +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** + +Add any other context or screenshots about the feature request here. diff --git a/tts/NeMo/.gitignore b/tts/NeMo/.gitignore new file mode 100644 index 0000000..ff04a26 --- /dev/null +++ b/tts/NeMo/.gitignore @@ -0,0 +1,176 @@ +# log and data files +*.model +*.pkl +#*.ipynb +output +result +*.pt +tests/data/asr +.DS_Store +bert.pt.json +work +runs +fastspeech_output +.hydra + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class +**.pyc + +# C extensions +*.so + +# Distribution / packaging +.idea +.Python +wandb +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +#parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/build + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don’t work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# VSCode project settins +.vscode/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site +/docs/html +/docs/docs_zh/zh + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Emacs backup files +*~ + +cifar-10-batches-py +*.tar.gz + +# Test data. +tests/.data +tests/data + +# outputs folder +examples/*/outputs +examples/*/NeMo_experiments +examples/*/nemo_experiments +examples/*/.hydra +examples/*/wandb +examples/*/data +wandb +dump.py + +docs/sources/source/test_build/ + +# Checkpoints, config files and temporary files created in tutorials. +examples/neural_graphs/*.chkpt +examples/neural_graphs/*.yml + +.hydra/ +nemo_experiments/ + diff --git a/tts/NeMo/.readthedocs.yml b/tts/NeMo/.readthedocs.yml new file mode 100644 index 0000000..9b10e64 --- /dev/null +++ b/tts/NeMo/.readthedocs.yml @@ -0,0 +1,31 @@ +# ============================================================================= +# Copyright (c) 2020 NVIDIA. 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. +# ============================================================================= + +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required field. +version: 2 + +# Build documentation in the docs/ directory with Sphinx. +sphinx: + configuration: docs/source/conf.py + +# Set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - requirements: requirements/requirements_docs.txt diff --git a/tts/NeMo/CONTRIBUTING.md b/tts/NeMo/CONTRIBUTING.md new file mode 100644 index 0000000..394ed92 --- /dev/null +++ b/tts/NeMo/CONTRIBUTING.md @@ -0,0 +1,68 @@ +# Contributions are welcome! + +We do all of NeMo's development in the open. Contributions from NeMo community are welcome. + + +# Pull Requests (PR) Guidelines + +**Send your PRs to the `main` branch** + +1) Make sure your PR does one thing. Have a clear answer to "What does this PR do?". +2) Read General Principles and style guide below +3) Make sure you sign your commits. E.g. use ``git commit -s`` when before your commit +4) Make sure all unittests finish successfully before sending PR ``pytest`` or (if yor dev box does not have GPU) ``pytest --cpu`` from NeMo's root folder +5) Send your PR and request a review + +## Unit tests +Quick tests (locally, while developing) +``` +pytest +# If you don't have NVIDIA GPU do: +# pytest --cpu +``` +Full tests, including pre-trained model downloads +``` +pytest --with_downloads +``` + +## Whom should you ask for review: +1. For changes to NeMo's core: @ericharper, @titu1994, @blisc, or @okuchaiev +1. For changes to NeMo's ASR collection: @titu1994, @redoctopus, @jbalam-nv, or @okuchaiev +1. For changes to NeMo's NLP collection: @MaximumEntropy, @ericharper, @ekmb, @yzhang123, @VahidooX, @vladgets, or @okuchaiev +1. For changes to NeMo's TTS collection: @blisc or @stasbel, or @okuchaiev + +Note that some people may self-assign to review your PR - in which case, please wait for them to add a review. + +Your pull requests must pass all checks and peer-review before they can be merged. + +# General principles +1. **User-oriented**: make it easy for end users, even at the cost of writing more code in the background +1. **Robust**: make it hard for users to make mistakes. +1. **Well-tested**: please add simple, fast unittests. Consider adding CI tests for end-to-end functionality. +1. **Reusable**: for every piece of code, think about how it can be reused in the future and make it easy to be reused. +1. **Readable**: code should be easier to read. +1. **Legal**: if you copy even one line of code from the Internet, make sure that the code allows the license that NeMo supports. Give credit and link back to the code. +1. **Sensible**: code should make sense. If you think a piece of code might be confusing, write comments. + +## Python style +We use ``black`` as our style guide. To check whether your code will pass style check (from the NeMo's repo folder) run: +``python setup.py style`` and if it does not pass run ``python setup.py style --fix``. + +1. Include docstrings for every class and method exposed to the user. +1. Use Python 3 type hints for every class and method exposed to the user. +1. Avoid wild import: ``from X import *`` unless in ``X.py``, ``__all__`` is defined. +1. Minimize the use of ``**kwargs``. +1. ``RaiseError`` is preferred to ``assert``. Write: ```if X: raise Error``` instead of ```assert X```. +1. Classes are preferred to standalone methods. +1. Methods should be atomic. A method shouldn't be longer than 75 lines, e.g. can be fit into the computer screen without scrolling. +1. If a method has arguments that don't fit into one line, each argument should be in its own line for readability. +1. Add ``__init__.py`` for every folder. +1. F-strings are prefered to formatted strings. +1. Loggers are preferred to print. In NeMo, you can use logger from ``from nemo.utils import logging`` +1. Private functions (functions start with ``_``) shouldn't be called outside its host file. +1. If a comment lasts multiple lines, use ``'''`` instead of ``#``. + +# Collections +Collection is a logical grouping of related Neural Modules. It is a grouping of modules that share a domain area or semantics. +When contributing module to a collection, please make sure it belongs to that category. +If you would like to start a new one and contribute back to the platform, you are very welcome to do so. diff --git a/tts/NeMo/Dockerfile b/tts/NeMo/Dockerfile new file mode 100644 index 0000000..9e364b4 --- /dev/null +++ b/tts/NeMo/Dockerfile @@ -0,0 +1,104 @@ +# syntax=docker/dockerfile:experimental + +# Copyright (c) 2019, NVIDIA CORPORATION. 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. + +ARG BASE_IMAGE=nvcr.io/nvidia/pytorch:21.05-py3 + + +# build an image that includes only the nemo dependencies, ensures that dependencies +# are included first for optimal caching, and useful for building a development +# image (by specifying build target as `nemo-deps`) +FROM ${BASE_IMAGE} as nemo-deps + +# Ensure apt-get won't prompt for selecting options +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install -y \ + libsndfile1 sox \ + libfreetype6 \ + python-setuptools swig \ + python-dev ffmpeg && \ + rm -rf /var/lib/apt/lists/* + +# uninstall stuff from base container +RUN pip uninstall -y sacrebleu torchtext + +# build torchaudio (change latest release version to match pytorch) +WORKDIR /tmp/torchaudio_build +RUN git clone --depth 1 --branch release/0.7 https://github.com/pytorch/audio.git && \ + cd audio && \ + BUILD_SOX=1 python setup.py install && \ + cd .. && rm -r audio + +# TODO: remove when 21.04 container is released +# build torchtext +WORKDIR /tmp/torchtext_build +RUN git clone --branch v0.8.1 https://github.com/pytorch/text.git && \ + cd text && \ + git submodule update --init --recursive && \ + python setup.py clean install && \ + cd .. && rm -r text + +#install TRT tools: PT quantization support and ONNX graph optimizer +WORKDIR /tmp/trt_build +RUN git clone https://github.com/NVIDIA/TensorRT.git && \ + cd TensorRT/tools/onnx-graphsurgeon && python setup.py install && \ + cd ../pytorch-quantization && \ + python setup.py install && \ + rm -fr /tmp/trt_build + +# install nemo dependencies +WORKDIR /tmp/nemo +COPY requirements . +RUN for f in $(ls requirements*.txt); do pip install --disable-pip-version-check --no-cache-dir -r $f; done + +# install nemo_text_processing dependencies +COPY nemo_text_processing /tmp/nemo/nemo_text_processing/ +RUN /bin/bash /tmp/nemo/nemo_text_processing/setup.sh + +# copy nemo source into a scratch image +FROM scratch as nemo-src +COPY . . + +# start building the final container +FROM nemo-deps as nemo +ARG NEMO_VERSION=1.0.2 + +# Check that NEMO_VERSION is set. Build will fail without this. Expose NEMO and base container +# version information as runtime environment variable for introspection purposes +RUN /usr/bin/test -n "$NEMO_VERSION" && \ + /bin/echo "export NEMO_VERSION=${NEMO_VERSION}" >> /root/.bashrc && \ + /bin/echo "export BASE_IMAGE=${BASE_IMAGE}" >> /root/.bashrc +RUN --mount=from=nemo-src,target=/tmp/nemo cd /tmp/nemo && pip install ".[all]" && \ + python -c "import nemo.collections.asr as nemo_asr" && \ + python -c "import nemo.collections.nlp as nemo_nlp" && \ + python -c "import nemo.collections.tts as nemo_tts" && \ + python -c "import nemo_text_processing.text_normalization as text_normalization" + +# TODO: Remove once 21.04 container is base container +# install latest numba version +RUN conda update -c numba numba -y + +# copy scripts/examples/tests into container for end user +WORKDIR /workspace/nemo +COPY scripts /workspace/nemo/scripts +COPY examples /workspace/nemo/examples +COPY tests /workspace/nemo/tests +COPY tutorials /workspace/nemo/tutorials +# COPY README.rst LICENSE /workspace/nemo/ + +RUN printf "#!/bin/bash\njupyter lab --no-browser --allow-root --ip=0.0.0.0" >> start-jupyter.sh && \ + chmod +x start-jupyter.sh + diff --git a/tts/NeMo/Jenkinsfile b/tts/NeMo/Jenkinsfile new file mode 100644 index 0000000..2f4c453 --- /dev/null +++ b/tts/NeMo/Jenkinsfile @@ -0,0 +1,1451 @@ +pipeline { + agent { + docker { + image 'nvcr.io/nvidia/pytorch:21.05-py3' + args '--device=/dev/nvidia0 --gpus all --user 0:128 -v /home/TestData:/home/TestData -v $HOME/.cache/torch:/root/.cache/torch --shm-size=8g' + } + } + options { + timeout(time: 1, unit: 'HOURS') + disableConcurrentBuilds() + } + stages { + stage('PyTorch version') { + steps { + sh 'python -c "import torch; print(torch.__version__)"' + sh 'python -c "import torchvision; print(torchvision.__version__)"' + } + } + + stage('Uninstall torchtext') { + steps { + sh 'pip uninstall -y torchtext' + } + } + + stage('Install test requirements') { + steps { + sh 'apt-get update && apt-get install -y bc && pip install -r requirements/requirements_test.txt' + } + } + + stage('Copyright Headers check') { + steps { + sh 'python /home/TestData/check_copyright_header.py --dir .' + } + } + + stage('PyTorch STFT Patch check') { + steps { + sh 'python /home/TestData/check_stft_patch.py --dir .' + } + } + + stage('Code formatting checks') { + steps { + sh 'python setup.py style' + } + } + stage('Installation') { + steps { + sh './reinstall.sh release' + } + } + + stage('PyTorch Lightning version') { + steps { + sh 'python -c "import pytorch_lightning; print(pytorch_lightning.__version__)"' + } + } + + stage('PyTorch Lightning DDP Checks') { + steps { + sh 'python "tests/core_ptl/check_for_ranks.py"' + } + } + + stage('L0: Unit Tests GPU') { + steps { + sh 'pytest -m "not pleasefixme" --with_downloads --relax_numba_compat' + } + } + + stage('L0: Unit Tests CPU') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + steps { + sh 'CUDA_VISIBLE_DEVICES="" pytest -m "not pleasefixme" --cpu --with_downloads --relax_numba_compat' + } + } + + stage('L0: Computer Vision Integration') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage ('MNIST image classification with LeNet-5 Integration Test - on CPU') { + steps { + sh 'cd examples/cv && \ + python mnist_lenet5_image_classification_pure_lightning.py trainer.gpus=0 \ + trainer.accelerator=null \ + trainer.fast_dev_run=true model.dataset.data_folder=/home/TestData \ + && rm -rf outputs' + } + } + } + } + + // We have no integration tests, please enable this when one is added + // stage('L0: Integration Tests GPU') { + // steps { + // sh 'pytest -s -m "integration and not skipduringci and not pleasefixme"' + // } + // } + + // stage('L0: Integration Tests CPU') { + // when { + // anyOf{ + // branch 'main' + // changeRequest target: 'main' + // } + // } + // steps { + // sh 'pytest -s -m "integration and not pleasefixme" --cpu' + // } + // } + + // We have no system tests, please enable this when one is added + // stage('L1: System Tests GPU') { + // steps { + // sh 'pytest -m "system and not skipduringci and not pleasefixme"' + // } + // } + + // stage('L1: System Tests CPU') { + // when { + // anyOf{ + // branch 'dev + // changeRequest target: 'main' + // } + // } + // steps { + // sh 'pytest -m "system and not pleasefixme" --cpu' + // } + // } + + stage('L2: NeMo text processing') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: TN') { + steps { + sh 'cd tools/text_processing_deployment && python pynini_export.py --output=/home/TestData/nlp/text_norm/output/ --grammars=tn_grammars && ls -R /home/TestData/nlp/text_norm/output/ && echo ".far files created "|| exit 1' + sh 'cd nemo_text_processing/text_normalization/ && python run_predict.py --input=/home/TestData/nlp/text_norm/ci/test.txt --input_case="lower_cased" --output=/home/TestData/nlp/text_norm/output/test.pynini.txt --verbose' + sh 'cmp --silent /home/TestData/nlp/text_norm/output/test.pynini.txt /home/TestData/nlp/text_norm/ci/test_goal_py.txt || exit 1' + sh 'rm -rf /home/TestData/nlp/text_norm/output/*' + } + } + + stage('L2: ITN export') { + steps { + sh 'cd tools/text_processing_deployment && python pynini_export.py --output=/home/TestData/nlp/text_denorm/output/ --grammars=itn_grammars && ls -R /home/TestData/nlp/text_denorm/output/ && echo ".far files created "|| exit 1' + sh 'cd nemo_text_processing/inverse_text_normalization/ && python run_predict.py --input=/home/TestData/nlp/text_denorm/ci/test.txt --output=/home/TestData/nlp/text_denorm/output/test.pynini.txt --verbose' + sh 'cmp --silent /home/TestData/nlp/text_denorm/output/test.pynini.txt /home/TestData/nlp/text_denorm/ci/test_goal_py.txt || exit 1' + sh 'rm -rf /home/TestData/nlp/text_denorm/output/*' + } + } + stage('L2: TN with Audio (audio and raw text)') { + steps { + sh 'cd nemo_text_processing/text_normalization && \ + python normalize_with_audio.py --text "The total amounts to \\$4.76." \ + --audio_data /home/TestData/nlp/text_norm/audio_based/audio.wav | tail -n2 | head -n1 > /home/TestData/nlp/text_norm/audio_based/output/out_raw.txt 2>&1 && \ + cmp --silent /home/TestData/nlp/text_norm/audio_based/output/out_raw.txt /home/TestData/nlp/text_norm/audio_based/result.txt || exit 1' + sh 'rm -rf /home/TestData/nlp/text_norm/audio_based/output/out_raw.txt' + } + } + stage('L2: TN with Audio (audio and text file)') { + steps { + sh 'cd nemo_text_processing/text_normalization && \ + python normalize_with_audio.py --text /home/TestData/nlp/text_norm/audio_based/text.txt \ + --audio_data /home/TestData/nlp/text_norm/audio_based/audio.wav | tail -n2 | head -n1 > /home/TestData/nlp/text_norm/audio_based/output/out_file.txt 2>&1 && \ + cmp --silent /home/TestData/nlp/text_norm/audio_based/output/out_file.txt /home/TestData/nlp/text_norm/audio_based/result.txt || exit 1' + sh 'rm -rf /home/TestData/nlp/text_norm/audio_based/output/out_file.txt' + } + } + stage('L2: TN with Audio (manifest)') { + steps { + sh 'cd nemo_text_processing/text_normalization && \ + python normalize_with_audio.py --audio_data /home/TestData/nlp/text_norm/audio_based/manifest.json --n_tagged=120 && \ + cmp --silent /home/TestData/nlp/text_norm/audio_based/manifest_normalized.json /home/TestData/nlp/text_norm/audio_based/manifest_result.json || exit 1' + sh 'rm -rf /home/TestData/nlp/text_norm/audio_based/manifest_normalized.json' + } + } + } + } + + stage('L2: ASR dev run') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('Speech to Text') { + steps { + sh 'python examples/asr/speech_to_text.py \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/asr/speech_to_text_results' + sh 'rm -rf examples/asr/speech_to_text_results' + } + } + + stage('Speech to Label') { + steps { + sh 'python examples/asr/speech_to_label.py \ + model.train_ds.manifest_filepath=/home/TestData/speech_commands/train_manifest.json \ + model.validation_ds.manifest_filepath=/home/TestData/speech_commands/test_manifest.json \ + model.test_ds.manifest_filepath=/home/TestData/speech_commands/test_manifest.json \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=True \ + model.preprocessor._target_=nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor \ + ~model.preprocessor.window_size \ + ~model.preprocessor.window_stride \ + ~model.preprocessor.window \ + ~model.preprocessor.n_mels \ + ~model.preprocessor.n_mfcc \ + ~model.preprocessor.n_fft \ + exp_manager.exp_dir=examples/asr/speech_to_label_results' + sh 'rm -rf examples/asr/speech_to_label_results' + } + } + + stage('Speaker Recognition') { + steps { + sh 'python examples/speaker_recognition/speaker_reco.py \ + model.train_ds.batch_size=10 \ + model.validation_ds.batch_size=2 \ + model.train_ds.manifest_filepath=/home/TestData/an4_speaker/train.json \ + model.validation_ds.manifest_filepath=/home/TestData/an4_speaker/dev.json \ + model.test_ds.manifest_filepath=/home/TestData/an4_speaker/test.json \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/speaker_recognition/speaker_recognition_results' + sh 'rm -rf examples/speaker_recognition/speaker_recognition_results' + } + } + + stage('Speaker Diarization Inference') { + steps { + sh 'python examples/speaker_recognition/speaker_diarize.py \ + diarizer.oracle_num_speakers=2 \ + diarizer.paths2audio_files=/home/TestData/an4_diarizer/audio_files.scp \ + diarizer.path2groundtruth_rttm_files=/home/TestData/an4_diarizer/rttm_files.scp \ + diarizer.speaker_embeddings.model_path=/home/TestData/an4_diarizer/spkr.nemo \ + diarizer.vad.model_path=/home/TestData/an4_diarizer/MatchboxNet_VAD_3x2.nemo \ + diarizer.out_dir=examples/speaker_recognition/speaker_diarization_results' + sh 'rm -rf examples/speaker_recognition/speaker_diarization_results' + } + } + + stage('L2: Speech to Text WPE - CitriNet') { + steps { + sh 'python examples/asr/speech_to_text_bpe.py \ + --config-path="conf/citrinet/" --config-name="config_bpe" \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + model.tokenizer.dir="/home/TestData/asr_tokenizers/an4_wpe_128/" \ + model.tokenizer.type="wpe" \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/asr/speech_to_text_wpe_results' + sh 'rm -rf examples/asr/speech_to_text_wpe_results' + } + } + + stage('L2: Speech to Text WPE - Conformer') { + steps { + sh 'python examples/asr/speech_to_text_bpe.py \ + --config-path="conf/conformer" --config-name="conformer_ctc_bpe" \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + model.tokenizer.dir="/home/TestData/asr_tokenizers/an4_wpe_128/" \ + model.tokenizer.type="wpe" \ + model.train_ds.batch_size=4 \ + model.validation_ds.batch_size=4 \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/asr/speech_to_text_wpe_conformer_results' + sh 'rm -rf examples/asr/speech_to_text_wpe_conformer_results' + } + } + } + } + + stage('L2: ASR DALI dev run') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('Speech to Text - DALI AudioToMelSpectrogramPreprocessor') { + steps { + sh 'python examples/asr/speech_to_text.py \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + +model.train_ds.use_dali=True \ + model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + +model.validation_ds.use_dali=True \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/asr/speech_to_text_results' + sh 'rm -rf examples/asr/speech_to_text_results' + } + } + // TODO: This would fail due to an unnecessary torchaudio import. + // To be enabled once torchaudio is available in the container used for CI + // stage('Speech to Text - DALI AudioToMFCCPreprocessor') { + // steps { + // sh 'python examples/asr/speech_to_text.py \ + // model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + // +model.train_ds.use_dali=True \ + // model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + // +model.validation_ds.use_dali=True \ + // model.preprocessor._target_=nemo.collections.asr.modules.AudioToMFCCPreprocessor \ + // ~model.preprocessor.normalize \ + // ~model.preprocessor.features \ + // ~model.preprocessor.frame_splicing \ + // ~model.preprocessor.dither \ + // ~model.preprocessor.stft_conv \ + // +model.n_mels=64 \ + // +model.n_mfcc=64 \ + // trainer.gpus=[0] \ + // +trainer.fast_dev_run=True \ + // exp_manager.exp_dir=examples/asr/speech_to_text_results' + // sh 'rm -rf examples/asr/speech_to_text_results' + // } + // } + } + } + +// TODO: UNCOMMENT TESTS AFTER 21.04 release (numba 0.53 min requirement) + stage('L2: ASR RNNT dev run') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('Speech to Text - RNNT') { + steps { + sh 'STRICT_NUMBA_COMPAT_CHECK=false python examples/asr/speech_to_text_rnnt.py \ + --config-path="experimental/contextnet_rnnt/" --config-name="config_rnnt.yaml" \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + model.train_ds.batch_size=2 \ + model.validation_ds.batch_size=2 \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/asr/speech_to_text_rnnt_results' + sh 'rm -rf examples/asr/speech_to_text_rnnt_results' + } + } + stage('L2: Speech to Text RNNT WPE') { + steps { + sh 'STRICT_NUMBA_COMPAT_CHECK=false python examples/asr/speech_to_text_rnnt_bpe.py \ + --config-path="experimental/contextnet_rnnt/" --config-name="config_rnnt_bpe.yaml" \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + model.validation_ds.manifest_filepath=/home/TestData/an4_dataset/an4_val.json \ + model.train_ds.batch_size=2 \ + model.validation_ds.batch_size=2 \ + model.tokenizer.dir="/home/TestData/asr_tokenizers/an4_wpe_128/" \ + model.tokenizer.type="wpe" \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=True \ + exp_manager.exp_dir=examples/asr/speech_to_text_rnnt_wpe_results' + sh 'rm -rf examples/asr/speech_to_text_rnnt_wpe_results' + } + } + } + } + + stage('L2: ASR Multi-dataloader dev run') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('Speech to Text multi-dataloader') { + steps { + sh 'python examples/asr/speech_to_text.py \ + model.train_ds.manifest_filepath=/home/TestData/an4_dataset/an4_train.json \ + model.validation_ds.manifest_filepath=[/home/TestData/an4_dataset/an4_val.json,/home/TestData/an4_dataset/an4_val.json] \ + trainer.gpus=[0] \ + trainer.max_epochs=1 \ + +trainer.max_steps=1 \ + +trainer.num_sanity_val_steps=1 \ + exp_manager.exp_dir=examples/asr/speech_to_text_results' + sh 'rm -rf examples/asr/speech_to_text_results' + } + } + + stage('Speech to Label multi-dataloader') { + steps { + sh 'python examples/asr/speech_to_label.py \ + model.train_ds.manifest_filepath=/home/TestData/speech_commands/train_manifest.json \ + model.validation_ds.manifest_filepath=[/home/TestData/speech_commands/test_manifest.json,/home/TestData/speech_commands/test_manifest.json] \ + trainer.gpus=[1] \ + trainer.max_epochs=1 \ + +trainer.max_steps=1 \ + +trainer.num_sanity_val_steps=1 \ + model.preprocessor._target_=nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor \ + ~model.preprocessor.window_size \ + ~model.preprocessor.window_stride \ + ~model.preprocessor.window \ + ~model.preprocessor.n_mels \ + ~model.preprocessor.n_mfcc \ + ~model.preprocessor.n_fft \ + exp_manager.exp_dir=examples/asr/speech_to_label_results' + sh 'rm -rf examples/asr/speech_to_label_results' + } + } + } + } + + stage('L2: Speech Transcription') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('Speech to Text Transcribe') { + steps { + sh 'python examples/asr/transcribe_speech.py \ + pretrained_name="QuartzNet15x5Base-En" \ + audio_dir="/home/TestData/an4_transcribe/test_subset/" \ + output_filename="stt_test_res.json" \ + cuda=true \ + amp=true' + sh 'rm -rf stt_test_res.json' + } + } + } + } + + stage('L2: Segmentation Tool') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + stages { + stage('Install ctc_segmentation requirements') { + steps { + sh 'cd tools/ctc_segmentation && \ + pip install -r requirements.txt && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg' + } + } + + stage('Parallel ctc_segmentation test') { + failFast true + parallel { + stage('L2: Eng QN with .wav') { + steps { + sh 'cd tools/ctc_segmentation && \ + TIME=`date +"%Y-%m-%d-%T"` && \ + /bin/bash run_sample.sh \ + --MODEL_NAME_OR_PATH=QuartzNet15x5Base-En \ + --DATA_DIR=/home/TestData/ctc_segmentation/eng \ + --OUTPUT_DIR=/home/TestData/ctc_segmentation/eng/output${TIME} \ + --LANGUAGE=eng \ + --OFFSET=0 \ + --CUT_PREFIX=0 \ + --MIN_SEGMENT_LEN=0 \ + --AUDIO_FORMAT=.wav && \ + python /home/TestData/ctc_segmentation/verify_alignment.py \ + -r /home/TestData/ctc_segmentation/eng/eng_valid_segments.txt \ + -g /home/TestData/ctc_segmentation/eng/output${TIME}/verified_segments/nv_test_segments.txt && \ + rm -rf /home/TestData/ctc_segmentation/eng/output${TIME}' + } + } + stage('L2: Ru QN with .mp3') { + steps { + sh 'cd tools/ctc_segmentation && \ + TIME=`date +"%Y-%m-%d-%T"` && \ + /bin/bash run_sample.sh \ + --MODEL_NAME_OR_PATH=/home/TestData/ctc_segmentation/QuartzNet15x5-Ru-e512-wer14.45.nemo \ + --DATA_DIR=/home/TestData/ctc_segmentation/ru \ + --OUTPUT_DIR=/home/TestData/ctc_segmentation/ru/output${TIME} \ + --LANGUAGE=ru \ + --OFFSET=0 \ + --CUT_PREFIX=0 \ + --MIN_SEGMENT_LEN=0 \ + --AUDIO_FORMAT=.mp3 \ + --ADDITIONAL_SPLIT_SYMBOLS=";" && \ + python /home/TestData/ctc_segmentation/verify_alignment.py \ + -r /home/TestData/ctc_segmentation/ru/valid_ru_segments.txt \ + -g /home/TestData/ctc_segmentation/ru/output${TIME}/verified_segments/ru_segments.txt && \ + rm -rf /home/TestData/ctc_segmentation/ru/output${TIME}' + } + } + } + } + } + } + + stage('L2: Multi-GPU Megatron finetuning') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: Cased Megatron finetuning on MRPC') { + steps { + sh 'cd examples/nlp/glue_benchmark && \ + python glue_benchmark.py \ + model.dataset.data_dir=/home/TestData/nlp/glue_fake/MRPC \ + trainer.gpus=[0,1] \ + +trainer.fast_dev_run=true \ + model.dataset.use_cache=false \ + model.language_model.pretrained_model_name=megatron-bert-345m-cased \ + trainer.accelerator=ddp \ + exp_manager=null' + } + } + } + } + + stage('L2: SGD-QA') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: SGD-QA') { + steps { + sh 'cd examples/nlp/dialogue_state_tracking && \ + python sgd_qa.py \ + model.dataset.data_dir=/home/TestData/nlp/sgd_small \ + model.dataset.dialogues_example_dir=sgd_outputs \ + model.dataset.task_name=debug_sample \ + trainer.max_steps=1 \ + trainer.max_epochs=1 \ + model.train_ds.batch_size=2 \ + model.validation_ds.batch_size=2 \ + model.test_ds.batch_size=2 \ + model.nemo_path=null \ + trainer.val_check_interval=0.0 \ + trainer.gpus=[0,1] \ + model.dataset.use_cache=false \ + model.language_model.pretrained_model_name=bert-base-cased \ + trainer.accelerator=ddp \ + exp_manager=null && \ + rm -rf sgd_outputs' + } + } + stage('GLUE STS-b with AlBERT') { + steps { + sh 'python examples/nlp/glue_benchmark/glue_benchmark.py \ + model.dataset.use_cache=false \ + model.task_name=sts-b \ + model.dataset.data_dir=/home/TestData/nlp/glue_fake/STS-B \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=True \ + model.language_model.pretrained_model_name=albert-base-v1 \ + exp_manager=null' + } + } + } + } + + stage('L2: Parallel BERT SQUAD v1.1 / v2.0') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('BERT SQUAD 1.1') { + // Cannot do fast_dev_run because squad needs whole dev dataset + steps { + sh 'cd examples/nlp/question_answering && \ + python question_answering_squad.py \ + model.train_ds.file=/home/TestData/nlp/squad_mini/v1.1/train-v1.1.json \ + model.dataset.use_cache=false \ + model.validation_ds.file=/home/TestData/nlp/squad_mini/v1.1/dev-v1.1.json \ + model.test_ds.file=/home/TestData/nlp/squad_mini/v1.1/dev-v1.1.json \ + model.train_ds.batch_size=2 \ + model.train_ds.num_samples=2 \ + model.validation_ds.batch_size=2 \ + model.validation_ds.num_samples=2 \ + model.test_ds.num_samples=2 \ + model.test_ds.batch_size=2 \ + trainer.max_epochs=1 \ + +trainer.max_steps=1 \ + model.language_model.pretrained_model_name=bert-base-uncased \ + model.dataset.version_2_with_negative=false \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + trainer.gpus=[0] \ + exp_manager=null' + } + } + stage('BERT SQUAD 2.0') { + // Cannot do fast_dev_run because squad needs whole dev dataset + steps { + sh 'cd examples/nlp/question_answering && \ + python question_answering_squad.py \ + model.train_ds.file=/home/TestData/nlp/squad_mini/v2.0/train-v2.0.json \ + model.dataset.use_cache=false \ + model.train_ds.batch_size=2 \ + model.train_ds.num_samples=2 \ + model.validation_ds.batch_size=2 \ + model.validation_ds.num_samples=2 \ + trainer.max_epochs=1 \ + +trainer.max_steps=1 \ + model.validation_ds.file=/home/TestData/nlp/squad_mini/v2.0/dev-v2.0.json \ + model.language_model.pretrained_model_name=bert-base-uncased \ + model.dataset.version_2_with_negative=true \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + trainer.gpus=[1] \ + exp_manager=null' + } + } + } + } + // Runs out of memory on the 12G TITAN V (GPU 0 on main CI) + stage('L2: MegaBERT Token Classification') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + steps { + sh 'cd examples/nlp/token_classification && \ + python token_classification_train.py \ + model.dataset.data_dir=/home/TestData/nlp/token_classification_punctuation/ \ + model.language_model.pretrained_model_name=megatron-bert-345m-uncased \ + model.train_ds.batch_size=10 \ + model.dataset.max_seq_length=50 \ + model.dataset.use_cache=false \ + trainer.accelerator=ddp \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=true \ + exp_manager=null' + } + } + stage('L2: Parallel SQUAD v1.1 & v2.0') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('SQUAD v2.0 with Megatron with ckpt & config') { + // Cannot do fast_dev_run because squad needs whole dev dataset + steps { + sh 'cd examples/nlp/question_answering && \ + python question_answering_squad.py \ + model.train_ds.file=/home/TestData/nlp/squad_mini/v2.0/train-v2.0.json \ + model.dataset.use_cache=false \ + model.train_ds.batch_size=1 \ + model.train_ds.num_samples=1 \ + model.validation_ds.batch_size=1 \ + model.validation_ds.num_samples=1 \ + trainer.accelerator=ddp \ + trainer.max_epochs=1 \ + +trainer.max_steps=1 \ + model.validation_ds.file=/home/TestData/nlp/squad_mini/v2.0/dev-v2.0.json \ + model.language_model.pretrained_model_name=megatron-bert-uncased \ + model.language_model.lm_checkpoint=/home/TestData/nlp/megatron_345m_uncased/model_optim_rng.pt \ + model.language_model.config_file=/home/TestData/nlp/megatron_345m_uncased/345m_config.json \ + model.dataset.version_2_with_negative=true \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + trainer.gpus=[1] \ + exp_manager=null' + } + } + stage('RoBERTa SQUAD 1.1') { + // Cannot do fast_dev_run because squad needs whole dev dataset + steps { + sh 'cd examples/nlp/question_answering && \ + python question_answering_squad.py \ + model.train_ds.file=/home/TestData/nlp/squad_mini/v1.1/train-v1.1.json \ + model.dataset.use_cache=false \ + model.train_ds.batch_size=2 \ + model.train_ds.num_samples=2 \ + model.validation_ds.batch_size=2 \ + model.validation_ds.num_samples=2 \ + trainer.max_epochs=1 \ + +trainer.max_steps=1 \ + model.validation_ds.file=/home/TestData/nlp/squad_mini/v1.1/dev-v1.1.json \ + model.language_model.pretrained_model_name=roberta-base \ + model.dataset.version_2_with_negative=false \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + trainer.gpus=[0] \ + exp_manager=null' + } + } + stage ('Text Classification with BERT Test') { + steps { + sh 'cd examples/nlp/text_classification && \ + python text_classification_with_bert.py \ + model.dataset.num_classes=6 \ + model.train_ds.file_path=/home/TestData/nlp/retail_text_classification/train.tsv \ + model.validation_ds.file_path=/home/TestData/nlp/retail_text_classification/dev.tsv \ + model.language_model.pretrained_model_name=bert-base-uncased \ + model.train_ds.batch_size=10 \ + model.dataset.max_seq_length=50 \ + model.dataset.use_cache=false \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + exp_manager=null' + } + } + stage('L2: Intent and Slot Classification') { + steps { + sh 'cd examples/nlp/intent_slot_classification && \ + python intent_slot_classification.py \ + model.data_dir=/home/TestData/nlp/retail \ + model.validation_ds.prefix=dev \ + model.test_ds.prefix=dev \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + exp_manager.exp_dir=checkpoints' + sh 'rm -rf checkpoints' + } + } + } + } + + stage('L2: Model Parallel Size 2 Megatron Text Classification') { + when { + anyOf{ + branch 'main' + changeRequest target: 'main' + } + } + failFast true + steps{ + sh 'cd examples/nlp/text_classification && \ + python text_classification_with_bert.py \ + trainer.gpus=[0,1] \ + trainer.num_nodes=1 \ + trainer.precision=16 \ + trainer.gradient_clip_val=1.0 \ + ~trainer.amp_level \ + +trainer.fast_dev_run=true \ + model.dataset.num_classes=6 \ + model.train_ds.file_path=/home/TestData/nlp/retail_text_classification/train.tsv \ + model.train_ds.batch_size=4 \ + model.language_model.pretrained_model_name=megatron-bert-uncased \ + model.language_model.config_file=/home/TestData/nlp/mp_2_bert_toy/config.json \ + model.language_model.lm_checkpoint=/home/TestData/nlp/mp_2_bert_toy/iter_2000000 \ + model.nemo_path=null \ + ~model.infer_samples \ + exp_manager=null' + } + } + + stage('L2: Model Parallel Size 2 Megatron Autoresume') { + when { + anyOf{ + branch 'main' + changeRequest target: 'main' + } + } + failFast true + steps{ + sh 'cd examples/nlp/text_classification && \ + python text_classification_with_bert.py \ + trainer.gpus=[0,1] \ + trainer.num_nodes=1 \ + trainer.precision=16 \ + trainer.gradient_clip_val=1.0 \ + trainer.max_epochs=1 \ + ~trainer.amp_level \ + +trainer.fast_dev_run=true \ + model.dataset.num_classes=6 \ + model.train_ds.file_path=/home/TestData/nlp/retail_text_classification/train.tsv \ + model.train_ds.batch_size=4 \ + model.language_model.pretrained_model_name=megatron-bert-uncased \ + model.language_model.config_file=/home/TestData/nlp/mp_2_bert_toy/config.json \ + model.language_model.lm_checkpoint=/home/TestData/nlp/mp_2_bert_toy/iter_2000000 \ + model.nemo_path=null \ + ~model.infer_samples \ + +exp_manager.explicit_log_dir=/home/TestData/nlp/mp_autoresume \ + +exp_manager.resume_if_exists=true' + } + } + + stage('L2: Model Parallel Size 2 Megatron Evaluation from .nemo') { + when { + anyOf{ + branch 'main' + changeRequest target: 'main' + } + } + failFast true + steps{ + sh 'cd examples/nlp/text_classification && \ + python model_parallel_text_classification_evaluation.py \ + trainer.gpus=[0,1] \ + trainer.num_nodes=1 \ + model.dataset.num_classes=6 \ + model.test_ds.file_path=/home/TestData/nlp/retail_text_classification/dev.tsv \ + model.nemo_path=/home/TestData/nlp/mp_2_nemo/retail_text_class_350M.nemo \ + exp_manager=null' + } + } + + stage('L2: Model Parallel Size 2 Megatron Train from .nemo') { + when { + anyOf{ + branch 'main' + changeRequest target: 'main' + } + } + failFast true + steps{ + sh 'cd examples/nlp/token_classification && \ + python token_classification_train.py \ + pretrained_model=/home/TestData/nlp/mp_2_nemo/ner_350M.nemo \ + model.dataset.data_dir=/home/TestData/nlp/ner/ \ + model.train_ds.batch_size=2 \ + model.dataset.use_cache=false \ + trainer.gpus=[0,1] \ + +trainer.fast_dev_run=true \ + model.dataset.class_balancing="weighted_loss" \ + exp_manager=null' + } + } + + stage('L2: Parallel NLP Examples 2') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage ('NER finetuning from pretrained Test') { + steps { + sh 'cd examples/nlp/token_classification && \ + python token_classification_train.py \ + pretrained_model=ner_en_bert \ + model.dataset.data_dir=/home/TestData/nlp/ner/ \ + model.train_ds.batch_size=2 \ + model.dataset.use_cache=false \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + model.dataset.class_balancing="weighted_loss" \ + exp_manager.exp_dir=null' + } + } + stage ('Punctuation and capitalization finetuning from pretrained test') { + steps { + sh 'cd examples/nlp/token_classification && \ + python punctuation_capitalization_train.py \ + pretrained_model=punctuation_en_bert \ + model.dataset.data_dir=/home/TestData/nlp/token_classification_punctuation/ \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=true \ + model.dataset.use_cache=false \ + exp_manager.exp_dir=null' + } + } + stage ('NER with TurkuNLP/bert-base-finnish-cased-v1') { + steps { + sh 'cd examples/nlp/token_classification && \ + python token_classification_train.py \ + model.dataset.data_dir=/home/TestData/nlp/token_classification_punctuation/ \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + model.dataset.use_cache=false \ + model.language_model.pretrained_model_name="TurkuNLP/bert-base-finnish-cased-v1" \ + exp_manager.exp_dir=null' + } + } + stage('Evaluation script for Token Classification') { + steps { + sh 'python examples/nlp/token_classification/token_classification_evaluate.py \ + model.dataset.data_dir=/home/TestData/nlp/ner/ \ + pretrained_model=/home/TestData/nlp/pretrained_models/NER_Model_with_BERT_base_uncased.nemo && \ + rm -rf nemo_experiments' + } + } + stage('Evaluation script for Punctuation') { + steps { + sh 'python examples/nlp/token_classification/punctuation_capitalization_evaluate.py \ + model.dataset.data_dir=/home/TestData/nlp/token_classification_punctuation/ \ + pretrained_model=/home/TestData/nlp/pretrained_models/Punctuation_Capitalization_with_DistilBERT_base_uncased.nemo && \ + rm -rf nemo_experiments' + } + } + stage('L2: Punctuation & Capitalization, 2GPUs with DistilBERT') { + steps { + sh 'cd examples/nlp/token_classification && \ + python punctuation_capitalization_train.py \ + model.dataset.data_dir=/home/TestData/nlp/token_classification_punctuation/ \ + model.language_model.pretrained_model_name=distilbert-base-uncased \ + model.dataset.use_cache=false \ + trainer.gpus=[0,1] \ + trainer.accelerator=ddp \ + trainer.max_epochs=1 \ + +exp_manager.explicit_log_dir=/home/TestData/nlp/token_classification_punctuation/output && \ + python punctuation_capitalization_evaluate.py \ + pretrained_model=/home/TestData/nlp/token_classification_punctuation/output/checkpoints/Punctuation_and_Capitalization.nemo && \ + rm -rf /home/TestData/nlp/token_classification_punctuation/output/*' + } + } + } + } + + stage('L2: Parallel Pretraining BERT pretraining from Text/Preprocessed') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: Pretraining BERT pretraining from Text') { + steps { + sh 'cd examples/nlp/language_modeling && \ + python bert_pretraining.py \ + --config-name=bert_pretraining_from_text_config.yaml \ + trainer.gpus=[0] \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + +trainer.fast_dev_run=true \ + model.train_ds.data_file=/home/TestData/nlp/wikitext-2/train.txt \ + model.train_ds.batch_size=32 \ + model.validation_ds.data_file=/home/TestData/nlp/wikitext-2/valid.txt \ + model.validation_ds.batch_size=32 \ + model.language_model.config_file=/home/TestData/nlp/bert_configs/bert_3200.json \ + model.optim.lr=0.01 \ + model.optim.sched.warmup_ratio=0.1 \ + model.tokenizer.tokenizer_name=sentencepiece \ + model.tokenizer.tokenizer_model=/home/TestData/nlp/wikitext-2/tokenizer_bpe_v3193/tokenizer.model \ + model.mask_prob=0.15 \ + model.short_seq_prob=0.1 \ + exp_manager.exp_dir=PretrainingBERTFromText \ + ' + sh 'rm -f /home/TestData/nlp/wikitext-2/*.pkl' + sh 'rm -rf examples/nlp/language_modeling/PretrainingBERTFromText' + sh 'ls -lha examples/nlp/language_modeling' + } + } + stage('L2: Pretraining BERT from Preprocessed') { + steps { + sh 'cd examples/nlp/language_modeling && \ + python bert_pretraining.py \ + --config-name=bert_pretraining_from_preprocessed_config.yaml \ + trainer.gpus=[1] \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + +trainer.fast_dev_run=true \ + model.train_ds.data_file=/home/TestData/nlp/wiki_book_mini/training \ + model.train_ds.batch_size=8 \ + model.language_model.lm_checkpoint=/home/TestData/nlp/bert_ckpts/nemo1.0/bert_base_uncased_mlm_final_1074591_nemo1.0.pt \ + model.language_model.config_file=/home/TestData/nlp/bert_configs/uncased_L-12_H-768_A-12.json \ + model.optim.lr=0.875e-4 \ + model.optim.weight_decay=0.01 \ + model.optim.sched.warmup_ratio=0.01 \ + exp_manager.exp_dir=PretrainingBERTFromPreprocessed \ + exp_manager.create_checkpoint_callback=False \ + ' + sh 'rm -rf examples/nlp/language_modeling/PretrainingBERTFromPreprocessed' + sh 'ls -lha examples/nlp/language_modeling' + } + } + stage('L2: Pretraining BERT pretraining from Text with char tokenizer') { + steps { + sh 'cd examples/nlp/language_modeling && \ + python bert_pretraining.py \ + --config-name=bert_pretraining_from_text_config.yaml \ + trainer.gpus=[0] \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + +trainer.fast_dev_run=true \ + model.train_ds.data_file=/home/TestData/nlp/wikitext-2/train.txt \ + model.train_ds.batch_size=32 \ + model.validation_ds.data_file=/home/TestData/nlp/wikitext-2/valid.txt \ + model.validation_ds.batch_size=32 \ + model.language_model.config_file=/home/TestData/nlp/bert_configs/bert_3200.json \ + model.optim.lr=0.01 \ + model.optim.sched.warmup_ratio=0.1 \ + model.tokenizer.tokenizer_name=char \ + model.tokenizer.vocab_file=/home/TestData/nlp/vocabs/mini_vocab.txt \ + model.mask_prob=0.15 \ + model.short_seq_prob=0.1 \ + exp_manager.exp_dir=PretrainingBERTFromTextchartok \ + ' + sh 'rm -rf examples/nlp/language_modeling/PretrainingBERTFromTextchartok' + } + } + stage('L2: Pretraining BERT pretraining from Text with word tokenizer') { + steps { + sh 'cd examples/nlp/language_modeling && \ + python bert_pretraining.py \ + --config-name=bert_pretraining_from_text_config.yaml \ + trainer.gpus=[1] \ + trainer.precision=16 \ + trainer.amp_level=O1 \ + +trainer.fast_dev_run=true \ + model.train_ds.data_file=/home/TestData/nlp/wikitext-2/train.txt \ + model.train_ds.batch_size=32 \ + model.validation_ds.data_file=/home/TestData/nlp/wikitext-2/valid.txt \ + model.validation_ds.batch_size=32 \ + model.language_model.config_file=/home/TestData/nlp/bert_configs/bert_3200.json \ + model.optim.lr=0.01 \ + model.optim.sched.warmup_ratio=0.1 \ + model.tokenizer.tokenizer_name=word \ + model.tokenizer.vocab_file=/home/TestData/nlp/vocabs/mini_vocab.txt \ + model.mask_prob=0.15 \ + model.short_seq_prob=0.1 \ + exp_manager.exp_dir=PretrainingBERTFromTextwordtok \ + ' + sh 'rm -rf examples/nlp/language_modeling/PretrainingBERTFromTextwordtok' + } + } + } + } + + stage('L2: Entity Linking') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage ('Self Alignment Pretraining BERT') { + steps { + sh 'cd examples/nlp/entity_linking && \ + python self_alignment_pretraining.py \ + project_dir=. \ + trainer.val_check_interval=3 \ + model.raw_data=None \ + model.train_ds.data_file=/home/TestData/nlp/entity_linking/tiny_example_train_pairs.tsv \ + model.validation_ds.data_file=/home/TestData/nlp/entity_linking/tiny_example_validation_pairs.tsv \ + model.train_ds.batch_size=8 \ + model.validation_ds.batch_size=8 \ + exp_manager.exp_dir=null' + } + } + } + } + + stage('L2: NMT Attention is All You Need Training') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: NMT Training Post-LN') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=aayn_base \ + do_testing=true \ + model.train_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.train_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.ref \ + model.validation_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.validation_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.encoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + model.decoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + +trainer.limit_test_batches=2 \ + exp_manager=null \ + ' + } + } + + stage('L2: NMT Training Pre-LN') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=aayn_base \ + do_testing=true \ + model.train_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.train_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.ref \ + model.validation_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.validation_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.encoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + model.decoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + model.encoder.pre_ln=true \ + model.decoder.pre_ln=true \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=true \ + +trainer.limit_test_batches=2 \ + exp_manager=null \ + ' + } + } + stage('L2: NMT Multi-Validation') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=aayn_base \ + do_testing=true \ + model.train_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-en-de.src \ + model.train_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-en-de.ref \ + model.validation_ds.src_file_name=[/home/TestData/nlp/nmt/toy_data/wmt13-en-de.src,/home/TestData/nlp/nmt/toy_data/wmt14-en-de.src] \ + model.validation_ds.tgt_file_name=[/home/TestData/nlp/nmt/toy_data/wmt13-en-de.ref,/home/TestData/nlp/nmt/toy_data/wmt14-en-de.ref] \ + model.test_ds.src_file_name=[/home/TestData/nlp/nmt/toy_data/wmt13-en-de.src,/home/TestData/nlp/nmt/toy_data/wmt14-en-de.src] \ + model.test_ds.tgt_file_name=[/home/TestData/nlp/nmt/toy_data/wmt13-en-de.ref,/home/TestData/nlp/nmt/toy_data/wmt14-en-de.ref] \ + model.encoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + model.decoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + +trainer.limit_test_batches=2 \ + exp_manager=null \ + ' + } + } + } + } + stage('L2: NMT Attention is All You Need Inference') { + when { + anyOf { + branch 'v1.0.0' + changeRequest target: 'v1.0.0' + } + } + failFast true + parallel { + stage('L2: NMT Inference - PostLN') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python nmt_transformer_infer.py \ + --model=/home/TestData/nlp/nmt/toy_data/TransformerLargeDe-En.nemo \ + --srctext=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.test.src \ + --tgtout=/home/TestData/nlp/nmt/toy_data/out.txt \ + --target_lang en \ + --source_lang de \ + ' + } + } + stage('L2: NMT Inference - Pre-LN') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python nmt_transformer_infer.py \ + --model=/home/TestData/nlp/nmt/toy_data/en_de_24x6_preln.nemo \ + --srctext=/home/TestData/nlp/nmt/toy_data/wmt14-en-de.test.src \ + --tgtout=/home/TestData/nlp/nmt/toy_data/out.txt \ + --target_lang de \ + --source_lang en \ + ' + } + } + } + } + stage('L2: NMT with HuggingFace') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: NMT Pretrained HF Encoder') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=huggingface \ + model.shared_tokenizer=False \ + model.encoder_tokenizer.library=huggingface \ + model.encoder.library=huggingface \ + model.encoder.model_name=bert-base-cased \ + model.encoder.pretrained=true \ + model.train_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.train_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.ref \ + model.validation_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.validation_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.decoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + exp_manager=null \ + ' + } + } + + stage('L2: NMT Custom HF Encoder') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=huggingface \ + model.shared_tokenizer=True \ + model.encoder_tokenizer.library=yttm \ + model.encoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + model.encoder.library=huggingface \ + model.encoder.model_name=null \ + model.encoder.pretrained=false \ + +model.encoder._target_=transformers.BertConfig \ + +model.encoder.hidden_size=1536 \ + model.train_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.train_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.ref \ + model.validation_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.validation_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.test_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.decoder_tokenizer.tokenizer_model=/home/TestData/nlp/nmt/toy_data/tt_tokenizer.BPE.4096.model \ + trainer.gpus=[1] \ + +trainer.fast_dev_run=true \ + exp_manager=null \ + ' + } + } + } + } + + stage('L2: NMT Tarred Dataset Creation') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L2: NMT Auto Tarred Dataset Creation') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=aayn_base \ + do_training=false \ + model.preproc_out_dir=$PWD/preproc_out_dir \ + model.train_ds.use_tarred_dataset=true \ + model.train_ds.n_preproc_jobs=2 \ + model.train_ds.lines_per_dataset_fragment=500 \ + model.train_ds.num_batches_per_tarfile=10 \ + model.train_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.train_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.ref \ + model.validation_ds.src_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.validation_ds.tgt_file_name=/home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + model.encoder_tokenizer.vocab_size=2000 \ + model.decoder_tokenizer.vocab_size=2000 \ + ~model.test_ds \ + trainer.gpus=[0] \ + +trainer.fast_dev_run=true \ + exp_manager=null \ + ' + } + } + + stage('L2: NMT Script Tarred Dataset Creation') { + steps { + sh 'cd examples/nlp/machine_translation && \ + python create_tarred_parallel_dataset.py \ + --src_fname /home/TestData/nlp/nmt/toy_data/wmt14-de-en.src \ + --tgt_fname /home/TestData/nlp/nmt/toy_data/wmt14-de-en.ref \ + --out_dir $PWD/out_dir \ + --encoder_tokenizer_vocab_size=2000 \ + --decoder_tokenizer_vocab_size=2000 \ + --tokens_in_batch=1000 \ + --lines_per_dataset_fragment=500 \ + --num_batches_per_tarfile=10 \ + --n_preproc_jobs=2 \ + ' + } + } + } + } + + stage('L2: TTS Fast dev runs 1') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + parallel { + stage('Tacotron 2') { + steps { + sh 'python examples/tts/tacotron2.py \ + train_dataset=/home/TestData/an4_dataset/an4_train.json \ + validation_datasets=/home/TestData/an4_dataset/an4_val.json \ + trainer.gpus="[0]" \ + +trainer.fast_dev_run=True \ + trainer.accelerator=null \ + trainer.max_epochs=-1 \ + model.train_ds.dataloader_params.batch_size=12 \ + model.validation_ds.dataloader_params.batch_size=12 \ + ~trainer.check_val_every_n_epoch' + } + } + // stage('FastPitch') { + // steps { + // sh 'python examples/tts/fastpitch.py \ + // train_dataset=/home/TestData/an4_dataset/an4_train.json \ + // validation_datasets=/home/TestData/an4_dataset/an4_val.json \ + // trainer.gpus="[0]" \ + // +trainer.fast_dev_run=True \ + // trainer.accelerator=null \ + // trainer.max_epochs=-1 \ + // model.train_ds.batch_size=12 \ + // model.train_ds.num_workers=1 \ + // model.validation_ds.batch_size=12 \ + // model.validation_ds.num_workers=1 \ + // ~trainer.check_val_every_n_epoch' + // } + // } + stage('WaveGlow') { + steps { + sh 'python examples/tts/waveglow.py \ + train_dataset=/home/TestData/an4_dataset/an4_train.json \ + validation_datasets=/home/TestData/an4_dataset/an4_val.json \ + trainer.gpus="[1]" \ + +trainer.fast_dev_run=True \ + trainer.accelerator=null \ + trainer.max_epochs=-1 \ + model.train_ds.dataloader_params.batch_size=4 \ + model.validation_ds.dataloader_params.batch_size=4 \ + ~trainer.check_val_every_n_epoch' + } + } + } + } + + stage('L2: TTS Fast dev runs 2') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + + parallel { + stage('MelGAN') { + steps { + sh 'python examples/tts/melgan.py \ + train_dataset=/home/TestData/an4_dataset/an4_train.json \ + validation_datasets=/home/TestData/an4_dataset/an4_val.json \ + trainer.gpus="[0]" \ + +trainer.fast_dev_run=True \ + trainer.accelerator=ddp \ + trainer.max_epochs=-1 \ + model.train_ds.dataloader_params.batch_size=4 \ + model.validation_ds.dataloader_params.batch_size=4 \ + ~trainer.check_val_every_n_epoch' + } + } + stage('SqueezeWave') { + steps { + sh 'python examples/tts/squeezewave.py \ + train_dataset=/home/TestData/an4_dataset/an4_train.json \ + validation_datasets=/home/TestData/an4_dataset/an4_val.json \ + trainer.gpus="[0]" \ + +trainer.fast_dev_run=True \ + trainer.accelerator=null \ + trainer.max_epochs=-1 \ + model.train_ds.dataloader_params.batch_size=4 \ + model.validation_ds.dataloader_params.batch_size=4 \ + ~trainer.check_val_every_n_epoch' + } + } + stage('GlowTTS') { + steps { + sh 'python examples/tts/glow_tts.py \ + train_dataset=/home/TestData/an4_dataset/an4_train.json \ + validation_datasets=/home/TestData/an4_dataset/an4_val.json \ + trainer.gpus="[1]" \ + +trainer.fast_dev_run=True \ + trainer.accelerator=null \ + trainer.max_epochs=-1 \ + model.train_ds.batch_size=4 \ + model.validation_ds.batch_size=4 \ + ~trainer.check_val_every_n_epoch' + } + } + } + } + + stage('L??: Speech Checkpoints tests') { + when { + anyOf { + branch 'main' + changeRequest target: 'main' + } + } + failFast true + steps { + sh 'CUDA_VISIBLE_DEVICES=0 python examples/asr/speech_to_text_infer.py --asr_model QuartzNet15x5Base-En --dataset /home/TestData/librispeech/librivox-dev-other.json --wer_tolerance 0.1012 --batch_size 64' + } + } + } + + post { + always { + sh 'chmod -R 777 .' + cleanWs() + } + } +} diff --git a/tts/NeMo/LICENSE b/tts/NeMo/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/tts/NeMo/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/tts/NeMo/README.rst b/tts/NeMo/README.rst new file mode 100644 index 0000000..585064f --- /dev/null +++ b/tts/NeMo/README.rst @@ -0,0 +1,174 @@ + +|status| |documentation| |license| |lgtm_grade| |lgtm_alerts| |black| + +.. |status| image:: http://www.repostatus.org/badges/latest/active.svg + :target: http://www.repostatus.org/#active + :alt: Project Status: Active – The project has reached a stable, usable state and is being actively developed. + +.. |documentation| image:: https://readthedocs.com/projects/nvidia-nemo/badge/?version=main + :alt: Documentation + :target: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/ + +.. |license| image:: https://img.shields.io/badge/License-Apache%202.0-brightgreen.svg + :target: https://github.com/NVIDIA/NeMo/blob/master/LICENSE + :alt: NeMo core license and license for collections in this repo + +.. |lgtm_grade| image:: https://img.shields.io/lgtm/grade/python/g/NVIDIA/NeMo.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/NVIDIA/NeMo/context:python + :alt: Language grade: Python + +.. |lgtm_alerts| image:: https://img.shields.io/lgtm/alerts/g/NVIDIA/NeMo.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/NVIDIA/NeMo/alerts/ + :alt: Total alerts + +.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: black + +.. _main-readme: +**NVIDIA NeMo** +=============== + +Introduction +------------ + +NVIDIA NeMo is a conversational AI toolkit built for researchers working on automatic speech recognition (ASR), natural language processing (NLP), and text-to-speech synthesis (TTS). +The primary objective of NeMo is to help researchers from industry and academia to reuse prior work (code and pretrained models and make it easier to create new `conversational AI models `_. + + +`Introductory video. `_ + +Key Features +------------ + +* Speech processing + * `Automatic Speech recognition (ASR) `_: Jasper, QuartzNet, CitriNet, Conformer + * `Speech Classification `_: MatchboxNet (command recognition), MarbleNet (voice activity detection) + * `Speaker Recognition `_: SpeakerNet + * `Speaker Diarization `_: MarbleNet + SpeakerNet + * `NGC collection of pre-trained speech processing models. `_ +* Natural Language Processing + * `Compatible with Hugging Face Transformers and NVIDIA Megatron `_ + * `Neural Machine Translation (NMT) `_ + * `Punctuation and Capitalization `_ + * `Token classification (named entity recognition) `_ + * `Text classification `_ + * `Joint Intent and Slot Classification `_ + * `BERT pre-training `_ + * `Question answering `_ + * `GLUE benchmark `_ + * `Information retrieval `_ + * `NGC collection of pre-trained NLP models. `_ +* `Speech synthesis (TTS) `_ + * Spectrogram generation: Tacotron2, GlowTTS, FastSpeech2, FastPitch, + * Vocoders: WaveGlow, SqueezeWave, UniGlow, MelGAN, HiFiGAN + * End-to-end speech generation: FastPitch_HifiGan_E2E, FastSpeech2_HifiGan_E2E + * `NGC collection of pre-trained TTS models. `_ + + +Built for speed, NeMo can utilize NVIDIA's Tensor Cores and scale out training to multiple GPUs and multiple nodes. + +Requirements +------------ + +1) Python 3.6, 3.7 or 3.8 +2) Pytorch 1.8.1 or above +3) NVIDIA GPU for training + +Documentation +------------- + +.. |main| image:: https://readthedocs.com/projects/nvidia-nemo/badge/?version=main + :alt: Documentation Status + :scale: 100% + :target: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/ + +.. |v1.0.2| image:: https://readthedocs.com/projects/nvidia-nemo/badge/?version=v1.0.2 + :alt: Documentation Status + :scale: 100% + :target: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/v1.0.2/ + +.. |stable| image:: https://readthedocs.com/projects/nvidia-nemo/badge/?version=stable + :alt: Documentation Status + :scale: 100% + :target: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/stable/ + ++---------+-------------+----------------------------------------------------------------------------------------------------------------------------------+ +| Version | Status | Description | ++=========+=============+==================================================================================================================================+ +| Latest | |main| | `Documentation of the latest (i.e. main) branch. `_ | ++---------+-------------+----------------------------------------------------------------------------------------------------------------------------------+ +| Next | |v1.0.2| | `Documentation of the most recent release: v1.0.2 `_ | ++---------+-------------+----------------------------------------------------------------------------------------------------------------------------------+ +| Stable | |stable| | `Documentation of the stable (i.e. stable) branch. `_ | ++---------+-------------+----------------------------------------------------------------------------------------------------------------------------------+ + +Tutorials +--------- +A great way to start with NeMo is by checking `one of our tutorials `_. + +Getting help with NeMo +---------------------- +FAQ can be found on NeMo's `Discussions board `_. You are welcome to ask questions or start discussions there. + + +Installation +------------ + +Pip +~~~ +Use this installation mode if you want the latest released version. + +.. code-block:: bash + + apt-get update && apt-get install -y libsndfile1 ffmpeg + pip install Cython + pip install nemo_toolkit['all'] + +Pip from source +~~~~~~~~~~~~~~~ +Use this installation mode if you want the a version from particular GitHub branch (e.g main). + +.. code-block:: bash + + apt-get update && apt-get install -y libsndfile1 ffmpeg + pip install Cython + python -m pip install git+https://github.com/NVIDIA/NeMo.git@{BRANCH}#egg=nemo_toolkit[all] + + +From source +~~~~~~~~~~~ +Use this installation mode if you are contributing to NeMo. + +.. code-block:: bash + + apt-get update && apt-get install -y libsndfile1 ffmpeg + git clone https://github.com/NVIDIA/NeMo + cd NeMo + ./reinstall.sh + +Docker containers: +~~~~~~~~~~~~~~~~~~ + +If you chose to work with main branch, we recommend using NVIDIA's PyTorch container version 21.05-py3 and then installing from GitHub. + +.. code-block:: bash + + docker run --gpus all -it --rm -v :/NeMo --shm-size=8g \ + -p 8888:8888 -p 6006:6006 --ulimit memlock=-1 --ulimit \ + stack=67108864 --device=/dev/snd nvcr.io/nvidia/pytorch:21.05-py3 + +Examples +-------- + +Many example can be found under `"Examples" `_ folder. + + +Contributing +------------ + +We welcome community contributions! Please refer to the `CONTRIBUTING.md `_ CONTRIBUTING.md for the process. + +License +------- +NeMo is under `Apache 2.0 license `_. diff --git a/tts/NeMo/__init__.py b/tts/NeMo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tts/NeMo/docs/.nojekyll b/tts/NeMo/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/tts/NeMo/docs/Makefile b/tts/NeMo/docs/Makefile new file mode 100644 index 0000000..417fe2a --- /dev/null +++ b/tts/NeMo/docs/Makefile @@ -0,0 +1,216 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenSeq2Seq.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenSeq2Seq.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenSeq2Seq" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenSeq2Seq" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/tts/NeMo/docs/source/_static/css/custom.css b/tts/NeMo/docs/source/_static/css/custom.css new file mode 100644 index 0000000..f168711 --- /dev/null +++ b/tts/NeMo/docs/source/_static/css/custom.css @@ -0,0 +1,199 @@ + +/* Width of template */ + +.wy-nav-content { + max-width: 1200px !important; +} + + + +/* Standard Text Formatting */ + +h1 +{ + color: #76b900; + text-align: center; + background-color: #333333; +} + +h2 +{ + color: #ffffff; + background-color: #76b900; + Padding: 5px; +} + +h3 +{ + padding-top: 0px; + border-top: solid 3px #76b900; + border-bottom: solid 3px #76b900; +} + +p +{ + margin-bottom: 24px; +} +/* Link Colors */ +a +{ + color: #76b900; +} + +a:visited +{ + color: #218219; +} + + +/* ----------------------------------------------TABLES--------------------------------------- */ + +/* Table head Color */ +thead td +{ + background-color: #333333 !important; +} + +.row-odd p +{ + /*padding-bottom: 0px;*/ + /*margin-bottom: 0px;*/ +} +/* even rows*/ + +.row-even tr +{ + background-color: #e5f1e6 !important; +} + +/* odd rows*/ + + +.wy-table-responsive table tr { + background-color: #ffffff !important; +} + + + +.wy-table-responsive table td { + white-space: normal; +} + + +/* Removes bottom margin in tables*/ + +.rst-content .line-block { + margin-bottom: 0px; +} + +.wy-table-responsive { + overflow: visible !important; +} + +/* reduces the size of text in multiline table columns. */ + +.rst-content table.docutils td +{ + font-size: 80%; +} + +.rst-content dl:not(.docutils) dt +{ + + background-color: inherit; + color: #000000; + border-top: solid 0px #000000; + +} + +.rst-content dl:not(.docutils) dt:before { + color: #333333; +} + +.rst-content .line-block { + margin-bottom: 0px; +} + +.wy-side-nav-search, .wy-nav-top + { + background-color: #000000; + padding: 0; + } + +.wy-side-nav-search img + { + padding: 0px; + padding: 0px 0px; + margin-bottom: 0; + } + +.wy-side-nav-search input[type=text] + { + border-radius: 0px; + } + + +.wy-menu-vertical p.caption + { + color: #76b900; + } + + +.wy-side-nav-search>a img.logo, .wy-side-nav-search .wy-dropdown>a img.logo + { + margin: 0px 0px 0px 0px; + } + +.wy-nav-content + { + margin: 0; + min-height: 100%; + height: 100%; + background: #ffffff; + } + + /* List (numbered, bulleted) padding Fix */ + + +.wy-plain-list-decimal li +{ + margin-top: -6px; + margin-bottom: -6px; +} + +.rst-content .section ol.loweralpha +{ + margin-top: -6px; + margin-bottom: 12px; +} + +.wy-plain-list-disc, .rst-content .toctree-wrapper ul, article ul +{ + margin-top: 0px !important; + margin-bottom: 12px; +} + + /* Alert Boxes */ + /* Background color of Alert Box Title */ + +.rst-content .section ul +{ + margin-top: -12px; + margin-bottom: 16px; +} + +.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title + { + background: #76b900; + } + + /* Background and Font Color of Alert Box Main Body*/ +.wy-alert.wy-alert-info, .rst-content .note, .rst-content .wy-alert-info.attention, .rst-content .wy-alert-info.caution, .rst-content .wy-alert-info.danger, .rst-content .wy-alert-info.error, .rst-content .wy-alert-info.hint, .rst-content .wy-alert-info.important, .rst-content .wy-alert-info.tip, .rst-content .wy-alert-info.warning, .rst-content .seealso, .rst-content .wy-alert-info.admonition-todo, .rst-content .wy-alert-info.admonition { + background: #333333; + color: #999999; + } + +.section +{ + margin-top: 50px; +} diff --git a/tts/NeMo/docs/source/_static/js/pk_scripts.js b/tts/NeMo/docs/source/_static/js/pk_scripts.js new file mode 100644 index 0000000..23c7498 --- /dev/null +++ b/tts/NeMo/docs/source/_static/js/pk_scripts.js @@ -0,0 +1,19 @@ +document.addEventListener("DOMContentLoaded", function () { + var params = window.location.search.substring(1).split("&").reduce(function (params, param) { + if (!param) { + return params; + } + + var values = param.split("="); + var name = values[0]; + var value = values[1]; + params[name] = value; + return params; + }, {}); + + var form = document.getElementById("feedback-form"); + for (var name in params) { + var input = form.querySelector("[name=" + name + "]"); + input.value = params[name]; + } +}); \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/api.rst b/tts/NeMo/docs/source/asr/api.rst new file mode 100644 index 0000000..174e053 --- /dev/null +++ b/tts/NeMo/docs/source/asr/api.rst @@ -0,0 +1,203 @@ +NeMo ASR collection API +======================= + + +Model Classes +------------- + +.. autoclass:: nemo.collections.asr.models.EncDecCTCModel + :show-inheritance: + :members: transcribe, change_vocabulary, setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + + +.. autoclass:: nemo.collections.asr.models.EncDecCTCModelBPE + :show-inheritance: + :members: transcribe, change_vocabulary, setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + + +.. autoclass:: nemo.collections.asr.models.EncDecRNNTModel + :show-inheritance: + :members: transcribe, change_vocabulary, setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + + +.. autoclass:: nemo.collections.asr.models.EncDecRNNTBPEModel + :show-inheritance: + :members: transcribe, change_vocabulary, setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + + +.. autoclass:: nemo.collections.asr.models.EncDecClassificationModel + :show-inheritance: + :members: setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + + +.. autoclass:: nemo.collections.asr.models.EncDecSpeakerLabelModel + :show-inheritance: + :members: setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + + +Modules +------- + +.. autoclass:: nemo.collections.asr.modules.ConvASREncoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.modules.ConvASRDecoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.modules.ConvASRDecoderClassification + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.modules.SpeakerDecoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.modules.ConformerEncoder + :show-inheritance: + :members: + + +Parts +----- + +.. autoclass:: nemo.collections.asr.parts.submodules.jasper.JasperBlock + :show-inheritance: + :members: + + +Mixins +------ + +.. autoclass:: nemo.collections.asr.parts.mixins.mixins.ASRBPEMixin + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.mixins.mixins.ASRModuleMixin + :show-inheritance: + :members: + +Datasets +-------- + +Character Encoding Datasets +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: nemo.collections.asr.data.audio_to_text.AudioToCharDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.data.audio_to_text.TarredAudioToCharDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset + :show-inheritance: + :members: + +Subword Encoding Datasets +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: nemo.collections.asr.data.audio_to_text.AudioToBPEDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.data.audio_to_text.TarredAudioToBPEDataset + :show-inheritance: + :members: + +Audio Preprocessors +------------------- + +.. autoclass:: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.modules.AudioToMFCCPreprocessor + :show-inheritance: + :members: + +Audio Augmentors +---------------- + +.. autoclass:: nemo.collections.asr.modules.SpectrogramAugmentation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.modules.CropOrPadSpectrogramAugmentation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.SpeedPerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.TimeStretchPerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.GainPerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.ImpulsePerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.ShiftPerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.NoisePerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.WhiteNoisePerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.RirAndNoisePerturbation + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.preprocessing.perturb.TranscodePerturbation + :show-inheritance: + :members: + +Miscellaneous Classes +--------------------- + +RNNT Decoding +~~~~~~~~~~~~~ + +.. autoclass:: nemo.collections.asr.metrics.rnnt_wer.RNNTDecoding + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.metrics.rnnt_wer_bpe.RNNTBPEDecoding + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.submodules.rnnt_greedy_decoding.GreedyRNNTInfer + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.submodules.rnnt_greedy_decoding.GreedyBatchedRNNTInfer + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.parts.submodules.rnnt_beam_decoding.BeamRNNTInfer + :show-inheritance: + :members: + +Hypotheses +~~~~~~~~~~ + +.. autoclass:: nemo.collections.asr.parts.utils.rnnt_utils.Hypothesis + :show-inheritance: + :no-members: + +.. autoclass:: nemo.collections.asr.parts.utils.rnnt_utils.NBestHypotheses + :show-inheritance: + :no-members: diff --git a/tts/NeMo/docs/source/asr/asr_all.bib b/tts/NeMo/docs/source/asr/asr_all.bib new file mode 100644 index 0000000..7008355 --- /dev/null +++ b/tts/NeMo/docs/source/asr/asr_all.bib @@ -0,0 +1,980 @@ +@article{matchboxnet, + title={{MatchboxNet}: 1D Time-Channel Separable Convolutional Neural Network Architecture for Speech Commands Recognition}, + author={Majumdar, Somshubra and Ginsburg, Boris}, + journal={Proc. Interspeech 2020}, + year={2020} +} + +@article{marblenet, + title={MarbleNet: Deep 1D Time-Channel Separable Convolutional Neural Network for Voice Activity Detection}, + author={Jia, Fei and Majumdar, Somshubra and Ginsburg, Boris}, + journal={arXiv preprint arXiv:2010.13886}, + year={2020} +} + +@inproceedings{panayotov2015librispeech, + title={Librispeech: an ASR corpus based on public domain audio books}, + author={Panayotov, Vassil and Chen, Guoguo and Povey, Daniel and Khudanpur, Sanjeev}, + booktitle={Acoustics, Speech and Signal Processing (ICASSP), 2015 IEEE International Conference on}, + pages={5206--5210}, + year={2015}, + organization={IEEE} +} + +@article{luong17, + author = {Minh{-}Thang Luong and Eugene Brevdo and Rui Zhao}, + title = {Neural Machine Translation (seq2seq) Tutorial}, + journal = {https://github.com/tensorflow/nmt}, + year = {2017}, +} + +@INPROCEEDINGS{LaurentSeqWiseBN, +author={C. {Laurent} and G. {Pereyra} and P. {Brakel} and Y. {Zhang} and Y. {Bengio}}, +booktitle={2016 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP)}, +title={Batch normalized recurrent neural networks}, +year={2016}, +volume={}, +number={}, +pages={2657-2661}, +keywords={feedforward neural nets;learning (artificial intelligence);recurrent neural nets;speech recognition;batch normalized recurrent neural networks;RNN;sequential data;long-term dependency learning;convergence rate improvement;intermediate representation normalization;feedforward neural networks;speech recognition task;language modeling;training criterion;Training;Recurrent neural networks;Convergence;Speech recognition;Computer architecture;Speech;batch normalization;RNN;LSTM;optimization}, +doi={10.1109/ICASSP.2016.7472159}, +ISSN={2379-190X}, +month={March},} + +@article{graves2005, + author = {Alex Graves and Jurgen Schmidhuber}, + title = {Framewise phoneme classification with bidirectional LSTM and other neural network architectures}, + journal = {Neural Networks, vol. 18}, + pages={602–-610}, + year = {2005}, +} + +@inproceedings{graves2006, + title={Connectionist temporal classification: labelling unsegmented sequence data with recurrent neural networks}, + author={Graves, Alex and Fern{\'a}ndez, Santiago and Gomez, Faustino and Schmidhuber, J{\"u}rgen}, + booktitle={Proceedings of the 23rd international conference on Machine learning}, + pages={369--376}, + year={2006}, + organization={ACM} +} + +@article{li2019jasper, + title={Jasper: An End-to-End Convolutional Neural Acoustic Model}, + author={Li, Jason and Lavrukhin, Vitaly and Ginsburg, Boris and Leary, Ryan and Kuchaiev, Oleksii and Cohen, Jonathan M and Nguyen, Huyen and Gadde, Ravi Teja}, + journal={arXiv preprint arXiv:1904.03288}, + year={2019} +} + +@misc{ardila2019common, + title={Common Voice: A Massively-Multilingual Speech Corpus}, + author={Rosana Ardila and Megan Branson and Kelly Davis and Michael Henretty and Michael Kohler and Josh Meyer and Reuben Morais and Lindsay Saunders and Francis M. Tyers and Gregor Weber}, + year={2019}, + eprint={1912.06670}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} + +@article{graves2012, + title={Sequence Transduction with Recurrent Neural Networks}, + author={Graves, Alex}, + journal={arXiv preprint arXiv:1211.3711}, + year={2012} +} + + +@article{graves2013, + title={Generating sequences with recurrent neural networks}, + author={Graves, Alex}, + journal={arXiv preprint arXiv:1308.0850}, + year={2013} +} + +@article{sergeev2018horovod, + title={Horovod: fast and easy distributed deep learning in TensorFlow}, + author={Sergeev, Alexander and Del Balso, Mike}, + journal={arXiv preprint arXiv:1802.05799}, + year={2018} +} + +@misc{NVVolta, + title = {NVIDIA TESLA V100 GPU ARCHITECTURE}, + howpublished = {\url{http://images.nvidia.com/content/volta-architecture/pdf/volta-architecture-whitepaper.pdf}}, + note = {Accessed: 2018-10-09} +} + +@article{NVTuring, + title = {NVIDIA TURING GPU ARCHITECTURE}, + howpublished = {\url{https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/technologies/turing-architecture/NVIDIA-Turing-Architecture-Whitepaper.pdf}}, + author = {NVIDIA}, + year = {2018}, + note = {Accessed: 2018-10-09} +} + +@misc{Rygaard2015, + title = {Using Synthesized Speech to Improve Speech Recognition for Low-Resource Languages}, + author = {Luise Valentin Rygaard}, + howpublished = {\url{https://parasol.tamu.edu/dreu2015/Rygaard/report.pdf}}, + year = {2015}, +} + +@misc{OpenSeq2Seq, + title = {OpenSeq2Seq: extensible toolkit for distributed and mixed precision training of sequence-to-sequence models}, + author = {Kuchaiev, Oleksii and Ginsburg, Boris and Gitman, Igor and Lavrukhin,Vitaly and Case, Carl and Micikevicius, Paulius}, + howpublished = {\url{https://arxiv.org/abs/1805.10387}}, + year = {2018}, +} + +@misc{MPGuide, + title = {Training with Mixed Precision}, + howpublished = {\url{http://docs.nvidia.com/deeplearning/sdk/mixed-precision-training/}}, + note = {Accessed: 2018-04-06}, +} + +@misc{Mozilla, + title = {Mozilla: A Journey to less than 10\% Word Error Rate}, + howpublished = {\url{https://hacks.mozilla.org/2017/11/a-journey-to-10-word-error-rate/}}, + note = {Accessed: 2018-04-06}, +} + +@article{Waibel1989, + title={A time-delay neural network architecture for isolated word recognition}, + author={Waibel, Alexander, and Hanazawa, Toshiyki and Hinton,Geoffrey and Shirano, Kiyohiro and Lang, Kevin }, + journal={IEEE Trans. on Acoustics, Speech and Signal Processing}, + year={1989} +} + +@article{Lang1990, + title={A time-delay neural network architecture for isolated word recognition}, + author={Lang, Kevin and Waibel, Alexander, and Hinton,Geoffrey }, + journal={Neural Networks}, + year={1990} +} + +@book{Bengio1996, + Author = {Bengio, Y.}, + Publisher = {International Thomson Computer Press}, + Title = {Neural Networks for Speech and Sequence Recognition}, + Year = {1996} +} + +@article{Bengio1992, + title={Global optimization of a neural network-hidden Markov model hybrid}, + author={Bengio, Y., and De Mori, R., and Flammia, G., and Kompe, R. }, + journal={IEEE Transactions on Neural Networks, 3(2), 252–259}, + year={1992} +} + +@article{Bourlard1994, + title={Connectionist speech recognition: a hybrid approach}, + author={Bourlard, H. A. and Morgan, N.}, + journal={volume 247 Springer }, + year={1994} +} + +@article{srivastava14a, + author = {Nitish Srivastava, and Geoffrey Hinton, and Alex Krizhevsky, and Ilya Sutskever, and Ruslan Salakhutdinov}, + title = {Dropout: A Simple Way to Prevent Neural Networks from Overfitting}, + journal = {Journal of Machine Learning Research}, + year = {2014}, + volume = {15}, + pages = {1929-1958}, + url = {http://jmlr.org/papers/v15/srivastava14a.html} +} + + +@article{Hinton2012, + title={Deep Neural Networks for Acoustic Modeling in Speech Recognition}, + author={ Hinton,Geoffrey and Deng, Li and Yu, Dong and Dahl,George and Mohamed,Abdel-rahman and Jaitly, Navdeep and Senior, Andrew and Vanhoucke, Vincent and Nguyen, Patrick and Kingsbury, Brian and Sainath, Tara}, + journal={IEEE Signal Processing Magazine}, + year={2012} +} + +@article{Graves2014, + title={Towards End-to-End Speech Recognition with Recurrent Neural Networks}, + author={Graves, Alex and Jaitly, Navdeep}, + journal={International Conference on Machine Learning}, + year={2014} +} + +@article{Chorowski2014, + title={End-to-end Continuous Speech Recognition using Attention-based Recurrent NN: First Results}, + author={ Chorowski, Jan, and Bahdanau, Dzmitry , and Cho, Kyunghyun , and Bengio, Yoshua }, + journal={Neural Information Processing Systems: Workshop Deep Learning and Representation Learning Workshop }, + year={2014} +} + +@article{Sak2014, + title={Long short-term memory recurrent neural network architectures for large scale acoustic modeling}, + author={Sak, Hasim and Senior, Andrew and Beaufays, Francoise }, + journal={Interspeech 2014}, + year={2014} +} + +@article{Ko2015, + title={Audio Augmentation for Speech Recognition}, + author={Tom, Ko and Vijayaditya, Peddinti and Daniel, Povey + and Sanjeev, Khudanpur }, + journal={Interspeech 2015}, + year={2015} +} + +@article{Tjandra2017, + title={Listening while Speaking: Speech Chain by Deep Learning}, + author={Andros, Tjandra and Sakriani, Sakti and Satoshi, Nakamura }, + journal={ASRU 2017}, + year={2017} +} + +@article{Tjandra2018, + title={Machine Speech Chain with One-shot Speaker Adaptation}, + author={Andros, Tjandra and Sakriani, Sakti and Satoshi, Nakamura }, + journal={Interspeech 2018}, + year={2018} +} + +@article{bahdanau2014neural, + title={Neural machine translation by jointly learning to align and translate}, + author={Bahdanau, Dzmitry and Cho, Kyunghyun and Bengio, Yoshua}, + journal={arXiv preprint arXiv:1409.0473}, + year={2014} +} + +@article{cho2014learning, + title={Learning phrase representations using RNN encoder-decoder for statistical machine translation}, + author={Cho, Kyunghyun and Van Merri{\"e}nboer, Bart and Gulcehre, Caglar and Bahdanau, Dzmitry and Bougares, Fethi and Schwenk, Holger and Bengio, Yoshua}, + journal={arXiv preprint arXiv:1406.1078}, + year={2014} +} + +@article{rush2015neural, + title={A neural attention model for abstractive sentence summarization}, + author={Rush, Alexander M and Chopra, Sumit and Weston, Jason}, + journal={arXiv preprint arXiv:1509.00685}, + year={2015} +} + +@article{micikevicius2017mixed, + title={Mixed precision training}, + author={Micikevicius, Paulius and Narang, Sharan and Alben, Jonah and Diamos, Gregory and Elsen, Erich and Garcia, David and Ginsburg, Boris and Houston, Michael and Kuchaev, Oleksii and Venkatesh, Ganesh and others}, + journal={arXiv preprint arXiv:1710.03740}, + year={2017} +} + +@ARTICLE{Britz:2017, + author = {{Britz}, Denny and {Goldie}, Anna and {Luong}, Thang and {Le}, Quoc}, + title = "{Massive Exploration of Neural Machine Translation Architectures}", + journal = {ArXiv e-prints arXiv:1703.03906}, + archivePrefix = "arXiv", + eprinttype = {arxiv}, + eprint = {1703.03906}, + primaryClass = "cs.CL", + keywords = {Computer Science - Computation and Language}, + year = 2017, + month = mar, +} + +@inproceedings{vaswani2017attention, + title={Attention is all you need}, + author={Vaswani, Ashish and Shazeer, Noam and Parmar, Niki and Uszkoreit, Jakob and Jones, Llion and Gomez, Aidan N and Kaiser, {\L}ukasz and Polosukhin, Illia}, + booktitle={Advances in Neural Information Processing Systems}, + pages={6000--6010}, + year={2017} +} + +@inproceedings{abadi2016tensorflow, + title={TensorFlow: A System for Large-Scale Machine Learning.}, + author={Abadi, Mart{\'\i}n and Barham, Paul and Chen, Jianmin and Chen, Zhifeng and Davis, Andy and Dean, Jeffrey and Devin, Matthieu and Ghemawat, Sanjay and Irving, Geoffrey and Isard, Michael and others}, + booktitle={OSDI}, + volume={16}, + pages={265--283}, + year={2016} +} + +@article{tensor2tensor, + author = {Ashish Vaswani and Samy Bengio and Eugene Brevdo and Francois Chollet and Aidan N. Gomez and Stephan Gouws and Llion Jones and \L{}ukasz Kaiser and Nal Kalchbrenner and Niki Parmar and Ryan Sepassi and + Noam Shazeer and Jakob Uszkoreit}, + title = {Tensor2Tensor for Neural Machine Translation}, + journal = {CoRR}, + volume = {abs/1803.07416}, + year = {2018}, + url = {http://arxiv.org/abs/1803.07416}, +} + +@article{gehring2017convs2s, + author = {Gehring, Jonas, and Auli, Michael and Grangier, David and Yarats, Denis and Dauphin, Yann N}, + title = "{Convolutional Sequence to Sequence Learning}", + journal = {ArXiv e-prints arXiv:1705.03122}, + archivePrefix = "arXiv", + eprinttype = {arxiv}, + eprint = {1705.03122}, + primaryClass = "cs.CL", + keywords = {Computer Science - Computation and Language}, + year = 2017, + month = May, +} + +@inproceedings{chan2015, + title={Listen, attend and spell}, + author={Chan, William and Jaitly, Navdeep and Le, Quoc V and Vinyals, Oriol}, + booktitle={Acoustics, Speech and Signal Processing (ICASSP), 2016 IEEE International Conference on}, + pages={5206--5210}, + year={2016}, + organization={IEEE} +} + +@inproceedings{xu2015show, + title={Show, attend and tell: Neural image caption generation with visual attention}, + author={Xu, Kelvin and Ba, Jimmy and Kiros, Ryan and Cho, Kyunghyun and Courville, Aaron and Salakhudinov, Ruslan and Zemel, Rich and Bengio, Yoshua}, + booktitle={International Conference on Machine Learning}, + pages={2048--2057}, + year={2015} +} + +@incollection{Sutskever2014, + title = {Sequence to Sequence Learning with Neural Networks}, + author = {Sutskever, Ilya and Vinyals, Oriol and Le, Quoc V}, + booktitle = {Advances in Neural Information Processing Systems 27}, + editor = {Z. Ghahramani and M. Welling and C. Cortes and N. D. Lawrence and K. Q. Weinberger}, + pages = {3104--3112}, + year = {2014}, + publisher = {Curran Associates, Inc.}, + url = {http://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf} +} + +@article{DeepSpeech2014, + title = {Deep Speech: Scaling up end-to-end speech recognition}, + author = {Awni Y. Hannun and Carl Case and Jared Casper and Bryan Catanzaro and Greg Diamos and Erich Elsen and Ryan Prenger and Sanjeev Satheesh and Shubho Sengupta and Adam Coates and Andrew Y. Ng}, + journal = {CoRR}, + volume = {abs/1412.5567}, + year = {2014}, + url = {http://arxiv.org/abs/1412.5567}, + archivePrefix = {arXiv}, + eprint = {1412.5567}, + timestamp = {Mon, 13 Aug 2018 16:48:07 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/HannunCCCDEPSSCN14}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@inproceedings{DeepSpeech2, + author = {Amodei, Dario and Ananthanarayanan, Sundaram and Anubhai, Rishita and Bai, Jingliang and Battenberg, Eric and Case, Carl and Casper, Jared and Catanzaro, Bryan and Cheng, Qiang and Chen, Guoliang and Chen, Jie and Chen, Jingdong and Chen, Zhijie and Chrzanowski, Mike and Coates, Adam and Diamos, Greg and Ding, Ke and Du, Niandong and Elsen, Erich and Engel, Jesse and Fang, Weiwei and Fan, Linxi and Fougner, Christopher and Gao, Liang and Gong, Caixia and Hannun, Awni and Han, Tony and Johannes, Lappi Vaino and Jiang, Bing and Ju, Cai and Jun, Billy and LeGresley, Patrick and Lin, Libby and Liu, Junjie and Liu, Yang and Li, Weigao and Li, Xiangang and Ma, Dongpeng and Narang, Sharan and Ng, Andrew and Ozair, Sherjil and Peng, Yiping and Prenger, Ryan and Qian, Sheng and Quan, Zongfeng and Raiman, Jonathan and Rao, Vinay and Satheesh, Sanjeev and Seetapun, David and Sengupta, Shubho and Srinet, Kavya and Sriram, Anuroop and Tang, Haiyuan and Tang, Liliang and Wang, Chong and Wang, Jidong and Wang, Kaifu and Wang, Yi and Wang, Zhijian and Wang, Zhiqian and Wu, Shuang and Wei, Likai and Xiao, Bo and Xie, Wen and Xie, Yan and Yogatama, Dani and Yuan, Bin and Zhan, Jun and Zhu, Zhenyao}, + title = {Deep Speech 2: End-to-end Speech Recognition in English and Mandarin}, + booktitle = {Proceedings of the 33rd International Conference on International Conference on Machine Learning - Volume 48}, + series = {ICML'16}, + year = {2016}, + location = {New York, NY, USA}, + pages = {173--182}, + numpages = {10}, + url = {http://dl.acm.org/citation.cfm?id=3045390.3045410}, + acmid = {3045410}, + publisher = {JMLR.org}, +} + +@inproceedings{prabhavalkar2017comparison, + title={A comparison of sequence-to-sequence models for speech recognition}, + author={Prabhavalkar, Rohit and Rao, Kanishka and Sainath, Tara N and Li, Bo and Johnson, Leif and Jaitly, Navdeep}, + booktitle={Proc. Interspeech}, + pages={939--943}, + year={2017} +} + +@article{chiu2017state, + title={State-of-the-art speech recognition with sequence-to-sequence models}, + author={Chiu, Chung-Cheng and Sainath, Tara N and Wu, Yonghui and Prabhavalkar, Rohit and Nguyen, Patrick and Chen, Zhifeng and Kannan, Anjuli and Weiss, Ron J and Rao, Kanishka and Gonina, Katya and others}, + journal={arXiv preprint arXiv:1712.01769}, + year={2017} +} + +@misc{NVMixed, + title = {{NVIDA's Mixed-Precision Training - TensorFlow example}}, + howpublished = {\url{https://docs.nvidia.com/deeplearning/sdk/mixed-precision-training/#example_tensorflow}}, + author={NVIDIA}, + note = {Accessed: 2018-10-09}, + year={2018} +} + +@article{gehring2017, + title={Convolutional sequence to sequence learning}, + author={Gehring, Jonas and Auli, Michael and Grangier, David and Yarats, Denis and Dauphin, Yann N}, + journal={arXiv preprint arXiv:1705.03122}, + year={2017} +} + +@article{collobert2016, + title={Wav2letter: an end-to-end convnet-based speech recognition system}, + author={Collobert, Ronan and Puhrsch, Christian and Synnaeve, Gabriel}, + journal={arXiv preprint arXiv:1609.03193}, + year={2016} +} + +@inproceedings{Zhang2016, +author={Ying Zhang and Mohammad Pezeshki and Philémon Brakel and Saizheng Zhang and César Laurent and Yoshua Bengio and Aaron Courville}, +title={Towards End-to-End Speech Recognition with Deep Convolutional Neural Networks}, +year=2016, +booktitle={Interspeech 2016}, +doi={10.21437/Interspeech.2016-1446}, +url={http://dx.doi.org/10.21437/Interspeech.2016-1446}, +pages={410--414} +} + +@inproceedings{Zhang2017, + title={Very deep convolutional networks for end-to-end speech recognition}, + author={Zhang, Yu, and Chan, William, and Jaitly, Navdeep}, + booktitle={Acoustics, Speech and Signal Processing (ICASSP), 2017 IEEE International Conference on}, + year={2017}, + organization={IEEE} +} + + +@article{Wang2017, + title={Tacotron: Towards End-to-End Speech Synthesis}, + author={ Wang, Yuxuan, and Skerry-Ryan, RJ, and Stanton, Daisy and Wu, Yonghui and Weiss, Ron, and Jaitly, Navdeep and Yang, Zongheng and Xiao, Ying and Chen,Zhifeng and Bengio, Samy and Le, Quoc and Agiomyrgiannakis, Yannis and Clark,Rob and Saurous, Rif A.}, + journal={arXiv preprint arXiv:1703.10135}, + year={2017} +} + +@inproceedings{shen2018natural, + title={Natural TTS synthesis by conditioning wavenet on mel spectrogram predictions}, + author={Shen, Jonathan and Pang, Ruoming and Weiss, Ron J and Schuster, Mike and Jaitly, Navdeep and Yang, Zongheng and Chen, Zhifeng and Zhang, Yu and Wang, Yuxuan and Skerrv-Ryan, Rj and others}, + booktitle={2018 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP)}, + pages={4779--4783}, + year={2018}, + organization={IEEE} +} + +@article{griffin1984signal, + title={Signal estimation from modified short-time Fourier transform}, + author={Griffin, Daniel and Lim, Jae}, + journal={IEEE Transactions on Acoustics, Speech, and Signal Processing}, + volume={32}, + number={2}, + pages={236--243}, + year={1984}, + publisher={IEEE} +} + +@misc{ito2017lj, + title={The LJ speech dataset}, + author={Ito, Keith and others}, + year={2017} +} + +@misc{mailabs, + title = {{The M-AILABS Speech Dataset}}, + howpublished = {\url{http://www.m-ailabs.bayern/en/the-mailabs-speech-dataset/}}, + author={M-AILABS}, + note = {Accessed: 2018-10-09}, + year={2018} +} + +@article{merity2016pointer, + title={Pointer sentinel mixture models}, + author={Merity, Stephen and Xiong, Caiming and Bradbury, James and Socher, Richard}, + journal={arXiv preprint arXiv:1609.07843}, + year={2016} +} + +@inproceedings{socher2013recursive, + title={Recursive deep models for semantic compositionality over a sentiment treebank}, + author={Socher, Richard and Perelygin, Alex and Wu, Jean and Chuang, Jason and Manning, Christopher D and Ng, Andrew and Potts, Christopher}, + booktitle={Proceedings of the 2013 conference on empirical methods in natural language processing}, + pages={1631--1642}, + year={2013} +} + +@InProceedings{maas-EtAl:2011:ACL-HLT2011, + author = {Maas, Andrew L. and Daly, Raymond E. and Pham, Peter T. and Huang, Dan and Ng, Andrew Y. and Potts, Christopher}, + title = {Learning Word Vectors for Sentiment Analysis}, + booktitle = {Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies}, + month = {June}, + year = {2011}, + address = {Portland, Oregon, USA}, + publisher = {Association for Computational Linguistics}, + pages = {142--150}, + url = {http://www.aclweb.org/anthology/P11-1015} +} + +@inproceedings{Povey2018SemiOrthogonalLM, + title={Semi-Orthogonal Low-Rank Matrix Factorization for Deep Neural Networks}, + author={Daniel Povey and Gaofeng Cheng and Yiming Wang and Ke Li and Hainan Xu and Mahsa Yarmohammadi and Sanjeev Khudanpur}, + booktitle={Interspeech}, + year={2018} +} + +@article{CAPIO2017, + author = {Kyu J. Han and Akshay Chandrashekaran and Jungsuk Kim and Ian R. Lane}, + title = {The {CAPIO} 2017 Conversational Speech Recognition System}, + journal = {CoRR}, + volume = {abs/1801.00059}, + year = {2018}, + url = {http://arxiv.org/abs/1801.00059}, + archivePrefix = {arXiv}, + eprint = {1801.00059}, + timestamp = {Mon, 13 Aug 2018 16:49:10 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/abs-1801-00059}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{WaveNet, + author = {A{\"{a}}ron van den Oord and Sander Dieleman and Heiga Zen and Karen Simonyan and Oriol Vinyals and Alex Graves and Nal Kalchbrenner and Andrew W. Senior and Koray Kavukcuoglu}, + title = {WaveNet: {A} Generative Model for Raw Audio}, + journal = {CoRR}, + volume = {abs/1609.03499}, + year = {2016}, + url = {http://arxiv.org/abs/1609.03499}, + archivePrefix = {arXiv}, + eprint = {1609.03499}, + timestamp = {Mon, 13 Aug 2018 16:49:15 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/OordDZSVGKSK16}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{FacebookGERENGBackTranslation, + author = {Rico Sennrich and Barry Haddow and Alexandra Birch}, + title = {Improving Neural Machine Translation Models with Monolingual Data}, + journal = {CoRR}, + volume = {abs/1511.06709}, + year = {2015}, + url = {http://arxiv.org/abs/1511.06709}, + archivePrefix = {arXiv}, + eprint = {1511.06709}, + timestamp = {Mon, 13 Aug 2018 16:47:05 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/SennrichHB15a}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{GlobalStyleTokens, + author = {Yuxuan Wang and Daisy Stanton and Yu Zhang and R. J. Skerry{-}Ryan and Eric Battenberg and Joel Shor and Ying Xiao and Fei Ren and Ye Jia and Rif A. Saurous}, + title = {Style Tokens: Unsupervised Style Modeling, Control and Transfer in End-to-End Speech Synthesis}, + journal = {CoRR}, + volume = {abs/1803.09017}, + year = {2018}, + url = {http://arxiv.org/abs/1803.09017}, + archivePrefix = {arXiv}, + eprint = {1803.09017}, + timestamp = {Mon, 13 Aug 2018 16:46:53 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/abs-1803-09017}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{IoffeS15BatchNorm, + author = {Sergey Ioffe and Christian Szegedy}, + title = {Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift}, + journal = {CoRR}, + volume = {abs/1502.03167}, + year = {2015}, + url = {http://arxiv.org/abs/1502.03167}, + archivePrefix = {arXiv}, + eprint = {1502.03167}, + timestamp = {Mon, 13 Aug 2018 16:47:06 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/IoffeS15}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{kingma, + author = {Diederik P. Kingma and + Jimmy Ba}, + title = {Adam: {A} Method for Stochastic Optimization}, + journal = {CoRR}, + volume = {abs/1412.6980}, + year = {2014}, + url = {http://arxiv.org/abs/1412.6980}, + archivePrefix = {arXiv}, + eprint = {1412.6980}, + timestamp = {Mon, 13 Aug 2018 01:00:00 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/KingmaB14}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@incollection{Salimans2016WeightNorm, + title = {Weight Normalization: A Simple Reparameterization to Accelerate Training of Deep Neural Networks}, + author = {Salimans, Tim and Kingma, Durk P}, + booktitle = {Advances in Neural Information Processing Systems 29}, + editor = {D. D. Lee and M. Sugiyama and U. V. Luxburg and I. Guyon and R. Garnett}, + pages = {901--909}, + year = {2016}, + publisher = {Curran Associates, Inc.}, + url = {http://papers.nips.cc/paper/6114-weight-normalization-a-simple-reparameterization-to-accelerate-training-of-deep-neural-networks.pdf} +} + +@article{wu2016google, + title={Google's neural machine translation system: Bridging the gap between human and machine translation}, + author={Wu, Yonghui and Schuster, Mike and Chen, Zhifeng and Le, Quoc V and Norouzi, Mohammad and Macherey, Zolfgang and Krikun, Maxim and Cao, Yuan and Gao, Qin and Macherey, Klaus and others}, + journal={arXiv preprint arXiv:1609.08144}, + year={2016} +} + +@inproceedings{opennmt, + author = {Guillaume Klein and Yoon Kim and Yuntian Deng and Jean Senellart and Alexander M. Rush}, + title = {OpenNMT: Open-Source Toolkit for Neural Machine Translation}, + booktitle = {Proc. ACL}, + year = {2017}, + url = {https://doi.org/10.18653/v1/P17-4012}, + doi = {10.18653/v1/P17-4012} +} + +@article{paszke2017automatic, + title={Automatic differentiation in PyTorch}, + author={Paszke, Adam and Gross, Sam and Chintala, Soumith and Chanan, Gregory and Yang, Edward and DeVito, Zachary and Lin, Zeming and Desmaison, Alban and Antiga, Luca and Lerer, Adam}, + year={2017} +} + +@article{yu2014introduction, + title={An introduction to computational networks and the computational network toolkit}, + author={Yu, Dong and Eversole, Adam and Seltzer, Mike and Yao, Kaisheng and Huang, Zhiheng and Guenter, Brian and Kuchaiev, Oleksii and Zhang, Yu and Seide, Frank and Wang, Huaming and others}, + journal={Microsoft Technical Report MSR-TR-2014--112}, + year={2014} +} + +@article{nvidia2017v100, + title={V100 GPU architecture. The world’s most advanced data center GPU. Version WP-08608-001\_v1. 1}, + author={NVIDIA, Tesla}, + journal={NVIDIA. Aug}, + pages={108}, + year={2017} +} + +@article{post2018call, + title={A call for clarity in reporting bleu scores}, + author={Post, Matt}, + journal={arXiv preprint arXiv:1804.08771}, + year={2018} +} + +@article{Ba2016LayerNorm, + author = {Jimmy Lei Ba and Jamie Ryan Kiros and Geoffrey E Hinton}, + title = {Layer normalization}, + journal = {CoRR}, + volume = {abs/1607.06450}, + year = {2016}, + url = {http://arxiv.org/abs/1607.06450}, + archivePrefix = {arXiv}, +} + +@inproceedings{Dauphin2017GLU, + author = {Dauphin, Yann N. and Fan, Angela and Auli, Michael and Grangier, David}, + title = {Language Modeling with Gated Convolutional Networks}, + booktitle = {Proceedings of the 34th International Conference on Machine Learning - Volume 70}, + series = {ICML'17}, + year = {2017}, + location = {Sydney, NSW, Australia}, + pages = {933--941}, + numpages = {9}, + url = {http://dl.acm.org/citation.cfm?id=3305381.3305478}, + acmid = {3305478}, + publisher = {JMLR.org}, +} + +@incollection{Oord2016PixelCNN, +title = {Conditional Image Generation with PixelCNN Decoders}, +author = {van den Oord, Aaron and Kalchbrenner, Nal and Espeholt, Lasse and kavukcuoglu, koray and Vinyals, Oriol and Graves, Alex}, +booktitle = {Advances in Neural Information Processing Systems 29}, +editor = {D. D. Lee and M. Sugiyama and U. V. Luxburg and I. Guyon and R. Garnett}, +pages = {4790--4798}, +year = {2016}, +publisher = {Curran Associates, Inc.}, +url = {http://papers.nips.cc/paper/6527-conditional-image-generation-with-pixelcnn-decoders.pdf} +} + +@article{he2015, + title={Deep residual learning for image recognition}, + author={K. He, and X. Zhang, and S. Ren, and J. Sun}, + journal={arXiv preprint arXiv:1512.03385}, + year={2015} +} + +@article{huang2016, + title={Densely Connected Convolutional Networks}, + author={Gao Huang, and Zhuang Liu, and Laurens van der Maaten, and Kilian Q. Weinberger}, + journal={arXiv preprint arXiv:1608.06993}, + year={2016} +} + +@inproceedings{heafield2011kenlm, + title={KenLM: Faster and smaller language model queries}, + author={Heafield, Kenneth}, + booktitle={Proceedings of the sixth workshop on statistical machine translation}, + pages={187--197}, + year={2011}, + organization={Association for Computational Linguistics} +} + +@article{dai2018transformer, + title={Transformer-XL: Language Modeling with Longer-Term Dependency}, + author={Dai, Zihang and Yang, Zhilin and Yang, Yiming and Cohen, William W and Carbonell, Jaime and Le, Quoc V and Salakhutdinov, Ruslan}, + year={2018}, + journal = {CoRR}, + volume = {abs/1901.02860}, + url = {http://arxiv.org/abs/1901.02860}, + archivePrefix = {arXiv}, + eprint = {1901.02860}, + timestamp = {Fri, 01 Feb 2019 13:39:59 +0100}, + biburl = {https://dblp.org/rec/bib/journals/corr/abs-1901-02860}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@inproceedings{Saon+2016, +author={George Saon and Tom Sercu and Steven Rennie and Hong-Kwang J. Kuo}, +title={The IBM 2016 English Conversational Telephone Speech Recognition System}, +year=2016, +booktitle={Interspeech 2016}, +doi={10.21437/Interspeech.2016-1460}, +url={http://dx.doi.org/10.21437/Interspeech.2016-1460}, +pages={7--11} +} + +@INPROCEEDINGS{Sercu-2016, +author={T. {Sercu} and C. {Puhrsch} and B. {Kingsbury} and Y. {LeCun}}, +booktitle={2016 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP)}, +title={Very deep multilingual convolutional neural networks for LVCSR}, +year={2016}, +volume={}, +number={}, +pages={4955-4959}, +keywords={natural language processing;neural nets;speech recognition;very deep multilingual convolutional neural networks;LVCSR;CNN;large vocabulary continuous speech recognition systems;word error rate;Training;Context;Hidden Markov models;Neural networks;Computer architecture;Kernel;Training data;Convolutional Networks;Multilingual;Acoustic Modeling;Speech Recognition;Neural Networks}, +doi={10.1109/ICASSP.2016.7472620}, +ISSN={2379-190X}, +month={March},} + + +@inproceedings{Sercu+2016, +author={Tom Sercu and Vaibhava Goel}, +title={Advances in Very Deep Convolutional Neural Networks for LVCSR}, +year=2016, +booktitle={Interspeech 2016}, +doi={10.21437/Interspeech.2016-1033}, +url={http://dx.doi.org/10.21437/Interspeech.2016-1033}, +pages={3429--3433} +} + +@INPROCEEDINGS{Xiong-2018, +author={W. {Xiong} and L. {Wu} and F. {Alleva} and J. {Droppo} and X. {Huang} and A. {Stolcke}}, +booktitle={2018 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP)}, +title={The Microsoft 2017 Conversational Speech Recognition System}, +year={2018}, +volume={}, +number={}, +pages={5934-5938}, +keywords={convolution;feedforward neural nets;natural language processing;speaker recognition;speech processing;language model rescoring step;senone level;switchboard domains;character-based LSTM language models;NIST 2000 switchboard test set;frame level;word-level voting;acoustic model posteriors;dialog session aware LSTM language models;CNN-BLSTM acoustic model;Microsoft 2017 conversational speech recognition system;Acoustics;Error analysis;Training;Speech recognition;Switches;Computational modeling;Context modeling;Conversational speech recognition;CNN;LACE;BLSTM;LSTM-LM;system combination;human parity}, +doi={10.1109/ICASSP.2018.8461870}, +ISSN={2379-190X}, +month={April},} + +@inproceedings{zeyer2018improved, + author={Albert Zeyer and Kazuki Irie and Ralf Schlüter and Hermann Ney}, + title={Improved Training of End-to-end Attention Models for Speech Recognition}, + year=2018, + booktitle={Proc. Interspeech 2018}, + pages={7--11}, + doi={10.21437/Interspeech.2018-1616}, + url={http://dx.doi.org/10.21437/Interspeech.2018-1616} +} + +@article{Wav2LetterV2, + author = {Vitaliy Liptchinsky and + Gabriel Synnaeve and + Ronan Collobert}, + title = {Letter-Based Speech Recognition with Gated ConvNets}, + journal = {CoRR}, + volume = {abs/1712.09444}, + year = {2017}, + url = {http://arxiv.org/abs/1712.09444}, + archivePrefix = {arXiv}, + eprint = {1712.09444}, + timestamp = {Mon, 13 Aug 2018 16:46:33 +0200}, + biburl = {https://dblp.org/rec/bib/journals/corr/abs-1712-09444}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{zeghidour2018, + author = {Neil Zeghidour and + Qiantong Xu and + Vitaliy Liptchinsky and + Nicolas Usunier and + Gabriel Synnaeve and + Ronan Collobert}, + title = {Fully Convolutional Speech Recognition}, + journal = {CoRR}, + volume = {abs/1812.06864}, + year = {2018}, + url = {http://arxiv.org/abs/1812.06864}, + archivePrefix = {arXiv}, + eprint = {1812.06864}, + timestamp = {Tue, 01 Jan 2019 15:01:25 +0100}, + biburl = {https://dblp.org/rec/bib/journals/corr/abs-1812-06864}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@inproceedings{Hadian2018, + author={Hossein Hadian and Hossein Sameti and Daniel Povey and Sanjeev Khudanpur}, + title={End-to-end Speech Recognition Using Lattice-free MMI}, + year=2018, + booktitle={Proc. Interspeech 2018}, + pages={12--16}, + doi={10.21437/Interspeech.2018-1423}, + url={http://dx.doi.org/10.21437/Interspeech.2018-1423} +} + +@inproceedings{Tang2018, + author={Jian Tang and Yan Song and Lirong Dai and Ian McLoughlin}, + title={Acoustic Modeling with Densely Connected Residual Network for Multichannel Speech Recognition}, + year=2018, + booktitle={Proc. Interspeech 2018}, + pages={1783--1787}, + doi={10.21437/Interspeech.2018-1089}, + url={http://dx.doi.org/10.21437/Interspeech.2018-1089} +} + +@article{Kurata2017LanguageMW, + title={Language modeling with highway LSTM}, + author={Gakuto Kurata and Bhuvana Ramabhadran and George Saon and Abhinav Sethy}, + journal={2017 IEEE Automatic Speech Recognition and Understanding Workshop (ASRU)}, + year={2017}, + pages={244-251} +} + +@inproceedings{Saon2017, + author={George Saon and Gakuto Kurata and Tom Sercu and Kartik Audhkhasi and Samuel Thomas and Dimitrios Dimitriadis and Xiaodong Cui and Bhuvana Ramabhadran and Michael Picheny and Lynn-Li Lim and Bergul Roomi and Phil Hall}, + title={English Conversational Telephone Speech Recognition by Humans and Machines}, + year=2017, + booktitle={Proc. Interspeech 2017}, + pages={132--136}, + doi={10.21437/Interspeech.2017-405}, + url={http://dx.doi.org/10.21437/Interspeech.2017-405} +} + +@inproceedings{Povey+2016, +author={Daniel Povey and Vijayaditya Peddinti and Daniel Galvez and Pegah Ghahremani and Vimal Manohar and Xingyu Na and Yiming Wang and Sanjeev Khudanpur}, +title={Purely Sequence-Trained Neural Networks for ASR Based on Lattice-Free MMI}, +year=2016, +booktitle={Interspeech 2016}, +doi={10.21437/Interspeech.2016-595}, +url={http://dx.doi.org/10.21437/Interspeech.2016-595}, +pages={2751--2755} +} + +@article{Yang2018, + author = {Xuerui Yang and + Jiwei Li and + Xi Zhou}, + title = {A novel pyramidal-FSMN architecture with lattice-free {MMI} for speech + recognition}, + journal = {CoRR}, + volume = {abs/1810.11352}, + year = {2018}, + url = {http://arxiv.org/abs/1810.11352}, + archivePrefix = {arXiv}, + eprint = {1810.11352}, + timestamp = {Wed, 31 Oct 2018 14:24:29 +0100}, + biburl = {https://dblp.org/rec/bib/journals/corr/abs-1810-11352}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@article{liptchinsky2017based, + title={Letter-Based Speech Recognition with Gated ConvNets}, + author={Liptchinsky, Vitaliy and Synnaeve, Gabriel and Collobert, Ronan}, + journal={arXiv preprint arXiv:1712.09444}, + year={2017} +} + +@inproceedings{Weng2018, + author={Chao Weng and Jia Cui and Guangsen Wang and Jun Wang and Chengzhu Yu and Dan Su and Dong Yu}, + title={Improving Attention Based Sequence-to-Sequence Models for End-to-End English Conversational Speech Recognition}, + year=2018, + booktitle={Proc. Interspeech 2018}, + pages={761--765}, + doi={10.21437/Interspeech.2018-1030}, + url={http://dx.doi.org/10.21437/Interspeech.2018-1030} +} + +@INPROCEEDINGS{Battenberg2017, +author={E. {Battenberg} and J. {Chen} and R. {Child} and A. {Coates} and Y. G. Y. {Li} and H. {Liu} and S. {Satheesh} and A. {Sriram} and Z. {Zhu}}, +booktitle={2017 IEEE Automatic Speech Recognition and Understanding Workshop (ASRU)}, +title={Exploring neural transducers for end-to-end speech recognition}, +year={2017}, +volume={}, +number={}, +pages={206-213}, +keywords={recurrent neural nets;speech recognition;Hub500 benchmark;CTC models;speech recognition pipeline;RNN-Transducer models;language model;Seq2Seq models;end-to-end speech recognition;neural transducers;Decoding;Hidden Markov models;Transducers;Task analysis;Speech;Mathematical model;Neural networks}, +doi={10.1109/ASRU.2017.8268937}, +ISSN={}, +month={Dec}, +} + +@inproceedings{ +loshchilov2018, +title={Decoupled Weight Decay Regularization}, +author={Ilya Loshchilov and Frank Hutter}, +booktitle={International Conference on Learning Representations}, +year={2019}, +url={https://openreview.net/forum?id=Bkg6RiCqY7}, +} + +@article{zhang2017ndadam, + author = {Zijun Zhang and Lin Ma and Zongpeng Li and Chuan Wu}, + title = {Normalized Direction-preserving Adam}, + journal = {arXiv e-prints arXiv:1709.04546}, + year = {2017}, +} + +@article{park2019, + author = {{Park}, Daniel S. and {Chan}, William and {Zhang}, Yu and + {Chiu}, Chung-Cheng and {Zoph}, Barret and {Cubuk}, Ekin D. and + {Le}, Quoc V.}, + title = "{SpecAugment: A Simple Data Augmentation Method for Automatic Speech Recognition}", + journal = {arXiv e-prints}, + year = "2019", + eid = {arXiv:1904.08779}, + eprint = {1904.08779}, +} + +@article{novograd2019, + author = {{Ginsburg}, Boris and {Castonguay}, Patrice and {Hrinchuk}, Oleksii and + {Kuchaiev}, Oleksii and {Lavrukhin}, Vitaly and {Leary}, Ryan and + {Li}, Jason and {Nguyen}, Huyen and {Cohen}, Jonathan M.}, + title = "{Stochastic Gradient Methods with Layer-wise Adaptive Moments for Training of Deep Networks}", + journal = {arXiv e-prints}, + year = "2019", + eid = {arXiv:1905.11286}, + eprint = {1905.11286}, +} + +@article{kriman2019quartznet, + title={Quartznet: {Deep} automatic speech recognition with 1d time-channel separable convolutions}, + author={Kriman, Samuel and Beliaev, Stanislav and Ginsburg, Boris and Huang, Jocelyn and Kuchaiev, Oleksii and Lavrukhin, Vitaly and Leary, Ryan and Li, Jason and Zhang, Yang}, + journal={arXiv preprint arXiv:1910.10261}, + year={2019} +} + +@misc{itu1988g711, + title={{ITU-T} {G.711} - {Pulse} code modulation ({PCM}) of voice frequencies}, + author={ITU-T Geneva Switzerland}, + year={1988}, +} + +@article{han2020contextnet, + title={ContextNet: Improving convolutional neural networks for automatic speech recognition with global context}, + author={Han, Wei and Zhang, Zhengdong and Zhang, Yu and Yu, Jiahui and Chiu, Chung-Cheng and Qin, James and Gulati, Anmol and Pang, Ruoming and Wu, Yonghui}, + journal={arXiv:2005.03191}, + year={2020} +} + +@inproceedings{hu2018squeeze, + title={Squeeze-and-excitation networks}, + author={Hu, Jie and Shen, Li and Sun, Gang}, + booktitle={ICVPR}, + year={2018} +} + +@article{koluguri2020speakernet, + title={SpeakerNet: 1D Depth-wise Separable Convolutional Network for Text-Independent Speaker Recognition and Verification}, + author={Koluguri, Nithin Rao and Li, Jason and Lavrukhin, Vitaly and Ginsburg, Boris}, + journal={arXiv preprint arXiv:2010.12653}, + year={2020} +} + +@article{gulati2020conformer, + title={Conformer: Convolution-augmented transformer for speech recognition}, + author={Gulati, Anmol and Qin, James and Chiu, Chung-Cheng and Parmar, Niki and Zhang, Yu and Yu, Jiahui and Han, Wei and Wang, Shibo and Zhang, Zhengdong and Wu, Yonghui and others}, + journal={arXiv preprint arXiv:2005.08100}, + year={2020} +} \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/asr_language_modeling.rst b/tts/NeMo/docs/source/asr/asr_language_modeling.rst new file mode 100644 index 0000000..2df9994 --- /dev/null +++ b/tts/NeMo/docs/source/asr/asr_language_modeling.rst @@ -0,0 +1,292 @@ +##################### +ASR Language Modeling +##################### + +Language models have shown to help the accuracy of ASR models. NeMo supports the following two approaches to incorporate language models into the ASR models: + +* :ref:`ngram_modeling` +* :ref:`neural_rescoring` + +It is possible to use both approaches on the same ASR model. + + +.. _ngram_modeling: + +************************ +N-gram Language Modeling +************************ + +In this approach, an N-gram LM is trained on text data, then it is used in fusion with beam search decoding to find the +best candidates. The beam search decoders in NeMo support language models trained with KenLM library ( +`https://github.com/kpu/kenlm `__). +The beam search decoders and KenLM library are not installed by default in NeMo, and you need to install them to be +able to use beam search decoding and N-gram LM. +Please refer to `scripts/ngram_lm/install_beamsearch_decoders.sh` on how to install them. + +NeMo supports both character-based and BPE-based models for N-gram LMs. An N-gram LM can be used with beam search +decoders on top of the ASR models to produce more accurate candidates. The beam search decoder would incorporate +the scores produced by the N-gram LM into its score calculations as the following: + +.. code:: + + final_score = acoustic_score + beam_alpha*lm_score + beam_beta*seq_length + +where acoustic_score is the score predicted by the acoustic encoder and lm_score is the one estimated by the LM. +Parameter 'beam_alpha' specifies amount of importance to place on the N-gram language model, and 'beam_beta' is a +penalty term to consider the sequence length in the scores. Larger alpha means more importance on the LM and less +importance on the acoustic model. Negative values for beta will give penalty to longer sequences and make the decoder +to prefer shorter predictions, while positive values would result in longer candidates. + + +Train N-gram LM +=============== + +The script to train an N-gram language model with KenLM can be found at +`scripts/asr_language_modeling/ngram_lm/train_kenlm.py `__. + +This script would train an N-gram language model with KenLM library which can be used with the beam search decoders +on top of the ASR models. This script supports both character level and BPE level encodings and models which is +detected automatically from the type of the model. + + +You may train the N-gram model as the following: + +.. code:: + + python train_kenlm.py --nemo_model_file \ + --train_file \ + --kenlm_model_file \ + --ngram_length + +The train file specified by `--train_file` can be a text file or JSON manifest. If the file's extension is anything +other than `.json`, it assumes that data format is plain text. For plain text format, each line should contain one +sample. For JSON manifest file, the file need to contain json formatted samples per each line like this: + +.. code:: + + {"audio_filepath": "/data_path/file1.wav", "text": "The transcript of the audio file."} + +It just extracts the `text` field from each line to create the training text file. After the N-gram model is trained, +it is stored at the path specified by `--kenlm_model_file`. + +The following is the list of the arguments for the training script: + ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| **Argument** | **Type** | **Default** | **Description** | ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| nemo_model_file | str | Required | The path of the `.nemo` file of the ASR model. It is needed to extract the tokenizer. | ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| train_file | str | Required | Path to the training file, it can be a text file or JSON manifest. | ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| kenlm_model_file | str | Required | The path to store the KenLM binary model file. | ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| kenlm_bin_path | str | Required | The path to the bin folder of KenLM. It is a folder named `bin` under where KenLM is installed.| ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| ngram_length** | int | Required | Specifies order of N-gram LM. | ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ +| do_lower_case | bool | ``False`` | Whether to make the training text all lower case. | ++------------------+----------+-------------+------------------------------------------------------------------------------------------------+ + +** Note: Recommend to use 6 as the order of the N-gram model for BPE-based models. Higher orders may need the re-compilation of KenLM to support it. + +Evaluate by Beam Search Decoding and N-gram LM +============================================== + +NeMo's beam search decoders are capable of using the KenLM's N-gram models to find the best candidates. +The script to evaluate an ASR model with beam search decoding and N-gram models can be found at +`scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py `__. + +You may evaluate an ASR model as the following: + +.. code:: + + python eval_beamsearch_ngram.py --nemo_model_file \ + --input_manifest \ + --acoustic_batch_size \ + --beam_width \ + --beam_alpha \ + --beam_width \ + --preds_output_folder \ + --decoding_mode beam_search_ngram + +It can evaluate a model in the three following modes by setting the argument `--decoding_mode`: + +* greedy: Just greedy decoding is done, and no beam search decoding is performed. +* beamsearch: The beam search decoding is done but without using the N-gram language model, final results would be equivalent to setting the weight of LM (beam_beta) to zero. +* beamsearch_ngram: The beam search decoding is done with N-gram LM. + +The `beamsearch` mode would evaluate by beam search decoding without any language model. +It would report the performances in terms of Word Error Rate (WER) and Character Error Rate (CER). Moreover, +the WER/CER of the model when the best candidate is selected among the candidates is also reported as the best WER/CER. +It can be an indicator of how good the predicted candidates are. + +The script would initially load the ASR model and predict the outputs of the model's encoder as log probabilities. +This part would be computed in batches on a device selected by `--device`, which can be CPU (`--device=cpu`) or a +single GPU (`--device=cuda:0`). The batch size of this part can get specified by `--acoustic_batch_size`. You may use +the largest batch size feasible to speed up the step of calculating the log probabilities. You may also use `--use_amp` +to speed up the calculation of log probabilities and make it possible to use larger sizes for `--acoustic_batch_size`. +Currently multi-GPU is not supported for calculating the log probabilities, but using `--probs_cache_file` can help. +It stores the log probabilities produced from the model's encoder into a pickle file so that next time the first step +can get skipped. + +The following is the list of the arguments for the evaluation script: + ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| **Argument** |**Type**| **Default** | **Description** | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| nemo_model_file | str | Required | The path of the `.nemo` file of the ASR model to extract the tokenizer. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| input_manifest | str | Required | Path to the training file, it can be a text file or JSON manifest. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| kenlm_model_file | str | Required | The path to store the KenLM binary model file. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| preds_output_folder | str | None | The path to an optional folder to store the predictions. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| probs_cache_file | str | None | The cache file for storing the outputs of the model. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| acoustic_batch_size | int | 16 | The batch size to calculate log probabilities. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| use_amp | bool | ``False`` | Whether to use AMP if available to calculate log probabilities. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| device | str | cuda | The device to load the model onto to calculate log probabilities. | +| | | | It can `cpu`, `cuda`, `cuda:0`, `cuda:1`, ... | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| decoding_mode | str | beamsearch_ngram | The decoding scheme to be used for evaluation. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beam_width | float | Required | The width or list of the widths of the beam search decoding. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beam_alpha | float | Required | The alpha parameter or list of the alphas for the beam search decoding. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beam_beta | float | Required | The beta parameter or list of the betas for the beam search decoding. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beam_batch_size | int | 128 | The batch size to be used for beam search decoding. | +| | | | Larger batch size can be a little faster, but uses larger memory. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ + +Width of the beam search (`--beam_width`) specifies the number of top candidates/predictions the beam search decoder +would search for. Larger beams result in more accurate but slower predictions. + +There is also a tutorial to learn more about evaluating the ASR models with N-gram LM here: +`Offline ASR Inference with Beam Search and External Language Model Rescoring `_ + +Hyperparameter Grid Search +-------------------------- + +Beam search decoding with N-gram LM has three main hyperparameters: `beam_width`, `beam_alpha`, and `beam_beta`. +The accuracy of the model is dependent to the values of these parameters, specially beam_alpha and beam_beta. +You may specify a single or list of values for each of these parameters to perform grid search. It would perform the +beam search decoding on all the combinations of the these three hyperparameters. +For instance, the following set of parameters would results in 2*1*2=4 beam search decodings: + +.. code:: + + python eval_beamsearch_ngram.py ... \ + --beam_width 64 128 \ + --beam_alpha 1.0 \ + --beam_beta 1.0 0.5 + + +.. _neural_rescoring: + +**************** +Neural Rescoring +**************** + +In this approach a neural network is used which can gives scores to a candidate. A candidate is the text transcript predicted by the decoder of the ASR model. +The top K candidates produced by the beam search decoding (beam width of K) are given to a neural language model to rank them. +Ranking can be done by a language model which gives a score to each candidate. +This score is usually combined with the scores from the beam search decoding to produce the final scores and rankings. + +Train Neural Rescorer +===================== + +An example script to train such a language model with Transformer can be found at `examples/nlp/language_modeling/transformer_lm.py `__. +It trains a TransformerLMModel which can be used as a neural rescorer for an ASR system. + + +Evaluation +========== + +Given a trained TransformerLMModel `.nemo` file, the script available at +`scripts/asr_language_modeling/neural_rescorer/eval_neural_rescorer.py `__ +can be used to re-score beams obtained with ASR model. You need the `.tsv` file containing the candidates produced +by the acoustic model and the beam search decoding to use this script. The candidates can be the result of just the beam +search decoding or the result of fusion with an N-gram LM. You may generate this file by specifying `--preds_output_folder' for +`scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py `__. + +The neural rescorer would rescore the beams/candidates by using two parameters of `rescorer_alpha` and `rescorer_beta` as the following: + +.. code:: + + final_score = beam_search_score + rescorer_alpha*neural_rescorer_score + rescorer_beta*seq_length + +Parameter `rescorer_alpha` specifies amount of importance to place on the neural rescorer model, and `rescorer_beta` is +a penalty term to consider the sequence length in the scores. They have similar effects like the parameters +`beam_alpha` and `beam_beta` of beam search decoder and N-gram LM. + +You may follow the following steps to evaluate a neural LM: + +#. Obtain `.tsv` file with beams and their corresponding scores. Scores can be from a regular beam search decoder or + in fusion with an N-gram LM scores. For a given beam size `beam_size` and a number of examples + for evaluation `num_eval_examples`, it should contain (`num_eval_examples` x `beam_size`) lines of + form `beam_candidate_text \t score`. This file can be generated by `scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py `__ + +#. Rescore the candidates by `scripts/asr_language_modeling/neural_rescorer/eval_neural_rescorer.py `__. + +.. code:: + python eval_neural_rescorer.py + --lm_model=[path to .nemo file of the LM] + --beams_file=[path to beams .tsv file] + --beam_size=[size of the beams] + --eval_manifest=[path to eval manifest .json file] + --batch_size=[batch size used for inference on the LM model] + --alpha=[the value for the parameter rescorer_alpha] + --beta=[the value for the parameter rescorer_beta] + --scores_output_file=[the optional path to store the rescored candidates] + +The candidates along with their new scores would be stored at the file specified by `--scores_output_file`. + +The following is the list of the arguments for the evaluation script: + ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| **Argument** |**Type**| **Default** | **Description** | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| lm_model | str | Required | The path of the '.nemo' file of the ASR model to extract the tokenizer. | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| eval_manifest | str | Required | Path to the evaluation manifest file (.json manifest file) | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beams_file | str | Required | path to beams file (.tsv) containing the candidates and their scores | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beam_size | int | Required | The width of the beams (number of candidates) generated by the decoder | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| alpha | float | None | The value for parameter rescorer_alpha | +| | | | Not passing value would enable linear search for rescorer_alpha | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| beta | float | None | The value for parameter rescorer_beta | +| | | | Not passing value would enable linear search for rescorer_beta | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| batch_size | int | 16 | The batch size used to calculate the scores | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| scores_output_file | str | None | The optional file to store the rescored beams | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| use_amp | bool | ``False`` | Whether to use AMP if available calculate the scores | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ +| device | str | cuda | The device to load LM model onto to calculate the scores | +| | | | It can be 'cpu', 'cuda', 'cuda:0', 'cuda:1', ... | ++---------------------+--------+------------------+-------------------------------------------------------------------------+ + + +Hyperparameter Linear Search +---------------------------- + +This script also supports linear search for parameters `rescorer_alpha` and `rescorer_beta`. If any of the two is not +provided, a linear search is performed to find the best value for that parameter. When linear search is used, initially +`rescorer_beta` is set to zero and the best value for `rescorer_alpha` is found, then `rescorer_alpha` is fixed with +that value and another linear search is done to find the best value for `rescorer_beta`. +If any of the of these two parameters is already specified, then search for that one is skipped. After each search for a +parameter, the plot of WER% for different values of the parameter is also shown. + +It is recommended to first use the linear search for both parameters on a validation set by not providing any values for `--alpha` and `--beta`. +Then check the WER curves and decide on the best values for each parameter. Finally, evaluate the best values on the test set. diff --git a/tts/NeMo/docs/source/asr/configs.rst b/tts/NeMo/docs/source/asr/configs.rst new file mode 100644 index 0000000..4c93043 --- /dev/null +++ b/tts/NeMo/docs/source/asr/configs.rst @@ -0,0 +1,528 @@ +NeMo ASR Configuration Files +============================ + +This section describes the NeMo configuration file setup that is specific to models in the ASR collection. For general information +about how to set up and run experiments that is common to all NeMo models (e.g. Experiment Manager and PyTorch Lightning trainer +parameters), see the :doc:`../core/core` section. + +The model section of the NeMo ASR configuration files generally requires information about the dataset(s) being used, the preprocessor +for audio files, parameters for any augmentation being performed, as well as the model architecture specification. The sections on +this page cover each of these in more detail. + +Example configuration files for all of the NeMo ASR scripts can be found in the +`config directory of the examples `_. + + +Dataset Configuration +--------------------- + +Training, validation, and test parameters are specified using the ``train_ds``, ``validation_ds``, and +``test_ds`` sections in the configuration file, respectively. Depending on the task, there may be arguments specifying the sample rate +of the audio files, the vocabulary of the dataset (for character prediction), whether or not to shuffle the dataset, and so on. You may +also decide to leave fields such as the ``manifest_filepath`` blank, to be specified via the command-line at runtime. + +Any initialization parameter that is accepted for the Dataset class used in the experiment can be set in the config file. +Refer to the `Datasets <./api.html#Datasets>`__ section of the API for a list of Datasets and their respective parameters. + +An example ASR train and validation configuration should look similar to the following: + +.. code-block:: yaml + + # Specified at the beginning of the config file + labels: &labels [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + + model: + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels # Uses the labels above + batch_size: 32 + trim_silence: True + max_duration: 16.7 + shuffle: True + is_tarred: False # If set to true, uses the tarred version of the Dataset + tarred_audio_filepaths: null # Not used if is_tarred is false + tarred_shard_strategy: "scatter" # Not used if is_tarred is false + num_workers: 8 + pin_memory: true + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels # Uses the labels above + batch_size: 32 + shuffle: False # No need to shuffle the validation data + num_workers: 8 + pin_memory: true + + +Preprocessor Configuration +-------------------------- + +If you are loading audio files for your experiment, you will likely want to use a preprocessor to convert from the +raw audio signal to features (e.g. mel-spectrogram or MFCC). The ``preprocessor`` section of the config specifies the audio +preprocessor to be used via the ``_target_`` field, as well as any initialization parameters for that preprocessor. + +An example of specifying a preprocessor is as follows: + +.. code-block:: yaml + + model: + ... + preprocessor: + # _target_ is the audio preprocessor module you want to use + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + ... + # Other parameters for the preprocessor + +Refer to the `Audio Preprocessors <./api.html#Audio Preprocessors>`__ API section for the preprocessor options, expected arguments, +and defaults. + +Augmentation Configurations +--------------------------- + +There are a few on-the-fly spectrogram augmentation options for NeMo ASR, which can be specified by the +configuration file using a ``spec_augment`` section. + +For example, there are options for `Cutout `_ and +`SpecAugment `_ available via the ``SpectrogramAugmentation`` module. + +The following example sets up both ``Cutout`` (via the ``rect_*`` parameters) and ``SpecAugment`` (via the ``freq_*`` +and ``time_*`` parameters). + +.. code-block:: yaml + + model: + ... + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + # Cutout parameters + rect_masks: 5 # Number of rectangles to cut from any given spectrogram + rect_freq: 50 # Max cut of size 50 along the frequency dimension + rect_time: 120 # Max cut of size 120 along the time dimension + # SpecAugment parameters + freq_masks: 2 # Cut two frequency bands + freq_width: 15 # ... of width 15 at maximum + time_masks: 5 # Cut out 10 time bands + time_width: 25 # ... of width 25 at maximum + +You can use any combination of ``Cutout``, frequency/time ``SpecAugment``, or neither of them. + +With NeMo ASR, you can also add augmentation pipelines that can be used to simulate various kinds of noise +added to audio in the channel. Augmentors in a pipeline are applied on the audio data read in the data layer. Online +augmentors can be specified in the config file using an ``augmentor`` section in ``train_ds``. The following example +adds an augmentation pipeline that first adds white noise to an audio sample with a probability of 0.5 and at a level +randomly picked between -50 dB and -10 dB and then passes the resultant samples through a room impulse response randomly +picked from the manifest file provided for ``impulse`` augmentation in the config file. + +.. code-block:: yaml + + model: + ... + train_ds: + ... + augmentor: + white_noise: + prob: 0.5 + min_level: -50 + max_level: -10 + impulse: + prob: 0.3 + manifest_path: /path/to/impulse_manifest.json + +Refer to the `Audio Augmentors <./api.html#Audio Augmentors>`__ API section for more details. + +Tokenizer Configurations +------------------------ + +Some models utilize sub-word encoding via an external tokenizer instead of explicitly defining their vocabulary. + +For such models, a ``tokenizer`` section is added to the model config. ASR models currently support two types of +custom tokenizers: + +- Google Sentencepiece tokenizers (tokenizer type of ``bpe`` in the config) +- HuggingFace WordPiece tokenizers (tokenizer type of ``wpe`` in the config) + +In order to build custom tokenizers, refer to the ``ASR_with_Subword_Tokenization`` notebook available in the +ASR tutorials directory. + +The following example sets up a ``SentencePiece Tokenizer`` at a path specified by the user: + +.. code-block:: yaml + + model: + ... + tokenizer: + dir: "" + type: "bpe" # can be "bpe" or "wpe" + +For models which utilize sub-word tokenization, we share the decoder module (``ConvASRDecoder``) with character tokenization models. +All parameters are shared, but for models which utilize sub-word encoding, there are minor differences when setting up the config. For +such models, the tokenizer is utilized to fill in the missing information when the model is constructed automatically. + +For example, a decoder config corresponding to a sub-word tokenization model should look similar to the following: + +.. code-block:: yaml + + model: + ... + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_final + num_classes: -1 # filled with vocabulary size from tokenizer at runtime + vocabulary: [] # filled with vocabulary from tokenizer at runtime + + +Model Architecture Configurations +--------------------------------- + +Each configuration file should describe the model architecture being used for the experiment. Models in the NeMo ASR collection need +an ``encoder`` section and a ``decoder`` section, with the ``_target_`` field specifying the module to use for each. + +Here is the list of the parameters in the model section which are shared among most of the ASR models: + ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ +| **Parameter** | **Datatype** | **Description** | **Supported Values** | ++=========================+==================+===============================================================================================================+=================================+ +| :code:`log_prediction` | bool | Whether a random sample should be printed in the output at each step, along with its predicted transcript. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ +| :code:`ctc_reduction` | string | Specifies the reduction type of CTC loss. Defaults to ``mean_batch`` which would take the average over the | :code:`none`, | +| | | batch after taking the average over the length of each sample. | :code:`mean_batch` | +| | | | :code:`mean`, :code:`sum` | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ + +The following sections go into more detail about the specific configurations of each model architecture. + +For more information about the ASR models, refer to the :doc:`Models <./models>` section. + +Jasper and QuartzNet +~~~~~~~~~~~~~~~~~~~~ + +The `Jasper <./models.html#Jasper>`__ and `QuartzNet <./models.html#QuartzNet>`__ models are very similar, and as such the components in their +configs are very similar as well. + +Both architectures use the ``ConvASREncoder`` for the ``encoder``, with parameters detailed in the table below. The encoder parameters +include details about the Jasper/QuartzNet ``[BxR]`` encoder architecture, including how many blocks to use (``B``), how many times +to repeat each sub-block (``R``), and the convolution parameters for each block. + +The number of blocks ``B`` is determined by the number of list elements under ``jasper`` minus the one prologue and two epilogue blocks. +The number of sub-blocks ``R`` is determined by setting the ``repeat`` parameter. + +To use QuartzNet (which uses more compact time-channel separable convolutions) instead of Jasper, add :code:`separable: true` to all +but the last block in the architecture. + +Change the parameter name ``jasper``. + ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------+ +| **Parameter** | **Datatype** | **Description** | **Supported Values** | ++=========================+==================+===============================================================================================================+=====================================+ +| :code:`feat_in` | int | The number of input features. Should be equal to :code:`features` in the preprocessor parameters. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------+ +| :code:`activation` | string | Which activation function to use in the encoder. | :code:`hardtanh`, :code:`relu`, | +| | | | :code:`selu`, :code:`swish` | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------+ +| :code:`conv_mask` | bool | Whether to use masked convolutions in the encoder. Defaults to ``true``. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------+ +| :code:`jasper` | | A list of blocks that specifies your encoder architecture. Each entry in this list represents one block in | | +| | | the architecture and contains the parameters for that block, including convolution parameters, dropout, and | | +| | | the number of times the block is repeated. Refer to the `Jasper `_ and | | +| | | `QuartzNet `_ papers for details about specific model configurations. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------+ + +A QuartzNet 15x5 (fifteen blocks, each sub-block repeated five times) encoder configuration should look similar to the following example: + +.. code-block:: yaml + + # Specified at the beginning of the file for convenience + n_mels: &n_mels 64 # Used for both the preprocessor and encoder as number of input features + repeat: &repeat 5 # R=5 + dropout: &dropout 0.0 + separable: &separable true # Set to true for QN. Set to false for Jasper. + + model: + ... + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels # Should match "features" in the preprocessor. + activation: relu + conv_mask: true + + jasper: # This field name should be "jasper" for both types of models. + + # Prologue block + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: 1 # Prologue block is not repeated. + residual: false + separable: *separable + stride: [2] + + # Block 1 + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + ... # Entries for blocks 2~14 + + # Block 15 + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + # Two epilogue blocks + - dilation: [2] + dropout: *dropout + filters: 512 + kernel: [87] + repeat: 1 # Epilogue blocks are not repeated + residual: false + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: &enc_filters 1024 + kernel: [1] + repeat: 1 # Epilogue blocks are not repeated + residual: false + stride: [1] + +Both Jasper and QuartzNet use the ``ConvASRDecoder`` as the decoder. The decoder parameters are detailed in the following table. + ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ +| **Parameter** | **Datatype** | **Description** | **Supported Values** | ++=========================+==================+===============================================================================================================+=================================+ +| :code:`feat_in` | int | The number of input features to the decoder. Should be equal to the number of filters in the last block of | | +| | | the encoder. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ +| :code:`vocabulary` | list | A list of the valid output characters for your model. For example, for an English dataset, this could be a | | +| | | list of all lowercase letters, space, and apostrophe. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ +| :code:`num_classes` | int | Number of output classes, i.e. the length of :code:`vocabulary`. | | ++-------------------------+------------------+---------------------------------------------------------------------------------------------------------------+---------------------------------+ + +For example, a decoder config corresponding to the encoder above should look similar to the following: + +.. code-block:: yaml + + model: + ... + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_filters + vocabulary: *labels + num_classes: 28 # Length of the vocabulary list + +Citrinet +~~~~~~~~ + +The `Citrinet <./models.html#Citrinet>`__ and `QuartzNet <./models.html#QuartzNet>`__ models are very similar, and as such the +components in their configs are very similar as well. Citrinet utilizes Squeeze and Excitation, as well as sub-word tokenization, in +contrast to QuartzNet. Depending on the dataset, we utilize different tokenizers. For Librispeech, we utilize the HuggingFace WordPiece +tokenizer, and for all other datasets we utilize the Google Sentencepiece tokenizer - usually the ``unigram`` tokenizer type. + +Both architectures use the ``ConvASREncoder`` for the ``encoder``, with parameters detailed above. The encoder parameters include +details about the Citrinet-C encoder architecture, including how many filters are used per channel (``C``). The Citrinet-C +configuration is a shortform notation for Citrinet-21x5xC, such that ``B = 21`` and ``R = 5`` are the default and should generally +not be changed. + +To use Citrinet instead of QuartzNet, refer to the ``citrinet_512.yaml`` configuration found inside the ``examples/asr/conf/citrinet`` +directory. Citrinet is primarily comprised of the same :class:`~nemo.collections.asr.parts.submodules.jasper.JasperBlock` as ``Jasper`` or +``QuartzNet`. + +While the configs for Citrinet and QuartzNet are similar, we note the additional flags used for Citrinet below. Refer to the +``JasperBlock`` documentation for the meaning of these arguments. + ++---------------------------+------------------+-----------------------------------------------------------------------------------------------------------+-----------------------------------+ +| **Parameter** | **Datatype** | **Description** | **Supported Values** | ++===========================+==================+===========================================================================================================+===================================+ +| :code:`se` | bool | Whether to apply squeeze-and-excitation mechanism or not. | :code:`true` or :code:`false` | ++---------------------------+------------------+-----------------------------------------------------------------------------------------------------------+-----------------------------------+ +| :code:`se_context_size` | int | SE context size. -1 means global context. | :code:`-1` or :code:`+ve int` | ++---------------------------+------------------+-----------------------------------------------------------------------------------------------------------+-----------------------------------+ +| :code:`stride_last` | bool | Stride on the final repeated block or all repeated blocks. | :code:`true` or :code:`false` | ++---------------------------+------------------+-----------------------------------------------------------------------------------------------------------+-----------------------------------+ +| :code:`residual_mode` | str | Type of residual branch to construct. | :code:`"add"` or | +| | | Can be pointwise residual addition or pointwise strided residual attention | :code:`"stride_add"` | ++---------------------------+------------------+-----------------------------------------------------------------------------------------------------------+-----------------------------------+ + +A Citrinet-512 config should look similar to the following: + +.. code-block:: yaml + + model: + ... + # Specify some defaults across the entire model + model_defaults: + repeat: 5 + dropout: 0.1 + separable: true + se: true + se_context_size: -1 + ... + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels # Should match "features" in the preprocessor. + activation: relu + conv_mask: true + + jasper: # This field name should be "jasper" for the JasperBlock (which constructs Citrinet). + + # Prologue block + - filters: 512 + repeat: 1 + kernel: [5] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + # Block 1 + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [11] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + ... # Entries for blocks 2~21 + + # Block 22 + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [39] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + # Epilogue block + + - filters: &enc_final 640 + repeat: 1 + kernel: [41] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + +As mentioned above, Citrinet uses the ``ConvASRDecoder`` as the decoder layer similar to QuartzNet. Only the configuration must be +changed slightly as Citrinet utilizes sub-word tokenization. + +.. note:: + The following information is relevant to any of the above models that implements its encoder as an :class:`~nemo.collections.asr.modules.conv_asr.ConvASREncoder`, and utilizes the ``SqueezeExcite`` mechanism. + +The ``SqueezeExcite`` block within a :class:`~nemo.collections.asr.modules.conv_asr.ConvASREncoder` network can be modified to utilize a different context window after the model has been instantiated (even after the model has been trained) so as to evaluate the model with limited context. This can be achieved using the :meth:`~nemo.collections.asr.parts.mixins.mixins.ASRModuleMixin.change_conv_asr_se_context_window` + +.. code-block:: python + + # Here, model can be any model that has a `ConvASREncoder` as its encoder, and utilized `SqueezeExcite` blocks + # `context_window` : It is an integer representing the number of timeframes (each corresponding to some window stride). + # `update_config` : Bool flag which determines whether the config of the model should be updated to reflect the new context window. + + # Here, we specify that 128 timeframes of 0.01s stride should be the context window + # This is equivalent to 128 * 0.01s context window for `SqueezeExcite` + model.change_conv_asr_se_context_window(context_window=128, update_config=True) + +Conformer-CTC +~~~~~~~~~~~~~ + +The config files for Conformer-CTC model contain character-based encoding and sub-word encoding at +``/examples/asr/conf/conformer/conformer_ctc_char.yaml`` and ``/examples/asr/conf/conformer/conformer_ctc_bpe.yaml`` +respectively. Some components of the configs of `Conformer-CTC <./models.html#Conformer-CTC>`__ include the following datasets: + +- ``train_ds``, ``validation_ds``, and ``test_ds`` +- opimizer (``optim``) +- augmentation (``spec_augment``) +- ``decoder`` +- ``trainer`` +``exp_manager`` + +These datasets are similar to other ASR models like `QuartzNet <./models.html#QuartzNet>`__. There should be a tokenizer section where you can +specify the tokenizer if you want to use sub-word encoding instead of character-based encoding. + +The encoder section includes the details about the Conformer-CTC encoder architecture. You may find more information in the +config files and also :doc:`nemo.collections.asr.modules.ConformerEncoder<./api.html#nemo.collections.asr.modules.ConformerEncoder>`. + + +Fine-tuning Configurations +------------------------- + +All ASR scripts support easy fine-tuning by partially/fully loading the pretrained weights from a checkpoint into the currently instantiated model. Pre-trained weights can be provided in multiple ways - + +1) Providing a path to a NeMo model (via ``init_from_nemo_model``) +2) Providing a name of a pretrained NeMo model (which will be downloaded via the cloud) (via ``init_from_pretrained_model``) +3) Providing a path to a Pytorch Lightning checkpoint file (via ``init_from_ptl_ckpt``) + +Fine-tuning via a NeMo model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: sh + + python examples/asr/script_to_.py \ + --config-path= \ + --config-name=) \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath="" \ + trainer.gpus=-1 \ + trainer.max_epochs=50 \ + +init_from_nemo_model="" + + +Fine-tuning via a NeMo pretrained model name +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: sh + + python examples/asr/script_to_.py \ + --config-path= \ + --config-name=) \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath="" \ + trainer.gpus=-1 \ + trainer.max_epochs=50 \ + +init_from_pretrained_model="" + +Fine-tuning via a Pytorch Lightning checkpoint +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: sh + + python examples/asr/script_to_.py \ + --config-path= \ + --config-name=) \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath="" \ + trainer.gpus=-1 \ + trainer.max_epochs=50 \ + +init_from_ptl_ckpt="" \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/data/asr_results.csv b/tts/NeMo/docs/source/asr/data/asr_results.csv new file mode 100644 index 0000000..3b179b5 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/asr_results.csv @@ -0,0 +1,21 @@ +Model Name,Model Base Class,Model Card +QuartzNet15x5Base-En,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemospeechmodels" +stt_en_jasper10x5dr,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_jasper10x5dr" +stt_en_citrinet_256,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_citrinet_256" +stt_en_citrinet_512,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_citrinet_512" +stt_en_citrinet_1024,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_citrinet_1024" +stt_ca_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_ca_quartznet15x5" +stt_it_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_it_quartznet15x5" +stt_fr_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_fr_quartznet15x5" +stt_es_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_es_quartznet15x5" +stt_de_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_de_quartznet15x5" +stt_pl_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_pl_quartznet15x5" +stt_ru_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_ru_quartznet15x5" +stt_zh_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_zh_quartznet15x5" +stt_zh_citrinet_512,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_zh_citrinet_512" +stt_en_conformer_ctc_small,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_small" +stt_en_conformer_ctc_medium,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_medium" +stt_en_conformer_ctc_large,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_large" +stt_en_conformer_ctc_small_ls,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_small_ls" +stt_en_conformer_ctc_medium_ls,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_medium_ls" +stt_en_conformer_ctc_large_ls,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_large_ls" diff --git a/tts/NeMo/docs/source/asr/data/asrlm_results.csv b/tts/NeMo/docs/source/asr/data/asrlm_results.csv new file mode 100644 index 0000000..d9a395c --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/asrlm_results.csv @@ -0,0 +1,2 @@ +Model Name,Model Base Class,Model Card +asrlm_en_transformer_large_ls,TransformerLMModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:asrlm_en_transformer_large_ls" diff --git a/tts/NeMo/docs/source/asr/data/benchmark_ca.csv b/tts/NeMo/docs/source/asr/data/benchmark_ca.csv new file mode 100644 index 0000000..ef5220f --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_ca.csv @@ -0,0 +1,2 @@ +Model,Model Base Class,Model Card +stt_ca_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_ca_quartznet15x5" diff --git a/tts/NeMo/docs/source/asr/data/benchmark_de.csv b/tts/NeMo/docs/source/asr/data/benchmark_de.csv new file mode 100644 index 0000000..f0f8612 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_de.csv @@ -0,0 +1,3 @@ +Model,Model Base Class,Model Card +stt_de_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_de_quartznet15x5" + diff --git a/tts/NeMo/docs/source/asr/data/benchmark_en.csv b/tts/NeMo/docs/source/asr/data/benchmark_en.csv new file mode 100644 index 0000000..ccdf05b --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_en.csv @@ -0,0 +1,14 @@ +Model Name,Model Base Class,Model Card +QuartzNet15x5Base-En,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemospeechmodels" +stt_zh_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_zh_quartznet15x5" +stt_en_jasper10x5dr,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_jasper10x5dr" +stt_en_citrinet_256,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_citrinet_256" +stt_en_citrinet_512,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_citrinet_512" +stt_en_citrinet_1024,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_citrinet_1024" +stt_zh_citrinet_512,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_zh_citrinet_512" +stt_en_conformer_ctc_small,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_small" +stt_en_conformer_ctc_medium,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_medium" +stt_en_conformer_ctc_large,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_large" +stt_en_conformer_ctc_small_ls,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_small_ls" +stt_en_conformer_ctc_medium_ls,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_medium_ls" +stt_en_conformer_ctc_large_ls,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_large_ls" diff --git a/tts/NeMo/docs/source/asr/data/benchmark_es.csv b/tts/NeMo/docs/source/asr/data/benchmark_es.csv new file mode 100644 index 0000000..2997fa3 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_es.csv @@ -0,0 +1,3 @@ +Model,Model Base Class,Model Card +stt_es_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_es_quartznet15x5" + diff --git a/tts/NeMo/docs/source/asr/data/benchmark_fr.csv b/tts/NeMo/docs/source/asr/data/benchmark_fr.csv new file mode 100644 index 0000000..994ab0d --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_fr.csv @@ -0,0 +1,3 @@ +Model,Model Base Class,Model Card +stt_fr_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_fr_quartznet15x5" + diff --git a/tts/NeMo/docs/source/asr/data/benchmark_it.csv b/tts/NeMo/docs/source/asr/data/benchmark_it.csv new file mode 100644 index 0000000..d605b68 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_it.csv @@ -0,0 +1,3 @@ +Model,Model Base Class,Model Card +stt_it_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_it_quartznet15x5" + diff --git a/tts/NeMo/docs/source/asr/data/benchmark_pl.csv b/tts/NeMo/docs/source/asr/data/benchmark_pl.csv new file mode 100644 index 0000000..bf646e1 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_pl.csv @@ -0,0 +1,2 @@ +Model,Model Base Class,Model Card +stt_pl_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_pl_quartznet15x5" diff --git a/tts/NeMo/docs/source/asr/data/benchmark_ru.csv b/tts/NeMo/docs/source/asr/data/benchmark_ru.csv new file mode 100644 index 0000000..b46d4d9 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_ru.csv @@ -0,0 +1,3 @@ +Model,Model Base Class,Model Card +stt_ru_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_ru_quartznet15x5" + diff --git a/tts/NeMo/docs/source/asr/data/benchmark_zh.csv b/tts/NeMo/docs/source/asr/data/benchmark_zh.csv new file mode 100644 index 0000000..1fbc498 --- /dev/null +++ b/tts/NeMo/docs/source/asr/data/benchmark_zh.csv @@ -0,0 +1,3 @@ +Model,Model Base Class,Model Card +stt_zh_quartznet15x5,EncDecCTCModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_zh_quartznet15x5" +stt_zh_citrinet_512,EncDecCTCBPEModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_zh_citrinet_512" diff --git a/tts/NeMo/docs/source/asr/datasets.rst b/tts/NeMo/docs/source/asr/datasets.rst new file mode 100644 index 0000000..d4b2a20 --- /dev/null +++ b/tts/NeMo/docs/source/asr/datasets.rst @@ -0,0 +1,268 @@ +Datasets +======== + +NeMo has scripts to convert several common ASR datasets into the format expected by the ``nemo_asr`` collection. You can get started +with those datasets by following the instructions to run those scripts in the section appropriate to each dataset below. + +If the user has their own data and want to preprocess it to use with NeMo ASR models, refer to the `Preparing Custom ASR Data`_ section. + +If the user already has a dataset that you want to convert to a tarred format, refer to the `Tarred Datasets`_ section. + +.. _LibriSpeech_dataset: + +LibriSpeech +----------- + +Run the following scripts to download the LibriSpeech data and convert it into the format expected by `nemo_asr`. At least 250GB free +space is required. + +.. code-block:: bash + + # install sox + sudo apt-get install sox + mkdir data + python get_librispeech_data.py --data_root=data --data_set=ALL + +After this, the ``data`` folder should contain wav files and ``.json`` manifests for NeMo ASR datalayer. + +Each line is a training example. ``audio_filepath`` contains the path to the wav file, ``duration`` is the duration in seconds, and ``text`` is the transcript: + +.. code-block:: json + + {"audio_filepath": "/1355-39947-0000.wav", "duration": 11.3, "text": "psychotherapy and the community both the physician and the patient find their place in the community the life interests of which are superior to the interests of the individual"} + {"audio_filepath": "/1355-39947-0001.wav", "duration": 15.905, "text": "it is an unavoidable question how far from the higher point of view of the social mind the psychotherapeutic efforts should be encouraged or suppressed are there any conditions which suggest suspicion of or direct opposition to such curative work"} + +Fisher English Training Speech +------------------------------ + +Run these scripts to convert the Fisher English Training Speech data into a format expected by the ``nemo_asr`` collection. + +In brief, the following scripts convert the ``.sph`` files to ``.wav``, slices those files into smaller audio samples, matches the +smaller slices with their corresponding transcripts, and splits the resulting audio segments into train, validation, and test sets +(with one manifest each). + +.. note:: + - 106 GB of space is required to run the ``.wav`` conversion + - additional 105 GB is required for the slicing and matching + - ``sph2pipe`` is required in order to run the ``.wav`` conversion + +**Instructions** + +The following scripts assume that you already have the Fisher dataset from the Linguistic Data Consortium, with a directory structure +that looks similar to the following: + +.. code-block:: bash + + FisherEnglishTrainingSpeech/ + ├── LDC2004S13-Part1 + │   ├── fe_03_p1_transcripts + │   ├── fisher_eng_tr_sp_d1 + │   ├── fisher_eng_tr_sp_d2 + │   ├── fisher_eng_tr_sp_d3 + │   └── ... + └── LDC2005S13-Part2 + ├── fe_03_p2_transcripts + ├── fe_03_p2_sph1 + ├── fe_03_p2_sph2 + ├── fe_03_p2_sph3 + └── ... + +The transcripts that will be used are located in the ``fe_03_p<1,2>_transcripts/data/trans`` directory. The audio files (``.sph``) +are located in the remaining directories in an ``audio`` subdirectory. + +#. Convert the audio files from ``.sph`` to ``.wav`` by running: + + .. code-block:: bash + + cd /scripts + python fisher_audio_to_wav.py \ + --data_root= --dest_root= + + This will place the unsliced ``.wav`` files in ``/LDC200[4,5]S13-Part[1,2]/audio-wav/``. It will take several + minutes to run. + +#. Process the transcripts and slice the audio data. + + .. code-block:: bash + + python process_fisher_data.py \ + --audio_root= --transcript_root= \ + --dest_root= \ + --remove_noises + + This script splits the full dataset into train, validation, test sets, and places the audio slices in the corresponding folders + in the destination directory. One manifest is written out per set, which includes each slice's transcript, duration, and path. + + This will likely take around 20 minutes to run. Once finished, delete the 10 minute long ``.wav`` files. + +2000 HUB5 English Evaluation Speech +----------------------------------- + +Run the following script to convert the HUB5 data into a format expected by the ``nemo_asr`` collection. + +Similarly, to the Fisher dataset processing scripts, this script converts the ``.sph`` files to ``.wav``, slices the audio files and +transcripts into utterances, and combines them into segments of some minimum length (default is 10 seconds). The resulting segments +are all written out to an audio directory and the corresponding transcripts are written to a manifest JSON file. + +.. note:: + - 5 GB of free space is required to run this script + - ``sph2pipe`` is also required to be installed + +This script assumes you already have the 2000 HUB5 dataset from the Linguistic Data Consortium. + +Run the following command to process the 2000 HUB5 English Evaluation Speech samples: + +.. code-block:: bash + + python process_hub5_data.py \ + --data_root= \ + --dest_root= + +You can optionally include ``--min_slice_duration=`` if you would like to change the minimum audio segment duration. + +AN4 Dataset +----------- + +This is a small dataset recorded and distributed by Carnegie Mellon University. It consists of recordings of people spelling out +addresses, names, etc. Information about this dataset can be found on the `official CMU site `_. + +#. `Download and extract the dataset `_ (which is labeled "NIST's Sphere audio (.sph) format (64M)". + +#. Convert the ``.sph`` files to ``.wav`` using sox, and build one training and one test manifest. + + .. code-block:: bash + + python process_an4_data.py --data_root= + +After the script finishes, the ``train_manifest.json`` and ``test_manifest.json`` can be found in the ``/an4/`` directory. + +Aishell-1 +--------- + +To download the Aishell-1 data and convert it into a format expected by ``nemo_asr``, run: + +.. code-block:: bash + + # install sox + sudo apt-get install sox + mkdir data + python get_aishell_data.py --data_root=data + +After the script finishes, the ``data`` folder should contain a ``data_aishell`` folder which contains a wav file, a transcript folder, and related ``.json`` and ``vocab.txt`` files. + +Aishell-2 +--------- + +To process the AIShell-2 dataset, in the command below, set the data folder of AIShell-2 using ``--audio_folder`` and where to push +these files using ``--dest_folder``. In order to generate files in the supported format of ``nemo_asr``, run: + +.. code-block:: bash + + python process_aishell2_data.py --audio_folder= --dest_folder= + +After the script finishes, the ``train.json``, ``dev.json``, ``test.json``, and ``vocab.txt`` files can be found in the ``dest_folder`` directory. + +Preparing Custom ASR Data +------------------------- + +The ``nemo_asr`` collection expects each dataset to consist of a set of utterances in individual audio files plus +a manifest that describes the dataset, with information about one utterance per line (``.json``). +The audio files can be of any format supported by `Pydub `_, though we recommend +WAV files as they are the default and have been most thoroughly tested. + +There should be one manifest file per dataset that will be passed in, therefore, if the user wants separate training and validation +datasets, they should also have separate manifests. Otherwise, thay will be loading validation data with their training data and vice +versa. + +Each line of the manifest should be in the following format: + +.. code:: + + {"audio_filepath": "/path/to/audio.wav", "text": "the transcription of the utterance", "duration": 23.147} + +The :code:`audio_filepath` field should provide an absolute path to the ``.wav`` file corresponding to the utterance. +The :code:`text` field should contain the full transcript for the utterance, and the :code:`duration` field should +reflect the duration of the utterance in seconds. + +Each entry in the manifest (describing one audio file) should be bordered by '{' and '}' and must +be contained on one line. The fields that describe the file should be separated by commas, and have the form :code:`"field_name": value`, +as shown above. There should be no extra lines in the manifest, i.e. there should be exactly as many lines in the manifest as +there are audio files in the dataset. + +Since the manifest specifies the path for each utterance, the audio files do not have to be located +in the same directory as the manifest, or even in any specific directory structure. + +Once there is a manifest that describes each audio file in the dataset, use the dataset by passing +in the manifest file path in the experiment config file, e.g. as ``training_ds.manifest_filepath=``. + +Tarred Datasets +--------------- + +If experiments are run on a cluster with datasets stored on a distributed file system, the user will likely +want to avoid constantly reading multiple small files and would prefer tarring their audio files. +There are tarred versions of some NeMo ASR dataset classes for this case, such as the ``TarredAudioToCharDataset`` +(corresponding to the ``AudioToCharDataset``) and the ``TarredAudioToBPEDataset`` (corresponding to the +``AudioToBPEDataset``). The tarred audio dataset classes in NeMo use `WebDataset `_. + +To use an existing tarred dataset instead of a non-tarred dataset, set ``is_tarred: true`` in +the experiment config file. Then, pass in the paths to all of the audio tarballs in ``tarred_audio_filepaths``, either as a list +of filepaths, e.g. ``['/data/shard1.tar', '/data/shard2.tar']``, or in a single brace-expandable string, e.g. +``'/data/shard_{1..64}.tar'`` or ``'/data/shard__OP_1..64_CL_'`` (recommended, see note below). + +.. note:: + For brace expansion, there may be cases where ``{x..y}`` syntax cannot be used due to shell interference. This occurs most commonly + inside SLURM scripts. Therefore, we provide a few equivalent replacements. Supported opening braces (equivalent to ``{``) are ``(``, + ``[``, ``<`` and the special tag ``_OP_``. Supported closing braces (equivalent to ``}``) are ``)``, ``]``, ``>`` and the special + tag ``_CL_``. For SLURM based tasks, we suggest the use of the special tags for ease of use. + +As with non-tarred datasets, the manifest file should be passed in ``manifest_filepath``. The dataloader assumes that the length +of the manifest after filtering is the correct size of the dataset for reporting training progress. + +The ``tarred_shard_strategy`` field of the config file can be set if you have multiple shards and are running an experiment with +multiple workers. It defaults to ``scatter``, which preallocates a set of shards per worker which do not change during runtime. + +For more information about the individual tarred datasets and the parameters available, including shuffling options, +see the corresponding class APIs in the `Datasets <./api.html#Datasets>`__ section. + +.. warning:: + If using multiple workers, the number of shards should be divisible by the world size to ensure an even + split among workers. If it is not divisible, logging will give a warning but training will proceed, but likely hang at the last epoch. + In addition, if using distributed processing, each shard must have the same number of entries after filtering is + applied such that each worker ends up with the same number of files. We currently do not check for this in any dataloader, but the user's + program may hang if the shards are uneven. + +Conversion to Tarred Datasets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can easily convert your existing NeMo-compatible ASR datasets using the +`conversion script here `_. + +.. code:: + + python convert_to_tarred_audio_dataset.py \ + --manifest_path= \ + --target_dir= \ + --num_shards= + --max_duration= \ + --min_duration= \ + --shuffle --shuffle_seed=0 + +This script shuffles the entries in the given manifest (if ``--shuffle`` is set, which we recommend), filter +audio files according to ``min_duration`` and ``max_duration``, and tar the remaining audio files to the directory +``--target_dir`` in ``n`` shards, along with separate manifest and metadata files. + +The files in the target directory should look similar to the following: + +.. code:: + + target_dir/ + ├── audio_1.tar + ├── audio_2.tar + ├── ... + ├── metadata.yaml + └── tarred_audio_manifest.json + +Note that file structures are flattened such that all audio files are at the top level in each tarball. This ensures that +filenames are unique in the tarred dataset and the filepaths do not contain "-sub" and forward slashes in each ``audio_filepath`` are +simply converted to underscores. For example, a manifest entry for ``/data/directory1/file.wav`` would be ``_data_directory1_file.wav`` +in the tarred dataset manifest, and ``/data/directory2/file.wav`` would be converted to ``_data_directory2_file.wav``. diff --git a/tts/NeMo/docs/source/asr/images/citrinet_vertical.png b/tts/NeMo/docs/source/asr/images/citrinet_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..a9a7f8c2e8530dd866aa46aa95f5c59fa56b442f GIT binary patch literal 138615 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

hq-Px+Dm0b? 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 z zIVO?T`k}GL`44+78vBfrSU#Y%kB%L>v-3GEsU%nbB%-JUQ{uB%&$A7_oP<4sKf~Gg z7S{8&qB@>mFw75GK4#Qv8P(Y$vhHtT8bxVN)-?G(i^dj)@5_dQAFcBd2AYPFu>Tgn zE%`vs-4mYh#)gjli?U+dKYh^jK`dHMUW07s+Vhvw6h@S}ZE!KOFv z<=mMG;s1SY~4$L+b{R+yo4OuS;+t1(jshauyRX1 z9*@+%v&DiXqEPRK;^62`o|@kYTm6$(=(+2<_xSQOD-~;`Pi1;a9POjr3m#h&l0|de z8!pprFn3xVTpcr6T6k(QlcMRAm4*cutOK&B`+F2>1u6*Rb!T1IZtcn;reE4QAsyZ8 z&oXVs%))Q49yjmTxp>6!XOC`q=Y|?mDgfg$cO4jn7bq$RKcjoN@0eMk8_;0eFYO8T z^4Nddnx248cUY$KAjFR{#v1vn_HpU0>(`_xY%13|5BHO}zA4_yP3f`hdGe~)^p}x9 z8-umGzW&{*qAc$ol~(E8x5}xx-I{!LiAzR5X3a*D?5(_#D6k~?-a7@|Pdm|z00z(H z>I9`kBxMDp3#f?N1h@cFsd60ba=DAJ)!D+}aCnHgM$tgpe3<}yePR#t*RS$gDu#Y3 z*KdJ6S_(Y-A@iH|Y5e*H+uxh+QLb@3-AF7M6;4rRd0^*=6q?nA`&)>L2_aIvRoJ!a z&QZinS9S6lD4*M);1hNBSCopy8gKONvq!n6*kx4c zTbrPm_%(d1>L$s+i#9tjxnQo?+uf>_K#%| zkh-}FRnI}VabBWj|H6}x%N+1#UZugM#k1aD& zK)mc;$+L*MAYEqhW1k+>PL4*8S*3?5c3P*06VBh6b)7t%Xb!IF2;>CfQQcgFdo#+} z<)-G-C>p3Yg6>lhCM?qjf!Txs>uKkj(9LZwA0H_%AsL2)wk9Sq}b-QyGbe>GnnrRUbX zJcV$p8b5KKo45JB>Rdx(j}DUgsLs!p(sajygjFwJVyEl_u}Q)&!61r`kBA1Ok2yH; z{;Q4p2si0zFOjULO9W#ct5%<$hPa&n;`4JYSY0nP@~_x&Vk6Kl9B4sb@xWv&g??P_ znnnRTMJv|{vY%pUORu3qXxa%T60uPPcQ7YJ*u2(JVyOf@>`XKT@tl5KeI!dIg=Y&i#kdqaF32Y@=W1QN&KkshCa)(tC0K)zK5GO%ftBa|?<7&*ZHx91)Qr+Y9H)%Z(9v?2dn`93C zdL#J5&2^Js2&vPVC!$b|QfNW9UmG@ZEb*8NVj7DL!?}+G#upb@4+Ws>aFx5eyZgD> zcD{HE%Pj^($a#;3+p!-9+nraew;kn& zDT|LxEq6WQ!;B<-H{O{mKUbPYdC&eeK~htLyU4XcW4Nc*Ao8K;s8;g#r*ZB+({@=2IOS5Bi+IYj&)N3NClfBBEw^+*q5>NuTA zK8wTM2N5@q72+P7&mTppp{?DG)MsUhD4%S=ZEFpV=*MDemJ7nqI_vk!{5w42q5f+M z^3Zw(F9`ACI6V_)gYYkHhHyfIbr%_xo$lpcvVg#$BeyshiuROfqEs zG)rten2eztmTB{LQa7VszvXAzNB-rTRsvd?#R8`+=excytijU0(6-Bb0Hoyq%bx@1 zX^tZriZ+I^u}l-!&8(_g4H!&%?F6IqA5A{;IO}bW+C5Nl`AOl>x&Am~<2)tECO9*i zF$wXbH)8ZCmkQNQd}qUqsv-Z!+(1+w$NMxS?KH~kALDU(7m$D_^T43D_$jnL5W(_@ zx<)j{7@ygkF4VcmQ&JYGzNkhPic_~KtWZfI++0i6=|VexdctZARh3m6QJjMh&N{hx zW=iOCuO>Qz%*;|3cdM_aOO&Xy#UDtsX_WYdMYy;}%w1=-M@t^#`37G9q)B33($^PN zqZ+BQft9%1R=4~vfH)|^uq?;s&N|BFZZpzP)zyiEX>KbJe{x$Qqq~Pbsn==GU!M#$ zSSE4^Y|8zA4wcKxL@Tk%EXs_EH%=MOWLa@w8PKU_r(@L;(@(ptXWY789zL&Ux4$~9 zur!!$7A#b1Ub6JdsX0eMG_2oX$A(K!2ZA*1a_xz!HG@Kvbo%RTR>zzy)XXNT8U}|T zPiDTDlfTS_=EYi<*biSvxbg5hxKB;#mYdD*;!8uQYI;~BXM1_t54I*MzhTF+MOsKt%$wO zNQZUDJP&^jj=Ys{-Bfe4t!q+}EzOU2$@PEPBF;A!8q$P?otNhriw9b0i!xljs+_ExMa&!ZC|++#KkKr|FsczS z))kuxtIxRi+{BqJijO4zgH5k-S&zlbQuN|ku0lS++oPJ{#$q))xe~D<1dWTqS8F!? z{`fiJN802bwB?V|cZ(M^1fpqbC%JPTW^3Ayk=(Mcpwn$s?jV29F``NMy34E<0qvac zBkzU?GHJpCCc)UQyr$^g7wIaGARjV+fGd*Yzj@cYQqyrJbV)vQ%ImTTAw zA9Oui$G#H%bC_P<(eY9A+j~;4j_hW`K zKbrnt(<)JesXm;MPrD0&dvcbBziJ*RJ!NhhpmyKQ&&rticm{z%?e`wSODy$58C8zo zmmUXemc2^Z!e8kvLY*~v+VhI!XjKxV66lLk&cPU3trsW#@w3I0HXY;Hg;?NkBoPoO z6e>f*KI+nJuZk--~33R**Ba2M(I`(OK*FGl}xIeWiy}~j1 zz+yGr;Lb9F^Y>xS zUKsupyy-j)sIm0;Ze(#!LkH_G>&5*rzJTq+6udiFm2NYX&l>CpLlLj$U!Pk!+LqpQ z5;H5dkYwuP^R=$o;+%tV=_k4`&8;knNy)I@M_Fu*lk44CR?O^a^m5-^l@KL_0L~Yg3@bx!z zFc0FWUbH4rJhh{W{aBDqf*m9U^=?LlBPBar=l&5FQdfnxM~Ii2qr99}UG#+3Y7t9b zfx&*~tboeN>FbCg+0Mw#W~9r>%qdz^u2W%qS5wK?^7h@`(v0)7&A?B{nu+Rocs9Z8 zs%coNvk;w2*iPRYWo6o0KWwVX_%rvYB~wil>h$f?r}q92m?s<&hy%=k?IAnYXDee* z%NvZxT5H^6hSJ8AOXjVi{&D_jYlVFFBa8q$v}EpsD6F}a-2O)nNA1CKMaL5ab2vW- zRtt}@J?>oGZNN<<;L2a|8te%X$j0*p^{*N5J5)u%q^5^6^EDN5vg2oqpMQ+aop0%E zgiE^m;g=oymqgjYUI+4#juvZXy%l=Skt(%TG0U^{{ELO#7zvFH-`($9R%)e^h*^={ z17V3nyJJa%UzLI-;Yg7oJ0*|pE7#_Y$E%EnUK14?INIf~k z-yGM;&oLz<>mRSddN|tc(Uk%sUbSL~cX9fXk3_WH2da(3Z=BF3_DCKX3+oRl_amp0 zwB-zwn6iZSvN{dQ64=j8XoSut9@_tG*u}}K!c))`5Hl3kM5;StdecrIf1ikZDE&;X zdwKOZpl_)8`(ra7J+vxMd?W~Z{c*1^y$y@Iw&=BLvC;}`zM9n5@069cXlR++xDu`A z>zN0`@51RN@4LM$(lc!&59{j(mmbm4CvWb@1e9;|uQWa^)$R#>WgW8{JUNgu-vLeE=3KlvFvKgP9Nc zVULbx%fllX|M100y+|kV$w0M8*0B?j`7>T zm)(i?%QI@{Sm_drY*=5s`OA<0JKXjIS-jI`{)~4MCJnvpTmdFrcPKPq3*S_cGIJR1lSf+TeeO?*A0%ap&E4fgews(I2*{{0DD+v^p4$;T zJ#JgTln=X=gWT>Vo-*9=q0P1~V$vw%wkE?~*(CXmB8Nu9QsY|KUS!#FW5(V|$*A55 z+%G#?r>B*|LMcXk`C`h(2+G~CbV2?V+r*yGrOl7|xTIXBX3&Wl-7U{FWcT}fNS6?7 z1=iW3Eo_~G+<2h~#dSr%-kDa(qD7nspEV`8}u>pgvE#_Ex1Tw~P zOXk26GG2`9lGHk@IrJ$k{uT>!CPJU;8~Pq#M?S8jbeX-pF@tM*%fDlf6$nXp+H(H% zT7uU|e7F)GmV6836_yhoUEPaJ-j|xiDSnjv`Y|G8ev~ zS=$z`2cQdG=aUGlQa)0J79d~c7W}esa56nao;Iya&IMQAhr!}B^#V)ky6P8+)=k1q zy-L{lOfr_fQ>G9Bk2bvg+9H0`kR?>Eroc#qq#-R@973l`p}h>v8>qmg-RZ)4c)g zJ0L#yKdxcna<_CQG-KS!wT3b&59fK6iJy~x%4i}(l``^&Q4k2AnCFOxC<}SRRC(LZ zJJQcmT*&syGvIeY8uvXcf;tjNQp_@^Be5Rs?48XhIN zC5X&Pas`jtiAsb`XE*6wL|8`#04XSK2T&|kRi@Mn0{U=UH>cCn@Dp#duB z&Ye}u_BfreC0nykrpWN-0pBGoRr^(x9LhPO-E`}~=%zYqDXoDFir40<&PmYa44WD` z9)HoWD&?jVU1SAY)Qn;_>PkfLK0|CCNMTclSw8UJ7#|S%RJG&h6ePTK#j*);+!GqZ zY_z!S3>sVb;s{&c40e9l_lB<2oxbkv`QBhU*{O5YLSP=9WN}bjAI0fb{TTM3;|{Iv zd4#9)w+)K{_~7U2_lStp7fJq^V)ZI3;nU+*4O)YKlLbhTwkFrerFUO{-qG(9h)sl! z1VKpVcCL{y-tA!bPmTPq8#Us?6_^PF-J8YttdWJ+1BMe_8rSmDN@{AIo$Pja8jIi7 zk42zOL~b(EIU;|&8HBX&>#Pw+%=c0eG93*kJC-d?)0N*%>?#F@Y=ZyW*CygSELu8g zX^XV!_eID)8ne-j7Mt$l>en5s;cdBcO>!^LQM|NBh_Js7^J=-tE1+w6BsU=(jW~Z^ z?UZ9fs3e!`h^SFi)I5Tp*be+Mk7SEks)K8uDUqW%JsI<(#l=q(-}FX*GecX#pxeQM z6Jg9k`Y%#8h8?JjcTe+zM_U8ZQj*`AC>#69Co#|N50-ZbELCzN7RY*{p0>Y)+J!s9 zwoVvoB^H|=%tSf&KS6ipLGy~B?I5gm)`n&h$jDE*QL6J6M2`A8(dE{i1vcVin%{p9 zPjyWz0lZ-4`oF*r09`G_qpP_2$mdysunmZyF$S-S71<03H8E!{ZaG?n^4y4^pxyKI ztTrKe6CteUGc$z1UxT>lBwgWXzmsB)$3`&uS)_vjjXK*ojU`D5)9(MGMCYs|kS8yN zdfLG}+k;*l=1a-=x`TC83UNw$n7`5MOcHqGZB^-*V_q7=Jc^ow{}CajugZc&Id|2Q z_fhL8NmXC|kZ+P6Qtnp1*ojpk_XKR8Ct*k3*p~BmK17)mt6RMMfZ#393W(D<@ak+A zRxzANbWd1a{1Bbq{enpfm`m?p3b<+#VR$?4Knz5 z#|tE+L}t)kGL9VC49h4vJyACEz-|T~iLU7Ldm^?I-Why>xCcV2ZcglMCwX9M?RUl} zavli^LpzeC2Y%AwC?4szlttZ8S|_}_`-|~(ki!TYl@I@yl@5wxQ|BbM`(2L((2JMp zhzP?*9pSnx2TbYV;@hMJ<94Hkc%#0hqg$??F7{LAk>^Gam{khVDT##PtBL1+2<7tT z;gsE%FU)i1F_#q_=OB&*?Mq2(HP%l=JdWDM-#hy$66fQm-db6s)S7i397>y#Akjghso#r#B(J$4Q`82bDWa4MH51|=D|h32*L zAJ#2YC2uE9BsPld?k?reXJ^_OeO0d=otP!nFIr_5v4!nj0~p~Ikn{xP)$1bE!5N=P&wbk+hl2)t>LeZb)VSB-Qrs*~FnfMN zu=^h5imL6|QEyTL?b?2VSjEagm=$bd%}bml~#f_#LwrHF&=kbmm9%~Ty6xI68N+r-7%8LLpLQCH+7BlkzP z@^1(3?r*nq+TsjwhGVt$gJL|M4{hvhdH%{n8h=!ezd!1_Gg%tie=AW{;;&uQh){e` zA9>$1?6Q0A+nUg-nU9}+pO0J_wr_bl_aq>&s!op}BO1JthZ5d%if)qjP|o9}HHNydx1=Dk_I^Dc}1I_zVF z;+F%JJTl^I6#ou`2Mso6O2)(Wb0W!CyLecyy_D!rL5Xm4Z06^yNl;4>LQ$!PALU14XVd0T>654^XDqw5=3v0lN0HEsPqv$2KNL9=wNXol3(NY&< zwE)LTv;^Xd9_}MtN=nM3BxaDT{@)KaMa067`aP3PcWba2duZglMr0VFJ@-C$?>Cz; zR9YKW(e%>%6??uwc9dw26hmvpxQ9-sYp=2O(AM*N6E2nhEXGvN zDtJ=A_z^KF1Pv`TBlHa5T2aK(b7Pl{4IFExUx_`6%!GBDlFP&%>?;hLqJZzb#GtPTzL35oDF`h@#hQP+Vss;L@+Nh*DnnB0lrHw zHi`JG%s%Eu{0|;2arVTyHxV0Tv)KmDrQM|^<*FI^{vK1}wjVu9dqTpSf`)Eh@Zy&y zu=A~1nd&bE`gJ@P6b8yUF8lkAnLm3W824#;dFkq3YgL?91VQ2Ki{iKErid5oVk_MG zEyNZgm3dayP#|7j!gL!{M2YRM#sp(PSV!^a;R)IYyXp@f+l-GGrG#(3(hU2&>m z?~)MvHN}hc_XUv!=kU|i&8mS{OOzM{VMl!MieuiEW%8tIjfD#i!(3OY$K0GN@#~)n zmhCu~u=QvCgVSUP{)fpc)1-DkTe4Uxf4XU2{8*n!@J#UwatZfiwpq4ZXKaT1C4~X! z5NkLY5fTytu;zT+4B2ZJPu_0iphfj08_!F}7M}pRLY?f`N1UESlL!Y^?)@tcaoN`{ z0ey*D8V-(N!F9>uT2ON5{rmTz-bgg3Zrn)=Q0rj8r@9!~PX!xK>(`_|jt2vpi=if< zYgFDKM3d#?eX3}|qBc-`sCwm+1JO!mh+j1@tVq_6Qal&1+H|A@i{}T2Xp0+>$1Q}x z0q3slf{A`KSbVh5+NR033zDZKt3wSntOzMSyvx@3EJQ>{4_DY3$XR5DIl?H$rtk5Y zzyAvRY-84&EWtqt>hrw`sQ3{ha4Tsd{&~r4lP{M3n|wn+B5}F?j;2n2MZ4v|dwp*A zfxnkKD=%H5V1WwmCBZ>_$7N>$zhlhI5SjQvh0*4<9>(XM-oC!C=l(!Fz%bx(edxx9 z-qCvUDG(;;6bRjClF}w(kvm@s+iD}0`26j21nqjwYWc5w)bNB)TRL({d{9aghMIjN zMW(1fe45s}lXm2l)*jmtp(k?WeYn5K+p*u;5}(RUPo!BrMt@qIe1Yzb2i(^M8>>~Toj_Wne}pOE9tY+@ROZ1 z@+j$9sF*gOPOgmWA{8%Zu&j<*SrmFHxS{0B_EkMDo7jBv(t58BU)N znVoMt!@lb2wgRkHo{mZojM%D*UtnHccUVd1$k zCI%58+Qeo4HurZGZiR3HYj&?*69S_`nB{HrPeTYAMqi>?5<@jY3C*!@8 zR;%C8&SJr1;xG3X?cYu&^Y7)V=M9y#L?T1%mc<5U5^i-<4wiWax2vv}k(W%r@4;b# zDZ08F4Mcj*QAV+;7L4SeB~v?o*2NBnQ@u7Sd3Cme_khJlB(!^FAjNroSv~e%QC-b< zu?kbk5#!QawH&2X&s;r&7-|R4SlY43t)F)1DS{30q$Hc~qYw)5<*!or9JZ!z_fNfz z&8HYol|rrzne(9@J5ExKf2TJleu4jY-^2Nq6n()Cq64e#Wgfz7kKa76z^K>kV*&bz zaZCwyHtG24fvA4w@ox>5pNc#BBO39Us;{dkIT|d(ZJx8xO_QN`JPj2nYn^{z&^*ybw64EllPIQOENn7pFD(Li5KjFL_2TIKlxTB}3#90AT z!l#MEFC}WD*3!=0k))ZTyyO}IceW0MO7TMv1DeO`ghhousSH>biN0{G-ZgQ9EN_+O zgwz})P(h$xtEHLxf*iHh$BDlMJBnM8hfl1m)_EuwC~Fs1?%m(>Ups1OIwzqU0h*~o zjRQ&abS%3k2XSNWdF{oNtuk^R$HKpQ94)ap;LeD>Zl9mO?eyi+>0A7q@HVj+Ab_aO zU@m@yb55LU5k~7fDMR~u12~uj-t2&#ApX}mS#+_QjZpBd?d>J`C+p@BR#}4FJSey& zZ~o&ji?-{VkJ`#JqUi2vS$ig=_Fu$zg{D<>qQ||2AhMx7#F6o~d~UZz+JbbhZsLVL z%xrG=V$=?0Xx25|tc0cn)ApZ~?Puxc{$8_))ajtLhf(PxCTUIlV>!%zB94c%hYa`m z+D19Et)H1+cM-yT9$Qnqh%k|)M1Acci=?n-bP@@7bkkzssC5ohc<`+NgBkC_8m0Nm zL0iPH9x(lN48P(wY`xvj4bHPlI4*zIfVbr`M(J##fMX(C zDUcgZ3PofSioEIm;0#+=bYobEqt}mrq4a~TcPFc{^Uy}^1NI4flH#6*o=ofPstR>c z(-@ax+K$&dXS7(H)6s~)>vFXc#w4lCDV7CnZ9rnI79B01(SKoCGDOz5z+S6MssH2$ z*W)Gj7@N-dJ76neyr2>!xIDwZ-+gRLvwW9Jzt&LCS3i{qcD_?tRexe3t`SD_R)ooypty{7E}GY{M(A*17c) zg1_93(A*e5l&hCbxo&53^q%6x_0xmZmyBabr=!HkO0)e{hhw_j41(3kjMsZbQh2yo zZJT%M9MLMFMy1(!ANxz=zh~)6$D9#J+F;7#pa?K9t7WfYM zSZ&d}%(K?6?h?!S4&|0)#a4C&H?)NFZ}>4@dOmyA9f;*HCXBWVU@O zPn>#Rg*}bu_)NuOqPFMLG8;OMJT#A8GYZ7C2^?CDYs);hlmuVawxC}0jeGZlg9O7n z{GjX7?eU=pl4vwFGvfl43s17XfE=kW{@3yF4CHqRR4d$;qNBqt@><0;t)!wO0ruH5^olXZlvxA3wi)^L!c{r%ckW8q_*tb;c5&im;CUxg``!exUgcmv?X0 z)pbH;+wITpw74`5c`c*NYIE;}hpIS)S#(oh&$X%Zxux-f(wcrQ zdB$@xupXb??|FIYBOszrRaovIAzJrhJlJ!la+Q2bok^8=yL6S^p~uAuUFQf}2uNNj zxwlcw)N0t6NUo$q!z{8@)i_?%)`sMr$r2;Qy@{RFR?EgOGVHA8L0P-&4l}>6hZv}3 z&KPd7Anvf(Dz)gTX7GH+K02~G?yy2KZJ`=#_L1pP_KnLyzd!T($=A;silyd5pGr-P zjl=8PBA6n=y}dEEr$8ZUCTuRE2f(SkaqHHte)5YlrPXS@(BK{;9@rwIg!AH9EcsO0{- zaE#JbK~ynMIfBaRwF-k(t$3ZyDe2D<&LR8e!`=j= zxCI+vRjZvQg_2#regmn)KOH+@TBe65>N~3Tj#gK{vH#w*wYJ(i zI!2Z_Q)t36A7FE7<8I#rweA;o4hstl!IH;Boymj~zuOqs;X%A@>fSKw?vYcvvz!EX zLl)LLPOkMwX~$F|u9A{*X(8?1w)Iw6v9qpTtc9!(`jrq2C|vk~N2)t85_)-gi6-e6zG*7ZkAe)%=z~rtbAt4Q&sZpe$SV_+t>NJEk)d#}pF3Ztvi?ps z12Fu9Sm1@=fc4=4zb2KOkO{dj=PCu#Ukz=n)!4wyX5sziX&Hf*g{Ng?^v_HJ=|I4q zoIQpf=-mz02jz-e`u;natCCjSHYhcnQO%X9rE=oBb= zy1&1Femr%)H1*J+ImoBt9E6@edjUg911=2Am=$iK^t`;hoSfZFP4hq!dLToAO|Sa# zDI#63##K>K@j1h1H^5mv2X}mNQjh_GU4j7mkF_^iaZ~`k?s+T^NEg}VB8~$hAwkq) zXU)O)#5_-4Rbd@~PW{(Y0v5xa7;~5bWL%09H6Vr{;cas~e} z$3KvKNhQ?FTU?XakNpJW+;kx`w)5VJP4IDCxxV_QfIF=1teuOM_CL;!3XeI}-Ki>N zs)J8IhlTxgq{F~Cz`6JonDl_w&QAJv&-0?iHr42sXkBT;Vz-dCd_hJKv*9rbvYaRo zJ2?;vTUN!u*i`>NY@KyjR9*M?QB*_(1a3g-6p)gZ1}SNfZUO0%9AIEj5owU_?v@y8 z2kJkR7{AC>GX$>UJ z7~FMQpOZ4w@g^Z?{T64=%O$gyM31ETMS{(wvO#|{-6PUzbfL=ozCC5!N}LTc2#Ior6(Z;41b`c zs%X_nhJn!wRQ=xpcTNDW7*yuS(7r3oj(fqP8eziq7 zcrQ8;4|r)D0?%OnW)*aW_Ec;dX7hz2xAC z2t2fEY*rSn#+`3~4dwSG{~Fm&L@{aWKXOJvaZLM2J~E4_tSv|*MjV>XPmVzOIJa?u z8F8~be-G<vav08PK5=BxSDw7OS4;GMIue}5EcWXcw zc%b}|bP@JZ7_Xiw#Ctbx&m=ktd7l^9q15jEnVxBL^Zf3#NTjcD;!S?_<2>xAWMf98 z(erW253;}y>Bsmp=Uo$3onnFnlN?&8&@a*%Z$1j#+`~>klKkzmamddP%E`cT02cP| zH85=2-0DRXo{8GUR?rn+G@(c%F?Xz z74EG+_xNTtu0M;4G$sVKf``*qZ%PlkyLC)P2S*p2KyIGGswaZdK*q4yJC5b{&kW#) z+^lrNF2o`i!P60PNw%n$kB9>yDjIIq3!Gj!7-|N<(q#tT?K;j4OH!X$de5*Gb00}} zdA(UyZ8QtI&;YXd7~e)RfQ$*X7?Zg76|!9QxC^#O>HUxv+2WniRYXp^zW2$2nT+w?N6A*d@j7PO%2Cu9 z+-`maSua&Gv=X!34Av9gWx$b-r*IRsCbr(ARF=+|xr_0$?xyyH)=ll98u?v2h*-z9 zEgQq=QM>tdhl~~CKGpTqm6yGk`u(KTZg4M_pJ8wwgOPfyNO5mDhBNW&^XG>td*hr` zi@~Q?P8`Crlr>&W{R{>N_(s?dy-)e+F$G#MPnH0{>}n^_hdbn73XCSlb|7ms-PwXR zb3qgAA{6n(pEnR72@knMu6o9&HxE0-4@&}EYodzqn*+o1jniolp6E6{D8vO)k|JE) z-Q9od#s9Y7(IBD^>Cwg8M|ZK9*Ny#VFN(qTy7tc$hgOxOUnbl2_F(EH+P(K(!(U!7 zJ$aT%^2aOjTh@wk7E}0Zgj~5f$m$w2h|ULzL^;JrTpRhMKizHm>y-y=|NW6D;_<_8 z{vtqt0hj^)c>8*tfKxGHNq*p5q!B*&m^*0|asAlk$-53##~D-Gt;;Od5AulDNtl>l zNdMd$cc)TiSHo_Xw zcp<8DuK8rk8toJ_%oYswEPm$gM)+33Fx93Zu}$r+OW61CzuT(G`sSi*Ksy<7-ztb|J!8wd)U$6 z{gJ>Ud@JZiwU#W$W;2!t21*5IfBm0NrPkzWgDQ{wItVvJlyv7KiF@WrpTHP=6)p6! zB_Ox|<&V5MC}p(fbG(pX-=K>6(oMM0G;}xcm5a>c#&xs}GsYSA|Nd*eM}kj7l%$jL zhP|k+dn`%2$%6IpJb#WkT$^ zM^?Zbo`{R_4mh#ts0)B14?XIBG+Xqo^nI4P60q<6AwRC|IODX9>?!Y#>b(2IxK6~* z+?7?ya@=H9eII_rPqOYP;r$m?|2Y_3u|Ukp1;f3-|IKeUe{xEt<#oWPR$R3kMfPslAFvRQnO7xG9ErhHA{C>Spueo>= zClL`rcpsMx*T74ZMtY5XE4|m;H+0|g@^uGCul>2J@f}&QgHRvB$0sM&cN(c>4?X0m!`Ljlat!=DJ<4cs*40>w z@}X^zhv!&>{Qg?=*lmGpky0Z{ZIc1B3IDxcZlAMksuPXqR(uzSRx>w3vI3R zxP1@a)(X74LnLwMMTbG_?+GWI%+YJEPJvZ*A%r_swOXdHWz;MOpK#ceWW$YefK!qL z{fy5PII0pyG2xoK-x(A`zSs$OS~#+vDouJ-0_g*Y8wr@iRY0zS&u+?ou6AgCejb4k z=i&m+rSm|=?k}kY7)d0{Fimq73cm&3tRM4{?3=?I!uEsL^V zsP~v8gKpPti<-?qjvj4Ro)yjs>#!wP`=Iie)Y~Md$k*}req=+STa$Km8~pY&quV2i zwzOGODe;`i)oy*COYki$*QC7+5rR&e*$pKT#-V+`4GT!5m$?8mqimg$!Lm}rYxS$& z$&%o}6vZh6X9pV|M_RR~C;H{Y^lS5pXkX0wWooeR?XbORcAHTD`iK^F^n{61?_sYpTg{$X08cZ;#jeKx{pg zGf9*D_Y=9NQPG8Eq}O4`1BOO~+;MAp+D-zoW;>J1#&J&2GYW#h}vlESvC<-uby=t){bFSE@F> zJzT_0CB}^3Ktm5n9fv%n!fnW6{Jo5Ari@ZDF+epnYOvIWvusElstXqiU4=kcn^EXWApT+>+rD|F4k`^`0t6aFZ9Q zNn@FX_8K94N$#_YTG~*#ltvB2%Oi`xwc3O;l8_qRcT6L4s6`}(HG{$M8Jozr56-Cl zLIGiq9cHcKztCVVIm^MsMGVbe0I%f)Z*&KmlmeaBR1=?P8Nobmg2It(0Fn=M?@~}! zwm5%6`ulE7BdJjDqy)D5HU&3!s0l6kTW|5<80$8!#wrJv&%xh8h5cN1uak)j?if}q zOq48DzMX}82{ktQm?mlG)TOtq>{x^6j$0R@(yh0Sh4=EDK7`j8>t{sIzJv>iheW?n zQ+oA1A|ketbkpOTiKYfp>N*X^^vQUh&+2gS%KgFXp29J^t(BQ-9X<8Hcz0mUx^BIu zmeQ?)=ki&VIv4^O3DH^~`*AZ(4Y%zHax8$r=Wv0-cihJc`*g$*k~wTH-RUrrx0514jUM`E=RO+T=P9WADnh-IgglVE{mGB63A-OubV7R zIqoF9QP>m0ry8Z-PKVW|83$4%o4ozu?5EyGpRgKUc;JXG$6_cLk`~&|iYH;P7^kdp53FEI zalQ;yG{!HPK#I)kt1nhJCU+nXV#=0E6!R6*xO2!TXa6ziiFnv$KlhsWO5Ra!@xEPbE$ruyL;2i?8~hvW78O!@@!z#0qzO279*BfKtGU9 zmz5v0yZk{`?e!c^QsJ9_Az>rzCHkoq>N4W@Q!{2tD-NCgU*>E8Y;PZGghFl+O5}ABRAHH z+h>I2309q9dv}{Go*Yphj+sMJ`YrmkzNqwlJia5jo1OO~<(Vd#PckqGs+JNjLUJ6F zl6FquuDqTPn@fm+K-i)`mR39gNR@HR*a87D^XDcHR3a-;vAPs%z&*;L09a2WyOT17 zuA29b*NxnsHnJ9)!>iSba{jH3CzKkNf7qxIT%)TNx+C+$Y|>$EYJ@q^fwGYHgwEIF zGxy}n+qJdR^nt~1tXW((3@P;+kXK9P1W*CVnbD`O{gK(7XXNhr$*-+{nvQDN*Z@g; zYWL*Hou9(4c51-hz=-sMT|J#Q>HyXvh3S#XS@! zIrTGvO|RV^(^kUTnz?KbXjWn#GC>T)x(~f}k(GEj$&XxDY(VgI(Ft^qvE**OXv&rf_oZvDzB*;bJc~B^n>$qI|kuRry zO<{RC63DnF(m_A*I%PgKFfjOI$BYA>)Ti%oOq>`*fc|8DmAkgkhdLdU^>m}m1+86b z&~$Q0Q>{dgXpN~N)7DC+SuC`6=IM=Y9U44+y@Skhz9oE4yh!9l?b8|Ry$P+2;V60y z9%cVW053ifnyit*3W|JT`)cw#vZX`HP?C-yP*&{-X!d6B68{eMjHhf7DZzL%99h}5 zLwbB|3U{4v%So|6kybl}ETSJ&5!^Qi%b%#78I63UCxhNP0udB~FNL~+_kPl}1RfB6 zGmgN~0nO^HOF1H@9Sspt+y>QzHqG@MTuR1mR0c1rEcc#{A70s&OdyB z5~O|B7YEaDox&nqUnQk(5~q9G>7+p}y40#n(iqgtuM-%LfJ@cZF##2@`imr%?ED)2 zA$??;LMozBMN{J#NT>rF8{n^?!HL<945EgKUG*NW8On_!RXCWYGER-ZBF>Jc4cYi! zJ-h;X%~TyNOHxIrr!UmlXp9LU5v?PCeGtD1HN22Wu1JyT+RS+A(c%}IOPm==WHw?d zyzDJ+rX41H^PJO5W(k5<$sdZY0aoNk%XUJBZV8sl0nw=9{#~HPsDjI)ywcqHO(T+` zww6hG+@@|p4E#n+ATZt;&M9&KOl&cHa3_Fy3d5j zT#v`toK#=B?SY${U-p)>Fxmj5>S@MZp8CG`;<}d2QFSNhO<7zIf=7x8H$CK|&qs=ob2=aCBB{vM8;Y#di&^p-*;^4k$9n)w?6VAea{MdcG zSaU_JCJgxVk6~L0eJMBCyEqSDtZ=fa9EZvF+r}S~DGhWO5^xBSS6fI!TOX4#(w7K8!6MbdJO$>&QH3Fkq^0wa;mW!HN~UvWX_2@vSpFOD_Z*w2IIbg9%Q>eDo^T*lI$=B_-2A}E35h7zHb6Yk)mKu z!|F)2toK(ZS?1L67H_i)WSQ&*UdsGYoNsr`3)Qr})Y%qr&s2=I$4Kt_RP|B&+`xHn zr6{=v@`strX%#4FhwOzd0E)s$9xC8u>5L2JB66}!stF;A`cm6N7i9SA1y++885Zxy zni}3LHC>>+)jz)vf{a)J1gW>adj_!*nJ+*V7h`_;8E>PhU54o6dCjL~TEiZe9u?Y5 z6l;|L-R?Ix>jM`@{;P5S{XKGnyM#_HZr68#qzwt8z=VX_&B*6FBN9%UuP5QZvCu3W z*#o}NE)R5Ab^Whp3u6UK>?vc#i>=z9@2k_U$>X(3Xxc{mwpGC~p;*)3bn_)8sy7g= z;?Afay6%@}(X0>5xo+LM^?wqD8IMR#OtUI+g3Z4R#~ZNn(N?_X&p4uAaJ^^7aC^7oYz7?MV8V}=qR&V>(oBhf#0h>498Yh?FoW?{vWE9 zFvi)Jn`EX6n4r=a+&{qeOH>hd%_TXCz&G(#@@N54nMN5K4+ot`u>ONwy5Vu*NnEXf z6_S&DA9LA9)9Xn2X84-2{4!zS4GRRk-Lc7fD(7X7%3qwu(CU4iYd~uYTKlwH0J_A;{h|2>Ab=1DV zh?Do@v!Na1mBXA^C?~f^!|sy+Y~T7W_VH~Mf{R{P3$AnreyI;s*$}KtM_MQy7>5Qvgig=p`{W^{b50eJ zWaRII`G+YbbAqJu0;`Th>*p@p5*NYUe>JUMJ0L7;+)q+%{F8MimNh6FC05mYkUf

WUrNa(%5K8wV)^1+`GY5DocW|h!<`834(oOn86 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 literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/images/ctc_asr.png b/tts/NeMo/docs/source/asr/images/ctc_asr.png new file mode 100644 index 0000000000000000000000000000000000000000..56ef705602da10b6dca5e5f01afd66bc1f5230d7 GIT binary patch literal 54705 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 literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/images/jasper_layers.png b/tts/NeMo/docs/source/asr/images/jasper_layers.png new file mode 100644 index 0000000000000000000000000000000000000000..af88379af98f95cd02141b9dfcb669ead346700c GIT binary patch literal 25461 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 literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/images/jasper_vertical.png b/tts/NeMo/docs/source/asr/images/jasper_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..13ba93c2c73b0b186a26076e1581698ede4f6da5 GIT binary patch literal 279466 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 z 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�BX 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 mGRy7%6 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 z zNV>l9zTaqNe_{6Q{{Ga&$|)wKvyv|S^7+EKKy0fZr1!gBN3)oKsxyV}*?fgftUGr6 z^iWv6t@JOhbMgKA5XL0m`B^uD0$b+ahJ8=^uOSP~+ht8QFU4+^7b|XLZ(A7IoTj#^O-0!dV=oN^=8(gTHzcK5q`D*cD-_%H%>)@=( zKN~&K?22-4OeC5a9PE8y{f_;lp%*7o_T0@m47TXw2Ii7WNVv2Qod-j0F2rp&ClIO4 z!v&m${da7DkSbMhp_y~Evra4G-U6p@gARaxzJ0>C! zOzSrFQdzL~=*Ax|O!2i+>?HO+o)=cAS5!EX4_!v2r1O!WjKfL;|XUS-C#(F z$$LP{yp?!VY|B3G*S*2-L^{Y9TCwVW97o&o`bMvOqwY-#TDv>+y}LUyq)>Cz#J^RZ zbTZNh1-wOCSPSmo@7&4d$+=JcDqWh{1Mz?SYU0*w&`6;cFbcIoL)ddxQ?x6GPs>)1 zWcr5wsHy}+xGeGbX80JtiNa8hS@k{qt{w*p;Ha;0z%Onac5Rxu zbjB>Q-E9#68kybItsi^?=AOCiH(em(9eX(m7wC?4OVojHH{ZxjxE#iO1)G6%{`m$3 z&&y=6qg_T(0h`x31rhExMhC~=sK@G$8XClEBq;+pIPPXd>M(TdI@zero_?-=gO^A) z;nKd*0v`W?jT2>}30+-5#JRH!*vYjp^;H5O!g}x>GxpLg|5HIpFPpS=9@Gy>w?9RK z!L_hAudsk$fD%E@*VtIrjR)>KJ`1l2z_wvg7sCGh29G_U_C_WxV4lv__LCOBS+f?L zQFsbup;9FPakyRYeb=fx=jFGHumQ${_tc4E%!Jr?WjmMbQh2G=(+4j?iDmc=WEB7U zmHaHyv1umJTRc2hR~|oy{=lQGU4ukFXwEUit$hC7DW{w76z>6$c0`UsGxT}A|qh%x+X z9YQ)6TPpajrCwWWhyFoD5L}6_z`n_*V=r2?Fr4rF>G0K$E)@Ef$0F;uTr|!{BztcS zJPXZe(BTv3&IQ{Ys`8MgdTj#87{i|2R zr81NM$CLWzm84Ep&c;2yhS%9jt{{+@|Acy36_Y*?9Fw0ms2xp)KpgQ&ALSd2fXVT2 zEBOz{#`2rDPHu*rglN}+^_j!c6M&nIBc1%v_TO4t-jT4k8ab=m&*2ccE*(b zwPf@+`w!PYvw}0n9V^UK%ZzI78s&xGH0{p63xbS)K@_0mfOvMv19_8W=!acPeTGj5 z?l2NV^9>nYWb3ar%l_m`n~sUnVi#BhrihqqKIINbE=`JU7=FQfy6|LDbS3E*BxrJv z5CkKLf;oGQHj|`PU4C6^ueAHP94-c_gv>PWfroHDPtI5oFj#(D*_t$e?)Yl~P5AMb zFJ@)XktehJi@u+w68~s{6d;2-a9*_5T#I}S0$DQOWe)`4p*c%h9DS`#OZz`+4O1Ze^bgH7TOG8?+)a6ft zRipH=y|DIpiOFI$boKjxH=bh7Nird|bUrW~AT79}{r_fPf&OH$g-t zG^wFTKtL%9SU|col@6gvla5Li6r>6$pdcW=uCx^P8L& z_Xq}tpniqlV)=VuIwFtgv2OF>1=NdZ*!T^8b@n@gC|?SY)tcFN+4c6JpmP_S+qa5W z)7=Rfdw0aXGVOEPpO=Ta9Pdad$v;|uBOUgkHPCO@7{VWi2_ha%-^2EmQ02BhvlE%? zWAx{ZTfSWIz#aLO`mg(V_9YCS#82<=dBwPWVl6#y&9A&(-Y$}Rf-k%$iS4U;)6o5F z?H+Kj!ut#lxWU2tz|_FA+5EwuS`LJ%Obj7?n9$X9YR;9xaB^b$Lts(Iqopnm1{u&J zUN-jVQXKUVnOScmkKIlu;&OxU)KdS{kiXnH=gkF?{J!7>*GE3FsdFwnoO7>P3DAKGk7>9y&*cA4M zy4TEVXjf##$eQiQGP^B)N*U!9=zv)0vuEhddWP2R0OuJ(j@l9dw&-1?-< zgUAravqE7}OvmBc$CH=O*4;jg9nOMio}bySCoZR$Op4SSCzOCyk_MPlDZW|lxK8d| zD%B&*&)agn1`s6>uW8JTOv1;K&()PSvuqEYjj_~a$2mR^>%k1qMUEZN?F1_y+Lu2z zRDdP53SgZ^ROlRP#ZPdoh|ZE+B0rvrJF>wpRQsP35IN3cB!iy*Z0-76+~rf*Yuoj! zt0`433Jbv<1J%$^{U7X(>!lnS8Nk%RFqGH%=cQ^uKY$e=Qm+U~qVQ4b1D3)=hosy; zBglh8OSah3Jt)3bk>0AV=G`r)wMkiw~ZG3Mf>^y*s8v!EQ)tV)a+0>(tnL zd;KW%K(wP%vOx$8jP3Z203eegjiprTmW=dSWRl=(BuwV?W@Lt4kZ53Hb|?DX%mZw8 zUhS<;{@i6uYQ$96k?K)R=c}F=y=VWaQW~6YJ6l(pI8LIf>xruAX%&{s!`xqU$2oo+ z8aHbibdG(D>!N=YLfknv|6_+25R%ai0pE2C54g6TZ2%QSstbe9dKGk~UN$}Cj>gfr z*beh<2ak(!pK*A~l1q9Qr1)i+?mxk}Ha)ige53V%^t+#l-_&4ZrjMend!2t3PuY5V zbE+6w^}Hc9qq?*6YnFG$rzEPIW|gN&r1i?|F74}Cp7R;t>K+8SeU3&gaCf5#)Ftl1 z;fzf04G7502vfa!chz)D!wS!M(!BW3yPvNc-kl6P>|=k~_&?nB465g*Gf2e+fI#dB zr}Po!2xd#5Pya*9q^2G?dAba{|9Ak2m3+_&+JQ=A;?%| z07inu6&CQ*(_wghD|8I|mA$=xo&ie=2fQaH?^HGV1Q>kSaZcK3G9E4P2bm1PTksFL zojK1yZ^1F3A@m6n=OO&ERqyE#a?P7Tkqsxs#SFLMet*7nF zJ8lieA@9HD}B<8w+^U zvmNT~pA}~|hmFrigx{c)pwnY(DeX(Pl;X#kKRylN(-hek{yl~1n^_->u`FxJ>N~2v znbwLw7yj>;*`WEb8beaUF}d=+nNgN zWK>^2)N(94dvzCEStHQ&LA}IO#=CHm>DSFoYNfvhDva=mB>X{_~?sXkh)m zmN43fp6L>rg7<<-$Ook}FGeYNYl5E9IfQF@>IFM~mp;`SqGknU`>bZk|LNR+Qi;d6 z;Mc?nJR6&+BTeV1*pqtrC0bteNc7A@gfRLrYi2IW!~co?|M{1G z{0Q@C)`~Opj~H&L-K%E>;uO%(j3)r6Fy_$yCv$k5S(z^_0ho{a{EE1@WHf7;dSa!S z99=2nIsBI?l}@&Y)tix>4z4v(osUbE$;fTHj7A@~Alt0K9S*ZD4f(mTBi_~v}gJ8SW|f(32Y ze_GL>iM@K3y*TMZ1eWD>@OickqV5mp;l*#J*i#Vzww(FPOsT~3%yMnDsLRm|&gQzD zFT4-@G$hjIfJs9+iqed3BnEJLTpxs&%WrkDsvydy z9t9_>@?YwtzYU$Ky-kxDe86)A4WyY0alu%v`w@cripT<&+E2P(_}$#K zX$pypMBYg{kM~=9U+_&FWhM0$oOE#NkS%Ifoe^;VcSMEGzu||J)Nz1YteG*NGRUE@ z&{@yr(H=SMrPHy4(_mMg*w3{7#WSCxwC$ne1@+f7Vs#q(gl$ePdoti^md_vic(_-B z-ZHY)*2Q8BppEZ;TQH5R2s1-;meeh$E`*-*V(d7ity68j(5*84Ts*pzhPF902-C@M zZaEU3hG#croMyweyj*4vlu%@RJu8nTO0bezGqM?9;{$x65F$@R08QodOmY3%=y65n zQ|*;k42mpyHU#uD{5F)!cYE)+FY< zL5EO8CfoCxBHt^HjEp4P+S)3u_0T3UxQmx8*8HNZdmB3?k}KT0 z_daujWPp^(z(t)nrlLy27^P=r5Rn?@7_ny%fV4~rb_u+Mu5>#BXDTP@V1Ew5D zJ%8rLjy%5K?pWPuovQqs1E#ti(CUd9!PF$uW!k- zm0O`VMnpz+K z?uzL@3fLg7K#WF4Zvvi9K{rF$&%H`Ufu#;CRt|Cb@-k63O-9T88uxE>TuP8Ua3|IJ+h3ukL$MFHMmC)Yl_T1V_R@rj(c7SEcHh7=rKoy3#6GGcL_UGJ__S{m5A@6a;5yOmPxdL2i;S|>i zDkKkaQk?Yw)IVt*uM(J}e% zY!1ubyTGXv?N@__onleHUdPt1uvQ!EkV;+<2Lsn&f1`suNyjo&&tPoru10&hd$={+ zX*ng$+>>{o{ldDmeF`U|na^kIvifsJ{ua(%`Vk!C^E~a9eYIKkLsq?h(*r=_PZNqR=VYZg1`-uV-CO#Q``aWw^`sJL_I8@9x<8 z8j|v!`$4zU_=3iP`EVbk8Md8;A%=84CXaD>Km+X)f~*ybV=WMQKNHuyeV&~5CM`g% zNPVSZfk%@Y8*Gm44Lfpq0|CRZxW~~ZFC$1QACzNv6xu7=h@sNyIpKEFB0<}7;qakr z_lg+L0dA`}b{%nl_K^}DFWZ}gQ?-E{(R31QKU}#T($yh0%Aux5_pu9d%7Fy*wLC<$ zKcih@7B645ReU+*cP-5!MDm@bW;5a%@0u``Bo^;y%z1$t!gkPyvN6oT^_P6a^j|#7 zgBX%X|LDm74Ql4IQluosF1fzZ93&H2%R|9sAL?cPQVZ`RA#v-4nU;gX6MHP;qL?YRth*t}H|%9ac`DKAc9 z5U1H>URz;7RFD$bBatr)-&3YMOLuaY=cv)%re=A&jWoRBVsq`Qwbi>;C$HfF2~ofL zF30JRDeZf(_7&s&-NoHZ)LZMdUnVS%03pS--n!Rwh&#Y*Kw^JibwHV_cFYu&LE?d{ ztcB$C#h}_VxIHEyvA%MBN{7>RW;>|vm|b|Nifq1%-;ji6y1u{36dCFr)aT_#^s^*X z60_Hcna%au&MyuppNeis(TVMq|9r1_2sXo8^)Nl>lsIZ5GTKfYO%=pYTTe%sW?OpU zrj3Qj3M{-*>X4>n2K09~7*p3mBN&di<3vcV;Pu(-SSPmb(jYc8Ut|YIvXr7o%q_4x zJ+MPr1y)M6Ch&ytWrm=8#URR8cD@wKTUXl08XNMJ7!&Yy9Wm`L6JWLeAx{kXo}uV@ z`?S#y^WiWQh<>AzY)F9B05$3g57us(0^Jc$Q>$Ybr2!|-@B(Tnc=k7M)!ur~17WCM zOq0{&&EPEQJ93|xb}&>2+Adx?8usm`t})iz%Kc_d2wb^5y&9w`f0fgx?=W`6839!1 zQ<%j(9W2&Wv#g?nOp7+qC&KVImh;C0Z|^o?_5BZ0FBFMjc6c^mAU}YIFWSpAP0?Si zSt~Uh=YTI|aCvw!x37fsExLO>=}MLNzjY=1C2uB|pL2(02+5LAHf6OY1Dl#|ifpBF z7)>{ACiv83Z56wB%lAw?xZoWSo#phx+S#u!LnSY>p1Zj)&D&@rFG}Qj+Qq$ zb60P#(ca6=0sBL~)2uhEWIlIo8!UHrDLG)R;w2}anOi=|*Rz4FADccGWG>0}H*U<* zzw^wJa8?(0Xj#s^9mhnIHsP9fH(pwGn0@UdQ|5^gSx7aBc3=7)2#+GQV=2=@cYC4_ zB00R`JAETqS6~s9ZUQP>f>;iP@z~tq(#JQh)`%j|HbB5}&OF7f4+QmwYtj4Ali4U8W}lCqc0g@rK{zBIyuShf#v-P9ztYs7 z9c^Q07Z{~`XYBe9IdG_A`YE7?6Kyp;w_S(rl9hlNZ+%mX-kj^}$c}}|k4#WmjGz`z zu7u*x?0n--CZ7oJxi@?#9J&tHVV=aZBIAVjbF2Y%oF)SntplOK0H|7YaW0p~oH58a ztPmu>oAu6GMSU$r2U&P|?*xo5aua8_wmp)wP_@PgE|mgxtlfX;p^mT(pL$p zEJCr$-20phcK~l@O1s>A?aSVjO0%Yl`0Nh%LG6)UJ zx(wAr;VOSES{_aece5|k6eh$g9&E;nmh1yw#+7&<);XCXw>uB$`S{h{TP;)hiwgqQ z&09DC&s4n=ZTW3ku{y<^dP~WC**A?=-x?r2Ata2`ayobdO21tMQi4;Symh%wyt>X^ z9HK>@Wf(p1>UOz}F1zxs#mdh-t3kF1HmKef5+-)$M*Y;PdewS>oJ<5wWY$`-eayMF z_9 zWRs?4!0;U3ZQ1D)(01x{1|Tyu@7?)8Ya9*=nMR;!;H2@*vuMO%hSc8Ivi^Ko1j7xV z?OPlQk*^k-YzH-WlU?PNqY90+rxA8^^&!g+27!@ov}STz3_%+DCjlD1Y&z}6V#-jP z-s3Bvd1}VBH*m3R#UxxeiuJVsV$^m^P&wt!`#cCK&Pqzyxjj!Mj5Mv7#w8m3Apouh z30x3o8$bHlPrRC}IxrNkvg6=NG3SoEdILo`>x6xT#uwDms|oQGG79X~@{|P>76gEz zhKMd;|MhlscOPilh{7zIU0@8ttBu#AI8H*tKQh-%tL__#T`diG-$0BwIZzdMVW%}u z-d`o{oF|*9q>rUs|F*98#V5|m3A5XG0ni`z|6pV^tu$U90U0XqfX2PfYA0`b9E?gi zz5v?oP&tN;C!VFu7J#WKkJhsuS)@(o4N9mkiJAojv<_&sm7#D1J6*^tB~2Qon^BVwr9^bZL6Rs4vQ`bsk|)PrV53QeO&j7eY{aRRwVpU4d!$2O?|qG6shESQ4HF8 zrarp}|t03XP6L^@9iE8f=l}7BFJ3N8BSBq*f0pRiVx&24k5RyM$p=vem zfajsm8{kbK4z;d`s$^!cPIN&d8`Y_2aLPVn(|=NSp!^0e@^sV8Q(nLRWB3?&*2Yoz zp-OdF0TT%76}XpX_){^E+0x773GmYt%5x-gh&XCJ?F5BwO-rD;oB=~MqW&YPzi(6w z5NH>x-G?+I;B=h3fnF!-$=l9Bf{r{M_p0iZG?8T|PgdFcv{;prQ+Z(K%w+qyFCIRR zx1BJn!(mJOT#KSNc`c$wOhKEw+H9x2=<8%cNx|QR{#K$*+?10O|EZ-3G`H;a} zNn@Vu>(cLfDDa`cqWLfuH1A}|0<9Xa6wc38FPj@c%ORavU>_D+)9+XRH$x7<#Ft70 z&zE`6%bLAkS~b3g`dzK%CWXoGbL})nW-UdG~NSob+nC(6xS#BuA zE1d`F5oOHbuNwToA2AjRwga=_RCr|l*rxpzTu`)dTt+Sl{Ey+-DeX$YY|vn(ZJMh7 z(N95I2P6wn7!cNXsG}3v-@9xu2pVpqGyu~Zk{(FUG|Im3%BJfT+cnQ=SrI!dXLD6k z<^`QR2u)7joMY@b=yt@$y4TW2y4rbMC}Z|#c9$>opZX;VLG$MrUsG=BtzB<^y^@_p zOrzZMpu)#LU!jUvHZBz2RKamEbr2sVlRM8mFFI$)0gisg-o7~FOi<_E#6CAkFSvCU zh7^=-$opskD#m4{0ml?Oz!aBnmjyi)r`1?hTw5Kgr}v|y>0Tq$V}c{mNi=3Y>0A?S zygVtDiq1!TPh-w?G6q9Qt?RQoC0-pTHDQ11&-z2FUAF4R@*#-v7+k*gbv0P0wax8T zvbze`g|}lod$5u=O-mIzZX*oH&8An7$?9CfDp~DqPQ&?K^yXRcB7J6U5VL4P%zVZJ zr}ggZxy0WJvL@~5$p_S&lC(xx4s+4Ke5j;MI|C*ZlB0YEkC#ESqhoEsAGC~f(~a?%UYI4I}~sx4av~cy(*_u(HvVcE<;U< z*x2cMaMAH*KWiB;8wUhn72>kt?kRuvKuWUSOOaa<-&1*M_+K&O%>B-m8Rsz~1-XHV zUIu%s`vP=7r5!8AxPfCVnGLb^(LeH%Wo*Tdr83H^P26r#Zc%F*rJ5LseH==42sb~0 zrrK&VZ|3zUG;fc*f)YW%o$SgPq2Oe(gO0uw0axNnll_ut=8Un^@VAv?Dw3EvqFcP` zF+}u;AHzGA5;?q-$2@KHKXX%R?f5V7ARLxT*_o4NYY;O5yL!F9pQNsM7t~+zi5}nX zg>HB}RkMac%+{YSYF;Nb9pGl#x#_|?Y0Zj#DZ4i6t#`ln6SAX-2}Gyi-T<*`YkD5s zFMYzpTINlAmUGVl+|*it?a08Akj#W3wB;68toa#xnN+@$-Wcbp(^CgHW z_R81N5XqXypMkz!PsKOZ zeI7%Dpsg)ni)|PN8T!(9F5Uo-Y$qeG|iRk!Z&Vd8I1W7aRR zt?~oODYmPnYU69`+SnaQwpuEUKn+31H;EL+CSj`m_v4Qq+a>1CT2)Xv!W~W;*W1Y1 z^rH~JBfr{F)f16CM_)iqI{C|+E=DZAU@BN%oDKP!GE}%}XX#lH`8#J-gyW3h4Aqg{ zh)ztib!@5h>Fsc*>CD?vK9~nCuU8+L2nsjYuk%8L|B9o9!v)?R-}mA0BCLp`bvtP z+Dqk^S$L?KF1z@bS@R%n#L^#!vUPiQw8VX-2Up#hF)`B{8y=%U^C`IvR@I?vrRAK_u6}{Cx=-u6yhpku zWE%mi>vka3P~&t;XslQ*Z)g9D^HLk6vSx>sMACNTfSuewgIe$|1loC5Tl+s$@aKY> zmE%HdVBiV`&{p3Pdc$!O`IQy{TP%2zkm2|8M>yz2v$>?hEE0!=C3J&;yp ze{w45=tMh1S2trAIZu(%HfyE(4fnS)9A%o^NIzdGy{(+84QhH=nJh>eU0DPw>{?D2}Nvx6M z+NAwhAJ;FO_(Q`_oNlH)@MSgE4QL_r+@UljDpb}3_IS|rEq{A*CBv(ftDS(Mar@vm91aZWd-q}3Te=d z*INg*oln>8dgvqg4*gdB0DW1*xr@9zreShx&-YL{=kv}V71`0cN26p7M6YC^4A1!~ z%mvkf*mjkBqzt#L@vI$>y{vOZs>~IxQ-^+EL>ILkXGO(U<;djScKw^ zi|q!3oAt4V1oWZiUHDC=;gX1>=|Vdm0rOIqY&UU9OOc*Ead#irW4pJkpUhyXJOR)% z?s#faATh86T7qq4W5FEwhkfCZ*>=oOrQa`nT6^I`t$;Lr^$6;I=Mw+Sx7VexXqjKB zT1p4XW=5CwqLP4c#__cOwiJKr7fN5DlviLn4U3gLudXP^d&sO2aoKi+jh0C)_8HfF zOosf+ACW-e6qCCG^woeWqlk8vX_3O%n^2-g(%BS}DMAfg9inJ_?OPY%4f^M2-Y5o}+2h+wmz-Cl;|Igz5 zS6{%LYR)66Ky_H9ElYe8FT*OVniUa`x#6*wYs#k{%|$PZ#x|E|9WnfTUaWPdzNN{P z7a?rGPFdThI++M$zyMRx<}arcl)3?v80H_9L6fY(#-(ppSbfC+7rTMqoig3N+>ikY zD>$LcCwA#@%Jh9uX!SMzv)@j~pJ#vmqm8#QsuCXl|Nj(PRcY4(YjN8I9u+)jdAg=N zgE{A6>Blj9@!>CPF0L$dj|7o|uil8a1Jx2bwd5(QTL@uw+T4G3{=bv^&Tt8J!vG!@ zNO0$b37)ujTI}T}uKne&eJ*`v;4<`Wc6Yp)4j|*qvH`Ip`Qx2Jrb z&*uw540tJ^iam=rW-n-VUpyI4?0(y;c}UP5ufM8&SzNO-;ICd=Nbpkqs~ zvi&X!OCaV_h?l8dXYH(4U6Xb9+rEMEL`JP|$lWol`Vld-W5Gw1M!vuL&)x7}*#bNt zXduO?m1EGVpk=Ut;ZNlRrvRFQ4+Hck=$lu}~lYx45p$-YQc zK{{BD#KSIzBjQ5q9MrG<>D>bp|~RKboq<0|NTeRKn^?U&I(t2cRm$-Hf-3@2Wkt1+0Sy zGJ*MprtNups=dL5d_%WFSH!|fN9B{1d;VEKpVUT_6EryBaS zt8OSE0PMNgBgtKWrT`_qGFZO^;Pt;}0P3o1!T#IlZfFT0ld=6@?d9h7nc`PBLeEU8 zQ0`~bIaE4EnD#~r@`xEWyjyv;a|xTLULh?w{w5eQh2YFn&r&Uh zg4As5jQ2PK8XHnX!>qfOT=@tdsyh5TN;k0v+R5NMGWof}DleR|GE0q*6gAoh>=$%< zImjqK`u~6QcvZsuabQ)-BH{P1F%Y}wcT~Mz)tj)d(VkC(Cj{`NarcCe!^n)AO2A0J zFwgZ5ERM=2JXu%hdk~$FQ3XkG2g$Gwy8qkw?fQUOO^x8f_vCoMy)eyl(crG9{G z#ixi;W}9Y&t|j+Hbx(H@o2?}5a)MSMNE3V{s2z)y{`+D$)|wEM_{dmyH6+l!<{&!P zl2N(E!$v^)8ihRdX7C{jabF#VZ8}lY3;`wd%Un%<48Mc&lgQia4>3>N9Jl$^JxgV6 zq%cY==~_ZSl_l8eSo!e(y*{+%ED1AIjMW~h^5Uqy%X8a6l#UNO&&7X{V`c8m@(89R&&2r$yx$p4+5Rm1~I@bsP6z4Gw72n)p5{W$O4MEjUt{}Y&*M7#mP^@t^Nx*xwLr9wEQ6Mq{!O6#vB{|2JSmh)bXlKX>_xV_po zzV#3xpmq*tXI0MJloe2{Uc6&9C=ht)u`Z3xLvp<)sI$c|^941*_^TI5&d=!F)c>^J zF6KRE=y+TihX4of!wu>rEXb%|Ks)Mxw>#Lxc{t$Q@T+UdpMr-a;BP)IyJ2Kwp@T5k25P2Au&0QAP=(Bgk%zo#?pk;EwQzO*m8Y~TI4-DzMn@u!V3dY}Ns zy?1%V`Tsu+$8@xf8O2>F8+%cbkml#JISP*`ewJuI0SOec%0EJt|M)Ak1yAZiih1IP zr04OAu-owq)5bpT5hBG74VR=?p{$P{S8g67tmbK&hyl$xi-|UQ^6_t$9{uP5j#41Hbc!PO z$vJ>J?39mLU<_U%D>^%_;I2RUA4EmXbnE*sS>n?TrfRqKV^v1}&;Ywq`D+#NLf^e^ zNBw#ayOUUTJcyEW|EN^|mBdWQ%nW2I77A*aoD}%`Z*sq?Q(j33JZZdjE$Y|Y+1(U` zh{3bfY36m>|J>iyOk%ENwmCCR8R;iKv?{@p352asBG5!Dn_+aUmqjq?8vm!XMtpv} z^hH3;8U?5b=vF>{{1`U7zYzqgM3jeO=g+HEs$wXzfcOSLPG~p1NGKX=X|c=F0Elpg z;*P#&Kb^McSFe2a`faTM8_@RkuZ<{$A@4-(|5+xcCM0Zx2Z>s(hwN1XQ94E3nEH=E zIh)@{|Imu%YiTBz^k|tRpWd1rSSquG=3B4b&}(11FQ2jHf~uRV_Hf_KN_viJON>da z+W&aNE043z#x`|!RC(w1pzYf1Ky|X)7sEAXkQo`n)Ay2VljY4e8Bh;`YRd=53aWCo zZb(W=i3JDQ52GDuY)^#Ru9WMAosNJzD)9lfn4oBp)3-pgI|RMJ;e2iDf}`oXZ}beI zZlkvv*`V*d5%RSb)BLE2#KfKZ`G%83AF`PF(bqz^y6*Vr70Zr>&DS{x1*InF%_KSA zh7wmC(w#kWUBqUEkDB(pCq;Iq^cD}M#2ed|(q%bH`VjJiCNtx5m|BO1RK=G`d_V%^ zokiET`? zw5kUy5Bz8el@&?VZ|rj-<2hCTslJ1ok9aL@ulKyw7eL7qwxKZ~Hcxys*0npDFhfk< zbjey&O&)1ml8MajmJ!ak3`tBp3K_I|p!PF_spICc@MlfnK^N2{Eiy1r~+inUyO<$LiNbvD6st%QjcNEY!+#B&D{Cz7p zrJ)}IkLu(%zbq}R!17Zs5O2v01xSv7n$4L(Pr{i&TkM&wbu7(7rO51Q_a^L6zRuN> zTb==!t)7pGrun*(F2=$pQ+b0+EL*XQ^-Z;g+PmiF2?73F`NmVwUDdSK)>D#FeuU%9+cAk<}+ykC5Afk54EbU#(1%e0-fu2Z4cTi(p6 zO;fJ5u1&}23nj@SrupT$T|bl9=E8Fedo*3TLsr_|f3mKKFE&fIb8UUqNvEQ)i-h~O z)v63BsnqpK=*gyEmft&CM0KVSQJutjRBB-ADYk?wKS1MgJJ9DinQ&ZNxS&y3+T%89 zqP{xM^H;t>hboXi_zBMc7Qi1#0yP20SZS9}LYo^F0m)$D(sC^Kc>h#H;SzY*+MX zQ5)>p6T2nxnWQJF)Wq&$o~hXDFX<4yq~aaD_mF{`6E8QI)$7SE?(Hu@)tg~S+3P|6 z?$O`yym(7EwWKJqD0JzR!ifK>{8w*0%X0rS46Cjvs)ji880T^-)<|(8+Q?uID^!cq z*A894TTOZx^YF}VLAV`6OJhye5T~KU>v~4Yg9>ip#4A!F=#IO->c&--Y59i%m7)@~Xg}IJ!FSMSjp@LB-oJl`p0r1t?-2M+&N8?7vmQuVqdFU1u zR?@{+;+lryB;ey7Q|QHm8?f6ii6 z==ImIuMbrA^OtB&Q94O-TP4a{_NounGWT3t7FWF8h4#W@%UF#x#r|YiwVmOrN9B2rOHLWv z`G+yT>8sMaf{OM0PCHd=SGHIo4e8cp%GS;jQ<2_VPEPq)xByf5+)sg9YARepCURQw zn3Wgw`%hKA{7jKhZ1T`fUCv{|VCYYAIjxyp#%g`5XK%#3P*2+f@a>74LvMwc;FZO)+SRr2%L|mt?tQOiqDE|F4l6o} zNLI{&d4KFy$|@H|HoAJQm-I^bZCmz;~*xiPT2k<8IDYyy8)kp8}VIW0dV+uK%^;J6FrFE-A!-8JsM9#y^ANksX-1(KR z3g@~}b-nJS$4f?*m^V_HSx?s3#3vhMUgJA2ZY?<~jQ&oO9`#pbF1Z&D2hjj`-Ib#^ z&Q~u_->liMkFi^YI-kG{wL)+y^;B>fVMX~tnJy3a;e#kL|2%nUNsb(l-&JAQD5W3u zB)HO)t-!Uwm*ew!vmmprg&y{XhUvz;fQ?H%Os^N_|0pN1(H1FqTFFw)+W@?=*m#lq z$!~%0R^v2!?c>n&UWy}E%p1jWwM9h_+?JtEdrA9S?=6kAKD#(c-aand{oZFjw!EWZ==$bVr7){nVx9SMYZ~Q2 z7M|@f8Pt3mD5aSiXBT~y7fA^=j|GrLpWh;sb$awb(|X#ns#9(h;$|C69(k>$5@ir& zCm$VZ2;1+|PmWwtuYBg9H3Xh`c?6aKKKVqS1QJWgDCBT*SF;tM9or76@;^yc!Vj+7 z0EAXHV5^~|_+y?_Y2wx0A(h;q+|eMOVAV-2>nP%S8X)B3Zwp>P8UG>MEk|TkrFg11 zOJsGMI_den;lA%zY3{yx!b&Ti9fc=Yy%Zbz z(hLKW%qtBAsDUx)caG+YsSzP*sI#NvsMTu}fCR3ixjS3aT9m@)yQ!oOT8=*kCi|1S zZnyZz?WOS^nRSamn751L*}I;x;?c;( z8KrxI*Oh7#GnhL-G3hvW1*24$pO{DW9`(qWw1k>ACSORqpBF72VDE1|*~e=&DMn{{ zyr!jV~}+mUc?_YyDgF&o}th55G{M4hX|g&1+(?%lTEUxNRxB(2#i z2~>8`hNSZzr3db%#|sUaUnwTjsMM!X-VqQc*}r|!H6u{a@&6}t2aSCNU@&LR@#=vyTB`=D2JbFN zJ)WoZKpU>S6d78b6%r0A9rUQ{lou!l5isbPvaw)euPa#Re?^b0dPvB5aKD4bp?`Hj z4~JB^g&64QFtI<9n&h7{{ryXD3s-?(AhTm2|Fixe0|Bubat~8n?a5Dm=8H|s zzh&s+!=oU7;qn=)Gz_+XUi_lE}!D~WlH zUr+*2>DaOXj~sVc`qS~yw{XvY?SWxFjAYj-tG5`U0uXk!k9{NKUGO#np_Z{}<)5bY z1clOT-A&+0B4q`=pdU`)R~eR+dK4vM@g1&P=9$Ol3xsy1QD0iSEUMooU-*0#F;{9m z!R}~R@pCD~FTr~OqAvt?IMa_W>th%r8mPa%r-ij>@;Nk8C-^AL+afX`hxoZ}@p@E` z^lCGYlX8kgH~oLC^wsz5uKld4RB-yGhyIw%{UM^W-*4H;?dVMo)}Nx*2YKVLOvJn6 zesX@Q7Ht1@rM;InHs09mTo4Ysw+1p^XqE9QuIkU8<`brZT29EJZ!|sLKlIrOY!%-s z=B>FSg0d=*?C``1ZgmuOgal0gC zsPFBP4K1R;l@RLwfbS57p|Kxgm5C^@JcEWTJ*(yniJW%x9m79zgE?b@k=+VM zcDL?H+0S0^Sb%U1U?JuTi^>Euim(EZ4n~6V7?2)-M}ibn$L%PaId-g9nSie)VN+!{ zKBG_+^))n^+u#kkMn}d)$GXMfPyYvEv_#&m*8GLnk287-Q3|UD1P5F(ZpcF$&=1Z} zrwOe%Pj-6*6!!BJ?u+Jv$vnpB!l(3L?dkJ^ZJ4@XHDk*!GEWDDu`@K)G z{&&!kp9Abk$_CwWN~Ck6^SNE%QkhHYN~If*@~q-FI15zY?^v7-yiP0 zw=5%t8c--V**P_fs_Kajbgk=A9I8J{tuOM|nn7NOAIYF8T*n)DVk+Fe|?5vjjzu!{gqr@Td&l9@O)6-wd=Y&zY#7Pc6o1yoK6}yMBC1*xcx*S@<)q zsk=B3yQGk}uzJ>DkE~hVuHODToldy6#H{`Ll%B$c{D>9t?-G5w2uu+f-(C|2U&iNU zRlhZ9HhP%8UE79pUQQx?@YtF&YrGu7cWLWDpgkEyQTDTs_~kbC@kWHQ$7YL^_S-Xj|Q zw)QWm|9$3wvGTNe&5o;ZS2+I0{oS)R_U{J>(B-;Bp+|Jah=q#))AYFWHgsmNfMVKB zTE4>Xc`~1y$6J@=0vJi|BgNL4kAHfniB_I{TA6CG9KoR@w3k$U*J~BR_HmU7|(E|d~Ii!dJ^UED*ay%|g20<^^ zQo8pSkfq^OcIE!=m+I?qq~% zckgSm-e9w9U74|JX6=6NmxWM&SyxbJvfWI<_J;@5caK$!a3V*yS2tbq4G)DT&w)o6 zj^9dn&?0}F8+ND4&MA@P9nRxb zOYR5a`Q>k^`TZH~&)qOaG|&O~n}kV>30a8@hvqk0T{-&j91tIeH!t1Eugl3>I(2vX zlJB(i^P#jK9|nIQjw1$71=bX8i!{qg`ZLFtp~J(>UFUf4IPGm^V7WXY;ceT}9nfT$ zI4GJN%0SH|1^itfcYL3%fK57dxUd^xb$BqSnpfvjya`a`V$In~(0$oZ*uQwy0 zD4WwZ9lsD)pO_P2#YU2{v7h*OgLIec!v5uLe5o}EQ;w$f7eYh8`$z9}kl@2bkt<{K zpW;|Y@*?!~4zoaZu-f-NWyHoMFCgTE`Oar}vct!lgNww{GyVSD!Nt+}~5 zQ8xuW<q@zGvf|+3vVLA1ccs>`dKD??>v1`gJwEBbK z33{}V!VA{tm}Yn>tLd+S%4sp5l>Ls5w~zJwoXhY9*Ih1ymjxbwF7CG-n`)9iy-+Mg zQoKDaBk?PVRJrfT^!GK&btX|1{*i`2 z#@GAZXW;JyuU8WAM1?nRD05h|`#*T082}+D+^Xva&;zGJL-AH##VEjZ+*N*t^Hx)Wt8y|vqQbVJ>1ucrx@y6w6w{a zPo|6Ayr^D#{4@!dUFLc03&!J*m8nF32sQoA)pWY6ZdeLs1l0Uk1W6`F|G zj@LB}E0D|Bob;^glR|j){vW#DJD%#lj~j2H93zoK8A(Oq*n53LsZg}+6^>*($6gf& zMI_a+XQ=G$9GeOq$Id>EeaJXuJI3#Qs_VM1`?{~+ANA-_Ip_0v&)0YkNl@tnZM^Rn zDiqYw&IcQLn7NX#OPyUwZU^^mvFE9xm&uCffURj5DE{7XZsGILsv46-%6~}`Zon){ zdQ}6f8*ht&Uo6(IV0s7>+9;&Jy)YPL10;9T2yl=E&ph()FrRG>pjM3ypb5!kssq zV<;K9sdscM1FGymy8FTj6RME(izF{!(stsGj<~3{^+ymtf443NFM_Z0vsX!}X_u4t z{xKuB96sWVIoRE{LHI@Hg>%7S{&k z*nT-1X58v!_;ePFY*!p?Z6$o`oKA!a#LH$eNs~dDp{nLm)8%|145Hm$II*fMAQ%>1 zWK2lI_5Mh}d*seNQb*gR`06wNU3(=P2q01e@*oYng`)jU%20|e#f=# zSu?h$IhhoTb4Ik~ku4~$PFtrORf|9D=5xTW8S4+{wRhU|h!W#53FWbihCP|XTpM!| z-G4{@x9h5gp$W}F@ILX|frY)G#+9za zIRJt1Ras|o-!(xXsT=7%xgsk>-61UJsSa|P4Kp0xVp|ngA*u0C!tSSwFVJ!x3j2xT zzabqYFod~(9<-VLe5$Y~3n@Uf*~lu+psi=oQJC zDFh2LQ;$9HTe{Sc+Q#Im-Qm>0e>_TsG(Oj}U`9iH0l@MRA9#`g+v@F)|D>~6-<92K+l?*T5itH12!177_`6bJ@a(zHy$ zS3IYl4hyQ11mKeeaAsk&nwR70fnn3t?1q}Olb;$BmaPGKk3)C%jcx`CR+Hs3-;8OX zw|5c)1vod)1a1$cc29Dow^*n7%{vRtWCt{5%6CC2D}#n2rv4}(N-nTr*kn+yRth?iZ&OAW>pdS>xB9|<|K|ZlRU3SbTBSu zl!KDeha+HDf>Mfo*>M)IVx{s?3w0N_JXzk(=Z6Aa5y!DS5Fd#HI(nMKF+mor_GJt= zy389dUbQss)Xd~z7!-8%$kDi-v+^^s2(FmE27*dXxK*SgQJli_GdAdsOBTf)6W#&E=y~^%O!?=9SsEgREwC}ha=jtN#J-QR zFeWQ2eX~y%F$!!FdUmoUMpahRePYMd!!rtvbMnH>`gbYu4Il1KVCYG4a4j+3BC z{^smhAaJQV9}n2cVAmH4_#NeOAZfVk30)VxJ9{e7ipg|Ly=R0aqLRC2X*<2srU1KC zth@nu&5FMzcrY9C&DNkv{%)Ei)@C74&2YO?gcuV&87otuIP*=P3jv4g)rlv<<;Fu{ z&F1&lFb>5rgI~pEtAqR7m&6gsi}{na!~Q=5*on=DLY{@!5o2Jk+JHLBSD3KwrcJOK zna*u!nzYg3tVQ>jfRe!0XXx8wwUGUhb+Svvprf-aa$IIJa4z-|;5@e6TvFJN$nA)+SCVJZiuJ>dE7#$zpzsdhopZ;N#NI#=tB`@FlOfuK)n zas}98rac6rYbS99l_j&IJrm<^(jdy4R~%H^O`!`FD2fH^d8Z~Lfqs=B|J&|CEJEeV z2WLF@ZdYNXAMF|m0hry^r%1blOy7uo->vx3F30apj<9+ahnAp@nyM5l4`RP*JJVA{ z2($*B;!kRJy2qcdIw#SLmWIWmP5_Ru;Bo@=8>&pU#@+MV9*Dxp~~UHkoHCY5wWb|v~bf<|DEPW zBY7YL1@I-esj&(Fxs(hIYHafTkt%Q`OQopu-HnzUV|DRV6!?6UT7OG70^)9#U%two zCWIQPno1xo5hAp;?G`Ghvt)tTQ-YBZW?KNCYWv@ z+tx+j=DIf;i4v9z1B}!?6*t1&4*rqlxGahsuN~mbCssf5m#*t}V{-$gjX$c>)wjqUry2;ZZHtdSwiHrX@V@-e+B?j^*ae1`a)^p5&%!MV)Z+ za_Kc(^5D7}rsKuo0Yn^1iZeoC3?i_qAA}J9+>zb#vsrAzk@#1Igt!5^iX6lTtEGLm z6c(#lw{_OYL070}6?+s_G%OPELp}FPuSd?w(38WDn^yAfb5$*jJ2mfHuwn0mYlyl- z&TDK@Cy8om=J-L~YPeU> zO%WKp+(vd!FL`Jt&+(j%Dyjw?$hPPRjyEofkzrqSNnv%BtIfR#ZIbh?+NfsYhEDTB zX-<`?QK(=V&Ys@%%I7~LazdHZkWIMB!cLtb@FY*pa;4?)T9-iiZfT}zso8LVe7iCJ z5`#jd!Z0CZFU#89HHeP(B6vQBUslArAjMz_fUK8ckf9>$)$e#zSk*V~^%y+CCJuKK z;1x9^Oy0chLiDNz_F0p!-;gIycHw#5C~@N+48~q2fWQ1QLy~jNsW6E%u{7X!N%% zI5(h8YRgThFx#ghe;tVczBVE3iz@EgN&GKWnqjt#r$h}bUpGWLV3MV^fzAXi$4EP% zj?fnsyl>eg3__b-o>nnd*yOR-_LDV3##^NqwxGBzo?0};f>&ap5IwwXYjKaCM>Rou z{E7{Fct}(!vYxV4lJaw1`QCYC17*IdtlJwiBg>Kyzrgm(K6n7 zZNjoe`iz+~>Fx;>?1VJfrjG0$uYEh9PWZP%WVg2QY$(B(L%UEul6V599t>=~zMqj~ z9KsAQmWErMA&^3N0t~v?Q|3b@{22SRSJcr*Bi+G8&bAn{S30s^JM0%WZ)lZi_R^SAbJ?H6CLd_2i3ns7#3>KDmA2gEE_KyLq5TM)@^brzz(8T%i1( zv7*R&(NYr|rA~X~d{H4Mw1As=5OW_$EUK*^rBy{1Igw%)J&(8f^7xlqIR)ehx)hNM z{sCwEqvLLgvKOR|p73b%HM6f6JlO<+5&d~RFPsmE%;S8%xswJVoE}a>a;oIKu!>af zSmgh<n!oBd0Dy2X8$$WA4;+|7wYhf=)D&Sq^iF}*S_Nu9Ukn@n@o1N~G$Uj!{dao+%OFCc1X{?6yli7*ZlR=hW zZ=w}|hHaIp*q29V87{N$q`_$U{M zHRDT+SJKP=%M$WmbkbtG%A=))+T&=vOqY^0>z1$cxF+vGas5pcmwT%9iqcICK~G8J zaUQoX03R}X(_8QGrX06S4$_6xqY}(q?E?y5F!xJ3Tow_uVCAb#AzRUv2k737A7QQl zy2FZXh)D`TmsG9-lnl+P*>8X)%=CoZL;(si;&a?wFf-X-83Kj@D9em(#5|t1y8H$RkN<#EY;vk4TZCqE6WTjRb?6`I{f%+bMpC%fFZ!% zp$%`*av&JFr$j5g8-U5JCJX-feJH%eflK=Ae*QeQa&-Z4vc4XL#%#ENanXqo6%}*2 z3==CDFJm+lwHv8iF$9(=ifjeGUd~XpFE;?DVRQY-nOyT;O<+2kf2h>|GHFWLPh=_@fiYpOasd*9H#=RM<%J&~h*s zEl~JXax`Y$Fwi498>1xD)gnLG=2ypU!wrA0GP2M-Dcpbw^AIvVIsFneiE9Qh>;6FgYu-Ey(q7JBa=F&Dl@^x!+yzCrb^8LP%U zZ5kt27x|JV>Re&9!yolB{HqG#8)dID0eu8@fLt(pJvB`lkr zG|*_D%CNTeCU)SmUB9cp>;@dVHKc=93u)RLUR1ZPR!`~h$ZmBR1f*Bo9IzOlk*v%C zRT!{7(jKO1J^7te2}V(EhpoRzBOAVE$iukK?$*<+&bzSK;l~|nbN~SUSOVYpZZ#`u zy5JcCd7`~*wOXf7HvX4A-xkYJU4H5BXfeEP9#9y+6h?Q44Rb9DTy4 z@#Yy~O=Dy^`xm?e!A>HBKQ{ICci&u==GeH6Vr7K9QN+ev23gYyd4_fMp6@)7Mwg=g zbuNz_1|aK*E1@ty-KJ|+)x4E1XK))E4&$Wu(ud0~jg zr`dfPq`)Kt5zK?<)Os?AcHUkFPHBJM@QE3l+GjR!^0^+~eZ_3=wRZyg8dv>5EsX83 z?9RN)(tfjIl>Va~1Lp@Em9(Riw_hHs|0DRGd5T(wmZwJPhipVpu<@*miDYoX=+1Sb zpmZh|c2=+At1Oh}^Ij$~^+X}DY$oH#_9`CP9GTm<8+7h|{~SwXC*9BLvGZw5GU%uJ zrYGY9UX_8H#(BFon#ui($cD1>^C_c&&H8|szkA&I z!QfhQQAJPDm=PO1R4!??Us2vW@awCe%+>q)w+yc-PVc|yCxU)WUTpHqIi^^ZHbu%U zR9UYJ&q15oA*cO1;B*>mslhS8v=Kx%D9_>yq(f?dmw%}J3%5UKs4?i@ALo2WZ|bwT zRHF<#X)fmSEYJd5Qt{cr?U%7a55}RvCTHjf* zruP3B;(ve`^?1hJGzg51GOo5#qmQ$(0o;1N(a*CZ(zXIh$5kefaVu5+$G@nLd&qmk z59qQJaHFx0jn=tshXQ2!kQ_>9B2R?bm`6!-L%3}fy7;cmY%y^=E6^=SAk|J(u`6^T zGn)JaP7nDHSoipES@-Z;bf{$;@GkGcKhK?>3;Q(FaGdvyJbuR|ttWi@IQKjI#YIJh z$I0HMoqnqZ_09gxl`7&{^*bNjL*@eSc*jjbnXknqHbouRkazWVw9oKPbQj-Tqc(`rlT zdC$HoLY%vbHY9G~GjS_p52mUzv5h-Cc*J5%Me&F2oLsWz*457EKfDZter0gxtVrfI z5{VLs{`#+=E(%XbQXrkpR?k0MkNoQ0f0>NP?&-bT@uRe~G{#lspy~wxYLq|u@kG}7 zfg?$2s~V8>fTQ*0d$*}s!atl^Xf;DZ0Xe3=ghX1x@+s~n%R4wO%reT z5IwN%GPg-b_WKE32fb{FO|(^;{XN3-IXapqy=5-=PCHkK8fjULg5L!&$n{s-A39lP z?kV^NZ?`FQ`zb8`5 z4~iB48Woe<Z!$H!&%s$^eQrh_y*(8Q+SmYV1&Yto!+%)(XrdnPDW4IkD1(%6%|72rQz_8h$8t~<+*}0 z-FZR~({lHB^D_O@!w;(hs)lm6JaokM1FHJg75g9bx%d63CHAbtfhl?)qhKW_UkI7u zuDsXk-gGD7B_?{mdJx;Xi5BU@Up>J7a5z!& zp=o)tST{BXJwKwjYC&EQ4(YGJT_`xT%u0V0>YMXK(S6*PnrI)RHafq5`diHF5P7{v zcyUti6S&DjqBttOpbzU{W@FYOZMZ*ltBOqz!gg7lfwr|)Ws zrUqDZ+w6cDe09V=dJi616d(~ESr%Y4E4Rv-w79dqu!0H@_kF(osQp+^UFQqsa^>S*Gt>3wTC7=ztJxuE_nnXP0;KLIh{7}ax!hd{Mq+V#L~CZsP^H?Zugk^ zU7Z{g*#ZfOOaW}B5pQo&Q3)&lH*EDV+NeJvbJzr^w>MxD1Lm<4!>_)Y+|;}A!3K1u zgoJ%)zOJh}N+$#khS&_Z8TaTX1o2!?dtGLR#lst1p7w}%ijo;bXq|QmhKH7q{1}L5 z%u?BnQg`OK7x?h}1wqgin+9CXKl$117F#El^H;dARM@z=3D?ZZ`Dfu@nE?eOcQWtF zO;R;dK!6Mw3Y>5f%zI`=^jm7DJR4270p!ykyyGYB*$F6{q1ebqzw?T0X#>~(to9_b zZ8hPH@EA3qW^C7f1wi9uA|h^ z;Bc69bv0N-!K}1uZmcC&3(@D@8w|y5$a`O+?70fQW_spi2|NO*#l;uQrn_qAgV3H? z1v0)xpY(1YrVquaDsV$0H`@Eu;-&1|F0{{I1A*k^wlX(qb9D6cP`gbbbfgPhaN|*C zYp+4C;oq0d)4yG(`*O$znu#MOT(#@4Qz_KkmCpHrE4W8dN9GR(&|g@hbfgPz+c2Wj z8$mgN8i#)tMGlUgK3T9>(c%dIqVis0`aMTl7$2m4eom=Qyyg_oSl;Kw1v+AIX8#E5 zJHXf(7TGMN7H$7^*8LuUXQ1?b-R23_dTe4jLBD7EqO*0j9YTe(~4*zQQ`)u5*8Y0I$(URjEl zCqQ|)krD^Kjy3OJ@dvb_e}sCja$(0BU5>&|1r~1~&Z_bX4@a0UrB!YVThA7o7tGBJ zo@mnJSciQ6JL4}pQDvrm4MN2Ds75}}uiKlLn(E(dA5wD(2wXya4xCu$aCYT*d=!An z`~Y;)OZ6T&3)25q1VDfHyObyv1*I?O2u-N|`W55+{aWSrE&v_cwflOfdn3-!fBgGJ zU7aY@7b+rSji;-}kYnIFLG%>3mbgqodVc}; zHn5?qPNu}pMbK%|ib^{|?G!-8T@8~f#Iv;LZ77d8WgQwF>FqSc2_m_>AjAn<){E=R z)WM`_QS3OuqlBY=ta&zP9Qw%)%Ami|pMYn%3)c7I$?kUlo>x8oF!~o5`B6jT8)52D zChk3$QYTnTh1}J&$xlEV^2~A5opuhZ9X3C>SyCUNT82=enN~pO$KPLJ8_XOlYnME4 zd~xBy>@Z4YHvS;hTVSlJ^r_1ISznZj!y+s4dNi5R?)PQqs<PfkIIvZ!y>nWge0lZju5DZMb`9Q_)i-v3H5t}y zn|su6W%TfBiuBP8OlpfL#J^oZup8BZUKS!=%MXJ1^L;iK^(p!g9mq1y66&yt@+mvs5c?9=jYD<<Dg3#9E3h z*?&!{vP}AoDa^0Ck&qL=yE)2`;>)fEpG_SvhOX~>8T z9(}Kr@XCI?(4HC8yKa^29=%!hW>aZ1Kp#oOiR{&q2$Yw^&0C|C>%N<{>An^#6k=ul zUcs`8!2*v#yZ^~e%!(E~-dCYamUC`yripJ)X9;@^wW&sYIl_vo68+}pj3h@@igpWb zHXAHOM{l-Dkl$sFiq`nTizqe@n{CD91eVSAMvCo5oO z6sdBK(~KW<5iqSyd$;~vH|gi80}qaAV5$y?2kbJ`GvWj%Gd0h<&+^LbKJ~o2i|o+K z1IMJvDCHOH*-|l=@t{*pXo{Ocd@GJLCq;Hon-+UM%x}3pxRC{R%V3KyJ0|}}IeCf~ZL7UtK z!Tj&{E&KDnH-L)5n8532&pw`^H>D@r(wn|q@&=lQ+Qv<_CMp%onsJ6sB2Z#!sT9K8 zwxArct3;M#DEq$JK0ZE0^(Z*pI`)#6h0j4wht8-^h4b(G612TdRH+@3KeO`pDZ|v! z3FDx@`|$_>mNW7e{_bjahQjXk!=(IcciPM#B@*Fuu-e?k#^{JkA_-PxU+RM#*W;=5 zpf))GumZFi|9)5t=wOV8>*_>&ZjW|x_LM+@EB0rn&9CnuLZ9GtGKbkct2Idvv(K7S zM5eYHS5&HPe)+W&4jM!wiV$+jS8`JH<{hxr;u_q6?R=Ob7wp#|FF~aXW5B!#@m^EC zMUUAj6qqqE7V%nV%PO&Z6vy5G4BmUG3c6quW@=DZta%uih>6Z=i><`XD~(`kbg3^R zEJkM78lb)6U=&Q3{^%+M-_}x!I}6x`LuGZ$n>diz3%vI<2R}JIYUp(!96*k!4g|Sy zD?>gnwVrrT1l`o*-lmhH&tEqoV-CYmtm6*~OApPQZaHTmp4-|;UU}WzX65}3a_S3H zA)t(sP63=T3U-kmOxv#72Q~D`P+0ExFOF(J8eInc$5J39fYJW4;}o?fk(Y1hm|rvQ zBUBLXcO#v_D&L9l-NbWpeI|asKw7rk(Mp9|UQT!THyML3J?Qsxi+SA@&XFY?I>A$mj{A&R|@y@k=(O8E)BOP4RLHJ&h5Myg;HbN_|*sdtUD_aj%v`s;TK*B9&$3XoN+L;F_%}h^50cM zUlUvw87gmQKZApq8t9t5Y$SA(Wn)o(=9g(&Y>3VhLV&hZ0UUL5{Ht`cN zmQU~`)0K>KXM}@kA?dBBun~qP7PYZ*jeZJFAGaNL#rj>F+MZs{aA-j6U{NR<9aZG` ze82Z3{)dTl72UP)Gb!KEmPpzO$^2c@b!``Zs>HUz>h89|%IfcFIAOM1now==rmR&88|-IDxu)<6-Z<64w&B8V zcJ_?Z=LFjDvKgycv4%P5*o(qq?~T0f&%SxIaC~s21iLfv`Bh;YJ6VW%_;+nh4PEaK zJjUiWwR}5DuOL_c1tg1E?wqy)J}xxHwXf$%jV%GjSI%Gy@4Ve3w9=O-3Ofd)fSFuT zq(?*jG-HcDpkmhf^w67rznpsM3X=1w8a$9q0g)Won}`@hWwkfZ#V2_Vel>#jWcMld zjC8N7NLuuH8P8w*p@x1Tc!McX;d`Qc17_yqWTbc~um1=6wU#D4pC*@6q{_G);%0`B zHd#MKI!1Td`fxY9jGh5k#m9Qi~3e4v1| z1ul2MQ3Gg@vy~`x#i<&*v79yNs5uYyw#)=Ou9}*=Jh_0h z#IwsNPWZ@3Pi$NTSj{cX?;e{Oe2Q~>oUma3F`GhR4zX%F$QbjorgOYHs+f~a{ls0M zXRkJ$UV7Pg;6yTA#npfiHMAT3#}~&<4YqbKIG46o=4TGNHghj-77g=M zC8$TKG;(>gMaw)LFUCon9c+AjD+DG)ito6@AW7*P?ARBk{Kx~KpSfd*winF_SUMgH z^y1T$y*{SJHa0e??A&-;b#xJA6+Z|~w)Gfv*I)hKOioM1NIjW-x=!wo{n1kDXmq@`e!W3uo3gOWG+h+85` zKr!j6gvC!9+SZ^yX&O4+H(3o`OudbsZ{ovzZO8XYwrV7Q?StKafeNH%7V>eCB2@yJ zVU>yJ$GgXg zVIgE|NZmjAltb5PH8UH|$nT0?X<~OfzsuyN`e)srM{-tL6l3=Hhaq+0v?9fAle{&S zD)AB{eoFqq-U#bJL`Q})z9gl_o;G95!02kPDDt5ck~8u-9LVW08v$*}Z^G(VW7yf{ zw3tm*QshQ@m0K8jc>?Dz##99qi9Fs&k!mchoxWbO$26Qk@E{V_xW!wh@{R9vU`<@M zFK#FcBzwFBnr-4@x777!yVv4#7G(MfqvfFG8I+5p)PB<`X?s04+4gjW7`s`!`=vB6 zHAjA{P<;^_b6fRmgt>vmjDwM0uI?OEaPU~`nM^S|bu{O_!UFY$+R;T~!APgg*sNuF z2x|qeB*F+dgucj5cBt?kPwEGjtSSSi$ zS+OMAYUiI^$W+(z;dX1Yz|-{ElXwfZeS)aN zE~i(>g?W_4S$?5HgAXZ3|Jv$dhYbJwnc*X|vF}RS1goP^cWy_Ssgx9swVwPY>KCce zAYn8s;WHSK{#@WFhw)g12-16fmDypov2hx(w($ekXl9-UF&EGC_%C8Ura>ILv6+Nq znpU7;E<5U;6IbW>YO&d7wC@MJYjeJhwLsO`W280Ddu@BR0ADSV^YZi+!*eFT_Gl%c zWXor6E1vWCQ!URk%t5v?0W1U?7Y?U{RLh3FZ1NQ(CoL{eF;V|>#Basy#V^;r=n@n{ z+A-{@=yFtQG{#>jIoBWcoa;?oBI92CWv&O7<_0`KJaI!ch8g24+Xo&Z(x?w7*sKSAh6F~QmBKU(S4M@S>Rw|i9J zJJ@SxR}uMfPaT<5dKoW)arTbE4GFWPK@vC|>-ILXntN&-pGgAI>h%hu1Kioj5}sP$ z(m0j-3fC6){3g7kW}|rCe0KHvIiw+c#@W>BTU-1S9-pNXh$e2?gdFGUzLEaC81K2g z3WsJ4gE0uzKXqo_MFulWUW=uMtJLvE*Vo(!fi4sr>F19Fb$Y?~KS~W1QT&`mGvUN) z+l$q-*TH%HOJ+(z=IEnWF^@|_M?z92Lr(-Oa?r{^U9K`5Q-|*N$CTY4&}1ZeFF+eV zgD^M*I07b8_NUTj{vkiBZpHV<7qH)1rT<_P3JYjhU7}M=@Sk7c-Q~%1XI5!J2INm@<4E@B=Fn=?w5ZVwnsKWDt_LKn&~-M zHgR3Z2V)d@mo1oPfPWnQdVa7%i=CH(5_hu#7Pz@V*lq?iS z3GSN&ytF6rk=dE8XWmOCo;s@u1(J#jl|gx&zmRnm4r6M(ev|S_ZDfZ!XPIftMUvU- z-GfcMy0en~?Htc6(||q{DekIdb3#!LShlKUt0>2)nhmKG?KAKM-l8#i__pxs_{Xa< z90Le)jdtCNx&s~!Vkk#)9ZqTE8)PP0KUrG84Ab5#zkCSs4P%>7QMX{5Rbcq|k`)D@ z`CT1|^VH$HH+XM&+@*+2 zdF&o$ei~lw9cjci9|#Ld!%1u<$m*4&>eyIptTi#{w6?7_@x0oE!=nY4BTdXK0Afp=>-kPx z6j5rjudQsaD#BEGxLRrKXbCRAYT(>>P4rO*UQzRoq(`?m8)GRvb57s#lC2=gllpjR zSx*OBw5x}LSiBU~a_UNp|8u>oU^U9~| z*#PK=I*^_g`MI{szd<6pl9Jl0CTZgi3qF1i#rnN!oZu(dS`#Ze_9<}z_v#vo?NBtG zEI3G8lXIN~@5rWVYNWU0ax=UQxTYfqohXa=%eG0DJESOaV(LG0>`JDF!@(54xo{Qu z8a*4AK3+!tj>=>E@kH0r!Sa*ev#yzUBwI(yZ+lf8kSH})m-6FmDF{vp`#0X6Ew(c? zY32qLhP@GnM3o^C6EGM0M8BH3-L0Ukdt^H8DjxZnT^y`9sgEaMO>d^`4pFwJpWXcf zaI#~rS$-Q=<@jpbZ`TF!rAX6~lGMiPTx|_^Hsq8>#$o;Pw;k3_uFkbI%=GA)C)`<9 z@cJ41F-=SAj>00_>Z24{M@>wLfyGE^BSVr*U;eOFhjLrJD>2p;;f9|zyq9MM*O9yj z?T}eNTZPYe;$T4^w=c!jtJUUSMU62h94aL zIdpEamD#+c%xJfBdP?$+Y>LiVs<_p!Evp5UlsQTWqv=56Y(|keNE(zzHXIux5!p^= zk9_L3pED}`H1(_HlyUx?H!flM!(?@hQZT$|pcuSV+q^XM9^?wW?vPu-u!7BlmbQW7 zkqv@GlC*K*{^xQhM6%Uwx%P-eMZApUO9oSTVR>uT^vtIU^KzXOCglm2)%CTatZByn z0mog?#rS6F&ARMOH}o`E=Yt2)ius;uUYdw7;9J_7yX3cef5^sU8w(&(WnXsJ5ESFC z5%Wr(K_G7zdZxdsI1jihlB-MP_orC#Cj?Tg%?Wd?_?sYF-59cUuF^@Ua*_-$&y&uu zy-n>3Wfu1abpW;>FoN2awT>D2pVQ=dRYmd3JHT%vj61YA_BD(Z;=p9(=8rJDnI2}K z1&%|}O9$uFqj7vWF9K<{Yf-Q9Z>d+%+W3(u<#A-o^u6ls?|*Lgjk#a#l~>Ejr@3lc zy~n#^caWB|-5+%9Daorp%_E*aUQwGp$##jzyZMe$s}g^-K-uwIL4v;1tXuDi=E221 zFf<*mIWw_2&NW@Ix>`b>2V2HkPQvhZe#eFk>%)#RnvNAAQY>@_uxV6xZXjX>vWM3f ztg~`OII+hxMbi_PWPJ(;?MO-Z4Mhj%}$!hdyxNcrwch#V5a(kWAGqBCUO|HP5%kWMUHVwU&HApHT z5B^GxY720m_mVa>i~5wMRoZE@_KR~Sk1u5?UPP12x72$PS6hCw2UIcOwaL<55r#5N z>`IQ7tTb&mbB_39b73`ifc`3q26y=0^?0lqYj$MRnwX@FXcQQer*RblMceS13y2}Z zzy|E1g9y75YuO#>%grv%Sa^d3uwT>^ohbLtVP_AR`KoW?Q-}IYiE9ozn)z*l>$nU$ z%Iu|z?QMTy@V5i`C%}dBfz<5_NZn}bk17v(FTGo4YzZ)_3=pygR=TokA)F=$D%NXrKIqByIqeO`3h zoTQItcxZ6kX104(+H=d+<0a)|>z>mbn=eBy!O03f)-*;a0+&jOz^0B}{vv%SBRvJ1* zf+n*UxdMr$5k%JhIGAj#M*;ntVtO>#^jsidf`F}j!}Xr`k7!y>gKDOg zt&XJcVhx%w)01W%|4tQ{qJK4E9;^rt;|_r-sq&QnuiDZ1Q-{@|fp61_O->YqM03%T zt_CXhd07toq-dQZ;@lUiY_4z}<{We3v~Lg_IMHXsm)#`aNfZrzH?zyoa@%chbLTKU zuaW^{7%ro1-gfm;ofR>yP(px79ZlxjT%m{FKT2;}t#(;c%*P7UEn@ZU$KN9ML1aAA z&tUq{qSi?6hhG^7>Z{Fm`Q*qvxr*Q?Zk4-uW3#5nJWhd*_p$n03eUV0BbRu9eM}UC!O)0*m8oaTcxYTf z_NyX%c$P?l@j!0&SNA-JG}psNITaJ7=mU-WV_U=F@$!O?uR}~#xJHP%6v`%ikU7C5 zaK!rIZsj0$t%|X{Q!a4w3Zl<@ePJWFRnjit8JMSsB@4c669FTS*qw|V^X(>S-4_Dk zjfqNUzkrjYYY|18CE$k8@ znhgi_DHi@5Qx{rpyJGH84jmixdwkkjQ(Cd%F&C405QD<*%=Nb^P5WkYL(#+wFEV)W zp}X?Qz>(0!8bT|>;IhTr^|CR=ihs)XzJBN{debAQyBm|;efBU7X62pZh#%aJ+WlxA zS?*--<2|y2S!yQzQn8mvn9(fq1-3TLHCY{}Cytt2j}8R6 zzCQj^d}I~hy?ZMZ=J2Rj)j7hSw;vHZt5^P1z65CI=xmNS@pw-gu8xJ@8Ptn_RZmD% zC6>?kwQ66xDn2xOEjmpLbo?iwcrmECH-_+gs$v}AQXWqE@;?VM7I(7xOG~dZB(T)% zbXApSSkNjD>dVTKnRj~qVr0A4c$IrcJPrslVw{S;SmS>pj+;st%SbM|Ey;S8*7cVK z%{y)qKrN6WZERq@^=s{{=rHj#aTSedmx-#`%Jru7)RrH-FTE5OvN!5tN?A&RKtNIO zi3pcrRM|Octwq5&YxGk)>5BI~fyl9*r zn3r*ch$QACI-kvqYGUIo1vQEfeeaxp)}LH7AE`L4u{zl63?i#gF7IH|gWk}B(;)L$ zPAv3D#+3EcY?LJL&FX+-ZR8P62Z&RsRb5~5eB=Tvo!5?A&5!EF>A$ zf)OvX62%L^Qczm#DyqDaZ3|@`DlHEh)rg`i#AT!$%m4ji*6;mRj;PmctG{=NOFk7_bX2n|Hq`*K>~q@ zqXDRv>j~QM!hlqbcn6~wv9y)~zeoNRj*o+;*utFOz@27Yvgg)k5as7~emuX7qS0el zsxy=O(FezDBpc(uzA6yYm%1ri;Zf63Eiub4>1S7KysUBf?Kp1UJn&KcXz$R-XiW{L zoK+%cq|G%{$K1?JqOW$(S)(|W4BGhUTy9oDFSo5(X3apme0$GuPMN@Xk;j06829w~ zRKMh%>CqthrqS zQH1;OyiQ6(NlT;e z)=sZ#_iOsb^*K6=F)MEdU#_RXGg2#EhK(d2Hy-b)wT1SSx@%Ee7YW~VBy>ojzVU~x zLIxZ8Ag}$BioM=rst~@2Jx9lJ{Kk67qfrO*6t8XXim|XG7a-wUb;QRzQD>ekEp~TF z*}K2PeB95>x`~^a$&cKOs|}(g*bp71aJt8Z>y|%uX0q4wkN{K(P@ez02&UGN^cR2d zLh$VlP4`tuwvlQpucJ!qS=96-{`EzSSO>cjq4Dv`bHS!}mRhS0M3JBw?PBgZrlyT9 z`m_Mc9+9W)cu8atN~gL&W1JOty|D1bkr`RR)L+uYV}@q46ZR0a;QhOGF0E;4tFq~b zFz|q)#!F35BZESdIm26rV`y4iaWiiPE#5zXcVMJ3%f9BG?W-z?Pb570o5>^N1@tVo<9catH!e$d_5w5-$ap@ z^9l{)Kv05jqz5)#G~XZ7Xq_!iEi`zX`nxzk62?8(e(i8kX`{7`I(Tsd4L+AvnTk}7 zyhETs*|!R_PO(V$8*q5fe^SNzHwGVE4Vza{u+bVSAOxys18@jH>krUWwd8+W9Rh>$ z2DQh9)Q%>*=u>uP(_12bv}ypUXFIKiK7ku)go8+Ftuc!i%N8O!9SqAnErz>d@?O8t z8bBEZ`62J7PYYUIxp7@Y1N`hGk$*r8vpxbDq>B~g4T06Ed&H&~{cX+u0Xbd!0s-`h zP<$_-6);fSV&6p^sQ+^QrR&9o#oI64KrP}gDCFMkDV)Dvn%3L@x1ZCIsjKrt9TZFd z4Ju*zDtAVOPX2C^;8_$5wJC{$UE5Sb!HP!yXUiMF*r-KwEey4x4hp#924X(!$xb8< zL!eLOKh5%g8p{9i)W2m1{?7y7dVMqjB##W`L5_TyVz)%7x5|kTI>%WzgmFyrd&^>p z5}gd%SEsRTRp!6n5QMk@8V|q`pjr0^5)yXGg!Z1Z1`mrO0CxE)A*#J4Hw}9bBl}rU zZgY3u+_&zZ7u4Ums_puDsS&mmit_D<1^Jjw|E;U0h&w6RtmZ=OO!Nyn4dUo(^!Jy0 zeIIHjXP%u{?GjW`8vkc?CPHe2IS`OF->_53h5vXxQ@q^x{9naAHXt#ny+A{0;0CB3 z|K1z35)IYSl*&1YZ{mb+-#?tHi{Y6JA0`;{xKnOmlC&$6H05W$&XL9fwlV-BvXok) zUHmI-^7kls1e7-7&=xuN_naA>zy0#AMG9;;vc2rTp`KvX0yg}gAGi#5RIL2z+QXc}VY83d(*GN$ z`7g8)^?y@evTXs95~K;}5{zI$HYNWi5B(?HS{c;WT5dSZK5u+7AJrVs{3kki!e*jb;NVWK!f;}-Y=js1Kj6P_Wf~5%9kYII2r^ds!(W&)2 zB|Uaon6>p2PJGfGq93uS2Y-g)K4SK{+C({k3np{cb<1s%II|Il?XiWXcH)3Ee0*d6 zm+(~C{kMSJ#aoE}zcIT|zDCVQYUp-v0l+@7rz&AZN8OPY)qz`rb_R8INONKx3Q=Di zXR_`<0T-dR;pj9_aP$_bE-43-aQYG5mUyl`Nkb|!lv4GZH}r2%@?UUcKramFN%1E- zm8@8xow1C(&(r{mhx*`8055e+!gdml=;W7t)k8C6f$U=$HKZIYB+DCPAZk^P4eoDjb`afdlUcS+AgSWJai9Kue&JrLc9@SI!X~%5V_4~GC zEcfge2|w-;dSWcppf$B5@09$)9EE>87kzB$?ipb3EA+aSGae$2_d=&y-4rb zgMn*P%0*e(g-A;dLPIwyBeW1%L;=5=?iU~plRJ$J?JDzgU(nik%OQu(FxZpNGDHXma<9%73&#*2la)g{#--YEfXz9P#ToVt_(hAPR`P-=ciZ+>g z{QuGQ)nQR?-P?k6_fXOuLzf`kCEZ<8l0zvW-6-NQX?WF9Rf;=bbJpU z&w0=Le%J3$u4~xO-fP{f?zQ&w$Toncd^WKEujfGn9sG$nYuQ(8e~k7)H=?xsFSB{B zmiMDbH9`HPocZ7wPU__T4P_BxR>p-DyL9n9ewhp%rVF$@LjM=xstK%lpFF^WY95lA z2V`cvEB8UMqVHj%mc&_WSIb@>sFz; zs;U^RF0C>pQCJcv*2}L-2ku$OKP1FkqzptbqI6OabtNc=b^(w~VaNQCAWWD}abLzb z%}S<(i6Pc|`Pqd(VrSS4khMY=UsUM517CKV->vMA=tj(Ca#m7Ty=#hRnvIfgL~ zq28aX9F3BZo7SI8;lQ*oBA6P;spe&x<|S_G#Y&~Kzn-1y%WCLlm^S*NIED?_>!&e^BE_$LH1Y40e5v5r7H0)+RZh;wh4-hyHYBQL5sS`wHcygmvWxt8A-RR2JB_s^{n97kFCO}DD z#Pp=NNF$H2hOY*wNh1ZgLsOuSn|UFkUA1yu(K(7KaagdAk$V*9u}pKf8gu?Ik~^+s znAySml(U>+;xocmGl#78N2o{~Ur@uOxy2$0>{NUS{YyaIpGpFa0v_RB1k>L4F(hB_ zZex06NQsrMZ%v%AG@^4SXawPx$Srs0_3yZ9piD51uI)eWVJww(gJH-*M*tC7&v8I# zZ+{lNE>#lP6F-eb#Jl3JOOBT~6D9K_5lUK`NLLjote@1ZShefY@Se`mG_jF0%LBVA zgKsl+jAKPuIwJPO{!ro9fg>gZrwa3UodTi<+2?scc2bXbhIIRq^7Hwm3`wobD3vMM zB_8L6dP-VDO0x{+n+eLUMEfYfFrP^2IJa<%H{{@QH484m>oPSh+sIgLVkv=xjjbVo;j*dZux`6?!us|^O zD6U%8}+2n7ounL=u)^0Nn-p6iZApI zFZ{)y>1g?5^JZqWd{XSw&yU{5oPFsLe@6$3`1zE0>gSli6QXU&GQs%iKErHn!&5#+ z@L35a#!O3HtM9(3iV-Y!6Ldnm}kqS1zIT@jUO>sx$0A01;|R4tPS4q{3D~ zuB{UA_ln1dUc^SIY=c~NYCN@hG%S8huG+|fR_nE=cf-Sk*k`{;9Tzo2I~jpzf1PE3 zVXdP!Nxo`rI}2DeOZ*yEouv=mygAN8_W3blTR>rW!FSxbXr>!@qhh&osLz&2R7Efp?+f& zIOX8AZa@xNWUE#64R0X<%Yoq?V9>54 zllhIjaE#ESNI-(N?B-G9T2{I-BqWW=>%%7as29nZmp??(*GeYuwa<(z*+iVA;y{ty zov6uOY%73(2*m8)p!F?uQZ6uCpH=(M`jf5T(ecjCLKS^h)bvg=PXYw!!DaWZ_YlgPWs8q;?FVq~S94VLCHd^RnC%W0S8lEHHC+A`fYlfz8~O}4ZWKY+ z@wltJyQ(nJJS}09nqj>WuOeCnB$7#X$??lZqP$QmZ^uk$b1-y#(D80mkC zWm55L>=iqe4RPr&Hvl&a2dGZ(4CLA(bm-ap>uPbfgKcB>$ACeA|CoC_{_?4#*|R^wzY8DsG%wGjKAD*Oqbc|lVzZ`h(spCn} zt&DK&zsw-TE7A^aOmupZO%#rw%5B_l1oo%KOo1g~K_+7;C_lmkbDGnRgTi6))qVfY z5bxmX%=4H*Q#m`8oasTV{Cw)duvUbL#^-azS zkY<7{8z2>T9_r5Zw@)xc1TTsC-gyztT^PO>Xe#)Y>)d^v=mSNJPN}QmKnR+ZbnB3~dbzY!=qV!_*Z1aXL|qPu78;ey7rkcgKoY z1Q&}i22;ZCQJyH6iZ`L46?{0GIeATpuR*Ub`Cfbk+lPzou zMeN$(zv9a(XEJT8{^;kA8_AoCH-PWJaC0X8yb02xCU0(~EfgvrahX>N5~pN%O@ZYQ zkvF$)gnt}>#I|fQlg33-I^YL&tPo_zQA~p!!~@~$zTY`b2OXdAGNjh8!jTK9MY3oz z5gQ9*Sb?OBLoe&l@|7R~z1|&1gfzB0!qd-N1IIOtqL@aVLmwBK|MX>efJ@{5M#Ef$E`|yY>{65?N?d%t-ZwqiM^pcl&MMc?7i~)9z_o zT_j^ASTeUGHSJb)U+E644(Pxoe&r#DFJ^?VnXG+k!>T$=;ooeC$C9{cJoiqEf%2It z2D6y9PP@>Z3OUzwrvsPG-=76%*Z!^ORab{-TM2}|oD>ri zmqQLG$IdlimD7Hh>Sz3fjFumxejtH{iOTyTUsQ(eqdm~T=Ns^pbL)~A|l4To}iND>slQ$qZ+`6XSj=gC6rd(D^$yS zgFN}8L84&Lk-nmS&OGTy{XxRcGx-UX+VCfwaH+rd2INGacK`A)KSm)U0K5ej!+y#Fbq{loQdq)}E9Tbt7P^Ke1$QYfgYH8(6Y* z(CY6b_!-0WuN+&Yibe>9xbF_iRq7c}F{ExN7XxpIA7ZO=AEq-(5;o{XAFE@LMOO{^ zqCl14ln_DRcnv;6*0Jr`Z^70_J~*VscCqD*S=-imc^1a+337%6E)A3wQ>vg*_F^Ua?|vUi zox=2f=$vFdfMriKw zBaGeR+!;!zDA8xfTS|w|A3Sw^PbTiUD!-cmeDH2mX*jUW(QrF@(ofd%e;>K01cwaL zMnl$;<$J%ncP&h}#`o2=RLLpFOd5eRKgvo)X`v=`>ar5JEWHFiOA+ays52BxU!l9( zuw;e$8b8e?FaHDZ_D}sB`r*$QV-Edwzy6yqnxrjuEY(eV07D?`&kk089S+It1|K|z zs|ehkjQRK-;9ASow8?bl8YlBpF(Nt*qf;GXgf~<`BajFagw`v$M(9HU-<{dhw+sh7 zYp0j@+=}+-^C~fYK3yO|zto5})BL+`^rbC$H;kw2v@P318>MkgXks|-84;d=43JAH zTD&X4QViihRbC1N(0|b(0{GBpkA{-GED@+7OlS40HLd7L2wGqT`6<#dIgF@=toy9v zmf$`u|Gs>BalZ+b3M@_`;$12HD7A3C$UFjG_J7iA^H~t+GJZekSkC(D&Dj@r-O|Z6 zpv=P)aGowV@bAGF@TDk;yEoR@S5crfn(XU!2*p>)l1jz>9{}5&8ovOFp@#Vu2!()y zy8Bh#FyCUyHFlQeovKA2Vq5G;_3gi%v!9eUPfTbR)h`qpHflSYysM2sQ5FCA{6Yha zroeBr+IyyOt-+)R?PMW>HxsjS%r8vaJwz`?x2B3|2lm}7wO`-Ff^Oaqn&*9g&n6$T z@N|y{sN!N>Nq(m+|3v~ENdrpaom<9NEIoAC4Y^zN%bonT=uBJOs^gbdY>yw5VoO;Z zFGS(fY6`G;R`Li2Pk{Tqunwd7n9So+?EmMeceYBS4A(k{UNyg3ISUz_0pIr9KhJp; z-Z$l~-0IrBUo~g4OVj(2!Z5_~-o}24q|NRMek>?wK>7bOKpG=B4y|N|%?;odilJ`uXYZ~>)=p0>xzt?*f26bkNM!kMB+4y(s0C`Ack7|Bcs`#4 z^fl3ij;Uk}@RFhf`KhNUHPs041`EpN)1SH>v$xR~`5QH%LIs|~&hjDL(mTxm?WhYG zAQNMC#d;YK=$C}K)#NDJg?@@#ubaZ-Vt)IP^k;(%)Ocl?0)Urs@P{r%FO7vDPN)6r zq=W*F)>#G_@^Vy^)-iM}t2|wKnpn&`qdr;O)osJh;p3KLDWcDepc9jGzNM>^w};=Y zBBPO|qVVjtd+W9V*j#?N<2H;d0ZQP2WsmR*NlZhEN%8Qg>r8GnOo~Y^K|z#SlRLtJ ztZ#o!^hz?yv9s`2-gkvRk*~Mnd`Irt`+;a-!2&gwdSxK`G%=V5uDq}Yxt;`3HlOLI zyD`t20M{pf!t~*WIkh8<(rWl`0?knaZHu0$Adf!DMLn9O$$9#YW1wXQqY~%csQq(& zBCd0A>*I{0cls9w2`Pv#G}EA@0rk-NrC@tt$6u@#;$iVY0O9hWR27CD>9%(;w5E1N zf6fE1WAwOwyngSd`&fi*%|ld(jtq>oCfE`9ZIkL9}xz zkaJM4uA-qdJTKu`x?>qqQp+>~8kaxM^&mjO7#}Q0!5V*s5%yEQYF*Y9cx9!n+_FvH zdRi){Cp7I$%Y!5WGcN|E_nu**=o_Xe>>8)m0ut+91!ggw<;oszF|2u=IM2tiWb?|O zi0;#HIPopNB6I0gBVawyG>k>3#qHe2MDD`LkUwalqZ3deaAYthNQb2%_i%h+C&-0rAI~Ecu!<;qz!ULNjrbC@LmE+tvj7<%zo_;QDHjG*Y z$}}!tLuUa~PSZ*^4C~KD1!!!p^!YTVB@T{nzJw+7olc6C%VZ^ssU@#kxs?su)aFBR zu=!E_=zkV4jV3$~bIq`fv7{RcGh6*^Nxx~xRf~0(SyKUJTKfbt(B#O6jr_*>(3;#8 zA-k6QQNqy%o?BOh6u-csQtAE28lx+EK?m(KkmIc>^TX%O1YO=1{?@m0*LVm8n%JKG z6=hpb&D{+OyJWLKM>)jCW4my`;W}%;{kz#S*ziRkY&fkZbgL~BRIhT2y7Z!t6Y{0~ z>;2Owxq)p;Fbi?aR|NGFq!kU&6TQ` zE2H4B=osa%N~7nZK)qYTY5AK11j11w1anL+tXj$qy=r38)txu!8;%Fwuh6&ic6WIw zPyuj|R=updb!HTCB@VuAfxWPHE{r8+MYcd$Zrd#2 zq#q{#+Uq}c!+K;`LV&5zITX@mcqZ%i@l|*r7l?LbGJQ5_`0}qngBV~lD>t3`MBtt+ z;S<-&f=EPcX&0~jFkiw>1q5*yFg5MNx`39VD7Cm+qAKXAViNV2B$Muh2jadY{751G z-hXH7`J!4X7~6IzfmB4L|IBkOGQu++Cms0i@LjgN z-CJRGAo9Cze^Ma?q~{vtL^8KLzOh083Nq-$d{LZOXGEKUN{q`qq1r4j?2+{dx~@jG znVxcQVAD@=j8V=#oBq2)MeAAsAt1Ea?vG zZ3XVoz$~EoK}){c%<;gi+JoNFH4EQCJ=z7@$#VExK)_lDrvNP#^h8qj)PPzXpfNR_ zpxYg|F(6Q$?h8@KK}xLH5lE-jCM&^uZ! z)cWlcm?y+V0y4j=@V9%GfOhLiegMXTq33Tx9JV31PJ6d(7vnVnaAuzX9I?7A6;W!08a{Eb*XM9-N#7g9&enn*J;u@Ym7+z2Qp^Jj%r>td()@ z7Q`WVgA(0W0iWDIz*l};cj6IQGFmu{_7~^wvQ3ot@?Mfm0q@g6^dhQMgGQsGW?w#% zlHZzHNvFD6u-dj+IwyfX=lESl51A-3+=e^eT9#jt2H>uEi0Wr43=6iMY5hi(xoTE- zmFVoj7@7a|rxjl3b+%A@P%&Te(DF$t?`opR@`B2K?ZxIGKV$4u`H;Ys@3=Z$9n?ZrUy%zyx@Ig*%l} zBmf!Hc`z0AJ1;Uka|v!h+Um9d&kAUH#Rworfi4c9QdbD~2Dj2aCGRJ>a7yjbte4{;`fqN+5uj4c z59l9(7!J^JbwKF=G@5{uD^XF74q#5*gs>&P!2pDvGp%&O_^5xb@8!c`e)*8k0K4eR zW9~SzCCy0R7R&2B&LyxdTW!{htuvrE#qrxCh;H0L_&0Yo_3eTDWe8MakP*n1oa>PT z48dN`0JrwXUI1X@-iZxrFc$QO87#(4EZvQnT-F4o1OorcNC`DIh@mA+6TDl1pZp6L zB-R9M_MasxqV7^AF6ph#xZjPSsi@!sD)NfxJlV!uk+Z0jzKTvkMgJ6MQ=mun_rI;^ z{q7!pqlZ`y)B$*3NzWh#V2jq|2B6?m7Eg-d`l=iuSpQnp5pXw3}AMT z3lut)%Hx;%2-3iUsMmkN_|Bkz<4;rQZj9jxq3o&tUp8xehk|L>IXWiu0uq-CV9|e$ z;~{t_#O?S%7LeEpK&#}{-|4jC+*OVy)AK*F{c*NPA-+{VygJ>!ii8NH>? z{j0Tk=Tm<}`qN+CM_@Z;RljL$N%Pd};XZ!HUq6+Vemjc)+U*~evvUI0kT>_9Vx6#U zxFX{>djEZ-GLfUVjgH^+c!8hU-vLEe+&HO&5l}0z^Z!xn!H$A2xeEd&)w`nAd8g3d zdwyw+q4HSs>2ERp^)DWkzh_E*62NO$XSJ(TK!)omeRL{!It8qz%mIPVa)Fzu z=8X}c`+w<_e*4Hz{<-ZKFU*tB>4gWNQ(XPdau@}!?3>NW9fjksbqfF2ze1_Dy6EPp zT%y=<{Yvg-i|xG*JIBH|I+1u0D>3Yrwt@6eHGWo(s-i^nu$OM=WlHO(Th9X<_1G_U)||% z6iJN{QrcD&8?8;7{UZ?oVw88I6+hYU@D40_=aWJwv)SIH*4ZTLdjA770Nl=ZO$~e> zswaS~JmfDJS_rElo(jK_k;^{J-&Wq9BB-iJ1|%@B%#zUxWp`0xQnpw;l;|xw;wPv* zVcvWk^kF|)WLJ<0Iorso90p-V_s!y7nhCFxgXm+E@3G31EOVqv%ZJ`gzQj(2{h%~U zvr%uYWE#Sn7i?u63Vp81C!({8N>gD%)UC_Rjnsi4((uPlLy_F(c)$Fnhv$*Pav?Mg z3yBQH9)=mFQGzX7ug_06t?VBx9C$W0#QSVLm)GrsIPYo`pT|`kqdbW81-;0qd~2-h z?|~TXR5E$O^8l72eXJu?zDyD_=_*vu$jCGXm5x{jnXnNJmDRCaW@Wg~Xu`T_3v&xI zd&@qF_ase3_Rcsj!k!&SfG2D-wt zUEns zk|GMjXv3wV^5utz-g2%J1FzBGt3`Ppqm^;)u!C!^6;`O%OV%yf(@S*a8oQ#~bE6~r zny9lJ1zqjn)v}g6yL>QOG$SZi)Fy-3V>$sAW~&YJmT-QhuPOhAOT?4I7d7x`fH%9@ zl}_FAkXqgNiYsvQm_9Go5|!1~AY0VF$4S5-a~X%wB~c$4U2Rp>OW3W6X)#SG%$syM zu-8NYoNi^#7yDzmNPi}`RgY4oAFb64&+x<9e4brwF=-9cQ6K%z+c<0tVJT z5qM`2eS}UiRkDo;W@;!O3lLGqB0J;JQ#EZgEdR0JCOUIXrSqQ7w>;JvWymfam4%;t z2RYOZylZe=P<=G2nrCl$>vYPvybZ0CltZTG0QWQmOcMc^rayXPwhow|m^t^IH#+&r zd;~X})(6^uI`Av%lSBfB9~~6AeM87D_Sq(p^0PH>K>(UvAKs10`4Cjn0?b9yu=;Pq zy@ZBBKEGEmkK`Z)ypi#5JO2;8EDBgoF>olnAz=iiSoAdD@i4E2q8%RPvi$E*31DJV zccTQhR8TU;_7n@i$gTk+`xgfbZ20M&Q8mB(GHeET@)N+5|7-d!@CC_;0ZyjkPrv^lSqx1rB;;D@3dE5KPRxOEdV@Qkypz!7 zjM-NoRvVd%p&6NxeurB>Qejpei5Lp{q8K`it{=2qzn{f;!+5Lvs`Y1~YV_i3$j<$d;&;;9r!%)4YFD><29dXA zpKP<|tYIrOX^AMSr(2x%##?muoReeV&6QCbyEwCHg{|9_zjM?7l3N_$1odn)6@3j1 zqN;{+`^5d%ZbC+K$h8a@Ig6!@lR(@y#`?tCzqo?3F-5{g)q17Rxs2pu9J(}(ZAQsC zCio@X#BNNd{9-tQ-W=XusrGfH>l2OxqnR#)?lhY#@4bipytF~T9j3K24gmAt^N>$) zRvAEId6nZiliEhHiH0+2c0JhBULD3})-RfKWudqDp}eavq|_x=&>O}tyIohqYORt; zzgZj*2dbM1ZoZ7aNmIMweN3PgcFuyV!KKwkje(6SGhl`p_P7=$%PKW>0%ItJh|3p8 zs7`+1eI88H`t5P0*r+-=$|&X&hWY+DBKdAr#y5I374p5#+@FiptN7|?WYIyj%<2&d6FeI0PA4{*dEh=FEhbKWr8ZEl^`5{XYDkgzBT`XTJ zN*zZe$9sY@`T{mpzSP%V0;EJu^Qz%Y*lF%Cxud5laj`ful_U8$%Iz&bTI)T8748gsF|?2sNPJJ?&}<>jN7Bi4ClZ084}96&ph^t6Q%I zw%hfu%-F9SA?>(+T<5_2YxMjLr#_1NnoDQm{w>*!C3}R12>=}Sy z8~Krx6Kcdap!9S@Pfx2()}+YGxhlIL;g}$gp$Ow~Rh8?!98_Az3jJZYdLQ7lh*JreS}S|R_-6ZsGD-+qYkHX3NzBsZ zdOiU!pN5r_qwL97BDs}B(h%R4fg9W6rOt%uRmab)BAm*qOuwfLjK=1svar2qY)4ITE1Hx?^Gs$7 zQ^&4<>s4M<&6TOI{XtH-gTxBikJoZvmbQbUaw{8P@urk>tCQIX8oF-*({FV|#t3X>$s++Wph$pq?6|whlK7 znSl}ZCJ5h~*EW%j%_XB75z-!-LN9b}c+KK|MRT_9r4b^1*6E9|n`(ey4#(Z^8xtg6 z5&6ih;6#vZU165{J16^qSBFtuF|z0KeSbZ^YK~l z0(A^ny_RS@&0idyKcownqHBpH4JNUjcB4kPezi+uckS7(x1Hu&d++G>27CQ_7o^-} zXvB$7Fd#}KRj_3~{6_1ya$>m;d?pI?@aez^T`b6$UgC|b&r|0sU$5g_nqiBQP@^?H zU<%;hohTE!$D;~(n=%b^leC;wU2JcPUyozmPY_?lj;`~1COEH(`pKX~t%}x61uH7N zAj|s8i3acX8U?Szh`hh|;3co$uFfoE8C?{#f|`WMWO2-De$}wr-E&FFwb-aw?|)h-YS}}$`I8_mmnkBS!`$)9BVqF9og2IkqTUE~U}#LXp2%vUnfvWk{4Wpg4s<{g>uBApi2XHpFnv~`J+|FAx-+WPw;8?;G57y1l61Co4Y7g9> z;Xam6qj>z>qRZ!}`C)3`7Xn*%Hn4tlEh392?|_IDNx_v6m0K7AGBM*y{C;PsyYKFc zgJTqW3s)Jq7HX#>@qmuNB=7+ z0J`m>`so``yb+TQ3~ub`O~3QL3Hr}<3?_io&`Pj<*x@9!_c;B6G4tCWDOg4j2|CW+ z`}Wj`-lSto8;-KU(hGXt*>JHK)4WR?szR%Azg9k+gvZ#k$Y&JQ5>#&50_HMlksT&U z<8nYmnsnO@$`ubL_6MBgKSE25+}=>lin-FmP)-CNKGdTWbi8+sE_wg!>3-O3?yI6t zqu0t=>(9^M{@e=o9M7yak@aw{O5ud5WF;)cS$)}bkw2Hbe<3HUO;$4hUgRa%xN9k@ z;qwE9SKqizU#O*s*xfw)=ui@GqSA5w`MG~_)_v}o=0j^Cwb0 zy;60#|DA5xoW6>le1x(oDc7K?26iG-3cInnmC)`UlXqNvbIh*y5bh9hXThPkekgHxto!!*15#@aNtNmL z(MBh2|E0@Jhu8;;dII5_16-~zjbw_C1Boex(h%!?k+gD-7WFD{GrSI@UsTi4iiuQx zoee|uMZ9B`5T}LaMA6{e$d?&u;KW=(!l8G(t{5HSwj2r1o>O;RUA&nrH8-t$=lOE* z?Pb4AOjmx;62g8WR&Leo0nHB#dM8gn;-5?c5>%VhsYu9n zn7Ujk<8fA}{V<80DB?lI7*(uD3SB?Nwj$LIzbO=K;g84pW3^vhVW0YE4^~+K^QV~- z>?V&do4zzAl&~HFIkcXdH)Sg(CZeKcQ7gqrH7wD+!7bPxVuKUkv%!WhWtUA<$y-Y( zyHROXYK&fj8z*o_%Mk;KOsa|~{&w=cxPg*D@yXg2_Vv+6Mzsv^;w$atm!$U>DW(8f zJrI9{x5%DKkWL&e zLf{7M0Uie6M^CXvvW>loY<@UZtAl{`ttE$=y1peB&2r%3Cn@di;Vc{IoY|f0W%pC! zds_p8&@bjmXn(LH$&9~zqXpl26og{q<}gALkA^+{KQgM>vHP0ObWuPQ=nkk zCUQyVph=bS7?{ANzMk(9;2>|Y#{`-S3I=%Csb53du?xjuq4i8SoY7N)u;akM5bB^! zl%oi<#xFp}lK2bV@6rnYQ6W0pTXu5V>+1a{$NyXvX~2M9;^dAi#k5k$2Fqb3YQZ!Y zG*Rf18H6aDL**u}IghxWz8$T?peU`1Bd9h*+r#M|DXS`6^}?RJdbNc-XV$t_ zc1y6>@zxRuuiY}@S8LZqH+7ct`>)H*pj6nkQ3i-HS#- zpePQeW`Z)W%-6l;w-i?M4&IlA?i*%l;0h}l#huDwMnX=FG2K4+G~s2LRaS_6noY;& zlFDIDDd>u!aro}hLWB5pwIN72@RU@Z6lRzUp(onk=xLGKC%U8wDH0Gxe=Z}@G)U$zfv{4rF7vVJY{86J&O8C^ z31VD`hJ&<47)|liK)-TWCV|^m`KiN})|>6kVqUKWnRkH#Y}KTSO5Da@t$XQHIM>71j@vHex-7-6k!?UPHH{D(gM-R-p8mKdMY64zRoqI>&|KgxgUoRGTD z{k1VF>9GVJ4^9XL%@2gJD{I?fc%RI{NL<((KBR*kweW!xe93(5&Nfe$?bX}|=;Gtl zVNr>cvh8@u-E~x1J@_s9dT@ygBc)dA9i%-^`en)oDA9T2vY!hUBJO=TUTa|4CGlzb>t=jV9@Uz0GgC=vr5M>pdZDWKcxj z&b;TqG9QCO6261zRGMo6*>-n`y0SGoe$sLMajG8DO19424@~p7+fZ(2_nJ;#wv%gR zemoW6GB>7FX;}6+&g~h-_nLC(Lnyo}#XM#=7e-^_b%P-%pK8B;%If{_m;URCA6V*h zMct~OzY}6m9pq8n_iV!|!Jsd}Ud;0gFqi?MC#3$s=P*}(jgwo^?LxcO=JBraXR52Q zzhdZQfaEWp@kI ztTD6-=T_TTV@;9VYWowF(IJ^QcPtl)-QK43V(rTU3>w%-53&zGxezM10tr#Gx79cF_5?`ObHf|+VK>NozS zY`1$#AJuy!d1EtiVuiL5Z>{CFZm${+cH+Zde|{0H1u6`e{~&_yE9Y-biDEyHl>+8A zX+}w&)iUY|;+(F~1);6h(Re}$3JOh1A==E?8iX3@EauI-mxO^tILm|&aLUYUyVE8N zbJ0$(SBKnTDLp?GS3K92f|Oio`P>Bkt(rRx9!K=ZS(021s{5-oLR74`88~7@ z>cT`J?hsC*r||Uss>6Z;2f5`w=)X&$tQzq4KYOaXjYtFoA=o>}(^e6`Q1I zJ7KQ7*1Hm?_kEB|0#!oUzmgbjM18H4?#M0~6*%(2CpQ-YX3ZyG-X|?zBB&j;9RBQ9 zP5rdcM>@2Wd*f%aDZP}fi~XySKSP;7#4_3D4;40gZx%6fg$+gW`y>&bAbSxjq~H{n zpqR<1MmXpGN_aRP1J_>wn<6INpr^VV0-X_=ez^H`U0}`Du%x5(CO@@q7%Rd8{}K9F zy8L~tLdC77nP7tmb0{C<_iFxbgU2FO5p!=Lu^Hi8Nri`<Lx`1cIymj$-B=kYhh0uqSlK)7^bFuCv>kH03Zx!}T@LH)RO7aI~J`eDF z^8GyW*;c>yS*3+Yvjb`x3T>MYS>S~Nq6YLJAAgavZ~dW$4uX03ok;lw-x*4sZnj5M z4)oi}R`_I_?FQra6eHXf)iJkq%G@6Cg%kR?6tO4g3cIk#PrlBw3^Omo!~9~S0dJK@ zkp`wA68v4NL?@!Lzo~AgWmxIMF?!On7*N#YWpW%T7}w)pK~ft)kB%IlZ(Z4eWZF-X zW1b%0IB@5n6Z)&`SyM7Cj7Bc7;>iFX&V`=72qws;Mtv1BPlkwGS3OzU@BKx`<4L_j zOodj_MOF{#!CI}oJ;6?pNTGYeXJUOuYu^MdZMX8O6o!nwMsl_!a%s+mVwiUw11&=q zWef=^8LTk0MEf_HucX*{Z9x{J2JDkRNjplXQ!k&ttL&ysMhB6jypOFLC3U=vK;DJ3 zy`3hUFh%8dQb)kzOyMbzfD6=s@w@v7TUI;HcG^jcpLfEs1l>7DlZGZzU}~Sb|6C8+ zq9;uSGZJw8?811DDddLnR4TgTg*^FZ{Za;J<%HMRP~3a>ZjV*uW%NEM?$OWj%hMEb zzbR!vY@|RG=(o0-nG4X4WCdFz)o%)rLKGXw2rHlVYW5-ua63QSuck?T13f>^cu{-Y=if7dvM}w(!0@Jnz-+K1Ps9c*;5Y=mwe7SYibg(@+bn})oFDFnK9cP) zQq5vpPan0-*|4- zcgnyDLk}i;LcLj0&?oXEMz6!4B28yJ<(@vjR02b8I5o|}Wl?r3H~Q)x zQP9$L*zuIc(CU>gGfa(rLc0dSzR`L#sR}CEuhQ6^NMNVCPR+81rVq)%XH0SCUxZ0cNp)$&#D_AQPq*~9Gf`O5+(*F=gDjdm46js zm>w%XY2e@CXo3Kh37;>|g=0oXY={Yj2aaq=bbmA*tQjlg!E%fyA+DFya&)m3sAYt`LxzjPFDC0awTVYg-hZZ+)SN9bw8;-5H>TzQ-j2)fP>tHb?El;RFe zC|AaUMrW#*%~IYt?jH5NksAnTzPY-8w$YEZO=OnMg*F4*HSv8&9lG36LWEEdf3A(O zhduT<3iBgt{B?L#Cx*zX937VwECPZ#sup$7t9RzLkLNh~I+Wc1w5XP$itInN?ndaXU_A12W%-i{U zBT%#p9Q2$Qiy|uqk{p}ll3O)v<53W)@n!VaJR-)x_(On^01nh8;_20mlseG1?$v>F zJ$$kl>8P7Rot}B}xw^KyKT${8aRQ1*sW!?aic$AqqS&p)PC#;Bz;+|R=_=daFmb|k zFtJOtP#eXmFuFi4h{gpG*&O@1iYEFN4FcZ1*>=3&xEMIlm?WYN!**)gMJ4mfBz7a9M=Il z4#?dlTwhxA4;Fd_knNZhX(&IFRDt4j`5m>8A`yTK{r2U!(Cn-I7Owo$SlMcwhjcy! zSoya^vX{Y1jkx06FT!*qk}F`?KFo7I zCm37{^>_w>O@!yv20;y&;AsCasXb0LIEvk%tiLvg>*9HJ%7dq0rI0rRYvK>hfo{4p z60t=JvhL=Hr+ri+IUcu3Bf%(OJ$v$5SMw2~#<#l$MqSrxMlDaV^WJ%q7CCiALe9^3 zJeALw@rhDDnTp81yAT{#M;BfD&W1L_yiJrwgWb27ve4{k213u`^w=3O7X9XL(D+PS zEZ`S%US}|7FaIk2Mpl?}DtOZ@|F!4Zpe(!hR z_xSl21=K||#tDtu>aS`#*<97~KPamq&y68@ke1JzoV;g`zL>|O zNzpXPH;+IkD)*_d5_&?)U}s{8<<8@W+e_u*!88yW4yD46IaEhNm9;$v|EXhG@vd*a zLK=ZFHCb&r{s;%2A_LA3La@KQU#;epnXSh&r=lu`V;|YKRKn}+eLSN*GGSMJ= zTGC0HP<JLaei?jn016759@M8hOYjgzPh~aF(8h6gdva zBA8ZufvM1OzD-SV|I&xb;~fQn+Y77p4dNL&rI@6}*~U!qt?gEauV4KFQ?~~iBy9im z-_%?tCB&h)3vvK7w{ng;%o^J!X)#XdZ2RwC6EF|~gBW|MxG@I29!cAiTMs6p;H(A3 zV>z?)oxVj*_T}tUG(wcV)Sf1vP_TL7c2b?8zkO{|m-jl8YWl)v&<%ibi$#Isltt*P z=diaxsH42ss@s*e5zG4a!_k|8{W2~<-%OY)j3%Y0U^Mc<&&nIXRmo!sCfTSUrpUyL zhmDiuBKskUo5i2y_a8{rDm)=A|17;15?q8l(diV7^A3%O9dg5(a37;fLU&vO#$AT+ zc}rbe_Uce5M_Va0tCT`2WbCp9^*>%vCF@pB*)4^f-f@SN@~iwiHWa!{5t2&Cds!MN zt^op7dt=zI5t=@E#;F$tXRoNX0`?@HA z0zqRT8gA*KjkDClmtYj!yvv#BdQ*)bzE4-8M~7CNRoTpv@Y4~@iG9x0py$1mi}V0mB7zA@fg}^+j^g}AQA^g`KrXjAR6`L}* zK0Ja>uyZstzU(#3v(iD9(_CGEoC5umKD!z`#VWQvAD16q_6I(N{TndC0)UpxxDjq{^+Xm?8r?;P{1hPI38~XS# z6(SDezxBe#%NJ*sbfGjmJBa+40=zGVWm{I3c{5p@*QJMbH7^MLI9e}_yEPw}mLZe1 zP2f(C7Y6y9Fi;*C0(U8FfZb6F8{EBbK~l1^J5SD^`x3bp#G@*6;4fwShP2p>P8mn* z2XPv~*jIL5$D(wceOEoJgLW)IH}C{!Nw+;afpQ5~SJcE$;QQ>2UFVEP1mZQ1%k?u-MO@0|GanpaJ%D}+GLwy(UADd!>C27{5KN^ zt39C=O|d7BGNKINlX`RUJY?8-ls}{3r<2ctNRyHcbt-cbe-tudxUtC#l5%mjJ{o@M zMf;wB@WmtI6{TdjBolCZNv~{;y`0_8m!QOLa z9uG~-@WL9g7*7L7*VKvTn)|08*gQ0_K~-OWB@(bP;Wp=AQOtiFD@&+J079w)!1KKI z=)>~lIvh`6U(PCS_NwTBY|n0c9%#nCcpIk23s9bkXIf{FYb?G2q1{`@DOP|?#)r14 z*sEq~MZgKUO`>bZjAW{@wi!&CN$k550(4w`_Kr}@uzwLYfC2{oA6U|qzVYBd z=eqW+z1F$TKu9rKZPD28kfqV!_qMF!|A7lqz4h|AXBwy245a!rFV~Hdgw8v|!(1F+ zvq4oqUUpJ5Jrpynwm(RWeegtKFDP*7V{8!#|IgsL@YQUQ{lQ&&%Y5@0$zarrq@zoE zF2G!NwU>Zh&NDaIdN8BlD~aX7iX&iqcH8KW0r`5!Pwdq@-!kUaH*NB4L<@KMXv2!X z=R4_UAY=lq@CkoY%C6K$t?bhow>_U?oKXfaaHF(-LAr!mr41XZ=*+JK^JFP4GJL~pH^=&-}O(~?0hZb z`|pBzAwzwgFypBUII>2zBt}N>-q0?<%Y3~I$F<*so9?+*w@&3iWKS@wZUPb`ow6nz z7njBh@Ap_S{!>v?l9^0flR8Qou?QR1LidDfG@1E)+qXtl1~=@f&aZ8sna=EmkMJtg zFw!eSmfhiZc&{u8VRn;g5*oH6Uzj~n3lvz5=Z%{T69d9#z2x)AHnWZK!l(T;X_~Ju zP;_PbpBeOMXumtS#FK{o9xL*bxmm~F3(+xQGU+~K(_eTiXzG|J>|msXT6QJ*E#!EI zK5tVOjsy_>t5^#&%K$2xt>-PN=sqvHbd8XX*LIOUL0Rl5l-ZMf|2(tM?z~OjTJm=J zCbV2!ESw>w2ZLrnH;g`Eqzqv;b5CJndO~UDcVg`pU|oVw=%doTBjPo!3KqS682Vw1 zo_jxZw)4(gpGR>kQhYKX%9X_BGwKUYWeD_dUwt!fG1;cExHe@@9=3JLcus)9CLiN0 z&t~e)D0#n68=sm?{q6qsn7>}ZiMna-tG%De$*@0g}JU_*Kh8I2?cxV`r zZ=HfZ^AMwn;lw}%1s7y1e<;tV@%i8_p}S;nq@iU0)Q8==h!W2NH;v8f#!5|R)?NVz z$>wIwt+DU~eGpNglJ48R_QK{5olI%(!{ayn;(T>>pr5ZSG)&zToMdp|GPPBu_xffh z83diEi8>t@h90{-6J?NO{e2<(_oh1dyRD(wWy6ohfbsW_DFpGO?^L`HC!rYu(}iNf zbVa%1ezBflW?g5P(|z_?fSv3`8IAI(AvMofvz($%wNx_3a?kMm`>Sle_t z`O=pu3fDGw%Nbjm7IpzDJ;z@J^B1RNhv9uXb!qCR-@Z4V^mp7iC^5Sdf|Z-EP`r3)vl*M8yylA90P)wlnxZ&ALLDX`t{hiMPwmw^7XBPV(_{03QseDQmo~k2P z*}m6?ed|mcf!W~Kv=!)yPK2+6L@q>uOCz2`T_9RBmlnJh!=^L3n@2i#WIfq?-{774 zA{nVB9Eo_&34d-ulXK!4QET9QR^ATaE10*+CDBg!{hz_Rh&MnBkx{e*fY_~Cr%ne6 z*BiEuU!?*j?%-s7j`J~XWIXxxUhSLr$lg!1F9G95ID=7;l^V^ng1lk6u=T<0*t3~x zL!AScXX@n4bGEz?nsIiN9<=yI8%Of3H~~Kqt$hkV_r#N}qCbpb8lGiTQke+Ar&Z^( zq1K*>3#y?8{S^7)zl65iD}S>qw~Lb*O>YG4G_Me8;=D4fn( zwuW7Ep1&&zd(9KiQ|N6-{b2HnqnTwa+$@`$yR1Lndpm7Rb1jtHls7LkpOQ-ozTwJDQaxtPDYA<*dJ~{D*W2F~B_3WoO zYr+%skm8Yl^-7{SKY23$EDj{{EB1Pd9C4Uzeo;f`HC}i=K3Uy4l63SsUE35=>igAlLKX6+DHMLjd^)XCRIo+(39ruUYkn+YcNd-zE9v zqo`C+WHE>}wsxhd{zXa(9E*ltur=QoH(amow-yMBHMhi&r7V7<1Yw~Y-dfzn0P+!x z%mJ-=GxK$LXGqHf2l>lX>_(L5WAe)*Z35wc+$ z@7n-L^BtuigCRe}30NE0@(R-2H@j^*0emw;*j!72sYH~*9H`LqaN6PmNmUah)S@P%fqkkjd0mM}5KM(yeN@Thnq9rYPKJ7_ld;2A zH2W3SBxn$NikaT-Z;SgO1u?I=l<2>P+i70qvCidR{gnS1k6n+GerG@jlUWdbS}J4?VDyDO#!nx; z`98L-RK4TU(_bx3?#0-fGG{xSKpzKE>+L8uV=wZs*0e{g6Fre19nLlwZ5irGvXkOL??=7&Pd zLSds9U?5L=rc|HGYSh#*KhSXktBhwVhg;PZU#0MuMsWOue=@d}GWB9I4XrI%zL_v* zw`-xKJThi3{;S8PSla68vi7W}pu#WG7E30=JVI;hS zL&{$vqY_ya^$!7lzT{7@9Lt`?0=2KV$Nl+9STdQ6UtV>Pz8 z*i);)993BBqXlM*39ce`_L5lTFH(4!W5p`A3Cf)%DhNuRF?McAH5_U<9+*4HiVEK} zDa!GfMx7V(j{XjRpayZWzCA%Hj)gvbw)TWF0PC7oEUS`V$r(Kf(V+m}v_eoNG4Kbu zi`9+AEeilREkz%Ou;KRe4{J<*7uaDhgqcglbf&L|OiIeAw^|06kGW9nU|^ zc@M-L=}QJ zeWhb3d{|{%Q-_+S%=?CGHVuk_OP+;UE<hj%TdI>I~gHj<%H))LZ+ zIOS`$8LW>^l1p&Z1V25=#EZw2L0{7rc{H)iey38;Ooh^tb{Uk*|A?q+l7*7u-II^L z{|D=CW^(CLawhQ%Ygx{^t3mamrhqzOoi5GV)<3Mv{jx{y(8N<6srBwnVA%w8=aDIaq!!67>;jzQ_}f9sh~NsGF&V8GH=` znt=CRojbECI%>IDh_c7&ILLOyLiF8*#O9NzsVABl1wRWnkBV0Q&%1v7&ja|(%BE4l z#6KFLj6f2O5-%Ic@;p|?S6fmIn=q4Cv>zFO!(KsaYPoh|wTKI*6u(liGfgOWJ^aih zmc+yc{-&Ci8exDxm{5)7CUwfhlWc+WNbQ25pw$z_=nT=m{D+o)`)t&m5XhojxlPgM zJOH<`BDn}dG~eQ7dPtZfOE}*A_P7CG2e#yL{FR5hr1U49j=}o8yC3H6`5fCdG;Q#> zzg@+iFVpF#AY+Je<6ua6Ty5?&2!CkNR=RvN<~iYMMn*!k;`|j&gFCkU{L&Z+&u9!r)>5|sLmlBMhza# z!x|s)Oo9H@7qX$zC9yz)@vnOvSnw>R5j?FzF@gd4hxdQWm~@PpNhLL*GqQ@v5#bjw z%BKj>DwvJ08-B(g&cSaxN%c&mf_M5Q z7QXphBH|CPlb&lCuaEozNCsh+t_iZNE!1c)je~9Tdi1jJ3~t^1Iqh@wX>^8|`K`&; zoI;*pyn{?$i|AXJv}t9AdHc~y0~l04r=B)x4{gh7&|p#zKDJgvidzSm!X8vULIHBn zg19wI1u_%}-1p{zptz-oj#kASVIx!6_rba>``&fWxMU8iQ`xQc&A*B=Fii0Yp!o0C zk|CY790vZiO0f(@e8=DGg-T!$X7H5p8)v}mIbM(y{*28KgQ$>)cHq`17C6HR_YJO| ztHB&tyMqip&0>;8y`J;nkrDqsV0&t_o2Yv8qMRVEjz~^fxhTkwqwht$naXvY7@Brl$*7-P{^^KJp(vy+< z>?~*y=~*BhWGC6n{f{6n9jG$D5ff&@zmj=4-UqY@SUjx8)|U}1iJ;1`Qo?u*8HnYK zhK~BwKT6<#9+8f5LF-holw(OO>A%zFJK$qvk1Wp%R16WJvAtfgs`}9-8ZbDqEX!k3 z-R-jf^w}hu$cND~cD#W7upGOn1kn92hnKzya-h%Xu9{gcxSB z^mSdZaD)BNfk3nRg%I-}-ARY1zs}wrH}jdXHmzfJok{5!7>gzPBzlSm4XrhGXZ^R; zV*ygjcctImUKlo{f>wB~(jCnFTNsM*Xuedy(s8A~Z>+?qI99Si`IiD8l+7m7?L4eg-LgXz?ULnTw2I|fwrtdSNjQ(^{)Lk;75gDXb3)q4~Wr4BHW z!c)G}EO#}=Wd~4jtMGB+kg?6s`iV+LV>$6a_;fQ)weX3w5)$f?1WT(tp>v-l^zE#F zoaxT^ZayjBt7O?rynmKMi4y|fsH;j`5Zoc(`xbXrP}r>JP$;Y7`}sinYzmm1|Hp6l z6dwF3fS{n&qbZqf^)Xz>aQtCS5Ou_av?J>yHq)UFzxK{msrn>3z|qKwKMCO}Z&k#} zNjw{`@nr6GA6>+iH1~QX7&O(&s)m;dn&)6W5I#{NWoz-Cgm+D>_Cfe0+eZ(Ral@X(yNt+zvy0Ajy(-{Hx zWR9ks%>+c!!y7;1hrwL$lROLho-O?fqDTZEfS3wN84$0TscVb_TvbW`X#W4m%w{!s ziY3R$?WAcPp^uorr}1f@9KU?F9d`!s{=}vFR<&wJt&;u*1M}$>Z_0%?f`nZ`4{)2k zr-?UK0=&TZm>&C555{|K{{-f=K-Z<7i_qLW~#lgmhRxvKRwnObjV3)yb@|D2*tvF6W zgZ7s+cGEKJer(2I3_z4Zh{QsqJhdW}kedAv`$2dpXuc+PWxqlO!ze!)wWSb#V7gIH z7*v6f@p081E@sb*eV61Qs0wN_EcNVdk1Y` zzR_SUFdu#Q%RosRs*v8@ zd#Rib1fMB*UoDo?&X%G%ze%|Uq)h_>@X;$&q$Y%Q)()+_`~Ru}Ri&#|SvG>k?i6HG z72*PF>qL_0o4;#DZh|+{IvU`^;N#vr2=2GP<>^&J<>8dxLxC831Am)LF+kfqU5qCMugW2;nA2bY4(=ljz8{xEjFD#7mu=Mzf~}lfciY@k`_rN1rA_=pf=;^%aHQ<&JE>$!g2ZXNv*?Q9AUq2 zhUwrz-IKog6@-=-^~}dAE-h@{|Mb;J2XLv#d9N7Qfo8`wDSQTor2jb<-g%ffKmI!K zsU<7*sCQ6^#Ba-$@%tDfE+X__Zc2&|-h~mCZP^Dn-O3-9xzg z;E;3-tGr>N(6eAiQZz5LmcID@>%*TW%oZOBi~X60h@qTVAy)1WZZ#(TxFLEa{S@lJaHZi$6E%W}EjtTEVd3%9b17!+iV_4E^g}zt5lVi-^)FqG)^}sbNcqK)@Mc&c5f%+SZJtpLZ*WI(yqK%f zpjvWvi+OaI^ZsWDQDyq+m#4zTS9*6U>#AhWSRKaL51gSLD?xs$$ZTx4dPn@R@X16| zQT(QhQ_|1r`I9n0h;dK+tfF1A-KuLicXRXuC+H=g+OR%^Lnr-aSUm%$^#89;XPsI1 z@8@*D|H(HPSBt{TRkX8uJtFm$js88$??|bnJMUE^n0{9t*~t)wb601QoHX!7E0`(R zbJPHoV{vZ9qT<1MyoKfEtAem4-E%^L=GYR?hBT@>-7+Q?+3nKjSKo=I{Q~&68@#cg zoEWVo=XX+X3wTF2Zct+YUBVxcFc0PXbf=AX&FL0E`1aME%L*|Zl>0mBWA-GU=XQ(D`ZkJQ^D{`W$UQUIHWPch`tZ1XGR$@8{y!btwN5i$_<5QXOt*ye^Ro}yCz%&JY_j6)AZ9s~28h-OiOtjA9FH2}coVkxL{ zoVP#7HL7vOlrg8~Sdgp(`dBw$gpwRvLvvx(8_cxz|5)yK?&<(fh(~Zq-DP$?-|f?0f{>ba zcN97fa=rs|`FXd0DpFpJMkaD7vAtMB0$~+0CA&rWTU+*%acPh!WJYolZN0)A%RKLj znxT86XroN0j)-@zk*0zp{QEgEhjiwyM!Q9#$^+jUUae+}q6h$!qi@c9!2Wo(i|?xP z2oy?MYSJ%zzo~r=PAo>=J2}|CvZj6P%$5-7FvBLi^O8{fVIi>HJGYSy(^tk2KWg(> zo@URUg1b5w+Je3{u1nod!IAU#L^=95`UELgvqGxjPN7FMekYlHLX<8hgrwniuA{#w za`CicdC>t6rY7j=q`0+_JR*0o)%I7Kr7%?_n>JNiKrKfAb#JYaK-O*2Yohp zfxS~Dxxp2z&DrLA!@=gebFM#f!XJ}kEGbRw4@C-;x@7^;>7W;t!L7ib6Ty>Pv9EY} zYN-kV%M$dB()poCP-4F4XPRMfx?D*H-M}Wg|Ax)`c>)iJ@;>npI$8T~WC~MG$WmvL z|Ht(3+weP_`Ck)067rkTe?vY>+h#p~G|{<1@%)Q{;4lLsAyyU;7oL*P__&Hc#4C4v zSvr#fWn_Yd!=ky!4D8FyCDk5X^CQf32Csg6r7Z4`-lyH)>696%Qgax!f3~~PzXZ3u zBP{FxMkzBE7wyaD7U4*}9l4uhODnp?z(n-^a+H37+?JlD@n1+@q)x$ZVP~wB<%77l z7Zr0iZ5|_kP@Dxon6clNUG!|kK}K$il4ixar)Q~9b)!NfMvr}%&>y!;HTRCj*)DUf z4o~WQrp7Ct8XsV*%YZhkzTIBs)OoWod>SV7t_lBh%Oe^F)U>o?k(I_D(J%$S)j$-xt$-wpv8cVk}Z;sk=xLKe{j-8c!<}VKbQBnqR=* z>TgiG_v*&dpLH&%Ywcmjub~RihwcO&EG<$~6PRf+r)-k!PlnF6jV&|(Q8#MsHoIUcVR8el_BN4Au3{$?AI-QKIthT^=IrMty&qhd<_I7yTmYXKb+};C*jc1zOa_ zqF3Afjj}a-;Bur~ImpF+4>#nq`Y!oKp@*vZL*k0k2wc>|pbLLX+Jp7DUduVk%wyMj zk~MVw)X*i%G=2hFR_qTuV@*7c?ML+`3a=FOU^%$%;Xp0Ida8DAOXIU#yVYCZ+Pa84 ze{q~PT(fEA+U0Sv+QC%mI(eE4lKyjwiV^I$k399^9#9~1&UqdLTgB?+KL zBlyMelV?cCzRl-+sRQkHReZcXMJrBDNa8Cfqe`lFiA~_A9`_5r(x9ndxcV#hSto?H zqgjA_f!7%oNXmbn<3_#uf0FkV{uSnga%h)HehbbCfal_S4b8*Cn_N;3DI z=82)%1>cL-dr&DPs1k=7L-le#JL{DpiM-Sf=0Ut#y-#(RwXOVk{Vhm%aF7P?7fBRe z+S$5U*DXD@JHLoxnEy0Zb2Zz57XZ)62d@#C45KHI%>Hchg*@D2iV9-}(V zeZql+0F@wOTH`Ce9A!zYQ>)_fCsl(+X*_DM^}BI7-6K0h*szFhtq};+eN_Y4zZ7y$ zJ&z?pt3>6wG`CMTZT`!@&CB&q-VtSr_>bmv;v)=z#?|(e#pvc{(d=OFhs&ZMNpd!C zhqCWjXVRNH9+KI_tiR~+i+(YA~5>FOe1m&VzE3t^!#`Xk)l zN8NTqlJj{N2$1N`f7O+HBEh^jip zAZ?E%spzT7jOI?c1q#jw%Yr%JecI>9>@qHJ3j5`QsUBg~V8F<1GSszbRSY?%8qwco zeB#Bz`?Hx;;@bUfH2du1whj^Z#pwi7(RQ>%mBkzyn-u704LW|Tu^;NxPF$vxjwZMj zFkxqS(kqOCDi;aJWv;IsiAl^c*4Z%*)y<@BWxP?($Ll2?gJvi4j}NLYzVSVHdGf+C z=S?Z7xIr(l_lIL!T)>*iy0Z=Y=tb-b=g{lBW?ac51>-B=E}#`&K@n)xeSP+O?v3T& zwwnIdpNl-j($`ogodog`S7|^UzCBO(dcXB~<<2LrR3=!a%>!kqN8e_ja^@c%%4{|2 zx1RhOariQyGW?EFn9aCY0$;TZ!M7SRn%`j8LIGdjtBd)wLJ1W4v$BtYK0le{);Uj< z=sIMX6PRy&c$>7(yma{f|8ac=@5_Z5Ho`D(l3dRuqBUv0Ue-?#O+!ZFIpBmSRW8-z z{FdAhMUw(0#YsPsxd{b#$bp7Q@&}wJQ%oI%1$u(I8Cf#MMB*xILrlvYBwVs|$$?Q9 zbQpwYx2%b{*XDrNMcfcEvQ^S8NiuVz-;w26`0#gw(y4A~O}`Khy~5r*7Wh`H4zRY# zpCpQ{b3vqkYbGNrH4D4gM@?-lT9U6{>|#UQbHOdy*nAab|* zhH)M<@?zJrmyh9@V>eOyO~Co&8TQ7gi5krAv|y(}VOFCryHBHAgD;5!#>$z%kT9zl?3#T*fDWDWnF1ENH+wH$=mp&2wjzkmiv+2D&*7Z|>Ho@>C{X zenXtw<)Du=-Z_UtTYiDN>RapVDe3LEj@dxptr?n9RA9_6^4-l)HBS(~>Tf+bdqroO z`bNL~`pX^vcQKm|EOVAWqpe9<#~G}aGL4&{&HF`yU5stX_xny`fuh}42%rfKCddN% zR39Fq53sMuc(D+tqkldsF^CFzsT4jm0$`G#t+51rrPrWeb5)X*Tj6@2??@bO)unk> z8nZ5j7*f!5D9lmMq8y(^borI_(>f3ah zR_i(N>nhOR9Y3h2+H+Y>VUkki3Vg$0*Jn$kScg~Azoy72khD9JT=leP;?LLboI*r% z`;EIkIc)F&=VD8zKHJ~Uy40xUR0cw6U@>`f9lcD4(VLknMAxY*54=35mT*haA zHXJNE<@vT^S_8ZJ^CGLw@eBbGg@NYz+lus@zW;lkUogPWglcF~@Ha?m`U%~zK>{+b z4p`HV6*vC$2Mb{~K3lQ)#E0pR4Wetfico*TNM^io0f9uVi4VvQTbOirJyxZUXy9Wp zLkja{?}H~<9zEhUW!Rg+Oo(iV$$-8q5?=~{-x)CaW-!}n95VbyZ?{5kL6h^;yCgF)S=P>dk^+y>a{-vV`d|r& z@3Yc)f~Fu-0lwyhx&E+Cnq&V1-^#z?LJ_Uy`?RhCt&Gi2f^o9y9GPodT3jh}@H`-& zjG-(uH?5^{mQ!oX=_@Hs4R(f(57;nJ|T3J ztYHM|d0>>=TjiEW_oC#{!oZ&RON@XjOCEO9D?zKJ_pSPIj4~UBr=6msNU&{^{)xLt zNsBQ|{f)9oB8cF8NdyEu0i>Ty%f{=6-g_=EcKOAjw!dYVE-x!(jfsj z=^Gp}1B0sLu<@c_)Wi`vY;&CNViSM~&SMn(Uwi9XTg;*qwxs_&@SkCds}3(tKJ=D- zg#`W^k@mmfNyh9H=shwH7|BOb!XtIWjeTip)mS*zEFV9>+QM+0hNYChX#v6s7VAsW z8E`(d_hcyGeQ70W`^h81+>KD_BGi74)G{N&K#zdcft`o>d)d<}DB<$5WW+`qtW zoTG5yF0VhAfM!&t#^Z{6=+k4TLx75^QWU}ZS^8T-VvJMKLa;GTrivRH92uAWSjjQ? zY=yc+IkUirh+EL5{g7-7EMbg0ns4~UIg4Xel&R)=q7Z!8!S}vmk2WW0c#@eWlx=Cg zdxwm23Nxd})3-uj#KNWE4emSR7PrnhZSd{Sc;JA7@At-mgt~)AF`4=biLWjQX`(9R zW-_2?^~0KJczGWU2)wp_kgqh!&ZX(dfva$M@-x|ItBKha1ZXFWS@6d#Iw2sG-uIFy zu?_z-NcyyrhtDd^NY5jy!UrdQ3JwE?U&WpT~$6k@S-91o!lT($2XCgfh&dGJ^L;y=gM# z#7I6r27V_e@7@_E*v|URXbu**Sx;0LE-4ObP#B?)bute@G6Gr*t7kT^uLNCT9i6IR zqDomL-W&LH$Ee1M@Y;+DM*;oqQou)klciL)HnfY#rP;-?qTc;=*xu37UbI4XybI*GnQnW{gsi`4 zI5U)TWg$u^vfRwOq?qMje6E#!s;#iKa(#{~6TTds2LYQKLPmbW`w7Oic6=QU#VX75 zCP2kT#IQGqdrNG_QB3$4h&r6*t6$&4y@jurH~n5gR>4y0%b52?ALbthGlshnX+B_a z@EgYz(hRpRf_ML8lmM=GRWI?RK40*+TLZVubKk2EMSQK@vZCs{E7sg{=#u-FNCOU_c-mKsjlgfNSd2^zF?3@uR#Eh3 z@#%_eExGg3H5RYq1f!Dg9`ga2;cF~2TnpFHVZtFl(e@wD_;H5fu=6m`g)x0Y^-W$U z@xhV6OSz18^hA?Ucw>nmGhqHZ`v4?#%(By4bk`_~_?%NN2CDGhGn#AQ)t3PbSHbhJ z7rGB**WP8}-sWA~y~Jm#e1Lz~l9h=GdN(DeD*PFj8Zya5iMuEC`?M>LQe4Eb7^WpH z0HG+}VZ!J29IX7{8PMO4)POA6;yti||0m?Fn{phZz*&fm?207izWoGORyn(>-6xIr z%E-pB5${l>h+#i|6kwd?DA>{xrp+cko>NfdPJj9FV#dz#HGOq~o;LXy`xv^qoNvs} z7&^D-8s+qhjt+wAx2;m38?JxgIe9td_XTjED@9bZ?33oz2=K<3!P{&V zKa=+Z7s{qG#y&liI1CpjI-YpCCeiFl7;41 zCt?3M@IGotrXk8jC0jmb-5c0cjt9MwTvX6Ec`PD#4mSi93Thby>!ydp~oq-(*Py)zSF-;0r;5%`S zlD!mE*@jp(y;g)Qha+&6(x`a#XUD=7Ta51*8oVje?x0zv(Ob8=9 z7jQCeQ&^TJ^vc4!XjVmJ#rlb^Hvstx_Ty`f@~k%ay4{@FhNXjG7-p38yq7Jb*RMBG z2DL^7)HD;Vt~CIo^7;dGz2BGy5ol9r85(1;J_y{|9awQqC068X*438 z(w=>Ss(b;gNJ*FFdLUfS0M{Bjqz>=~Em80?K?o@XBZ$2?mTAcRc36nL^&$L{2IYp= z8ze)aN(GCSSq+LqW^CcHUZ_ItpIk*xZz+i22m&FmbiOjz7`w1BOSp;>iY3`JLDx3P zB!!O~H2d%_+2))kMHSuVoZcR7Q11&ZS;yGbG?|Q=6qmGXJx4+5(TVqk6gb$ZMItwv zLq;AcnU`at+_}f_&&(sPEoRvxc3i*jzl{zH-D6)`r+Zk5PUIj=b`ypv*_MpctHs)_ z%My%O34Kes-8RK3QclJ$Qo`<67d_4`;E(ZQVA>%fEct7tQBbG{w_Aq<`39yWKC}bk zF&cLrs=`6^-5S4wjjlSzs<4mQRa;3ELq9d~`=9-J*MXO`CTgMt`sB&QtTw{Nu4ZVDE+$zyYaG1m#>F=6h6r_>3p9?oQS(G8@(3*j8ysapHtAqJaP3} zHWC64PQE0s?~i^2~PW<2RdHot;pQb--(>n!kY(qQQerkNyFH|dFoEi7zy zWPFO!WhN(J4*3s%ur`CJhYQ&6YT8R9dmLy@+plClWR8yp`S9UCaML5XFAOOnV-t2^ zq55pC_;JYXlekHT>%|2NNe&hI4vV9}{I2XUd@BA|CxSze& zF`jeahpHCignrf4X6{gQ^`=2Up0@^JV;fX^vSXBv*YFXxRgE81QiTB*(RyWQGA=2l zESaw%N1^Va2gYc|z18JM!#UHT;{U|sH2)iqqpJzxal&uoaZ+yMagc@sJJ~+;jn*I@ z=W+2uI*7+%1@SlvbDa+PB5y+dlm5hld>nI(pWH2EEz2h(IpWK8znCCr#%2m&mU9G& zd)pGGq=$DNF_1ytCw;-Xj(QSi(621JGgh>QjnHO{mbRTGozYa+W7f?Wvitcqa_A9l zfn8C}a0z@&)-*TKR)$YaLT+O6{$&2H&g2b^qP9F=YNV%Zb%7yQ^#&Jyip~#^J@_AE z_GzQCPFz!T2P+duVCiIW?7@spV{`e`W8XlY=C0l?W3H)s?Fx@WBhJqrol~Ncu@0t~ z6))2p*VDb{bqcm}|I}!h{q3k3{(bU!+abS^NIu<{e!>j@S}iT;2|=5~TMcD4UV|ze z5Y&aPP$3*uQ9a{OxaL*4S~GfuG+3yq>^Mojze8i#x>a1`U|l}dk7p*x6EF`m6&w7V zoiU|;wDscPk*#N>Y-Pt9Y0QZL^EC~TrF9QjKV9}>Ju1=lgn_`x2*oig!h zgACp+!otSY#dPm?%vVa0=#hrLewiHmB^^()h>t4YIUu=7iUa?>MSjik-Sxq0O zN~Sw^8bz6^UKv?0FqV(Kwn5WQ-eQUbHK-(Z-H$3O69XG8lPj&d+g=M;Esk5qwh94| zYk%fHHuUP&fMB^RNL)^VYV&;!0(}4f{MvOdL}@}r?+7DS*(Kk#w9IYx*jT3zU-1^> z;O1FxVK^MQNJzH8+k~kA6^ja4zBQ@b2)ctA}0n8#E$ z{D4D`tWw(m^cU1TQMbe}Ej?E9HOqLAO!3cRWz_8Kn8_5r@8`2QX2)z$-4;$_^^Mn* z;HG?(By{S@KhL3sflmER>n~!E6hoh-<^CEtq3;S2S9%u2Y@AFym|MqwCo{K1;LiT| zj>&j?D>Y9_?S0b#!9wN-LZqSYpmnD8t-^qlcE&5mb2$|zH}ZWyyc~) zNNJn`9W~HWt;D0&gIKa&nF)dYbvEU+?Ce0byj zK^2t}la4$#kL?hBN(KrBL&^x#-Ve!qKQ|Db0D+_TYyq;M0dn!th!8uTgrP8FS3JEj z9I2_#igXk8Jb+Q*J^$|~9NNMNo(tU&`Z{wuR9&gnRbmXA(%Fn~xap7#Ap8&%I(lUD zopIpbhV5b!x@90x+_xU440->|&jvV{$xomwWq!}`sb`?S<51@kGS!uUxEYqjZ^}bq zheZ;Gxb3OE+EEC)yO*YTFx8l!gYo+7wvO#|8S^c538!DBmiiy|BQv$zerMwB;)wuj z!QNN&eBj^K7UgF3Y~_@nnVbJ<4^_?KYfm9!b>X*>w>uM@)%eOHUMj+In_wKb@Hd53 zwuT`C=QTJL7xS-hQ-6htY+;7Q=HF79cS}@o z1`PlQI*oT_Fg!L!G&MQcsJj02pWu_FG|1Hs5Z)}gGCUwI@N`qf3(c#@3x5$oPD;O??yjDzJX$IA!uR3}s0N|uWRyLr z)PeD?D=LQRDT7WhAHwDI=Glx(JZCO29l(DmYprD*qIz9ILX`UiZAVO;yYGbYoVPyw zTv{|Y70~;bapSihYCx{(Njr8P1f0=S9wEygx6UeY*3kYwXV#x4%Tw?zWJCsvv6dA78Vl zr)~|IzHAt~cH%8x18ydYbbqbj?Y?5<>4Wo{g2EaV>k`2Eq{}(<4CVahMe+FqSSdU> zNlkoqw7c_VXP;rZ+Cfb9jTpHNzu}!AlmLm8HajPp4fH}bEjW16GdmeN(bvhfh;^%- zoRJtKnsl7UA#zS|9X%5LcwvcN?KqET?m=%*X~zdFFG$nnQlPgSjRlpng(ntgmFQnK zI+&+ba>Nn+*h`!2*jfb>dQ9WNJfY+X8wK;MiBVSAgubK!mTgQsQ-vw%3Sg4Cw!s5v zg}X9HANZC5J?@SQ1pLft0V{x>bPL4`LhP*ZofsdvvjrTY?#533b9uT7Pu^BQ8Ple- zTPNk9qa-EB29PG#TnM_6F93qY`R{2nS0&=ettb^Ez*v)SBmKxA;b%Yql@Vj zm<$G$yc$R!TAtT?s=?+tE6E9oZ3(HDa+nXRnK0ppm4*7Rxi8-Pvq#2O$m#a-GMgTz zcEa9}%GoI*lOELkXu5y5e+QU~p5}_&f~;4!p7ki- zOPBfN=}Y?8G-YoMzW{#7M#%WX+6nXFi5Z%YEC$$bYs9W#5iwxoCbuRXWM)tD+%j)3 z)c6t5(}|Nv9pLIZ4V+~ph0m962+dtW64wVJM2;lDAIXrH9I7NM^&|0QPt@~7(ASqw zf94HPtTg8wxlUGl-(GD0<~e!i$>GeqxC#>|MFJmnxudeZr<)TeN^YzY)~$~95$V!1 z6`v3(20vFkX?_dYGW7vp&6#xs#bi@`;N=_iMUrg}?ri(DRPL+|_?$&#JM*;v8k?|{ zA!IJ7=j5(xmY`|QyTAD%UyiP{rrp+=t`OE0otRl2Ds~j=E!)E9sAXJ0PUD*Rpig}3 zH3Y}kk?Yhp9=#_>P1*%^c1YDXf;zf%8c5TKPyQ{DgJLb=I?f3s5fswzWhbjWqucr{ z=RWa<)IL;lw;n3=U4BID6O_McDQoo&$U^bkBchyo&%P{2rZ*LTYbb036|6XLPc@e< z!EU^Q&*bFf6<7*qnE8SVHtI41v?)-_cq4i$%1Ct92HT=wH=6FjL!XhFe#kB zTb5k3c>V*QB#=kPguh*}cCkjo-}E`k((QjbDS*>N-u?y&5Hhr}=*qxEob2h=74z#i zV++C$pjAg1e9ykMGuLO385NQ#rw{TN+=L66kqYg|$Twm!7>>FwEaKjJd>U0dV`iW2 z-Km3xl^>##NpX#dckWrW9{cW63zNIj=d9ed0Q{ekFIuc_3^alfxtU1plg(e)3I3v? zFKs;EjCBg}bWQZF9YEhM`l&LV+fd>|oaA)$9;+y43Xt!!JlJ`1Fz2;3NijQ9<3fC- z2YvjMtsiVEY*{MZA=U^R#u#Yd1L^q)ocB_CWpF#KH^nhlZExwQ1e~jV0$nt6F-8p% zxMM+N_LU0%tD-zHI${6231$-bLM(UXFa_6~o6GMieKI357v@7g7;QPZ-M<(9y+W`0 z>-Ud=iFPF~P>0B*iT21puQvFwpy`nH;Cbyo3*G4^088YD$b(=*i}f5so3XXc^sgjl zN%j{qh&8X|+kuCu`}WxX+i!u#+mK61^mU4tRA|ri^7vKzLV_y=Puyg2|D%t>>ZUOL zw4D=2$@*L}yp1;T{9zCDj@pxNEoegGc}mFV@@-vt&FGDnAw#Blp{Wx3a%&#f6)ubH zMU5!Hs|jfI6BsaRCdmkDV1P#Yhj4l+a2K_qQmF~SeWOPwxzx^OiN)IAXX86o;@spn zQst#W^~geez`O<{B9WfGmi*UMBR+vaFR(H}tZ{^BSYq6&#RWlq?V87>i=x$kB;0Bk zaI6tcmfq#glSY{i+7OXNDpz!dtvMwEd)2R0C0E)^+=)i0v3ezP+vjNp80mp8`urE^ z>A8*SG_3{Dc+yfZZxxgDXw*&nEQdYdcQ57Iz}cqjBbI2!mqgk*2k1l_pfr z0kkdrRZ9Pm^#4^N6*lC8o=+Df%uENavwHq&T@sgqjak>_mf-7&+lgo5el3m8J_zA& zxkF?jB+EW-#GcmWWLR%kbAPr(L0_1Bo4d;!C8UU#MCf0eo&?Q44dh4O@j~6ea`xTG ztiGMEceckkWp@a)cQq2BVJao5a9XM(E7FU|gwOth)rJ8nl`>72Y!-Ud{oQ!(hiW`TjOOS@!XNwc59BENn{Wmf;Pu6Tc19txB%4M0&IsQmlVe z&SbnY_2MywT3DxY=d&&Z>dXbSz+P^;?;FJr&9n zL~_q3WH_dyqloDL7?s%YANEE?c%W5uQ3u|eJ{%{)sZRt%)+A_jYQCe0gVySx=k&`P z3{CvkoJa{=GhD2n!=^e76MDR?U&#DgrzmdiJ9RdO5X2HUJw3dFHUrt{`gfgsoaNV^ z-hY&?L{qd@mB>@=G^O5XM#c-Xi8b;qmiD&uE;=jK2>*b_P!$S-6AF*U7Q-4Cqpixe zCD=ATEjLOpzMy^6f+Q}L8vK}ZK3pdZTk&0hO)|4 zfcbTAgUB(Ea2C`vS-OKf$R?m7U<$XIFCX4_k!+a5qw|9BWV@^Iq!Yd%8ll{v@w4VN zB@aVf{g-^p=igX9e;z?16~26aCR!9AjCua}pgZS&7^vs?r;yjE$r+o=W`@2@_*;I? z&?bci*sNXC%8#jqR2^B}ajM`nrd1CDYO4~$Nw8cGQ#d-y<f-fiB8X3A0v3{*d8U7m-}_MLHb+;Uyd2D?SH ze1{i`p?S8$5|c$4EqR}D2zVF0peTUNOBYcjr`IAT!a_{HMZV5D2g5?9KuJ$Fn3OF! zI!n+IXA5@c=ybdAy!z345NC~uh~6@?`dpsD&1;tav!y8$3iQjgEVr)UjA^YT8XAg zjK5Et=U1SOBRD(3T3t|!H9m<*zJ%!mYn&E-zD3K%j`EJ)9r(r1n?;ePjZGGmkpc&O zhnx;`C*%5a`8z9LVZ#I({&o9sj*%&#r2-1|xuzNlm9_2pn%G;#Jw)^)>?G2nGY4aZ z|7R@_y!~79bJ9o^xU-i4N~4FOCqSpgU*`gGC@jNL*3|)0vdVN-f8trvZxcXT=mpNk z@5>Ds9a;?Q?GYDM9vv!4FmlM<^~A>Y0%YsS zBZ!rUq}9trtO+LblT}WeikzWm@ggGy!$U`D{hX=*ts6Cu437>|zo<8l_Um$8f#QPU zKWL`A7j^;8(N?CENF<*efSUVncpqCYFHU#dGy?VOeltc#v!S@z$54 z-}EmYX6ZStK@p%2?QUCBWYu4#N4P&_enP<}@4`h52tMpw0dg!w4;mpm3Zcm+Ui!YE zizHC+q1bUaMs8-l5}jmX@An-|aeZ?*OZQ8dIrx;pSCtY+*-$_UsZUQ^B#KanBG`DSEG?F{yRAj>8<5&bkoK9rY@HPO#BoIT-%Oi`aXn= zBDvL-)2pD2HPU@-5ND9n)H41`CM44uz1DZw8*O073^3*4AxnLt;d7RRv&PzW?;p6r zliDf=Z!BskI}YJqR+t2CM(-dEQjYiBP>kier1<`WlFS0ERbfCI!fBaw_=v*ii{mkK zZ=2Vs3d95~TKaEb{glk^F_DHkZZf~S&PT?il0p(vwpctr^?P#pR2Q8#<=Y~r4*h#Vy2V+5sF#wmIF}qG+9`l zD<*KXUAEW>PXBOb*uA^w-k@}B<0W3Is!?P&87gs_Vv}9b%ei-&9Gt+5(KWT$EL6_+ z8YV8hYB*Z#-Wb=71PE#c(NEWVV)`Kp+(kg#7)D9e=ac_E;DZJr6vRdUl1vupuTGSS zS!t)eG3kf}vGP~)+Xp-|y@*%+$Xou={~TSwd#`L)R+>ou12$ng0b*qg88bvPGC9-F z$3l?V>xbpY`S`5(jHv^OF10(oF-EnyJiGDA>r}KMjno$g^2tZn9RidX%4F>nHmoxx zqKvMO(Pcz``$3*!IK39@iXz~WtqlOQPl}i6EJKN`SAY!BT>>v>Hek{wtH?da;v{9B z`)VyeHl8z+KDBVks(51>)Z4PYLzl1!YP%dLt#W|!m4y!}7BwL3r@jw70%(LTdQF1g zvm2~&y65Z!idOk9%Ff+i;CQxtRQ0s!D|LFk_IgPklY~e$<`PX{{Rj!@_e57t<-_NH zJfb;3+kDxHSrI`L3ql(;mnItJ@V_-dO9uoVB4(9hmQMu-+r{8aQ{gCDX%JL-ppSRYw85!kgsh6`2 z$B$2WCVSHXC@GYG;45)YC`;7wdQg@1A1-ICdQy7la~_atswi>=vR8!50>-jrg#5>sZVISc`#7bvj2o0_AUeZPbrD(8C5;0C0~+Bph#US zX1Zl=2F2O?;()DOvgqL0B;{&ei>e?Qg~k6Yrq$*2!2Eh4Y0;)v8mPg~ASVo+$NT7n z=0V7=zckGt9eSw|f@_qsSxvwHq0Cn!befx+pyK7{uFzMiO?dn800St?QhPYSsmJH{ z1TDX$7XEfxA9@!Y-z_KHG8h_;Vf9LfzCQ8INdj8+_)9@a9iFdKp=e!PK(KwPf<GwtA3+)K<1%3-dd0&;1gI7Kw$UP8~>W1_7i zv(lXguzOIfHPaxz4a=g?0a=!kv@4KEYP}|`u8BxgpwmaQ0N0jb{PjP05to-D+48u*N>>qiHkNZuI4qJtYZ3-*pes zD-Z#lSw9kGZGo9d0Od|uQ~L7HNEdc#DYPlP`>stdBZJQxW*%$&?Uf#L{#6Z2td{<> zM9H$`tG={OCUeKxGL2RXs=tr)YC$aU^m^&5_NPgYdr zrv6v6h|QSA-yT3@{ILP@FfY9)j0;d^ObS!h)RDfYbG*emolC+?@$065Ah()>0f(2a z#rY@3jk%t{AmS<0RK&X{nW&=KUn^ZuyD`;YQ&X(N!(I?+`FvWV1qriE7gVa*qE*MG zpQHE=nI)E}M0g>^jrslo2M{+iX1d?R@hl+e>f4M^3n-AlNdBXKP3j>rPrms3x_ry2 z&L)sjjvC)qn*tyZ4e^Nli*^7q??$-#EeZakWvA}bZbv+w4hAMdPuT`QM->px`x8&} z)*?YWPH<>})Qhlb39h{pGuXz;*DS9Um9ht8f6rRC%#7Ie^@6g~K!}h)pZwUs5?(rk zIl8KVoJM)3=xld5mOgh9;)!%*)pseh%pakK@y@gwiaw7C6!$*L< zNt7?6RYX8m$4e+6!0slOtg(0#@_rDb$3<(SiolwYABQ#I>;*j%y53p5bgFy^Q=)Go zWB3f7)HBAkaBb!{K?3YD#d?$6FLRivSiQeV6OsipCN7fcRS)wpT&X0H*?g?2=6b2n znWj0?PFdCkPW}08OJbYj8yn$Gu-%5P!dNBp`z;KN>T{iNBK|~r!ka$R@H9PV?xItu z;fpU?k4@P8>^H3S@8gyv92nG*`OjW(puW#g{hUNW|3f=6fxVRe5w$bGC!zi=d(^5d z&LEe2tou)q{}#DqWVCL1r*qAr5@KM!M1oL{JU zo*$U)cCeG8Jd&bS(x3&d-<9KAZ@9CghSPfXVlb2uU@_n*$|liDzZzo637+hua~(+N znd_ZFtL=ibh#@sg|9ni_8c;*1qp&9mw$!nk;8vR|BqoX-V|LOqIH^@6stc3Zeq>?-KWt z1Q>g<-jRbkZ(W747RWG{8)T&N>esW`IERSmTME?l$y(I(ok9$_oCGYvRMG+5SlU+q zrm6va@n6O5X;K>wKp1vkfy&bI8mnvs1rYjzY0dQiBGcAcLspU}-Ml7jKxqg0ymzK0 zIK}fN{u~x#DXX&v4J-Uq=-^vQe|{>|V0^mIZ$NA@gSA0JgQp6JD4j$#ms*?_BC{<*p32yMc6w93ddn5)=rwTXjI&+>NFJ&sA7HrOK z+3v_Xfa2wEzz;xpZwge}?ZC~ymdlggeu$gX8JhZ;G&FSjVrZtE$C??ya&o#IO1+H$ zE=EhnDeeD4(f~iB35c?rKj{UpJ1K^wc0Dx4-P8s3t_vsRI2$Jo_p?O4_L(I4r;7QX z#4g~Q|B)yM0L?Iqq#1d7Nii&Gf+-Zh$Z$=q)fx%qwHs1$T^}Os{%KbICpZC&PzxYM zobw|FwCn-JXXcWKKQ(Yqe`5t&jTVD+<~1(@`IfAN!gJn;U20{rjGqX6KOlA7u4vOwOlH#s@>;n6k3_*j)7!`PD z(s%;o&Ke46#72MC(n-xXQWZ6RthJyd=f84N01fcY)6!0Ayb)+BMVlvh3vi#w!~Y^y zc;;zysuD>YYZuoSSc&XURt-Gv+Nuv-Ymy*^3|B%{(ly>}JAM9@$B3S%>wVg*4@e5h zu6XLP4g_rPzdaXHz$>I@RN^9KLwo6>`9}K3RsjY*`!CfnCd}LmZbsy9q=est^%5l& zjNa;?Z$#FN$}-n5c z9Lj9QIshh6%)7S{y_o(yZmh|Fw2!&ly?c*|h@_j0uwqSIT4_wS^}91@focqpoTX^S zbCn|SK?Gq4BPE9m^bmq5nsW(G07>+ggJnH&a0xxxbbog>D1f zs2R?$yhr2(e8B=CTm9nVI!zJcg!sX<-1KyF!FcpSC5(cT!D>n_7PKP>QVwN|sss-7 zDtI~HI3h-3I3%=!1SgTvzey^*d27xo6M<)#@J=?JmTbd8aYH#DjX=u*zc|)f;u|gY zHwUF}qw*yAKbGjYX#WKBY&g8gUmbm_qk5{Q156L6e?bqFbUFumvN{yBD{g=FvUyja zswqAC{8LtMN2vSCSF=y5%2RXOH*F1P_E^Ilbs+^fHI#qo+yk+k8EDeV2rW6yl z#dyjrqp}%QE3N2pz}G&LLwEq>QF25(Ih&^a$AvG-8R-fXr-D z4PNn(v+?D3gLu$t7dZ#=j2CyqfHzHFBk4lJOm5Wkx~yVB9WRzDR=ZaKbGS0lJh~ia z#j)WeFjNExBPM<8Ct#5hBY#?XjIRgh&ovS?+gVy0a#cW$^Uxgr@dtT zcetx>q;+T+&8QiV@W}HGpGtE6Kjh~jX~#ctLR!e@P5<9*PbQKc|Iwd!{b4(yzJ*@> z-toV`#2l(0G9f|)JTLso1P_IV<356OGXPupuL=39H{ZJs)D8g)aDpY#kr)Xj`oO*! zHuCI$y?E=t<{DV(Xul$47YrMg85WvvAXu0k@&DgP!}5RWgrNAfW=)(0&{O=MmFFh8 z2?IiS0m>)PQ_ch1fR=<6;1vQat8n07^rdrti!-JOs%myz`OwGiv>0f z>mq4d&_6tPe@_hir?saX3j6ueWl{wwu$s9RhC6HQh{=9P3yw8I<_nXz_F{0z^E)Wj zi<+>_xtQMcHoaN81f={*ADdH9fwG8yDD%FD_x+Rs*8cAk-(^bT{E`tuS4uW``zZ^7 z=19{F0)HU+DSxmmizuZ|JLs(R8ELEJ`Su6o6_`PgAS#hwB>xHpq9V1S{%$khHS6ga zKJto5Q5S11k>}eQggnvsaehFNz*hL3pzRh1lD8eWvoPB*z;*4w!K~J35@8!ZH@zUsX1Md6HseLw*fm5v4&-8oZOwx$rbaruI^FIC-r{-MbuRhX_1L1Src| z2FOptdO3lui4&Iho~K3zq$2=0f*@beUzJi`1auq%VvA(fi8AH0`a-t7^WPUWZ-(V8 zKjy~73=I}95_wv5*d66&?#!Q^-xDR$Gg{047JiUC6ZCE?>xx=#dT4PL69v7l>{_%X zx^}|t7`wAm?$rV^J^x}A|M=uE-~XNL-)?gL(y3qSzl8qh`daMo`z*yrFUUVn(Z~wm z5ngcn#ueIt4`9OYx|xwPJsYl#9LvkENjVtROtN%+?J9Kv#Xy!;(FkI0MyJ!bA)tSp zV(5d+C(At%H9>FVOL8S!_q-0=@-FqPUN^R+YL6(e^Ye)W)}tF5;(s|N4;pfLenpTA zZ~#3`ie~!2Pmla8y;8lW_^}#e`M%OEZUafo-g-qP$ZAz9`z>L!39zr4D1Rp92RC3v zV30>OzSYz}2E>HeK7vdIVw(V^vdrXYTR;yWn{M5_+*g0Xwg}#Dhg#ii;|20Sxt7@i zv?eqvmTzG;xH8LRwT=qI*SkS4dqj*mhN{yb=-1*qvMX-7^_u%s1a1$O({5Z0Het=7 zyIz;lWpH-qboElv&Jc|95)e3gvSHw!>m;!7ci%6l@#i#dnTJYFh5GZeEV36vfI3Qp z9157FE|K+$PS8p(k=|~0*OC+lj{{vLFHlxxoiV0r(E_mG3Tk%7a}AWGBlA4x!R}HT z#6uh)M-Bzw30EaGHf*Ft8Fb zhw_zZcS%)|md^5&S6z@m@oVb3^QSXk9g~+CcgyU0g@XPw_Rmso;;+W9-u_z#9|Mq@gOw!Upd6|TG5^sZ*SOj zc9+IgW5EYA$+@2!^jQtb83p?Sy9UT&jK=_28vDO^FKxCH>FqQ1V^TpED4R3-2>=$OGz}8i!EYr=M2)27L zo#)TLW&UdiKSe8Y0KN+Ro7V7CA-_Y{VxV0**z%ko<98{?FwS=e zVNGt#Lv zYforkv##>y?Z2I>O?chY1t9F{I9*Q|@y{?-NL=-H&f6AT5p8c80B7 zBKiGjD!a7`N3O?>wteI&^iN}C9PjRV!)?!JPy+pwjnQD^{Ut{j&cfqj;=$E3F8xD@ zZV0HtRZ$Jq{ zsdmn_Oh0ve>v*ZtGqi}J!WpD(O(}3o*g||FtM!l#s$jC@PI;JB^&B~Gh|x1oHs{3geH z^!|vw_&;m*&!n^i>t{1lHXpn#O)n?sm<;6kgFrB9e=UE5^fHO$#y=!4+~9?9eAccs zeI73>_tl3xv4r7>41H@>5WlDm-Ip*6?w9&r%`CixR@P3hIbvR7yWRA8)iYHbc)Y$I zl_IhCze@6i_#B+j+`5#*UxWo{3|8mU5Q=pEXIAbsnqVgUwt)2*d;*Q8^4@ttpzB%1 zjsZEmyHnZ2m0OsEEkAZ#x|p3uY3KC(dox|GE7h`)-QdMu(;_TTx&$Dzh@E&Jjlw9d z&nmjfSxW65Z+R~&aAyOMJ&b#)I35b8BYTWjiAJwl$w4cnoO!fW33)e*h8pdFT||E3 z-L3h(IIwOt(+E7??Ewb~5AB zcptXFvFd}Y%VhYh;p(oXwe4|)AJaHWm4;}_9sA>(ONp*=+GhsjZU36XDPZrvAKh;J zXaBFxGq0!pX@r#*!)iWW-(5^^yu)s3D}PKAPhN%fX4dQzi+~>tAqk26<*_-Ro*R9M zdCiJhqU;~{i6n5KkjAS$V>N=WfV>!5a}k?abM`1=*?eWf@ws&j^vMi$DSTGt=-g*g z?C3|aWN6K1cO}WfLv3fo3Ch8Un~ib@OgRU0b_~8~#e$NF0j z^t!)3icHj9LiJ{OwG?Jp3tojmC%}HTun`z&)RkERW?PV1vrJ;kX^at%ym)O{@reE- z2Q)2y1CcD8yXVD#HDb_nj&tzAO9FB9@);ESGT1{(lm3vvx8^ z#he{fZ@L~uz>c~VEQw+Py5-Mn2RwL>cC!~*dGt?BDx;lE92+s-Kfb>y`3djR;iMcY zw|v$0bEl%j;+&1whM2O|`2=vt0}*l;Fuu-%VHK&37Lm;hjiwl2Tl|lsvZwp`ot=qa{!jA4c2m)(RhRJX z-Rt_9K-iC!Vb7uWQ_gOko%0?^W{wjD^BZQ^Eo@i+xPcYm_ooq&%&V+-?h5RBc&h`C zO6#O& zF190EIx{A~{WKjq1MQbCH=lat_;#lbXMuMH4hr7C$0*8O5t z9;;(eau{RF2|L|IX2yiNd{<9{;UlKJ$sYJ&g9j{@! z{sxb{_W`)Kok>}J2dW#5G`P2_L!F5*@=KZ`SeDalQ)LVEs+R9jwGHa?Q5m{?V6ymQ z_QBJHqT;0DCi&3tJJfHM2I`doyD?t1^{MoED2FH;4(!+a$hIGUwRf}knEh?lQC)uQ z2aUSD*@J6hR2wTOg$W0pp_3>rmp40 zhpy0c?*RL8$F?!&*_heYk68zIvpXfNmEOjPC$_Mi6Q834ia|$g6WAgD!_myuRmUi- z<8h@utF!(1;r<~L<~RHKK^v-fWCcWIMR&*UCz*mUlgil{KA3xl*WRu6j@cvM>a|aM zRe;ldr~nYtmsn zKmM_nnkOqP2=Ff#e*MsYZisGd!gRJ8X^R3om@J#;0G#7fsG`Oe+@gvz@DV&H_7DJu zB!iffFEcbMGTjxM9Uu|l0l~rKR?~X}uUjyk<&!!(rIoZvSgyk_*)cCgJZjTGx zn)T~MuFb{F>%Ks0*xt26-yz-4w|S>OZ`v{KZnOz@0FFz>VO4GOmG?RXOAWi%sxW;V zeK7F%7ru|s{hajH8TLcBlb{kc5!FPvW=Rm5(gd>wcO*xH#s@ye$ShhZ3pJ*TY_?fn zP|RmJSNi2dVbfeJkPPq6c4$$1@13@tR5Y88@0<^Adf|4uNkf8GMRzE`k0dcHAIEOI zoAaSjF6t-xV8iwztGk#sUp*rq&t|VNXK+bSyv5;Q;$q&{Gz*;L@Vlt>J>Aa+WaBt;M|VdAwW$b>B49Hm%mS@)snzY z2<2vZZOqpW-&*0b@t4VA0iNF1HsHMgLC#xG&yipF^H#3cm!+uvx4sOE^(y@1qM!hN zm};ksQ?ui-IyilAC#e(_c(AOGuCytLLO|rs#r_)nP?U6nm7aRneN7Y5?9Fuy&U||m zbv2nXjJnwCc;W zW_Ic5dHD6te3bf&pf8_)qiR`leSP6V%j@kK@7*2bv$n``+f}l&$8;Cx)$eCf7OnxL zmAnvd-KAm22rEMcd)|=9*-eBl4l|+2o$vSCJ>-(f4HXJnuaIJ}s(qTnGiG1^6LSh|fBI2uvOD&pscovu1$1fZx@3BJa;pDU;ln zH#G~)s)@B(c7L7GGT@BP*M2t>wNT#rK6%`>ZkRWZEd=vlcZz3eG%fc#s{UFXg5XFn z_xOnh4q2nCpzl2n*p{$?l|*GZd+ATBBpKi7tmSprYQoFARpY{u#|y3xGp32Cx5>;< zXlLcptBVKll+8hMZIPXkN=BQPpx;m-xQ;n3k?@71zDj0|jG*KGXYl!+ZSt^Hneo{7 z^Pnb=<@0izgT%-}d$kV2)nzW%M9+b9aLf17MDC4_%@+>FDv=(*PY2Pg3722H%UX(Y zuA`6D-N(xctxWRk#dGQFO~exxTv-}n*htf3u;+}|G~bsUJ0nn9hf4FSOy`BI(IJKS zMy8^WEdDD*@X~JYDP_Br;JZT=@VDXvtAMeH)eceTMVE;bxBbVFZ82AS| z4NDePyY9^$354A=yn}pDUz2}K)Q{m&ZLWthv%Fe zx+=}^}qJFT&au`T6XQ`;TSd;i-l`0ox>CY=^D4u> zE>=_Wc+9$NUE_keJM16K+h#5{NOuw^2fkLLR>WMjdJm9;zmVC2)2T!qiq65DtyV&E z1O8n6VX}s%{SE2lL=S=Hz3t+=+?k)zTxFo8vJ4?&-gn2Ky;ZpUoP+bafy2t$bj6 zSf38tU5u#K+m##Q?8ALX+g~RtbH~uIx_cQu635%Ksb-W*u`v z4)S712HRh5^G+7&y*${}ZLC5Dsm))2LpyyOv5rb;CC$Mbq)ew z77Ha_6x!1q*{N4#Hrq6_+~0nuVbUF2Vmk)<(pyU%GtRrZ$ibgGz7E-FdVI+a7-8;{$MM~eMJ@eY4CM0a%c-rEgNDQ5gE&%m znk=62T|owS;US*HCF(_LZC=(u@v`IK$K=s#Gow~_2(<54>p<;CP|=%}=5!(`>EhMo ziv0sc!httGX!g>9pc2>}n-BHe-5J)d+uPuD(xN+HpPCZ-HL+w?;vWA&9T$3cA7(*$ zw)CrYu+}4L&9^b7w0&sy#W4^Pbp{A}9?H?j!aO^~{HKo3Zt?)L5LL&CIvJ1ZFcR=f zbJ?z=s(~es%$4}s4kUr6PEYzSMvHDZS9g>bLBaR-=RSUuCu!dNU%cj-23llpX6o22 zu=zN2w|(u&U8^hs;+jd==0k^Jd15FjxW+( z3mvjt{gn<8U44v4el=Q%c8b2Obotpdr%DKo;De61Q@uV8bmYk14Y)(9!j^4W^+a35}eu-$pwhr~43jop4Y8cA+&!O3gy-So<$dHCg`HbTL_ zx_xurWZD@uPicUA;WZM{UTZq@u%Q=l;Ur_^^QnH6cO`#mx>Lo=WrhV@tj{WEIx~K@ zP-L3bqHF6=w5Me zgD-y>CWLkPc;5s7QNPcD-N|Xr)e(XDD)ohrh}7rR1=s7j^DsFqjzM9kfM&aQBHceE zlD9`mlmmovhFM|f27;Hzdj&gd_ytzh*L1z2!q=uT0FnTJ7y!PI-1BG1Zsu@wK6nD$ zXCuX+Muc@@7#(ePNpT^OY-LrR(q-9q2p+DQXHBx|%?cM!!2H%pD6w;ce~Kxq8g6z@ z3cuGUGE|H|lF54{g)Rp7MTtSY-S>8T{#XWo3&RaQ5?IivRWY@()bkt{yCqalYgD+i zj1DX^=sKEbBP$fAOg}SXC+2(Y8!rcl3%KK&jdb?WeR4pVn}0~xuf^__xEMbI_@c;O zw<5jT25BuVnY-vXw)>V7-^rBt0Y4;wwL*wv0FIJu7sqV zzE1AgzPF=KdsL&~PFpz#sE8QE2pF?)=2fg~K&#sJ?l_SH*%g4ZuCrMKMW&A=Kz z?bf&5m=k#7POo;Z0cZEi{`3QGyqvEXaV$)NHs>Jp;K1;_mq&?JsC{r>x=^6T&&KPb zXZwW%(YE)$NHo1Ot_OcNO{>y9EQ;xC_Zc*p;lrhd#(CXg&Iz(EAQd0t9$02Ne(^#n zJ1lLzon_{~bV%5|hg`C|fE>fG{y-~L!yyCy0?^2YAeQmz9jT3nWZ3{=Xp~n6+)@Oe zV>s`$oULVB7Ug4!6Td#3J6sePpLGFJNcjbvp5QL(F&tw1PXJga3GQ^Lv;yOd?t8%JrNW9CwoO zbPH;nnnBl{l_{D0W+5e)zU73;TA^9E#smdX`3*F`b0 z{`;4ZOdv+=ArU+T9$ksa;{gI+PmhrmI;Y7cr0gq3k7Q&wpD#*Mjv*pe10?1$jfgu z2lnM`ilwjZ?xJha`6T4MIF1keWf08pa?n7R^zB%q0`HgRKQu$%7w=|RX9ulZ4+Xn$ z#8DxE&l9+xz1)tYA-{n1PtwFZ+^wJg;iMV0N+x<{L9G)JE7KJ`)#e2B;Q?RO=xf=!VsnAoSG=S52RYeoC8jD z2J7^uXSc-sHQV-HNQ7ZB;Pl=DhO?r0S9&_#yPBM3(zuGD+jNr$Kq$4JWO0rJ-)SLf z=MBBA3~2IgEg<1_?2x}(L^j^Ohx7C*w{x0FnR3M|7(NX+61*-Jqq*mht9{=&@pR-r zMah_h#33NlEML8w!5y*GZrB8xK>;+76c@WJ6aMAy`EFMUxcl+X@O15_tM5lsm;o6Z zCImU}@hbC!_$zi#R3kW23HDR^2~?4>2wP^9mcXpn2u$!q`In4c;e7dl@|yT59wo>V zmRn`uVb|JZ_86=-u}?1W<&Y0f*lt?SKd&N9YFLOzx)%B|!AC;6qv$Mfeg@K@xnw+} z3*3rAODUH1eOVqlRPYHC!Nm;D=ybV&yJX>034ED=%@7DZ2b9{N&7z64kbr~WE`C5` zdaV_;6X-IPZ;S$unmEt_9_BnTLt1nH?YSRoJUjt7z2L8_92MoK821z7)AX@L=K>BJ z$ATsn$u10YMGLQJZUb&cMr%35(W;OMj7S}*M~XyskVkaTTSkN?5ZuTjtqcsSy5`Dh z)Ldjnl#24tmciVtOJ^CjL5!P%!nY14b=a|Lqm<+pxr*@8Bg@5SZ(L2_DPJ|pl*o>7 z$L0lOT8v4MT=>{U-JM#q-U)g&9+vu{yqoJ3{}W^(ssU_Y*NWy+(7BN4?YnL4WqO9F=mhsM`QHfDlcNi@a0~&7vAldk zWq?E3s*2KUN_{bj^#S=iE~JuARbO(?#T1sRzqxU9eJ_76dn8UoKk-aYQwEMNc+EGX zO{tLl`DHj95u9^*9Rr>e3y#c}gm1M)_B5U79|}m0bX1~zko#{L!--EdGUTCaF>+!| zDqW$Vqr$>*IA+6lYreng*a=rW3*k)nzrs;0!J&YnSA!5@dt9$BMs|xJNI!$!*PatG z;K$xY*MyuSGa-oA9d(rK&vPa+YNR2}o59mgF>{JSdtMUC%5%DifKk_SJunL}d84u^ z-Qv7AgzyHqRj_BrLo_u%GVS#HxN^)vu`bGKDuf*O8_=c1X%w*(p9Kz6X7TCMG%5;s zsE=gu!r>CQ$+XrJ|2h_=p;F_1X*SgFoaIMHg=LnF*4+H@lZ)Z%t>8}P-fLb%CJ!c& zI;(p*)g>X#q9024I1O4|vXfexwLiX&eXsFrX1le07^y!g{+v&q2{7zoOAg$#!Xb^< zYRjT14p&Tz;Ns5Kl@wQ-JZ_$wJt&1(nz&=dk@kT^;`)2=2wLVJL_yBCzbeQMG5Bh; z9ojGwkc+Z0(GYa0CVmAC^gN-qatXU!m*ep|R1Lt03KK(G>Nit6ip0z-=p8h*Eb$!)ndgf1Y18ja^Me z!i4~*NyY`H8rnh-`f0vTCge{%d`($s_50;yw96o*p(G@kb_(#rHfh-z77OK3ApQ1Y zN_VhPZ_}91+MAL$W9ygfHSAX(Mk)=M_m`Gt8dVTp4L!46_g9RqRGt$uWtRHk9ZlJ( zD#${4`0DY{RvYd`VnJ_F zQfj2?^rs`48p{~eECAu(4Wu$b?wL+jNxSH%Y2SHMD5O&Rm`sm#@IBRUme=p6GOuo` ztq!eRGh!X_;5=T9wFMgvpp49^c0k{#{U}V=-aS9H-QfXn@$v@CUJmqRjooHKuTS+9{-r-5;s_747ARDpbJ9*iN*fN41a0YrdpG;11TepAh4JoQ2-Q7@ zEO0FS{+qAH?S-}cV<(M%HNw(Sq0!u@|2XvzBE;JQfQOGMSp z(E>9HFZG1)x`X~ircz`pOD1c{*d2M^w#EIixBt`kWv1U5)a)`Au zL3x})*ZZ@u9QfR2Tq5roq2tVp2`4a%g%{Q+ozTCJ(+ZPt9UBsmQEWKshaj%QlbD4XT4qiHc(tO9loqcp#ru;QyY< z_Pgk&ZAF<5Hh`0wP_&mMI=@ozNtB`&AhKRv>2%1)sNUjaw{ z29BtULV^<&S0$^>qA-V&`|Ws$qFHc!oJu%E=o*fAx7JyGyy>J*q4gbL%$T{zXK-Ph zRv$D4>X9bah3a)j;0sVgkv)-w)t>o5LRFJEVs7-t8oLbfjhSVn=u`M%QUlm5d;=$G z57QNVr8Tl&)RFc45kmmkM<^10AdyV;%`OH)8VR$|j_NXBBH3CXLghB2ghZYF(f}^O zciV|B?tRa|aP}IV==!1NXe+hcKz#l_XaXJJGZ8^1WJkd-sjm(Q!)u#;xpB*lWYIfxv}h)xW64K<@>5XX%hNXB&}!f zT9089)fXpaffBs-3zfJ zLF;$=(2=5{{@!EIDv;U(GEq~jIJ@WPxTdTzDp`h)*Qe?QJ5`g<|2V+}?#EGJkx%)N z`v0*OiCveegdF@I$C--oLm2SPvCg)u-r$Ok`XLL%(xkh)Sti^NF+m@&Rtwy#FKZ^G z5+8J@k?hu2N`Fb7t+mr?XOIT9*-8*eR1lgYHB!;WO}Tg@RRR_hKiJ~f1&7$c$##MHE1*BRud5p+2DHi#zo>iD&pv>*Nh ziC%!;RHl9a;xo07S*Un0r@~8k;uinXi*>Ix6yAt6Dz%9UhTsAdbrCm3`g$WuTx=Zq zPrtlq-te9)q9anPwX0D9uTTZ2u{cP1l<)vob*V%%N=6#zZc;eg)6f+ zgcFF|B|fV{eL>|aCBxvS;ImSClZy=n8(=rU(+8^ZLuTseOK6Iqdb+ME>+q@Yf@ZM^ zlnzEyt%t}D4Sdho(b;nCyK;|X*oXd1T6JxudPZCMWbTY*4WLBNTWsTvAaHkZZCl)| zxEA=hn^kClM0N85o0_nOt%#IgQZm->-hBJe1b{u* z{}gFp_5)X*A{C(~EUHGi61@DTA35~aZS^19wVH%EZNb9b{XV?f`NV>vEv41!wt>GT z>wY669Dzh+)b>A?1Xheinyt3~#*aoI*84=99ZZ{U-evcJ1Nw7a|)!D#*Ts-v-Cp<0#sbN+rhl^^e*Mm1B)p{b1_fD1;H#aKk4XKx3! zm-I}D-A#9#`??~N8c(-6OOpF&8pLU~W=1`rbm=V~^Sn5fF?_~9Gb>zRZtG-9Dy2NV zz&u;{2{bj_LF`IfkLHOOsR9%?d!7Gr1&Tx<9&yUz7(2n>Tz&S*rYK6uY$4{JEKhT)bvrt$g^ z@`^BQ+hN*sc|bHO8^-6H>JggC?^+jb|RqUekR+L(pj%^XIt%%@0%NI8Jp7e+vK(FpaoXh>++-K2qVZuniUv;)`hXhUQcyMdVeR<{yyZ^tB3*ieKZ7G&YG<99`$ zo@E|+{eB6gd3YnIN{BS?7%i>Skf@&tAoxmj{^oEkqgMQXn0m{oDE}^8cxLDZ=|)f~ zX_00?M3C+-L0TH5VE_@Nm6RO1q@+PgQflau?(Q65IJf`joOiw7XD#@!@BQ2Rs$H=6 znz02rBn+aoc)_zNG~QOA*8a&lXuT4=^6U_6gl6V@<54> zz7#u&ME`1sP(Mzx;(odj7U{3nU8OILWjxS?Z~WF9{7-GR(Ru@3Z0QDqCG6OU(b`Xu zo(O-@#Me_j0iX{*3ls*EB|KJ_aSW#x{Mh66!ySm=c z-h!n+XS@WdGbZkEfUE1LHL8#eLipl6X zN>OK6 z3%3WOPg_DmTdcfIIM}+QCKX7B__m7v0tU&*TYUsJs9JqqJ7uWlxELWxl-|!w9GI#ZWgF&5A=(7zj$Mrz|h??6_T$PYhh`Z z=MQmIoZAp_k;Wp;qwV^=p+F3ow9T1wIT|XDZ$5(Lby`JhH?8rm`2=pc#(N(a1dQ#8 z=~5X5-w$g4&hugjjl7ovqoIOW0|YQH-gC#GU_5X{-pvwmRR9gf7n} zEe8Z0C3D2y->5XSMVfA6K}R%)sp<|5A;wk@@B&Kz>)kK;TkR`PC!J)nNW}pKtvw)W z`ln(2r>}Eb1fCOX#I+sz*Jdkc9=3c1;unk4ZC1adeUT-o{8bjaB#ac7cug!oql}$-S;*0UlIXa54*Y@%#usRf+}w#6 zQTPkSkRpv!XqJNAjA2RrMtTRj|45dkjdjs%(@QS#D`sT_Q)H^TtZFMHy2yXww}P#A zu{RH+xxwR)F35|<0{t<6L`i2wMdEfF`II;Dn@BUP)fW!ha_E?s4bCR_`n^~oA2C0S zNojBr;l8ZW{G3;48^7Blh_v>DGZ9;e+uf>_q*$m8eO1_^f25;PVVd| zl<`rk*WZzqtkMhGH%YY!FMz5eZg{S=?K*iDo22+A-89D6@80!}6uQTn=cIQ3$8<>b zj(X{s68RPnsp*&N9dPQjUHGd5s;1(NOuj8{8xc~09(*@lP<^0YT2Dq&XFvypxC(s_ z<7qc;v$m{JZ(3)?p`~Z<+8VPY5JG{uL=Thq=_`hJ1_6#+EEMNND20H&0ek|d;lD}+ zq`DtgW`J$_2Q`-La?@Y4krvNal+vur%+YcLlyHn~kf~pw?!(*$ZUj!yc7jiT97vD% z@JR-m9AjL^FEdK7xSy}TgSxOYi+RusGg(Fwt(a}Lf;C5&$KNnFXd7KN*l4aShFMRN zCgh1PEY_R6B9*TG-Mni_2X(2(|Ao;#21W0K1;ZLS3q;@VhiN*1l+>iWbSMg=TQ&YR z$VqW|{JEY-!**d;N)W{{LthAy{fIF&hlNX*b)fx_Kj-H$C`bCryP&Rv0t8Z{p;;>2 zwY-zO(dQ-9qdJoY5Mz)rT=l86tTg>te)p4vaLMi5rD7%SlqLtrbF+a=I#O;0w% z(Vl28Xh!1eZbY~^q`6t%pWX0zBIPX6AL)^<)o|m~W4;SH@fdmAH1d7iE_?Rzs3-3q zFEXvEz%`*Mbe^>KP)VUn~+kO z#VWB|>hSjpQ(gX~buJ@_xw+}FU*{cuif?n;bIf)&3l&K;$x?D~-PNJkZ~?i?>#8cb z7^=1_GhCe?ZhlUt+oghP)_r$-X(Hq0E$ErvK<5kPo)E!GSYvfC&h**+Qk{#5WgQzKjn8ftNVBrGuG}SeLeG7-&TgMYb6+V3EHI{sKfCW> zKf9edRol|+O$sZFN!yCei&YJDH`pTWw>Z058-JD$`l$-hpm?J{&4-4jj3J+F6+R(pZvd^e5e-(th;Wf{kz1ozDxc*3s^LK!?lb!32OC5 z`E6C-j+^R@Y~d%2;$6>(RF@#iBpovmDvV1vk&~>ygtx5yRu$crmg7x)s*nSdtZjE= zd#HXz0Ab*1>nJQ}()@ShV86!iDmsyLbMkHYY?LV6Ai9_bwUhXg`fD$b5h0y*yS zu0andB87*mHcAJ4NOCBSalo~~&3SaZA|i;z4!n@f5<`7gAp>AoN&hHiLq#6DI_D3- z-nlqf@tRn^?57iEP6E0X8@;>w>*QSwn?@&)pMFcxNlsiDNZX8yN*gafQ&cNN)miEo zpAftMUPb>glSe8cNQ%VyU{E=thD2?30=pq74u3zNk^r+f#z&`9)`0XHtqIt%xn3^^ zzA@q~!eGg(hl#;s1Jsw)G`Evs#<21t&f|FJC&5+~898X5z)y>$+i5srxTCSD;C&#R zlGWT`sx0y(k7zy!?IGBhO*ba9K^ODd3={jcgS1Bny8!wMJZL;u3Jn+A`4tWB#gK?* z9pa|M3~PIqkDLPO;Mh)LF=={#r~y0AopM*dEhsSqPR@m*;iicBzcdAfzF@;8j*C+G zG}d!8r{UWzY;UKnEO=^|Y?bG4zie_V-}1;G>Jf2XBH{KND^`LjQE}^u`|Qs}Mh8n# z^Mwjhh zNjcL67;c9atDK^@HfJ8-c!`lLWAquB%g=f&%0YDf&!%b9+JeyEoID3%snwub*F1O} zlCMJar*6ZYcVw4RDjmF=$j2NmFXu#7?5FD`1Uh+sI8nOMik{+0gtZ=9*d<3J{C^sq zVlMxzgb##llniGDRvO*k$(-G#x~pxj0AE!G^jpA!cwmhYLQc2s-MNL+F|8cb#F0+( zzCgOodysUpS5n>aZ6N=>j${l}+mZJCuNdQlJCgqFCWAEd`MhCT@4n?$68l}?-r8?} zp4#cy#m!nLunKui>1%qG>@)Bw8M(MjI(|FQm0YTtx`nnAFBTYz;LxNvF5amgn9wa% z^$kJ1&04&%_jCMS1w*Va`MYHDC~cpP5t(wuB2o-dz3RCNh{uTHjZ-@S@zbHcJ-rpC=&9k^c@eD7E)=|2B3X2y&!*cnkx+s?D;Wt)zq+!}bJ8F1RN{SB zqc8Tt7?_Cz#qpjBW@sP~o?U@+$)l@g!gbK=8lpGy+M`JUlbVrsC7K0d-POecKjZ8; zqzLi6ZH%@yM2h7&g&8_I2CwS7HFoBT!-1e zQ_&*!WOF|<7n5y+cV$7FjDNV>D>WJ8~TIuXR3_$_LZGdF$BbzEP zls5C2Uz+yr~C~? zk=Z}5T5l8RJ;NWkvwU6w)m#M_GeAv)DCu7T50j^(_Rl6Qa)=P|k;6216|aDfTnGFm zzyT3zj`s=>&d^f@ElZN@2fomz2);gg9Y^S@_Uk=Y^5R9m2gxr}0gL!kvxnWCU^8&* zUh$Jhym@nGZTJfG-#N_+_|;iuoH@M;>eOyusZW=e<9W%DGpl(>6v3lAbGcL|LEm5! zvG_l94v$Q$=SS-u3+QY$)eabl!E~dP;B);GKlbOy9U8kNgT9Xy_^B9O8d6e}?M#}{ zzcFUW=_Ye?N^^24V#_#^%LKx8vp#D;21k+_o!gd38b?eiN-$?t0?-rLtiz12k@#C?-LS-?YY)SC;-=xRJX#=c2{49YPi&jrEi zgS54AE%rnqVeOx9cw-2Q)N@m&D`IZ+27N=l=O7poM9c9sSeOe`ZqLfNV-*?oYUjy) zhcYWOaS-MYdKP=ilNL)`bUki)K_VD9ajvOJEh}A|&I2vTEj@cwH(yq`$ZYH6KRoEK z!bacn1SraEz>e|ve-6A? zRe;k&M4*+XW2cT27Z&=@Hk{9ON>9JO;NHtSf+_pA$woPCxmx`$I;f_%BTyjN!(N8r zj=8lH6w2t!xS8#5PWye7d+v6?8UBGg@00q0jSNl9&7gZ0POVAQiAH^1D*GmDtV_%u zzq0i=i{`!Jw@etsTLw&BqTk(aOG4NW!3IT!Y&NZr&SW>tB_&MXneDto&a+z#R(N~7 zBJ)tf`gm?AZ9+U?t8n=XDLuB&_VYaG(e_LVOR?G1oaE2x{O9xxXR-^H(SxBL1&2Q= zdYtdp7b49k%cr*xv8dN2sp%%?>zrHvwU`)}6J;$5RrLyGa@r zh=p`vJDt1td$Y;YiDg@9qQc*K1()-G+jKAsm_E0gE-y+`vOm#aoxscv2eF9iNlTAo zpx}`c%tz7~woi>mb=f(PuXauVxhHkU#i4g_lonC@M)`KytESyj>_zD$t>901KFy*` zX41MuT}K)g=<5;L&t9Y&s0#8E?qY!@K<|{`k#!}3ysBt9hc37yp(HR(e(ay@27{pi zS(1%YRoPZ294T1Nuy5QAR}#dd#rkYcQKUv-G|98yh5S^MeYX;kvpv^Qp^wv1p z4rbaCN)!3l>S+9l`O=!kX{*0URK)MJNE>P2PGfIF1dtZ^V<~R;HJ3;*+5JM1YI3%P zWV+e$7yZ(tch$O4_jNwQX%f%0znE{PkzV$RY{z8RnGStNl^(cx3}VG?Gn`o+v@!S> zF!NVv^tujps;1s`obH!e|F3wK2%*e=y>~TvvmKpvfXCqUVUHSVbi*h|#AzD1jB@RE z0}NYVM=UoRPL-~wRYh9&Yt~|@pX49?RGjr}^B-7XVW_Zu1N_EiB(#5HBQT&Azr}uc z&sJ6@Ok(tGqY&kO+=dQlB;Nc7PER3;{_m9Y++F0CpY31(j=~+DB#hbNH8LirQ5FBk zw}&~Rk6ww6Pg=G3t4ed%_BOscl#E!~3zUSpgEghEM@h6E*3PmxmeLyx8(W<2m2SMA&+nCuLZ`DNFlKJdARwuA zLy~hlQX~2N0j4K?!Nucs${>)Bk)RC8B4F-x#(oZ>lL{7Kk;nYPCVZ|9B|pXB2R%WQ z70YY5*QqkaAKTcKeaR^+k(_cAVp{Ylz{bbtjNJwSKjA^iDv00kI6Q|#Ue|Yg=_)~G`R-m4ziaTiLe~prpx|Y zP}}%3&IWO>7oOsO8>I7|*U;V{;NGYDmeBPlh4kticZqoA4n;fJ!=Wtc_Njy$vZ0JxSP39{Y_OmxhFrnMYq-MB zGWlTkX;IJ#AvHFdw6<-v)hi0=+K(WN9k~h8xv{|eJ&o^D*c?>LSjX_BIA*kTDm2~Y zDLwRuU^|f968gT-RasV{&_cTNyK&}dtRlD>@3RZ535D#Q5sG8x1=%J-uMzfO^!s2R zuxBVSqw?~%9oZ9HOto?~d-*?Lv-7uU6E97Q1z?XZRHd-ivJJqLQqKrs^Yiu6!#J`d zz^K0A88A)=TJbsf9^&JpE}{Jv85!V9^gCU^qd8qJE?=y>&ud5ozD7OP1!8C)ylbR< z0nw_lCm_eieBCO(xmGNkllgUcW3H2RUpMAEC{LK%FYLzxWI3fdvS89bx2?xkvgZ4R zR!-npXshTZ3r=MNQaFqDzSvbMYGsw$<;W~cy6U+Vt-aGCa9sRgtexyE5n|;~CbZ4} zahQLjadu#%^=uzKh;L~*!XMuR41nEc7WF$aKr@7Y>qbPDdZ*qaOWwSjv5l;(X`VjRmwfTZ04#NUL>+wF+rjW^{GYl^VE$&Dmdo@CExb?zLyZghqlPKMOK9 zS+J*|7^eQJ^vr!zs>|3w^T`W^;p-x1go7Z2E( zPnFVKS-LQGCZKeV+=B6F@3>06;tn+qLc_(+xNT!=t9Ibj=DaV)W$+AI=FCEs?3;PP^GDShC(7 z$)y&HjsVqL)9lz-TOrxWN%eFCm+Tuq2HSR)frwotRje+;8T}=(?s&N!0bQZ=EY@y= zy9I{nkMH-n2oUkM`Tp)&5k{^s5Bb~RQkUCg8KCqCqpZagXq~H}`xt72sZZCx@M$oE zdFL+E%cUx7e>FOF^7~yzSk9+gu09-d$G5Au(5Q8v4dI1bmjyx9q78a+444Ks#_Rhe zAtIL!hZWbx^pp`lD|(Ot+>2;xz5h`q{oWhB|Hu;GX!pyUV}j0UJk!(VfjH}z|ELl{ z@T?ONy}IPbgWQe&EkK8*0UsFmUmI{xg=$^SdNN9nBBUq@d;HF7NC&F@nG^w78RGu^ zEJU||UDuS`FdbTcPAB{;FXsSGB6LM}ZH5<-#zhwS@DUin&r=_qUT?U%1=s-|3qbt$ zG&U;pWD?upiY<(&KpeY{C#_MogoPoq*1-EcZ^qWFKIgMfe{%EIggWY&OpX;N9}ngJ z4n|{cpBI3PFYs%JJ%R;GAMdw-beZ6aYFKJKFtDzC$QP*@Yj7!?;e)p* z@LJ}h_zOXB)q%_#SA{*&-!?=fd?ULN* zIlCB)m$mE_YOD{VJT#3hR2-ubQeVw7N_y^>gJ28QY#ixR?>_{)fJL8%>YjmLQxO$9 zzFq#tK{=Ao@sf~14#P!?gJm91X?wa`MD_2}kv}X|wL;miut%`ogEA%zt0ZGkhbnOX zrHQ9wrmX@k1u{WeT3qejU)QeQ>X{RzM8+5Fe~bH_G8lS0bXLpPtHprhj-39pmcTB3 zw`p^rHTc?aLR4z%Eug}>h&h?D2veDXf=BZOpnAjUbuuD6Q+kiheSiCy@H*_x>mo7T zVO)!Dvi?Ctus%Np9M}2Uk8QljwPJjTAc#Q?=R+0G{+AN>*+x16+X}j)QPQio?Yf%X z91}T?Kf|JI|9M{A+>!>GxZ$~5hG=mrG}M)lIj}iA)#H@m_@}3|+(EFh#-&~MQtUH2 zNM2r?w}kCj(nhiFuq~ka5_=aGYD$Xgbe8o<78kSWf}YbM=VN^cskKqdl`9*H^%6$q zeutUBOpU%hCe{i-RBMZR1D0Sci_2N3CD-ZW-u~mDx4;v(IfCK*{boV8Kdd5C53rn@ z_z?PMpW{Ut5!@K%i00x+z_(Vgxm~lJZNSZe8vp`X7aAWm@zI;9m2_~*ht}}Ta)V+p8dxlasSlm19b7_Q0#m)64*!ioa-AjS-~35@H+ehx^3me!TMZ8> z8dhO26~qhFITNjTPX>Pj&tk>s_GQ9x2frCCPGIk+uZ2e8D1G~wYgReO00@`gGZYK@ z9nqXIk5oumpP|dQqj}(lV|)Wc#|-!}IFWeY^s>0`d+%W2r5F^FV0jsaX(pAyoblyR zCs;JKPIlPCVbzf~JA z%9RX~u9`v)SL`f2nPi5g*iUSq+$I9r9ZKga#9*=eV|$!kKkpBrRQi7{=TY7VlcN;c zG2>zT>}z17Jn|sM2+2Kx?uZ-384CXf)+ywdphUn=pc5l;)VJ-yPhVD2vHL}9%JkvD zrE=InkJCX7y^+vM0D)xpzz_eqx!EWNguHk^a=&?dpY~5p_}9kp6O;m#wZeI0{zagW znt(pQ3XzSlUI=?|nW*GHFAwY2<^j5nuuQTwk~JZXp{-*7;VaRD5?3;Yu>&P5b#w{< zC#~WeTiuTjSPny5Gyt|Q;nWZonUIss^3Z7AS4l*GsulX@t4B4D0?3nnAPK7FSo2g9 z2xRD?&}uT`T~j16J4y#GkuL2T$n!iZQdIYLHj75*LJXR)XX9NnU0{QWhR(8JjUX|MFH9z|Ir_6fj5%*}HS`KtG}9zIAH?;(vC1<9 zos0ejykUg3GW3xw%&6mckGH`i8>#$}VgvNe7-W6|*tO{erL9=Gi$rbsWgfXmDzazM z$LInOvu)0l;#xFoi8e4U^S+T|$Rb^`U;CC$SxA16+K+w4Atl7RX~6L{q1@Y+Z|!p6 zoV!*MM0t$y15PytJ?!s;w4h{Ty7-s@>dgxlJQEXGiA;ZAJdPs}h`z5*N z?>Kg`WX-ei{S3{okZ;arfK=HKm+3F<=F#c4Y1u&ayI|�lM8bM0;{AmIMe7HsUi` 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 literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/images/quartz_vertical.png b/tts/NeMo/docs/source/asr/images/quartz_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..4cbede907736f631cb9774b207289a35dd07c757 GIT binary patch literal 262776 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

r#Kg%K(*;;0~-i)^uk9+_H& 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

YrYgQ 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%0A--N@RC6$X>%rv_*U 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 H+fV-w)^vp{ literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/intro.rst b/tts/NeMo/docs/source/asr/intro.rst new file mode 100644 index 0000000..193e544 --- /dev/null +++ b/tts/NeMo/docs/source/asr/intro.rst @@ -0,0 +1,59 @@ +Automatic Speech Recognition (ASR) +================================== + +ASR, or Automatic Speech Recognition, refers to the problem of getting a program to automatically transcribe spoken language +(speech-to-text). Our goal is usually to have a model that minimizes the Word Error Rate (WER) metric when transcribing speech input. +In other words, given some audio file (e.g. a WAV file) containing speech, how do we transform this into the corresponding text with +as few errors as possible? + +Traditional speech recognition takes a generative approach, modeling the full pipeline of how speech sounds are produced in order to +evaluate a speech sample. We would start from a language model that encapsulates the most likely orderings of words that are generated +(e.g. an n-gram model), to a pronunciation model for each word in that ordering (e.g. a pronunciation table), to an acoustic model that +translates those pronunciations to audio waveforms (e.g. a Gaussian Mixture Model). + +Then, if we receive some spoken input, our goal would be to find the most likely sequence of text that would result in the given audio +according to our generative pipeline of models. Overall, with traditional speech recognition, we try to model ``Pr(audio|transcript)*Pr(transcript)``, +and take the argmax of this over possible transcripts. + +Over time, neural nets advanced to the point where each component of the traditional speech recognition model could be replaced by a +neural model that had better performance and that had a greater potential for generalization. For example, we could replace an n-gram +model with a neural language model, and replace a pronunciation table with a neural pronunciation model, and so on. However, each of +these neural models need to be trained individually on different tasks, and errors in any model in the pipeline could throw off the +whole prediction. + +Thus, we can see the appeal of end-to-end ASR architectures: discriminative models that simply take an audio input and give a textual +output, and in which all components of the architecture are trained together towards the same goal. The model's encoder would be +akin to an acoustic model for extracting speech features, which can then be directly piped to a decoder which outputs text. If desired, +we could integrate a language model that would improve our predictions, as well. + +And the entire end-to-end ASR model can be trained at once--a much easier pipeline to handle! + +The full documentation tree is as follows: + +.. toctree:: + :maxdepth: 8 + + models + datasets + asr_language_modeling + results + configs + api + +Resources and Documentation +--------------------------- + +Hands-on speech recognition tutorial notebooks can be found under `the ASR tutorials folder `_. +If you are a beginner to NeMo, consider trying out the `ASR with NeMo `_ tutorial. +This and most other tutorials can be run on Google Colab by specifying the link to the notebooks' GitHub pages on Colab. + +If you are looking for information about a particular ASR model, or would like to find out more about the model +architectures available in the `nemo_asr` collection, refer to the :doc:`Models <./models>` section. + +NeMo includes preprocessing scripts for several common ASR datasets. The :doc:`Datasets <./datasets>` section contains instructions on +running those scripts. It also includes guidance for creating your own NeMo-compatible dataset, if you have your own data. + +Information about how to load model checkpoints (either local files or pretrained ones from NGC), as well as a list of the checkpoints +available on NGC are located on the :doc:`Checkpoints <./results>` section. + +Documentation regarding the configuration files specific to the ``nemo_asr`` models can be found on the :doc:`Configuration Files <./configs>` section. diff --git a/tts/NeMo/docs/source/asr/models.rst b/tts/NeMo/docs/source/asr/models.rst new file mode 100644 index 0000000..0b9f071 --- /dev/null +++ b/tts/NeMo/docs/source/asr/models.rst @@ -0,0 +1,97 @@ +Models +====== + +This section gives a brief overview of the models that NeMo's ASR collection currently supports. + +Each of these models can be used with the example ASR scripts (in the ``/examples/asr`` directory) by +specifying the model architecture in the config file used. Examples of config files for each model can be found in +the ``/examples/asr/conf`` directory. + +For more information about the config files and how they should be structured, refer to the :doc:`./configs` section. + +Pretrained checkpoints for all of these models, as well as instructions on how to load them, can be found in the :doc:`./results` +section. You can use the available checkpoints for immediate inference, or fine-tune them on your own datasets. The checkpoints section +also contains benchmark results for the available ASR models. + +.. _Jasper_model: + +Jasper +------ + +Jasper ("Just Another Speech Recognizer") :cite:`asr-models-li2019jasper` is a deep time delay neural network (TDNN) comprising of +blocks of 1D-convolutional layers. The Jasper family of models are denoted as ``Jasper_[BxR]`` where ``B`` is the number of blocks +and ``R`` is the number of convolutional sub-blocks within a block. Each sub-block contains a 1-D convolution, batch normalization, +ReLU, and dropout: + + .. image:: images/jasper_vertical.png + :align: center + :alt: japer model + :scale: 50% + +Jasper models can be instantiated using the :class:`~nemo.collections.asr.models.EncDecCTCModel` class. + +QuartzNet +--------- + +QuartzNet :cite:`asr-models-kriman2019quartznet` is a version of Jasper :cite:`asr-models-li2019jasper` model with separable +convolutions and larger filters. It can achieve performance similar to Jasper but with an order of magnitude fewer parameters. +Similarly to Jasper, the QuartzNet family of models are denoted as ``QuartzNet_[BxR]`` where ``B`` is the number of blocks and ``R`` +is the number of convolutional sub-blocks within a block. Each sub-block contains a 1-D *separable* convolution, batch normalization, +ReLU, and dropout: + + .. image:: images/quartz_vertical.png + :align: center + :alt: quartznet model + :scale: 40% + +QuartzNet models can be instantiated using the :class:`~nemo.collections.asr.models.EncDecCTCModel` class. + +Citrinet +-------- + +Citrinet is a version of QuartzNet :cite:`asr-models-kriman2019quartznet` that extends ContextNet :cite:`asr-models-han2020contextnet`, +utilizing subword encoding (via Word Piece tokenization) and Squeeze-and-Excitation mechanism :cite:`asr-models-hu2018squeeze` to +obtain highly accurate audio transcripts while utilizing a non-autoregressive CTC based decoding scheme for efficient inference. + + .. image:: images/citrinet_vertical.png + :align: center + :alt: citrinet model + :scale: 50% + +Citrinet models can be instantiated using the :class:`~nemo.collections.asr.models.EncDecCTCModelBPE` class. + +.. _Conformer-CTC_model: + +Conformer-CTC +------------- + +Conformer-CTC is a CTC-based variant of the Conformer model introduced in :cite:`asr-models-gulati2020conformer`. Conformer-CTC has a +similar encoder as the original Conformer but uses CTC loss and decoding instead of RNNT loss, which makes it a non-autoregressive model. +We also drop the LSTM decoder and instead use a linear decoder on the top of the encoder. This model uses the combination of +self-attention and convolution modules to achieve the best of the two approaches, the self-attention layers can learn the global +interaction while the convolutions efficiently capture the local correlations. The self-attention modules support both regular +self-attention with absolute positional encoding, and also Transformer-XL's self-attention with relative positional encodings. + +Here is the overall architecture of the encoder of Conformer-CTC: + + .. image:: images/conformer_ctc.png + :align: center + :alt: Conformer-CTC Model + :scale: 50% + +This model supports both the sub-word level and character level encodings. You can find more details on the config files for the +Conformer-CTC models at `Conformer-CTC <./configs.html#conformer-ctc>`. The variant with sub-word encoding is a BPE-based model +which can be instantiated using the :class:`~nemo.collections.asr.models.EncDecCTCModelBPE` class, while the +character-based variant is based on :class:`~nemo.collections.asr.models.EncDecCTCModel`. + +You may find the example config files of Conformer-CTC model with character-based encoding at +``/examples/asr/conf/conformer/conformer_ctc_char.yaml`` and +with sub-word encoding at ``/examples/asr/conf/conformer/conformer_ctc_bpe.yaml``. + +References +---------- + +.. bibliography:: asr_all.bib + :style: plain + :labelprefix: ASR-MODELS + :keyprefix: asr-models- diff --git a/tts/NeMo/docs/source/asr/results.rst b/tts/NeMo/docs/source/asr/results.rst new file mode 100644 index 0000000..df9fa83 --- /dev/null +++ b/tts/NeMo/docs/source/asr/results.rst @@ -0,0 +1,181 @@ +Checkpoints +=========== + +There are two main ways to load pretrained checkpoints in NeMo: + +* Using the :code:`restore_from()` method to load a local checkpoint file (``.nemo``), or +* Using the :code:`from_pretrained()` method to download and set up a checkpoint from NGC. + +Refer to the following sections for instructions and examples for each. + +Note that these instructions are for loading fully trained checkpoints for evaluation or fine-tuning. For resuming an unfinished +training experiment, use the Experiment Manager to do so by setting the ``resume_if_exists`` flag to ``True``. + +Loading Local Checkpoints +------------------------- + +NeMo automatically saves checkpoints of a model that is trained in a ``.nemo`` format. Alternatively, to manually save the model at any +point, issue :code:`model.save_to(.nemo)`. + +If there is a local ``.nemo`` checkpoint that you'd like to load, use the :code:`restore_from()` method: + +.. code-block:: python + + import nemo.collections.asr as nemo_asr + model = nemo_asr.models..restore_from(restore_path="") + +Where the model base class is the ASR model class of the original checkpoint, or the general ``ASRModel`` class. + +NGC Pretrained Checkpoints +-------------------------- + +The ASR collection has checkpoints of several models trained on various datasets for a variety of tasks. These checkpoints are +obtainable via NGC `NeMo Automatic Speech Recognition collection `_. +The model cards on NGC contain more information about each of the checkpoints available. + +The tables below list the ASR models available from NGC. The models can be accessed via the :code:`from_pretrained()` method inside +the ASR Model class. In general, you can load any of these models with code in the following format: + +.. code-block:: python + + import nemo.collections.asr as nemo_asr + model = nemo_asr.models.ASRModel.from_pretrained(model_name="") + +Where the model name is the value under "Model Name" entry in the tables below. + +For example, to load the base English QuartzNet model for speech recognition, run: + +.. code-block:: python + + model = nemo_asr.models.ASRModel.from_pretrained(model_name="QuartzNet15x5Base-En") + +You can also call :code:`from_pretrained()` from the specific model class (such as :code:`EncDecCTCModel` +for QuartzNet) if you need to access a specific model functionality. + +If you would like to programatically list the models available for a particular base class, you can use the +:code:`list_available_models()` method. + +.. code-block:: python + + nemo_asr.models..list_available_models() + +Transcribing/Inference +^^^^^^^^^^^^^^^^^^^^^^ + +To perform inference and transcribe a sample of speech after loading the model, use the ``transcribe()`` method: + +.. code-block:: python + + model.transcribe(paths2audio_files=[list of audio files], batch_size=BATCH_SIZE, logprobs=False) + +Setting the argument ``logprobs`` to ``True`` returns the log probabilities instead of transcriptions. For more information, see :doc:`./api.html#modules`. +The audio files should be 16KHz monochannel wav files. + +Fine-tuning on Different Datasets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are multiple ASR tutorials provided in the :ref:`Tutorials ` section. Most of these tutorials explain how to instantiate a pre-trained model, prepare the model for fine-tuning on some dataset (in the same language) as a demonstration. + + +Automatic Speech Recognition Models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :file: data/asr_results.csv + :align: left + :widths: 30, 30, 40 + :header-rows: 1 + +Language Models for ASR +^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :file: data/asrlm_results.csv + :align: left + :widths: 30, 30, 40 + :header-rows: 1 + + +Speech Recognition (Languages) +------------------------------ + +English +^^^^^^^ +.. csv-table:: + :file: data/benchmark_en.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + +----------------------------- + +Mandarin +^^^^^^^^ +.. csv-table:: + :file: data/benchmark_zh.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + +----------------------------- + +German +^^^^^^ +.. csv-table:: + :file: data/benchmark_de.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + +----------------------------- + +Polish +^^^^^^ +.. csv-table:: + :file: data/benchmark_pl.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + +----------------------------- + +Italian +^^^^^^^ +.. csv-table:: + :file: data/benchmark_it.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + +----------------------------- + +Russian +^^^^^^^ +.. csv-table:: + :file: data/benchmark_ru.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + +----------------------------- + +Spanish +^^^^^^^ +.. csv-table:: + :file: data/benchmark_es.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + + +----------------------------- + +Catalan +^^^^^^^ +.. csv-table:: + :file: data/benchmark_ca.csv + :align: left + :widths: 40, 10, 50 + :header-rows: 1 + + diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/api.rst b/tts/NeMo/docs/source/asr/speaker_diarization/api.rst new file mode 100644 index 0000000..a820e1d --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_diarization/api.rst @@ -0,0 +1,17 @@ +NeMo Speaker Diarization API +============================= + + +Model Classes +------------- +.. autoclass:: nemo.collections.asr.models.ClusteringDiarizer + :show-inheritance: + :members: init_speaker_model, set_vad_model, init_vad_model, setup_vad_test_data, setup_spkr_test_data, run_vad, extract_embeddings, path2audio_files_to_manifest, diarize, make_nemo_file_from_folder, save_to, unpack_nemo_file, restore_from + + +Mixins +------ + +.. autoclass:: nemo.collections.asr.parts.mixins.mixins.DiarizationMixin + :show-inheritance: + :members: diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/configs.rst b/tts/NeMo/docs/source/asr/speaker_diarization/configs.rst new file mode 100644 index 0000000..f7910be --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_diarization/configs.rst @@ -0,0 +1,65 @@ +NeMo Speaker Diarization Configuration Files +============================================ + +Since speaker diarization model here is not a fully-trainble End-to-End model but an inference pipeline, we use **diarizer** instead of **model** which is used in other tasks. + +The diarizer section will generally require information about the dataset(s) being +used, models used in this pipline, as well as inference related parameters such as postprocessing of each models. +The sections on this page cover each of these in more detail. + + +Example configuration files for speaker diarization can be found in the +``/examples/speaker_recognition/conf/speaker_diarization.yaml>`` + +.. note:: + For model details and deep understanding about configs, finetuning, tuning threshold, and evaluation, + please refer to ``/tutorials/speaker_recognition/Speaker_Diarization_Inference.ipynb``; + for other applications such as possible integration with ASR, have a look at ``/tutorials/speaker_recognition/ASR_with_SpeakerDiarization.ipynb``. + + +Dataset Configuration +----------------------- + +In contrast to other ASR related tasks or models in NeMo, speaker diarization supported in NeMo is a modular inference pipeline. +Datasets here denotes the data you would like to perform speaker diarization on. + +An example Speaker Diarization dataset configuration could look like: + +.. code-block:: yaml + + diarizer: + oracle_num_speakers: ??? # if number of speakers is known input it or pass null if not known. Accepts int or path to file containing uniq-id and num of speakers of that session + max_num_speakers: 8 # max number of speakers for each recording. If oracle num speakers is passed this value is ignored + out_dir: ??? + paths2audio_files: ??? # file containing paths to audio files for diarzation + path2groundtruth_rttm_files: null # (Optional) file containing paths to rttm files (this can be passed if we need to calculate DER rate based on ground truth rttm files). + ... + +.. note:: + We expect audio and the corresponding RTTM to have the same base name and the name should be unique. + + +Diarizer Architecture Configurations +------------------------------------- + +.. code-block:: yaml + + diarizer: + ... + vad: + model_path: null #.nemo local model path or pretrained model name or none + window_length_in_sec: 0.15 + shift_length_in_sec: 0.01 + threshold: 0.5 # tune threshold on dev set. Check /scripts/voice_activity_detection/vad_tune_threshold.py + vad_decision_smoothing: True + smoothing_params: + method: "median" + overlap: 0.875 + + speaker_embeddings: + oracle_vad_manifest: null # leave it null if to perform diarization with above VAD model else path to manifest file genrerated as shown in Datasets section + model_path: ??? #.nemo local model path or pretrained model name + window_length_in_sec: 1.5 # for better performace try with 3 sec and 1.5 sec + shift_length_in_sec: 0.75 # for better performace try with 1.5 sec and 0.75 sec + + diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/data/diarization_results.csv b/tts/NeMo/docs/source/asr/speaker_diarization/data/diarization_results.csv new file mode 100644 index 0000000..fba1a2e --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_diarization/data/diarization_results.csv @@ -0,0 +1,4 @@ +Model Name,Model Base Class,Model Card +vad_marblenet,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:vad_marblenet" +vad_telephony_marblenet,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:vad_telephony_marblenet" +speakerdiarization_speakernet,EncDecSpeakerLabelModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:speakerdiarization_speakernet" diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/datasets.rst b/tts/NeMo/docs/source/asr/speaker_diarization/datasets.rst new file mode 100644 index 0000000..f178ad4 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_diarization/datasets.rst @@ -0,0 +1,72 @@ +Datasets +======== +Check out page :doc:`Speech Classification Datasets <../speech_classification/datasets>` and :doc:`Speaker Recogniton Datasets <../speaker_recognition/datasets>` +for preparing datasets for training and validating VAD and speaker embedding models respectively. + +For Speaker Diarization inference, ``diarizer`` expects following arguments : + + - paths2audio_files + - oracle_num_speakers + - path2groundtruth_rttm_files [Optional] + - oracle_vad_manifest (if vad/rttm files are known)[Optional but suggested for good performace. This avoids FPR and TPR] + +paths2audio_files: + - a file containing absolute paths to audio files or list of paths to audio files. + For generating a file that contains paths to audio files, you can simply use ``find`` bash command as shown below: +.. code-block:: bash + + find $PWD/{data_dir} -iname '*.wav' > path_to_audiofiles.txt + +.. note:: + We expect audio and the corresponding RTTM files to have the same base name and the name should be unique (uniq-id). + +oracle_num_speakers: + - if number of speakers is known input it or pass null if not known. Accepts int or path to file containing uniq-id with num of speakers of that session + + Sample line (uniq-id `iaaa` session has 2 unique speakers ):: + + iaaa 2 + +path2groundtruth_rttm_files [Optional]: + - To evaluate the diarizer system with known rttm files, One needs to provide a txt file (path2groundtruth_rttm_files) for groundtruth label files. + use above mentioned ``find`` command to get all reference rttm files (use '*.rttm' as search pattern) + +Each groundtruth label file should be in NIST Rich Transcription Time Marked (RTTM) format. Take one line from a RTTM file for example: + +.. code-block:: bash + + SPEAKER TS3012d.Mix-Headset 1 331.573 0.671 MTD046ID + + +oracle_vad_manifest [Optional but suggested for good performace. This reduces FPR and TPR]: + - To perform just oracle diarization, that is taking speech activity time stamps from groundtruth RTTMs or another VAD from wild instead of NeMo VAD output, ``diarizer`` expects an oracle manifest json file that contains paths to audio files with offset for start time and duration of segment. + +To prepare an oracle manifest file, use the script from ``scripts`` folder as shown below: + +.. code-block:: bash + + python $NeMo/scripts/ --paths2rttm_files= --paths2audio_files= --manifest_file= + +Here ``paths2audio_files`` and ``path2groundtruth_rttm_files`` are files containing paths to audio files as shown above. + +AMI Meeting Corpus +------------------ + +The following are the suggested parameters for getting Speaker Error Rate (SER) of 4.1% on AMI Lapel test set corpus: + - diarizer.oracle_num_speakers = 4 (since there are exactly 4 speakers per each Lapel test set session) + - diarizer.speaker_embeddings.model_path = ``speakerverification_speakernet`` (This model is trained on voxceleb dataset. ``Use this model for simialr non-telephonic speech datasets``) + - diarizer.speaker_embeddings.window_length_in_sec = 3 + - diarizer.speaker_embeddings.shift_length_in_sec = 1.5 + +Input paths2audio_files, paths2rttm_files and oracle_vad_manifest by following steps as shown above + +CallHome LDC97S42 (CH109) +------------------------- + +The following are the suggested parameters for getting Speaker Error Rate (SER) of 5.4% on CH109 set: + - diarizer.oracle_num_speakers = 2 (since there are exactly 2 speakers per each ch109 session) + - diarizer.speaker_embeddings.model_path = ``speakerdiarization_speakernet`` (This model is trained on voxceleb and telephonic speech Fisher and SWBD. ``Use this model for similar telephonic speech datasets``) + - diarizer.speaker_embeddings.window_length_in_sec = 1.5 + - diarizer.speaker_embeddings.shift_length_in_sec = 0.75 + +Input paths2audio_files, paths2rttm_files and oracle_vad_manifest by following steps as shown above \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/images/sd_pipeline.png b/tts/NeMo/docs/source/asr/speaker_diarization/images/sd_pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..258781a2aeac68d98690b46840e7f51b627a2064 GIT binary patch literal 55717 zcmeFZbzD?!*ES5pfQ%q5CEXxW(k)1Lcb7DRbdE?UjdZ7U3y5?#NOws|$4G;Gd%Uj8 z`+o1|{+{>$@AvsTaca-r=XtDkt~l1(^Ilm|>d`~uhX@D=k7T4@sv;mDZy_Kcnxdir z?|igH4Fnz#T~wvS5XwhLc7PWi7TPkF3JM5Jz;jdtFd{JmGW-zWPZ;sZpXZW@3Ce5`qB9?lA(~LmAe^b z30H-J-SWfo-Cvp84eDRl7FP}$)YJK0%Ta^C(gFYLps)w~SlhmT6oUYX4hVyU`+9q1 zPfBNh%JILiQ(XD#;(BwN2$rT023hFV1x(t%j%KyMm6Ydm3U|T7nN*f+@lfX9u8Bh@+Ue8rLpvHQ-4+JsTvrnP5O)|vg;;x5REAghk`fU| zS_tY~2Fa{Ye>?DsJX)1_Uk!6f;n`$nV0OA=Vd|Sa7Mkcy@T4FKGj3+9d}fGs<>)E4 z)y1E6>B|KKd(L1ydQ6RoF3P8Ul5OR<&r-jf=+Nv=Eg{CI$NL z2EAhAWitCvX@Wxm)duro_EL52(TIZn9;AN{W7Jkfy zh!7fS(dSqSUyNm6zunYf4g`PZn~h@q_;&qyAxbJ8u#z;XDqmIP<_u}RNJhUv*Z zhoR-ieYe=8S>*=Zru5rWi~0V6OHcuTO9_)ao*ueLD;nr?7%AkP0Rz9va&K44a=^fd zb2`8vKu6J_fd0hIf(qXa%~3(30p$ROC_YY>i7?uOcmpb^9Ua^G@LD&MzQX%mYN3r9 z¿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/tutorials/speaker_recognition/``. + +There are tutorials for peformming inference using :ref:`MarbleNet_model` and :ref:`SpeakerNet_model`, +and how one can get ASR transcriptions combined with Speaker labels along with voice activity time stamps with NeMo asr collections. + +Most of the tutorials can be run on Google Colab by specifying the link to the notebooks' GitHub pages on Colab. + +If you are looking for information about a particular model used for speaker diarization inference, or would like to find out more about the model +architectures available in the `nemo_asr` collection, check out the :doc:`Models <./models>` page. + +Documentation on dataset preprocessing can be found on the :doc:`Datasets <./datasets>` page. +NeMo includes preprocessing scripts for several common ASR datasets, and this page contains instructions on running +those scripts. +It also includes guidance for creating your own NeMo-compatible dataset, if you have your own data. + +Information about how to load model checkpoints (either local files or pretrained ones from NGC), perform inference, as well as a list +of the checkpoints available on NGC are located on the :doc:`Checkpoints <./results>` page. + +Documentation for configuration files specific to the ``nemo_asr`` models can be found on the +:doc:`Configuration Files <./configs>` page. diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/models.rst b/tts/NeMo/docs/source/asr/speaker_diarization/models.rst new file mode 100644 index 0000000..7a543e9 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_diarization/models.rst @@ -0,0 +1,5 @@ +Models +====== + + +Currenlty NeMo's Speaker Diarization pipeline uses `MarbleNet <../speech_classification/models.html#marblenet-vad>`__ model for Voice Activity Detection (VAD) and `SpeakerNet <../speaker_recognition/models.html#speakernet>`__ model for Speaker Embedding Extraction. \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speaker_diarization/results.rst b/tts/NeMo/docs/source/asr/speaker_diarization/results.rst new file mode 100644 index 0000000..c20be13 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_diarization/results.rst @@ -0,0 +1,76 @@ +Checkpoints +=========== + +There are two main ways to load pretrained checkpoints in NeMo as introduced in `loading ASR checkpoints <../results.html#checkpoints>`__. +In speaker diarization, the diarizer loads checkpoints that are passed through the config file. For example: + +Loading Local Checkpoints +--------------------------- + +Load VAD model + +.. code-block:: bash + + pretrained_vad_model='/path/to/vad_marblenet.nemo' # local .nemo or pretrained vad model name + ... + # pass with hydra config + config.diarizer.vad.model_path=pretrained_vad_model + + +Load Speaker Embedding model + +.. code-block:: bash + + pretrained_speaker_model='/path/to/speakerdiarization_speakernet.nemo' # local .nemo or pretrained speakernet model name + ... + # pass with hydra config + config.diarizer.speaker_embeddings.model_path=pretrained_speaker_model + + +NeMo will automatically save checkpoints of a model you are training in a `.nemo` format. +You can also manually save your models at any point using :code:`model.save_to(.nemo)`. + + +Inference +---------- + +.. note:: + For details and deep understanding, please refer to ``/tutorials/speaker_recognition/Speaker_Diarization_Inference.ipynb``. + +Check out :doc:`Datasets <./datasets>` for preparing audio files and optional label files. + +Run and evaluate speaker diarizer with below command: + +.. code-block:: bash + + # Have a look at the instruction inside the script and pass the arguments you might need. + python /examples/speaker_recognition/speaker_diarize.py + + +NGC Pretrained Checkpoints +---------------------------- + +The ASR collection has checkpoints of several models trained on various datasets for a variety of tasks. +These checkpoints are obtainable via NGC `NeMo Automatic Speech Recognition collection `_. +The model cards on NGC contain more information about each of the checkpoints available. + +In general, you can load models with model name in the following format, + +.. code-block:: python + + pretrained_vad_model='vad_telephony_marblenet' + pretrained_speaker_model='speakerdiarization_speakernet' + ... + config.diarizer.vad.model_path=retrained_vad_model \ + config.diarizer.speaker_embeddings.model_path=pretrained_speaker_model + +where the model name is the value under "Model Name" entry in the tables below. + +Models for Speaker Diarization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :file: data/diarization_results.csv + :align: left + :widths: 30, 30, 40 + :header-rows: 1 diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/configs.rst b/tts/NeMo/docs/source/asr/speaker_recognition/configs.rst new file mode 100644 index 0000000..7b84f47 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_recognition/configs.rst @@ -0,0 +1,117 @@ +NeMo ASR Configuration Files +============================ + +This page covers NeMo configuration file setup that is specific to speaker recognition models. +For general information about how to set up and run experiments that is common to all NeMo models (e.g. +experiment manager and PyTorch Lightning trainer parameters), see the :doc:`../../core/core` page. + +The model section of NeMo ASR configuration files will generally require information about the dataset(s) being +used, the preprocessor for audio files, parameters for any augmentation being performed, as well as the +model architecture specification. +The sections on this page cover each of these in more detail. + +Example configuration files for all of the Speaker related scripts can be found in the +config directory of the examples ``{NEMO_ROOT/examples/speaker_recognition/conf}``. + + +Dataset Configuration +--------------------- + +Training, validation, and test parameters are specified using the ``train_ds``, ``validation_ds``, and +``test_ds`` sections of your configuration file, respectively. +Depending on the task, you may have arguments specifying the sample rate of your audio files, max time length to consider for each audio file , whether or not to shuffle the dataset, and so on. +You may also decide to leave fields such as the ``manifest_filepath`` blank, to be specified via the command line +at runtime. + +Any initialization parameters that are accepted for the Dataset class used in your experiment +can be set in the config file. + +An example SpeakerNet train and validation configuration could look like: + +.. code-block:: yaml + + model: + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: None # finds labels based on manifest file + batch_size: 32 + trim_silence: False + time_length: 8 + shuffle: True + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: None # Keep None, to match with labels extracted during training + batch_size: 32 + shuffle: False # No need to shuffle the validation data + + +If you would like to use tarred dataset, have a look at `Datasets Configuration <../configs.html#dataset-configuration>`__. + + +Preprocessor Configuration +-------------------------- +Preprocessor helps to compute MFCC or mel spectrogram features that are given as inputs to model. +For details on how to write this section, refer to `Preprocessor Configuration <../configs.html#preprocessor-configuration>`__ + + +Augmentation Configurations +--------------------------- + +For SpeakerNet training we use on-the fly augmentations with MUSAN and RIR impulses using ``noise`` augmentor section + +The following example sets up musan augmentation with audio files taken from manifest path and +minimum and maximum SNR specified with min_snr and max_snr respectively. This section can be added to +``train_ds`` part in model + +.. code-block:: yaml + + model: + ... + train_ds: + ... + augmentor: + noise: + manifest_path: /path/to/musan/manifest_file + prob: 0.2 # probability to augment the incoming batch audio with augmentor data + min_snr_db: 5 + max_snr_db: 15 + + +See the :class:`nemo.collections.asr.parts.preprocessing.perturb.AudioAugmentor` API section for more details. + + +Model Architecture Configurations +--------------------------------- + +Each configuration file should describe the model architecture being used for the experiment. +Models in the NeMo ASR collection need a ``encoder`` section and a ``decoder`` section, with the ``_target_`` field +specifying the module to use for each. + +The following sections go into more detail about the specific configurations of each model architecture. + +For more information about the SpeakerNet Encoder models, see the :doc:`Models <./models>` page and at `Jasper and QuartzNet <../configs.html#jasper-and-quartznet>`__ + +Decoder Configurations +------------------------ + +After features have been computed from speakernet encoder, we pass these features to the decoder to compute embeddings and then to compute log probabilities +for training models. + +.. code-block:: yaml + + model: + ... + decoder: + _target_: nemo.collections.asr.modules.SpeakerDecoder + feat_in: *enc_final + num_classes: 7205 # Total number of classes in training manifest file + pool_mode: xvector # xvector for variance and mean bases statistics pooling + emb_sizes: 256 # number of inermediate emb layers. can be comma separated for additional layers like 512,512 + angular: true # if true then loss will be changed to angular softmax loss and consider scale and margin from loss section else train with cross-entrophy loss + + loss: + scale: 30 + margin 0.2 \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/data/speaker_results.csv b/tts/NeMo/docs/source/asr/speaker_recognition/data/speaker_results.csv new file mode 100644 index 0000000..450c0a1 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_recognition/data/speaker_results.csv @@ -0,0 +1,4 @@ +Model Name,Model Base Class,Model Card +speakerverification_speakernet,EncDecSpeakerLabelModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:speakerverification_speakernet" +speakerrecognition_speakernet,EncDecSpeakerLabelModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:speakerrecognition_speakernet" +speakerdiarization_speakernet,EncDecSpeakerLabelModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:speakerdiarization_speakernet" diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/datasets.rst b/tts/NeMo/docs/source/asr/speaker_recognition/datasets.rst new file mode 100644 index 0000000..7439d72 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_recognition/datasets.rst @@ -0,0 +1,57 @@ +Datasets +======== + +.. _HI-MIA: + +HI-MIA +-------- + +Run the script to download and process ``hi-mia`` dataset in order to generate files in the supported format of ``nemo_asr``. You should set the data folder of +hi-mia using ``--data_root``. These scripts are present in ``/scripts`` + +.. code-block:: bash + + python get_hi-mia_data.py --data_root= + +After download and conversion, your `data` folder should contain directories with following set of files as: + +* `data//train.json` +* `data//dev.json` +* `data//{set}_all.json` +* `data//utt2spk` + + +All-other Datasets +------------------ + +These methods can be applied to any dataset to get similar training manifest files. + +First we prepare scp file(s) containing absolute paths to all the wav files required for each of the train, dev, and test set. This can be easily prepared by using ``find`` bash command as follows: + +.. code-block:: bash + + !find {data_dir}/{train_dir} -iname "*.wav" > data/train_all.scp + !head -n 3 data/train_all.scp + + +Since we created the scp file for the train, we use `scp_to_manifest.py` to convert this scp file to a manifest file and then optionally split the files to train \& dev for evaluating the models while training by using the --split flag. +We wont be needing the --split option for the test folder. Accordingly please mention the id number, which is the field num separated by / to be considered as the speaker label. +After the download and conversion, your data folder should contain directories with manifest files as: + +* `data//train.json` +* `data//dev.json` +* `data//train_all.json` + +Each line in the manifest file describes a training sample - audio_filepath contains the path to the wav file, duration it's duration in seconds, and label is the speaker class label: + +.. code-block:: json + + {"audio_filepath": "/audio_file.wav", "duration": 3.9, "label": "speaker_id"} + + +Tarred Datasets +--------------- + +Similarly to ASR, you can tar your audio files and use ASR Dataset class ``TarredAudioToSpeechLabelDataset`` (corresponding to the ``AudioToSpeechLabelDataset``) for this case. + +If you want to use tarred dataset, have a look at `ASR Tarred Datasets <../datasets.html#tarred-datasets>`__. \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/images/ICASPP_SpeakerNet.png b/tts/NeMo/docs/source/asr/speaker_recognition/images/ICASPP_SpeakerNet.png new file mode 100644 index 0000000000000000000000000000000000000000..ecdccccb69ba94f2af56a627113a11ff0768a43e GIT binary patch literal 211990 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�%Whe zy(HPUwdzr#wQM|TFvW=&vczX-l3BkVV`$$H7w_wnx(y6l1$BG?sXzfJYpe02CI07k zg%D7on#|4bKQ;wIr`;_xqu^^eeH+xt-M=AY&{UcFPnxV%86Pu%Xc%AfmppP#4zPn=sk9C0HxSaSlxw7( zX4-Dm_YbZWAym;64d=`{A3`w=ziGY`F#tfwJ04^Fcs^-bs>9V0WBO}T%FM9gU;pr@ zMLo!+RjT`(!aNc*nm4b(mrWAR%(nVHL+SM;Fif*bBYYu|!tGeV+(tvW_z3ofV^664 z&JGZIAF<>8a%@I$`4j5FHbVolRwxPB~Ye5%SvhP>2uy!?}|BwKmujmG2 zxatj#^)_Z?W$ts>?QlUI_a`Ur^dnkz*DP#1s3@e5ku9aCL_67{03FAXzHf4Lteq2ik;U z!ZmSQ;WrBm^Es>-Q&$U=^)80nThzP1tabQYJ5!PdtN`2#-E01<65{_mWja(S?#kn| zxriXM#?As$NP+5cg~ymBU}o=m^JDkB#$dqTO={5%D%oGt@rCOl&x zU;XhL#X3(k1l>UpFpV6(dLF$6$Zr6Kncaz{;zz{UCRZwih6Vl>4xOHVc6hX=i* zTmod9Z6KL~o`FgSC@l%BII`<}HO46Wf%Bab#z9tVd3@aU?o2FZJ+KdWZ>o;-$c1hF z4K4zUH;4OFEu!Pg#|2_gNXu?ZJ1l>#au+HvJ|{fG+UB%2QO-n90XQLU6*0%JaY}v; z4s7GVh~~Jis2E;-J*TY+GKzu?W)%{cP@W3FL;Ep(1qKbzSqj$UZcrWy*9#u#)m`O> z)lee8|~0T;z;W z-yHtp5}qRrgCH`N&0;iL9-x#)!cQeMhcvf2G`bb1E*59%n$*_l zz4ehj@C{gblxSCH};a|%(-q$|!-TVy1;AIRWY1|a8XB>dJ z^1HqPeJ<#)95mU-6!x?&lFT3Ix3UKvSzxFr7E|U`O6b)a`QS?qqYkM2yrjr}S6lKA z67Z9Z?al9meovt7K8@k`o%;C!qeQnRTmmhoo5{mf^{YN&ah;P8kHT8cNS`FDFDrBP9Ik{qrMQ_>1Ej3V{AmGGWe{+@0 z65yZToqbI!hJ1j;wsn08qGB>Leqkhm$Y-t=WsOVaBIODmo^y|9TcatBy2>+Gt!D5v z>NWxX*^);_pS4b~oZL#?)2k`tg8R$;f|zXsk4*Zz7CdM?Gt&885xixuu;#AogQlil z&})}LHsmwV?iC$!lujl^T@~`=toRls3OHE{?;@Lh8i-%gPFPL|#Tbblo%m-Bm&izj zUmAvAji)<1f)@-xcYRTJb=*(qi7+HteB0{IS8`r8$$pDAdT2g>1UmAx<+?S5f8%Yt z$Rd#Y9F6C_E8i--jn4>^0KTTpJ@E0RdbousL~Yk%bcz*9{96VSqp?K;4KuwX%h`SE zuW_W>ehsXhR3RoE?)fN~YIzc~rWoI#ET1l|Tv{GGf9K-cC5qhVr5;-~HeTRZd*Kih z+c9A?Rq23q&uNt2AJ+r#db3bxU3fZn^r3WLi`NQ$D3d>Kpu*K`vNiy+&|cW^lo;3@ zX(n=8Vb9hO`8Uis8+HW_B=b2xWijoc-x2<3YhXTf4_E6pFm zCwLms+A5nUIvgg86&=oRL6}@s_~T;$zU6`2ovuO@5D)F%hn?pMvDe!C!p+#)?yXn+z)=w6g`KWL?5@W6Qe zvIu+ci?#DLX0?l`>*XI4VTUtc0?Ze_ zrhS|F@t$fhi;H3GeHwe~ORFTn@0P_aUw3)*D;=)6ly1F`#Z80HI8v6=_Ts4;!Bl9# z%!A0z;GR-p2usqp%H^e_HVF+5=bT-oZzk}?8%zsw@dz>KrZOuB)>h?9l8^3n$`vn( zd;Cr=^}6F_C^H7#Lw{yeQwRI|eu$In9uialRPsZ+NzVbU_h7zWw_xEV4=UhF zbvvaXtPOYBg|1{ZVTvJC%~eU2a~|9r5wCJqGSIc&o@01Q-Dg^z#so*F==Z5`&@rd zQ)=Z!?^1+U7Ls_tmjsimH-7L4G&HnL$^&`U5!dfc1b{^lQ7{IZIwLg#;qPkk_i@$0 zsf^u1=7e0V`yfP5k|Z9GN~3=d=%R6V{jf8X%ZZ)qGlv!JC1+a7rd6eu7q$)D3|g#A z!&LRbxXcb4>$)ky?mR9cunG{-oH5n4Kz!m z2~2$U7Pdr&*t)jTrRqH^THp_~b-8=O9h}nU{rB3#?o$TQr4dO|BdWhU8ipb90i*fizWP>rjvL=rub+Siw+dCIj#4#Qq%PCjY6(a7b9YWF3+2p>TR; zH-o$$VEu&Q3A^T8T-o!It0Jr9$`*0m^zEC5QwtTcNiGQqzva;E*Vvp>OBqG>6 z$d3QIk!z5Umqy^QVOG5(lsha>nA{zi={eC2J8c*oBc}cO5WGscTZ^FD0>gM z(LYT4JjAgOQ=cY2Vn{#OH7jpjyKw?fW`n78TW9 z>djAL(Axdo;Qj-#gwI}vQLo-*8P9=^G8zI~H)#_SdP45RzU82wzRFAIp_ovtGm@9i z`Zp<#=7JKur=Pn?*~x2T13WadV~y7Z`1zz9JO}!*r7cMgSbrddfV;%jfu^F%M=3 z^owb=ja>JB%39RQ^)B|#FKjyI0`G9&`IR#hJbheki2sTs&_<*)5P8N9e}8{J9=0Q2 zOv_xR?;-Q%STB~tLPdsb!$Wf3{UQ_0WgcB!O?SNUj%YG_pon1QK3RN8I22`C9 z$7myJk~x94XT~N?BpPfx3h4rFK%BJExn(2VGZ*aj2XO9S>ks-R8d4y3NhiW8gITfqPU%I1=KH#@P-*< z5ZlrqWNCy^L~N(QF@ii9vWYw43po!!1yMsK*Abx zM1CAr;4f3b2MJ^G5Es9Zn~$B+z#8^<012^Y!E=`C>lSP8t&rE^Ve$=ipN1~lA_`RM zg>jt-rx4@g*$;m^rt`X?U)=2zi@s1wb+(8S-_s^xBggEzAZquut`p0h_?Z0D1|9*E z>Eko!gC+k#D}Nrs!#mDyrr7jY9RW`wuSr|!Qlwf&#c#o~Ueczk?80?rmFRcgq}7)Z z^5bO*n@-PnEIGeK^_;vVO>!pE;qt_u`DGo;+o1aS8V38_>DwGsFR+aI~R z_cCxc0*=gfY9n0ES8-|8zJ`mXsln?q6D^YioF zNlaPBjM3^Hkl5%)u93-c-3JTnr!~+{B}l8@WeKsA$N7Fw@ZB3qFzbfwhBhY`J2R{C zsamMfzZeL8X3<33vk>DXNLkb)n80!ts zlIxSMRwln!XcB3Y1kaLMy5{cG@^bE!!US4^ep`H|h-mPDF&f@V3Ju1n+3EN%398qm zz+MZ;tA{c$N=WMiI}3lLOI+;tiRKk4yPG$CQ(C|@!eIPR&_mmqmth)@7E2<$%APX^ z)6LHd({K5$gz1=WwOZ1(=;x&Y5`AM5QKt8(cYJx@bD6Yh z6)KTdFfweUm&9@h`VC&-t>|jJAPTj1sMzRdbofS1!j>8e8(;7hV?@~7kgb5kU9Kbh z4v2e)^Tl|750&rWEN1rdtL-Jgx3dXYNI86|T}q&jtEz>keKuF&HJTeiI(Gid;QC%@ z4(nB|l1(@oN@6nn>F#d~kf5~z_Jy%pwQ)q9bHc^wY%5(D1ue|AwurZ*s)ZIk+(5?y zfm_U$p6j%G=yh+z@rBUE$MH!O+wBCdv3WBm{$9T#H{CkwyRGRSsn8Ef+t#Lhcej&+ zI6dEncH*r2igq%g#<8vWVOAcdbaSb)_9|{zLwFL!q70*B*ms*fqpss0q;cQ8*zElv z9db_J8CR=HEULGKP>JXFA+_Ym-nhH@tH<_V&c1{fswiJi@b5fpd44pn;Qd&2>B2h! z@-oH85nb`&m&S~!;k}vEMm@alLUEDlNPxiY#j&{pBO|rfRa_E=B z8j3>Jdm+lxdQthv&(lI2hOe>_R-#l0=9 z;?Oi+Sur9X@KV2A5f6_g;l2NHKrHNX9UY#+riT}o4$RvboB`R1TBD2@__OS&?yPsP zz*wPWw->FqQz&14;^zPVLqMpS#nEP(B=|(2aIz34Y-X_S9y~gpP4@N8QQ;tt=|bZUeMRm9R*R4-m#TitUqSy524uS4$a_G@ZB71CNs1~ zf3$Bjv%<(PkQfCQQ@AE(K+FP17J}YsLdzAB!;KDe{k<9>QsKC)oiT|WR)(+~Vm{UD z>{Rh4>HkP1=!rt$4q;S_Ai5iW3J%EDh=9KH245l68`8kmPj20!e1iL=ep$i*5SXZy z^WeCS%x}3Itbos;uk*;B0NJtVKj=`X6&*OB%e8(mH?*y%DE;rJpj5|V)Wu<3?VlKY zC=!&YL^c8*f&5|wSA!?hAO*GKfPIH)U(GwXQ-$YSY13I!MY1lat!XXKhl)`q2HTR; z$=fF3wKuh#9_Ju$Xym>DY^Jhxc};iL^3oBb1|S3}(5IMgJ`rQfUkW{WDl%}lsp^*M zb#~CYV+LJ#RUdE&ir?~I^TqO`)tpj~o7cwZ^NJ^U_yQqiF37E*OsFw%D~ZwI5BFI^ z;F9Y8m={l>!rUjm72)(NT-JbmaVuok8m^+EIl8Pu{GQL8RWtAzMjsrEc=3Yoxx{`w zvzEo`WTX;>elxC!8J9D{Lze;q?8v^rO7F{@xaG{l^H$BAs1iR}x4H^4Q~IPd3MXiH8>|m&TC; z7(yfF+*p$&zkXEw!Wy3>c9k+Xo`GA0A!hNZ3qN91!cf;&o`?3C}z6N8E zsebFRA3;=R2M}?N{)p<6QuDr=t8uKc3-?^BfXQ9vT%{!pGjbs!Qhh|fZuo~E;(ZS# zuWdeAHNK)OGws8UXVk?5E+3pFi*#TWFN+a#?K0Xl=ny|Aok6|VbJeGvqClDtq5>|O z_1+t~f;f|Anbv`Qj?Sxx=HVYR=a!aIsq|JH|20$|fgxDb%(7`517EnNsEyvt@+DWG znXAx}rDFH_3?x0S%wIqaj47XC$(BrfwR-IF><4DN2}{a1^-T6Rnv8wVX-^Ad1}kOO zMC;f#8B>%DS>m*7C|T7)*_d<}#P6sdi*CtnZdO*|CYwLKv%5A)>vYT2*$Jx+o&8$k zJ`!Wkn?EZ#^ZBJNub-OuUKQfl-L`hx?s&HP=r|9nM(MO)qh6`$xM(HEmk~V6e79hw z9g~oP6v>q_;%nwyy)BuKZKQTr_SBKHURJ9l!gvFrW{(=)YV>2+bq?d6u+;>@w`Voi z1y9xxUGm=gnd3`7{=sg)mU#5O@^SRh>i$mEaygOfShYyG?Bm5$KDo;O@6^|iku2a@ z`_1H2u&cOE8)P@O`Flx#(#qrs*8{Oenqa`Fj@K^jOD&SD7pTMdlFt#|7miGbO{}Be z5G&HUThiZsF7uS-2ziT(j{Xtw(v6Q-d!*PN6D7iPVf*_0D70I;lJxf%4B2QUwY!;U za>1;}S*y4YmMx;~tPr#r{96V8B5&pv`zDpvxT&sWAGzND4+aU~*sF@?*K{ z^9vW_JmlDXEnS{P;S9$I(TK4-hLOU2Mt3?Vq=N<4cA@bJh2|S$YX++|E-k=&NetVX zuKKz{AF3Wp4%u(i^2KNJQaCMV63lv3W!SU7t$p815Vs}4ygd*)sbEh{ zqnl7W;dSfr8eEQG$9QR)<}>ChAMJR(e5{}_bM+H_TC=K>G%2zg5hfJ`gcd ztj)zU!& z_f{L)e5J|oR8$AP9<`g* z0km1qD#o794c|Y_wR2$~ujcSuvI6$?L9mctr*uIByA-@A4y{OMEbyZQs_o}eJQ76d z@X2J&Ijrm5cH9`jDMBvo_?M08gcZ5I;)70WNF}*~4Hw6%rwFyveM8=2gKS8^>ZOg; zQ|(WenTyO9j7KH!`TmQHBfK($WIO zqQKc3vpOz^yn=Bjwc|8@B21R4#kYppGdJASD;0LuG`AG#j7Gw|-Gt=*F^wrPTe5S= zc--^}G+zJ&BSskHta3(MBIx!;he7;FLe|E`gbf}JuI#wqg^LoE)fW)gJ^?~yH;_m4 z_kM%sFKE8O7deOCcTq~3%6gXwpCoING5&FDrm$haBKmc=_#3=M(ajKgW|!zCf5$NL zS1$XEui+FoWx+rLj69}&e|Ro@Ux^lNRBS`urw7r88>BzF#m(xF>h+)}<}-i+GLeA= z(oABIiP%$Q2X<Wo+eO?XUM;n;suqH$wLH{(51QlN-Xq(}<4MmWA zz{FLR5;f#ez~J~d&A7Nnh>U=u6Dk_Slp=HrnXj)4O3K;zr2ajd15nbiXjO;VfXD}t zlaq6gr8zLeh`{|(BSFP^{0vu_QX%tQ!qpM6EHMvksa^wgv?-SpC6A;| z7bKSitZMpHtsS+Z&SR`BW$kL?C)Wx-zl9!4F84on-&{0T-~4BEl# z{H9s)6tq|*lNd7`8Te8s&NoLMpMvm_hzf^Lhg+<5Y{DoRGdr+LHr*LRTa;yDNaW&H z`C>esgn$wQ9$o)WG<=s1D%gc!>ObRX1qNbW^G7NGT|-=2S1GQy;G+I^7$XNZVmLU&-+1fDDNsD+N*J+vmW4PP6sz zsqGFRAtAAIcAgAH`mu_HfY1tzOkQ*QZ2rm3XDEaO*~Y)TLCo^HE*i0#{$RG7&Z_dD zrg3w??;gsv@xZCaj$tPW3-#>%_(Bv8**%PF)f+8MU)8{X7@3F@pkTQDq@HnujFuJ`wlHx`pnh}S$!+VF{z|6-0 z9;T53aL0K}CJ{OAHNv)Q2&nVH!LJ&SNUQAa?MKGn(6PIQfn!*K-$((Ze!qtU%{ZQ@ zHFJnC87#V~R7pvRM!8YItx-oNNyx`!UQ^f*`94ng7n<6 z)TIDC`gS3MW*?Zh>|THiXdXd&YM2DPhS_1J-v{cr|54oWf|zD&Ji*1sM*zrdtiJX;WDwoLWh?TI=g>0 z@wI9NTW-L&FB#eeM}8^LpTl~q?+f1^Cv@rF5p8I}2}qN%+)t^UC08Y`Pq$1tp_?0Y zL^-fYu6T+m(`C#L?oMptBV1w4cX2`hffqutLUa$+NaOl{Y`tYvRoxdaET{-bgA&r+ z9n#(1NJ=*n(k0T}DcxPtEe#4tBi-HIyzA)mALG4u+z)=xfrowe-fOKn=dU9F=G1^C z)$zh-vP3;czbhbH0c(u?zt%~lW1)ve?f|Vg+5-3H{w}0n z^M*@%eugnd!K#q}ya~A91c2P@|M5nBf#mCq0&!KYRQzCOoILpTK{Qav)6k>r3r>cl zPV=~yN))2@9AOu(`qjfKE899dC-j}?Z#z(rmWV9lZH=h60!<5APxfW_`~r`~KPlrj zhW&S3U8iwU?VSDRw+}`)l%Gw&Qj{CqB$XckFmqs2pXu8QqQr8&Kg&hPLKi{=fdp)CJOjFSYiQNWpy{c%I??@fm64l>Jt zMkorg`#v1ji!jLV!I9};h8~D*{4rie3oR6(HPtbw`GFTW^|K5T8iW{*w7@bo1-#xq`xq%V0dm>WDl78Ork zROgqQTrjx`Ko%!>l=5Jw+Wcetm(d0}^+ZUHk5`0K`MvQ0^E3hv?uH$d#la4qIuITS)O0Ys>aE*f$^M=MovRSNoCUjdh z=pvFi;1DVKEW^t$)Ad z0I_`&r*1%c9;tKh*grcA1kIa& zd-wK)^WR>Dg#rs3baz)P$Wg_&ah$9{vIYab@C*r*T#ZGf^N`(^OcqO-X04Eix1*D` zPzy6TiZ^(0c_QVkc&kf_&=*nso|p|moc|-CS%ZQi$a(=e{lA<29tsLRZRht7r?yf~ zD0|)PShW6wQBVv6a9N%x zQ6KS9ACNYLt`qDabERIFpMI?l-S>et3sl}ocDY|gn{q{N6C|p_9-@d{Eu>XG{P!N0 z%77=Y1~c6CpAffB;t`{0^tm9z`+^dL)Q@Wp$N-oXyn_y3;1tqn9T7y8|u_t~Z_KLiqhMNexe6EECF5~rzkpWFU7JqhA~y2J?P5IO{lBBLWu{0Ep1U_JU|!NMbo zci&xK4e(;2!-m4_Hds5a?4}PkKE!OmD-F9_ zD*QHhhX_%M4eIX+&pKso-?kIV&A1Xs{NRQry*xOP+6#%;V9t@h*r$x^;jIe%KJYjo zoeL&j6476u?q}B#S0y=FePj+*72iJyXuC7@Q18(uo5NP;mFve>xu8HU>kA1==CMJ{ z)lu2qYbI}M2frs?JB_YD0dy_%vjW0T_qWN-ZA+7FLgW{mb0kX@(qyUHO+voMV z*=yOB4Nt@qE7OCoji5JS{X!M;+avfoz15*Bv$gam`V)s!i-qIwZf<<=9d{?}3L$cw zFRiHk-|D{2z>y=C!`y$pf|dWhLm>hKl!?GvBe|EEy+yRw+UF{<#A-?jI;k9 zm2;%XRxQ2FHi>puZ4P06{y{&Njy@ZyfMGPlysIBQ$9}@?}NAH@2 zV(cm(OQo-`);i4;iF0s&MrZU(=YoV$TTsic8=uZ5ebGVbkI$#$QCjcv-y%Updn6Uy z+&_$Y^WTt+T*7-E?%!^w5eUkO(yl)y;#mp_=HvNfgZEs{hqUd_a%GZP8*xDTLbQsZ zIE)lNaXtcZGH+*3;*XDUKT%=oF}MtauBVEh+={p{Us@EEj`J3|Rm(YN?TC(LaTdWK zi>fZww_WvfRmYn&1kKkgNsmO&1*67!OQm^C?MZl+$#5#(sm&I#OqkJ_M@4;Acqhc z=V`umpg}TBhpJ2F|D;QvkgeTwp@KA-4jZ%X(-M7OImo}5=Uh2n>2kTdq?1aZ4Gwuj zgF`0cd9wNv3HN>G(B$|yIw+;5%jq~zuCDrkSkmrfRrHTDu;W*3^KflwY7#S-JDaPu z#2n7xXYls1{+$U0|Av~B_oKyhc{otPh?yG>K@SoM5wS$`ir`>)`A(7fE)%o&M%??4 zrJSu*C4o^}u9GbJV|xLrm;kcOEP7C*xUN~(n5C~S$yPv|;|wlITU%QLu!OgmEY2(Y zCQnNdMIn!0WOdMOnJ^N?b`bx}e-z{AdxXWErsb)hFI})&5Lb?tG;44ZjSl-)MzLP< zHg|QgMMg8tWg}?>|2w>`zCw!9RrZ-nQhYv-AYi8PQ}QjnHWnC|u%y_6j-JVUj8tI} z1&vv*@b2nR7v_y+_8Bj*o9(TO|7(dxmd z?oC8Z?-uL5c(Iz{8hSFCm_ekvTR3;j=Y5MnBf>lBIeYZFHu;aCnFOVYT*}ww%#YUh ztmfl{-_+Sv&WgfgjHSO>zf%_dDDdp<@S`%$&@BRdD`F{D*w6A}9)yeU} zxB4VbEvtew%LR#;`zDX{vO2L@oN#G z{J|DD{C-SlqxL;i=+8;k=%G{g2uUH?56@E}1u1p;s zAQWB9;xQlHMx<(!^0GeTr>LTN?!j2cv=q-YGoV=A6 zpU343z_XUYClzWpG8ZoWN@iID**=iq!TXDNuDp4&ou0&2P^9*AD*gc$7qJtBLUV^> z^eh2mnYN4;(SqGD>r?T2Nz9)S(s^0iR(QIFJnixFi&Z&R(ZavazA5_ z?TRngK;j?y2FIa;g^BHxaL+_wbdPnpmPBa{o$>19pN!Yb$xObYVyLsaw;3;`v(JTJ zo_T%qZIZ?LxF46Xyt!$jMA0O~yiA+&kf^f5R@nX_2X?1OEPB!Rl?YQv6vyQK2k(Bb z$1C$`Qnrx7y#pn_GT0nAmQ$<`w)ac{H|wAK58S9Sf^HY{nU^6AL!EdBStECg(zLi! zvEh zUJrH!91&($W6^>(UdGk>3`UnRteWj9D7J4?m@ue!QeGdL?L6J(*{n4oG=L zK<;R`_oF7R>&^A23%C9G+^2RlQ6i+5ytm%LE9kwMTODnbn$->a`d8j_RR&%YCu_f3 zyV!1;kX*yIt-oZ*1}A?=ASIL?}3DUpLwx{Of;wN;Mv6k^5VU z#h`%plxcw$W9{eKsZRq6{TEBlpGQAjEchK%1HKT8omTm8Wt zD4_&6h3-4&{3zr?{Pr$ey)&*XzjtGYDRuIo`HqW%>7Ta=WE=&S6gxSb55_<58H|h5 zr}1pV{#xu9e~*YMm&Vi>FhJ6`_Cu$q(nN_U!C!W+PNXD)AltoNH>uu5^H0Q3}rYcuz$$VWk03XuDiX@$*?XYq5(< zD9QGj&A%3xUl|+tUR^pDwb-A;_Fb{HF_dFfy}I@+adoya)P-8e#(sS$Jm$^MY}Z8O zXraUxSNX>RH>SfvH5iNJM_nY9jvH>*A&hC~*u0881#dMS4=7LLNc%t-UZwtyRPLEf zWEOuo6Hbg*{5QsHEpyVl)jgknWyTD});!E2UM1;C8IvhYTns;;7+B+2(Glux@WaqF z+(?t>K(aX!L+8QK@ z$X@De$gP3d&MS!jiK{fFwz#8gK@<*rD-o4$OT$20siMoHVC5*IKXV{a-i*`qTM@RP z^S$y{N2}!z$qBdyC_2n3l|@rAyoNQ#Pad5C)QmbM#F32$ukOhJF5|> z`Noydg2?pcv|&car%N3OL8}5_St0atvRa=8Fp)Jc7uT0>u=YUngD_I z4$9;k`~yQ7YHN5If_Ga{6Bh^8e7olpLTkQ-QRA<^rn7F9ZvGYJ0p_S<0@Z*3lKj)} zmM{`i>e)AyRRSyv)*AI$+nl}J78e(BIBakyqI$+Pu74hl5ysRjK>eDnK?p^*>Xnz? zgk^}OZSZ<{ncUe}r7j=BXFMDbdI9W z?#_VQxAJa_$!_X%)tan@Io5}IgS`AB1d5l;jW~2Hr&kiKpB7K)*CX zJ+Ls8GMmOmV|D^vGC>@Q6VRgo3!fP7?cY<)ahVtW(IjJc{--gd8x`LLvwFo)oYm)! z(TD;f{eFD)Lo3xJer&6^^B55=gxh#LqEbnuVXx+x+rurYWi!s zKaTD-<+S*S{`2Vho|m7NT2S#xBlBz=(q8qo(Q*4l3&7D48xDd1!`x}ft~$D~+pwKg zPmvef!nD|2lpg+d+YheY8mV0Nzl_F9|Fj-Y&K%_u+06ewLZNg5$x7$<$0V%OdU$E? z>bg^@+6SLX@c0hDzQvohScs`2mAK!P(7L$9nI~AU63XJfNMW52GIe?#iE0{CbJ*)0 zLfr1OpZwB)_%jF)N>BWV?l6+Z&9VKX6JVdqEwF5eZa0Hw63n{{VGREbJlf!F zufsf-_`fAR0FV6ap&ac-``N}u^i%RIg>N9A3A;#PY|3#DNCA^s8bElN;`VFToI*IY zf#Ynq+$j9u(Cg|05bl@C>G1Uyo82mjhXbc$5YvDJktAB{8atkJ!M`~$Ceq&^j}Fy4 z`spiaqqIFng@RamiTp;f7oogfsNS${@PUo0-K6Vd;q+mVGLa{Y{0rDmAswb8(K=XC zlmu|t@-})`Jw&L?!s%pl(^fIEyY&{uJ=U?PD?g{6l$&Gv+Ll5@iur282UDCa0@L*_ zV!u(gd0pUynhy62zLaKMJ%iHl{)}mc6x~zsfdqH4nE>!PJ0rWq*Ulc|W9R56;ien!HB4J}QeZ5BB`5rdJ_t#A7k?1kM7}$xWxb6p8Lo?-k+temB*@^1Uw@XdjJ5n3?D*$o$9v=%~~lO z*6ozKz6W4>yfM}AS$2h1wOA!<+$_&VXCrhSU{c1bDw98R_1e8M?@394QQUalT;6Y7 z_((-w39$%VDo1+lhA+TU$K|N{3<1c>Yx2n) z=s)Yq#bep&j0v9TH3LA`k@GmgLxN%OUD|58gr_cejUCm=K|0{K(XhdXRjr(eo6b#G zfCJ!heXeYDJ@Er?Z%}ea54!0_1WP{az(;%AJsV}!|7EG15JGI#ATVq?@f5j@;hHr- zOwJi8;wr}!9`DcOe`W9!fbuGiyQ9z%D5bl=IXC&!ED}U*LV125G!z3Y{S#pIW(Z_C z{i&Sad5#vEIporLsC4qEL^gl;zJf((?eSZo``2Y1Hp-bbY*n z#bJ{=u|>h_W7R3`yWUwf&g`STixqQ_FIm9hvF)xn?7={@i1;~P&gCnQ`#ov3RL%4{ z9<%qZO!8;Pxn0DuN~Jb8`_zqsJ74=M z(x1q9cpV#yN9qC=HLTl)+lcbUYj%X$NbHhmQ!@K1>37CJ2v$0!ibQ;7=CrMYvpT~D z)AofWV3}1S`2ac*CK&I3AO6S#4;lnGu`fbQks&WuM+f}Z3KVO-tc`xfP;s%9|C1~E zXrMsoQWNRy)|#}MJ$kB7l3b6TcF0a59mmpfjppN+Qf^rA*i?mKb=_oHX_l0ceSp8F znC)lBEbWNEEQcipNjTIOo#c=yz3su&`v^!6)eJa+PPs(Bu-H2N4OPJ7%vug4ct9fL z1e(VbR#gFTw^O#dwnnlgO2h%cjlLhgQuGL2obT^kYsDOm`%#T2mMVY07c3s!tQEwq zRX@Y*Q0fZQ&$j`0OYg%E%@yb50YxNyJ#2Fj?7_Ec0!&a zkKV>J1#WU;-?`hoPRGa^Po9KT#d#Az??!O3Tdpg{Io4p_O)tGm(saUNG#J#@)gI${ zPr@TlpT=8pp`KY8J`$-}$W8#zLt833na4t%^*g7-d8)IRLa}70~ zb^3zpLv`*SFSF)_B((aN6|>jb?Csiou|t(i7#tdj3$azh&c&idCz5Iz^va;BP?iDho6~HoNvZb^*Y8uFj=J8zQ)j2u^6zTCB9S3w@;u#+p1(~bpH$kn zS1uC!74VjMCOnk~idWMy>`Zea;QYz`x?%KMg4C?l>jpkyL@zAT%_}5;F2$fPzij5a z<0}~NDXl}H*dCg9hYO9NmOwINFgcjiYLzt`?o_Ha@%~4d=BT9tzXuV1R~v!<;Q`mr z7K*f#8lgpxMZjV4Y3`&H>6K?rMIhjovhM8@AqOf3z%Y?oS8Q+x_Yp1S*@J9uyJZ4w zYyII;%X8}{8vWLUn*ZJ7N?z!FDg*Z`KT{(jAK?3F@Hguteb zmzNqwaL!0}BVsTc$*0bf^_X<~ja4IR(Qhd~b6Wkum=Y2>CZKh!v=|$+F}U0n$z`sC zeHt=c5{d%}9&}Kr6&sD|$wT#Xs%&)FtK+FqDT7b2(eNiG3o-XRlUzm3v=x#<(E+bs z_q*-^Hz2TMg4B6v-#SoVw~9=-YV&$a&TZ<_t^LJ)0nUf%W3=k)lp8L5U){=}0l#E|I z=A5`X_;1DF2PAT;_RpB z<5bSH9WHm_+4p<#W09D3oc)6Y^3g&c_sS?lk=kGer`!XN@rE;`4nHNFcDi02Bdo%l zd)3|fD1?WEDoUC(MK(<;17j-Y(msAPLOuuQm((_nHkC3O*?FW0=XScIaR6QZ0dmLr zgHK4c3;ti0L|`kt|E;22PB40WC7HWUAl;Cb=MjX1bOirUmetN#%u4sxZ*%oi#G`Sc zx4fcW3AOUYMN!+<_FfUkg;eSe#su0$tB9xM-k#&Z=QnPij-(D3lKkmMd6pV?iF_h) zCPu*+l)5ht_@8E$J+*Xd)8Ac?z?tFJqLrmhNl{vCnaomoDiXjnRi`Os^M;<}(!YU? zR&RnX>&;Bdw-n@FP@2#+eyYJLLoObrqB3qWl_kP93A*ySeU};1+Wu6sw`@3u4(Nz5 zbv6qY_QYTmn)r<)sdT-Qlq|E&6vAQ(93kDYu8;gd6d13#RQLSpk+7 zY7b$|_4gAreTi9$)fYGsF+bkYDf0NZt=Skze-SbTy&(RaNhvUf5kNzK-{koz)x`E} zOm+UMIW+agYU`6m>f6rnzkQ3G6gcqY+|~@gTMhmZ#3!z!j!TNi|7&jJlS^(37!5mQ zN?;b5n+_id`8ZnG`NqxASI+l_qn#R#OPki)^96x+M0)=L#yWt?5Tr9to=*A?KbmIWFXTmvYaj)ar!3rU;CY4L9D=m7GM?+CKU6rVn38is43f!=n-D%EJ*MlToEFKp| zfJy{nGU$qM`?q=CWqUo`5+;691%~He0TA+mjkITiXX55K`Y*)-`2}Sk>c%>iR$VEt zOyU;AL^Gme^xzK7&%eEbz@tK2KB}z&{ogTHi4U+wjY!Aru+NZ@`9d>h4evoRi>d8O z=S!=(Iz(`^iALh{Lc&15-w04L?SO_Q0tg;fL2)4!ccWOqVKWc00!P8Yv9L$59O_zM z{%030K?o4_SOLPucjO;Mp^=Z~yR1=fV-%|8T_8-gzxT=$703ebn)F786Y3JPa|^*t z>b>_Pk6h||C=e3|jGi$7Zz5rlBmfVCN=YQ3PrKFa4VclhmP%Egflf6G{HbmS=S0#x zVlU2_MCD66@xMJ53xqUtFk5S4(U=5oh!*Mb{Rw(psWyJib4}(G3Hp}SiL(+@`eoHj z^T;{-NqzyCD#Ld>Kbmcgsg7Z=qP=fR)%4a;I6%E0Fm{p%IOC&SrP0sMEf7E1Vmph;4;i3wZD9apdzMMr;sfs38!i)kro*Wg)29+y!WeQYC2DjoE-n(D@HB1@w`@{zltiuiGT7df z9;SdpW;Rud-EY|wz20BP+u(Tt6QWA#%REVqO?Lnap9ZH(Vx?RepUYOhNj?-Dsy{P5 zz%S(3_2;kzXb>NH8`x(5r187L1UerH-y)=Mpa1Do{2Y169dzt`q_9vR7uV$d_C9<| zK0Vu@cCb(-C#7_$(Uqn=wLPd@?>x#=%-l$U(PCL)|Mn9%Oe9W(6M-XhA(QuPtF@^% zpEH#5V`{L4qeZg1Oh=0G>$fC&KcEYhzPmwR?xyP4ZOg1KUWtajB|CgJ&yCI~D8Lq% zRM>eJ1gqThzh2Wx0#bXsj2p0QKmx)^et>mY3380gyEFMuA>r7zs zoVoP#-V|c)JJg-7XV~17B7r>0DqwDc1uFF%-E84Nq}dx_i7*OEcC0PIEZ&;d4bT(S z)_oS@UJHB2fdqbFvhA0AGV@Dd6yA4zvX&?47xNnj9$SgsYUa!SpYN7E>!Qj4blst2 z0TASTvokVqPM_XAcvzok>muxeU2qW2=_h%*yMAaUKs~*r+n#v$=WAXrxOti=6sL}9o9RUBX(?i$7k-?L zj6L4^^qq0_P7#n&p5@o9{Q{BqXqgm;fKCpj1vts9o86j6lbgL;|0H!JXbQ2D%H=Ya zAvezMmcw8Bq(D$Iryv^0IOV0!Mrf+Ww;!^?jMhpz<>G5AyVp9}{IN-(fZ!_DkOVqj_ zT!RkiD*`ci{-Qq<=<@0jRAZ*$$voIFQYuoOB?x);-}Q|8A1>{W#^ws<+U}s4Ey{i> zwa=|hq*T{*`y9nF4m$MkgvzV*0eo2X zJ7cI|-YT%6X?IraVtd3lJ7E#TZ~BWFXJi(WLB!)e=+QS%uzS{!d)Gxg0ykRMc0IZm zw0>XKP=cnE{YuaOb9IZ#e6byP+|M6CvHi@13#bLL86#Bo4-U%cwg4~jG_{4A{nKJ; zyq3KX0TLuE_{QaU*=PPDAf~A}_+?jD*9nL#u+WLN>$I)d0bR8LaJfGf)Pju_;fMrT z(Q5$W2Mtdw_wH|os_!O4G0po?ufk^2TeuPY+d77mn1pfOQ)+JmJEE~K!dwvX%_4Jg z8*pR?AU_=g)vrRpPO*sZ!smEuMVlVh@zbJq_TY3%lA+uR3e9_ZrRuq%?aBK;F8~bR zWhPW=LrUO*GWtk>J73jT2_Ja1pE#}Rchbd{SE4q3w6Tlp#+OIwa}m;z?SI zJJX6;w#(ibpqh%nN_6xxaF~=-_AnG~1_??k(?SkVyKu4pX+CENAc~E4_qTi4C9XV$ zL=P7D1Vmj>yee4?>3|0p)A+t0Aec+Cu&$T;*Z`6wZ@vXd9c*1M-$eDnW19lr6tP3z zZ%l|_#k?!#l?+JIsM$jxw#o(;ZkZ^=@KD*>)L^m{dqGc6&)mHQU{Ij^$eHR@ls{Z- z@Q?qFIk@4;T8UY`F&2ncWZC9@N6$`s`^rnbJoGq50TjNz)L`b~W=Np=5=uUOB@#|K zPk$r!M{AYIBeV8F?AM3$v_rQjI>*F}|C`xAod$?k@!dK_p({3K!X6 zg4j})Zxm;V-EfBg_br3*-HUBfA=g>QD%wv2K>vQCvS0JNRF+1Y&l{?Z!v-gO2-A*4 z07lD=-vH1EJE~ww(VGX7Vz0f@nWq^N{}EEZT)+W(>+P>HK4Sl@!t8*u!f88BCHx4G z!+{N`WHDkWw;xeZPzaluacSs1ORRwq~ZkUmEo*5yDfg(3n|{=Cj4Bf)Op zZ@{44Lx4dYRA(~%McRU%C2riK_La~2ThY(y2yv(Vo>C@$5)~_o!jSeOYutre0&%Cq zo+!zspQ{|i7<@AYblJE05=e1^Yev76m&LV}@YS!N^ z7(^uMB532Q#JK_X0jXRbGJ63CZ!2`$gl0dR8xv1{F&z=?t+sG{!w_p4nX&rim{u`Q z{AqEQ3Jjnk_4UqQ`L9JOG&@kpSzheIVM|63@DMW$y#M~`j^0%_(^gPblsf|Vy4FdK zf}=vGFWU1}rODOX+%Yn0uZvYOuLpDZes0TCWc1M{Wp~axMPYPI(GW~@n7D{SwGwhZ z^XcGlVsfmWx}e2ZRLF`at38HuaTlOeuCxPm(&Q_Q;Gj5`!QRBq@&87IX0S=#^^y6g z>VGhy;O&Tr3Tqxt^JNW{ZNbHWk7+WULUu8v#?D0(~CR|)BB$B1CGe7*Cp!P z!=<1+@p}E=BZkZLLe>$7^N~81;lkxXWZ1ambPvzH31-5W9P%ZOP;1WuiL)#hHp3Y| z%~|~VQv-dWMH7$|F0BqPJiuLadA?#OLm(@uC;WRSRKDtT2FdFEcY-CEWWruqG6a(5 zD#r_$+MgPD1BQ7@h-4~z{kmj+n}zSkX4w2OrR-Mx1>qDU_f>^VkX{QTNfyCxM6r8v zx$5TV;+67N;-z=~>`@RB7GiQ+W;913`V>K?HD$0AuYB!zqG#`nE4<()`%ZuI@W}|Z zY^U%@^hTr3I4vuMXC#ReJ%8ls`K$8OUOzpGE|T!TU+&fR1NO3sn`)W1M6No;+Ss88 z#JTgzSf7h0i?c4eC{8E@j)DUubJvzgu0DncfPx+(SpFyrJ?a*+&3C2Yz{dj-Wq|6L z6bZsTL{k5@b5S;<Xe{sYr&+{?Jnf{ly$!i2olW3KcOqM zIgf9SeTe-4ASa474lE<`4nrDWZ#0OCj7^t&x=Ve6O~jy5$kEq9YDf+utS4X!bzOcz1(pL2L!Vl=(S9|b zaVF|_gL2!0U_p7e-BRNYO~r#~TXcg|JQrJTmCzyU*>ct|?3hlrm&H?MRADTiPUf!l zY(GB<@?bP~X}8)+A}Mzj$c1&KO>QWd|0zm4-wdkq@rRF2_5@S4N3CWkdC|h8tSDXV zmC??a&o3^ImKdB@v+=4R9l0$JbU^QZf61CiNp$cr8{`G;@PgZJNBwhzMwM ztw(bMM`;Rk0Am;o=!a6Z)5KSuK!T}Q7`2*T5l|DA7?dUG7pGbg-mi-nfKTxFxT@|L zeLjJf#Y81Yd(jL8SjoR8D;FTP$SBd3F@C3^-Qo}uAkg*XfHVK}wVcOo^+sL%?v%jY zV#Y_2E!_s^J)}BXt?;)x+-A!8%rSSJ&rXgHdCOAe`b7kZSksfkVn_4kV#Qp1jM&D) zcfQ6%$FxjSExzHDmN;B&3cqu{cg(we?*C0eLQ>m5j4_Woq3e$!1=HOY0OI`XCNEGN z3dH{mzOlRQxBGQ#o`U<8htGa}^xgfh@Vx?-ne~ChkyNR#ah76eZ#2H152lg6fRZ}> zrArJa7;^`xT#{d$GpdH}I=}zb$C9!_Rx|4;>3*b>jm=^URcz*%Q%&*xaToI2 zcccjQ$7I5TAQ#CPA9a!hLIi1WIU$C0b?Cg0Akhm_8m}wVJXjabREe+!6vDhIz6bw& z0;t*jjOn0}%>q#`yXV=sRHP=$9X?5n`q2Hno)CuHxpO z%mslY&P+#8P%s7=+XlgTud0SXYx?Y0Dr!aq)|b!NV>ykm&L1e8LO<|2GZk~33ieth zZ=8<@iR66pUCKOa_@wZ`?-ykoj*4g&{vdo$vVF{#5%aNvH_fFl47Wv4*~c==YdQ+o zD070hT#&R{b*;@Y{yf4QzL% zepe=rh}m>J7y|h0(#EH-Sy~LpK0RFN#ZjwDvFDLGuZs$C>&DT3Km&EQ7*JC~0=z!R zNyV8t0#krlh4miAGEFvD**Ue%pNaB^6AGZCOO6y#X0;OvK%O1->D?PIh-B4V|COw4 zGa}u*5Owl3jA=Jf8C|DaLu9}JupNaw)A{fmx1zAPtDgH?7;rDtq)V;-R$F)qq~&Zu zAr=yUE1y<2#OM6O;EH2e zz=g;mMysdBLI_8`mxJq8Jhf@hAzKydV1W?#eB}%W6mx)!tE+kX=gU@{bY8G1^I=It zO|Gz!GMGfee*PV6osbCdr-)y5x!${RENMQ;cC;W(&oDw=NN012!pjpKA)ICc@D*ro z1vmv{g7vj#rBvR?%gdXq5D5 zEfE+XMu2#*{zFRqL>>*wi~-QL80&rNP84#kqJiCj&r-m3ILoxAk0juyk8Mz*L~(Ug zP*P|9rBbeq?R|gp3UEI2<+P;z%x5w*%{5FK)CdR&I0JztT_%9x3YA3v6p2`GQHpn6 z6kx2-5Fj7;>cNC}D^|Tc@;8)KJoSYy9L?pEBX}QzSHhlcRg0`prKW0qV~T_?yt)4; zio3mDEkS|8@f$~PuxH@OQoE&MmB||qLi;a;_NyKGz+4T_^)t-3un){6dHs6m)ItSF zhcmvjvN(msqxj!L=gDq*F6-M2_Li9q$}p62q_{@TnVG1`J`9oGGN?7>YQ8zBYLcgm zavq3~)lw+1^SlniGm$V;PZ1|}mNa5Qfa3DnhQ+Bf!}&m_Hm%(E6gC9>oxL-hgs<9K z4JH%f*W|wlo34&Txl3R{ch$kEbDbRR_4Yp8ynLs3rn(R3havO)Q-#XcBX?41dIPK- zN_>Y(`9){_)T6g+^=T_76`q7z${y&tCP z_QSVBJv|LdeJ*lP0Cb^ageO1+sW6PFs#$Ln{+3SjOBigNc6{BIYP&6iMx{VNbJS>; z0$33wU9OZ&yXeuhF{jZANs-i}L%w13Mz&e6uoe3$g#s|xc*GBUBS5DgkKDz4kve5) zQ8t0>56YPS4m2Glwps@9_X#D6*l+e!`ht01RV{BVG1}c|t5~XFiu*;cUmreCV%_G( zKx_VOgwn`^zu^95ZrUc>D9;{?u5Mn|tcWg*=~dlf=SrG8Q{B;Yrj8l2@eu84%6#C_ z#5d{K^5r{uR zz)N@}Fq?0BsYa(8L9@lM+UzB);4+obpFqN0uG17IesxiS?O3X^`effz9B;RJtmrZA z4g2_^;RWz?ke^Op7~SuhDozpYQ)kdM7)|BRJ0uwQ?(5ULoCy2+*0DqCgj}H64ez}z z;o^hsU%@s#RJ}}vAgJvAP8)5lpmF)uX0A9EOGtcQZXhvXoYrJA5B6l?h)lT6UQXL? zVb!KaU@Y(A-swPwtOEx|+?=3u&o<#rK*d3vkv0 z?>+=Po$@wa-r<54X?eFX^gU@9OU;^$qCTPdR8?8@t*P)W2=X>;tUWSB$Hx{Mgu&cp zZ)T(VBuScOi*qVaL=>?}dYTgSBdo_e+iq`jOv3qK>`miBg?sTtzZPNp{ga3m&bz^S z{)aD}Jt2eH4ixfh`HZ*o=)FQQ{Y}*h3F5Un1+p1(AQ!$s?RkcoYsrHMUrG~lwBz+G zs}C5$`Uu_pYMoBD>B;*$LH>6G!Eq`*FGJKr6pZ?#GrCz_(= zbY~NzT(Uo(r;HDmLW!KBv)m>($ahGi7#YB z8FBgq#CONh%cK;?rmi$x$VFR11?o}_wDn!0TFpEM-d1n-oIOJ=MkDXEtfpGSvQ^%a zd=uc%;P?;#o1^HY9MeU^5+w!kBB!s~lYv(^ey8uK+l2bY@lVEBj{cqV%8~8Suuk$7 zd8VFRr6a$heqOfkfqLn?kdTed#giYEfFj^Rmc4?*L^Exd; zU?PJs4GD??GQwAWK^YiCJX^1!Yyqd6z}BoD$1sx*bMi}Kj=Rss=0-#p)gh){piSd4 z|0p=-VRPt{>m4p}ADraANdCz9+rN(|4@IqT5RN-5K{NI0A zgn$xiCTs7SR)1il4CX>cd` zJA};4KD|gs{?|m!&_XRb_L_V`l>e*h{ks~0F9$L3wXo~#{fBJHbo_yBL3jN)Rjxzh zylG!od*=2(eJ!}8<-!*;%H4`bv=yQMt`IHm*#Va@oSHcW?SISrZ@b0_)d#VQ=xc~{ zstN(h=4=3&J29#M!?y^Tp#V}R<5%(j`{0jH5aHwFQI<~W$Bn`G>!qj1z;*jj)#fB- z`54Hr%7g$|09nyL-yYS(&d`W_=DHm<-{Ly%=6foEBuz++>td_=LDyvEdSi2?QhLMx zKWObGM3ezVsum2a0fJybQTP(@MqXJP?`&?qy&7&HgWMUyU|6fAHaq~72!fQ*STmSm z-qMPS3Ww*FE0cN)$f??|{aW8dqI^L>qF)_1c4HuP*U$8zAynm>)9lzY?T8T^Oy$FU zwO)bIepB`UMX7{Nsn+Mg-~99}{Tk|q8ajS9WqJ+g-`cI@gWy^jjpJb;#8(u2m**h# z$T5YDdr+uLNZ8J04quz!8_wBgUT6wew_mH_8TCYAi1tk^Uq)x+T7m81jHEW|*=sL6 zzx_u0Y^9;%LXB4VF;j(0wxj7AWzg4PubImJc*RztwJ}wC>&^+7gpnbW)bGN@dw*nz zhsY0+4#fGcID8w%Qz%t|>ms(AyC#S@?6O-C4M!{EBUFl4&d})ZO`^3gj`Q z@_7m2;7P~P`y(wh5ekbLOMjaAp(a}H|4IgIyJv6B^6ufGv?9cA$3vRf1E+iuwSfgLYZY}PKK6i=Fki9I~5rd@v zz6p{LBtsH*X*AFVz%@2YZHVgX>R_6Vjf~G@drrpPeX9%8(!rn?-d+10v-U!p*8%E| z3XR5qd zG#@K?ZzJzDr~Li>ea;66^%0ZV%(>ov)I`~Pq*=K~?x$8THd~G%FoRh)BAY0ORBR>0$p`7?L z$$7ZnPkEr}Gn{{a63Yy+)-i!&y@8iV!*@AEp6AQK5*1o{w%7MOgMo4GS9VCx^DliI z{)wX8b1Wghq5Gvx9$sYbeO{qjvlxx}pCpVJ_4r)HYd%aRbsHk5{oFmw{mlO-z`hVc z&hU?H(NIS7nCqgTo_sjJ_Sbzg>Ato{Q`RoI(xGYu&KUT_{>SG(g!M80M9_4;XTIty z8k@^fbYDTod*$l!MC8V9j$E&DSj8S9bMJ<6`PvX(a=`>qvC#=J7ZV>$83k(6WB5(dvaG8{JzqdLJeRBO?2-_jB)L|MHD(* zao6vI$5RAzw|+mGJ(**2a_ojY2C|ti&8ir|t5T%k{&9bX9uUcVIuT@EImlK*)LO90 zU)IWupi4sY_K~i6o8JI-_OT*|hXKTH(5LevFYR$u9xkbFbAM*MJeUc;BmPWYqRuXp ze)f&A#wF7r9yyBI(E?$Q1%;d4`Ul6F7zuE;WReZuGb98yRZP!TEyzCxJlhx{%z=g5 zIALTB@oPt4Ax-ot@X9`Hgrz~{M>1g`?zHOeTBbw&q!-F4xY8hjPeBTGCEBT@qhd2S zA#kW9)wsff{V{zW&2vfZ^qUb~;rYR?Nnsv8GFrwDsuw}$yx*U@4nmu=?CcpjI2j;D z)weJrcz$%Hfk$-v{M>~SpU9v!xi#K4rzSc4&gDd6MU+#kh3450pAc~**Uc!KV7E@` zt#n2KxYm{pj0oqRCVXvFSDmrvA9^xA!y9I!9nJWDp%^iGFWbsK zl-v0!$GdYck>O+~stuUQB9%oiU3}BHozv^zkAI^VhUF(s{LA>y{!KL>Eh)wt3_{}8 z2L~hJiWT2lr+m3h`EO*Qq489~$N>6^Q=6!sX3*7-fVIxzAq8@0!KyK`lRue!{c%0l z;5nR{5UWF^!KJu1@N3&91~#=9ESag*R}=g6^%+ z+p|z#(CW}eHoKll9pCZ^na5KhD>PNbbZvC9XG)psZ*vl`E&YFVeRWur-}5%Ci=;FN z(n~I-fJk?Dcej+3h%}2dNQWS)G)RLW9ny`YAfPlzNh^XDJ z%-nO&J=lyX92zupHx!3wDV-5rie~TG)IUT^kmvl>n8*wP?XHD_(#dHGhAYIWR#-i*gdlwUnintu5X z9S0SSx#`w1<{8t-c^#x}dSh=S$$6-qd_FlQKiXE6{~C8|r#fPN8B!_tASEepqX*Hg zUuX0BuvDIL*R<6yv`H%Ko^IPl|a|z)n`Tx7iN+wj5#*;KjsuS75c8HX|YFp)b622JrwcB zf@Li|g*oTrSyUF+3*u zhRYC^O`JSsrD1kNU2;X9bUnGxH#sH!QaT+CoJDzw*Fa)kw&rjQANDP zs}^R>K3GfZr$?;D3kAa#Qw+J?aXzo^ev_j%z=RtvsvQL@aBk>UMI|P!j~due6Gusf zWgF&@eJscdUCQE2th#uocH`H-Pafaja}+!>yqk}oqM~M zqlF|F?+oP9wbqvDg<=--M^4XIMgjXrGqH=&^4$J)47S-V|6Loll)k*BKaafEUJ84k zkWr*oN{8=%Cn}Gxg9S!;n@8j9%MGSXGXBraEOyc*{IDY!sO@|B?$MRzNmV*J3DZ%v?(=-IjzmY0 zu<7Q4tm0@3@s=BPldh^Kq}wc-KtqHRYZhhj$(_N-hsOpjB%;KUwFYE_{cj|x2`aN$ zW#g2aNX8PHa-z<~j_gX!brQ68eibX@aZFH1_w!3o<2jJwl9N8m!tYHn)c9&caJF&w zyjT*qW@VO6sM9A6fnDCc^DbE@P*2A@z{@%)7A__|z0x!}ifv^uLG!K|OXs z4gYTJWYm7My7`E{%_y@jrs~M+d*b;ioY8aBoA))c73|;tAu2K6%6=R1N24^soqz>L zv?m@%%^E-NL&Pr~^_>bD&EEHHmSeI6q1a-e%DEy8?fD8rMlz8SwBGp#gG>PoiZK>H z7VTEFuJ3OFnca)InEbKgE2p!)BO;y$6Zgw#G!>#-9(<8|{((ATk-XG;G*v~Uev99A z7(=^4hibn>vlH~hX#dg>B{6IFn=Zc2ObN8wh(fzquS}O+$8?i$9R8Vwe*0&SXpi3m z16f;At1TSjcrGO=dDy4D+Q-houkVL-|2t>mxGd?kx>TfzLh!5M-9q^U$(Xljc!3lJScXfr8IM z==kvof8d0S5@8URby0NJXUaf=5=FSez~Dk|#Md1K(DZfkJ)K2$QFmCzauuf9y!)7h znwM$jPY$QFTeV{C42R7q4bNIWV+_Z!Mumme>Fo0-9Af3pzJg(D@e03epU(fLsqoI1 zntfYvzU0*(;?g%z=t)s0+}%a5BNEdbmG=ldzk!IaY3rvt z`3cCGZ(kzGcsFRGk)JA5DUf_Z;)Y6Po%~$4xxr_lFhm&9oLqqZZcMzY$Lf?gA#^#y z$&3LaMpb28g~d)hQuaaSpsg+Uy`fX@!mDl87M~*2?fGB00E~Ad7 z6rgy3=aWh|k2|DSVV#}B?>;R2LWJK<`y)Qw4t`+RJG)6zrpxtK*so*6EZp|l40?6- zZ%?;+)&5U~2TG6Cl{{&~@u(-y7X8PK6x7kLBl&*X#Y^;mZUe+x3b*KA$LsbK8R-4;ucG`pLik z-Nt~r(iCpgbNa2?8g1|J>hc#vDFN{1?v|^)kcK44qYT;89@@AqR6n-rMgR0eE#J(y zxnHY2LioC@pSFHo*S)mA-?_cwRH--+<`ST&wj^lg73RQUr6c)LbJEHHAF7Ctg&B{6 z86R|up$`8p*5D*Ci20>bU7wY7ie?S*-O`8Jz)N0FFa-91{ird|?!NQWUrcI5EaJvC zqb^f*1-yp_6NMgfJYUuIDHrUj(RG_PHMtusv_HA-w`7WX5Au&ZkE{0Fo7Q3DxeU)? zoKR`4i?(+kt#)FV>Xl@fI&{<=u)x&%6_t?@N5UR$&~E5WQP-b%Ie25N@Rs6awxYhW z{C(C#qdMuY6g2u#9=ex=aMO2dyz*t9gP6fM4C~_E z*SoqGnC4pM#4umNg0>!pbyUhvV%BHcR%cI2w&Ls^Mo_zGQ4dEop^8 zwdTg?o05Vot*G+zu=WBfuhxR19#RYwM#{VCFScv^>c%U`JX-DQ2B532lbM2yy5*+#IK2D=umHo zI=U%)=Ki$zjc=_E?6M8?MdL>MoJ}#%3FIg*8B70uGD#mE(#w+do~20gNc8dZsu+K} zd?&*uUFw}VIUtF^+80NulW^y`5GWk)44B;dbQma5)$hJY(hb-BZP6vq;GG9Mu;3k}n&o9lNm zH)9wA#DU_}yGv$+x-1W?3wS{5Vs5y)gd=n^06Z;AY47L)n4obkl~IC-4&AQyq8EwWXk{I60W>R6Nuin3H%Rz3I5@ z$GV5JpKgwwtOUd+)BKJHm^-Pl{&?ZfwFkDp&;}J#ZcGbEgt4Y}XoN`RB8+iQht8f^ zkiPLtvxE#k{2gpc`-Q6cSHFY|6`2(^sOS^?uo?Wav3vO`x{4u0f0FM^kvIsHa>q;c zBonW{g5I{k*g0UM>||xfe#+nnX~pkrD7Sxgh$O1P300|;;!WN**hj@l z-1-l&Sbn`-K1|D>(fNHG_hI+RU|W`(dk;2xY1W^!#Pjw)#uZNbYP)Q!TU;u1km!ir zXHLvkfjPNws&NC+-C$>>1KFoWN{Jmsa#Ok-b@{tG{ia?vK0L2!XM11&Ug-2l z*SR=+<+DNFcbH!N)Re_NuHP>bDw9nwq7ksZ7rR)5YtJ$ZQWrA646W8G;9c`yzpD@? zFCoUtS)#A8EzJ)2=?t5$n1~~gSsy}|mW8K@)9awTQmBlgj3YA0OMcuLzvE#1VZVRQ zqfAJ~==YsKHjiXn(jRE;M`Q4!I)zV+n8`vBxKjVQat)&{;sB`>^>s%?Hm`MWgO>YN zT^lhZ^2aPGiT>-8XK&ckg_Y1>n*;uPLCM0(`yZ}X67|}JEyNFXG||d*DytST*n{p0 zU%#oL^;VCi;%Bf)=9Qu&k-c9a^lef^>I0TT)5uoj^5DcPxwS-}*Ltb~ny+7WU{9W2mIsn`aSy~;Qap;4 zFJ3O{%iUIpl=2lRZgXEu-(TO>GmU>AjyohnqT3jy>C;op)tt1u@G+$%+IA>?s%ZVB zM7qSZwy@b!vsj(Z+vCfhW3z&mg?6tT(sWt8-M4Ny&nPe?VX4C{d}11H#b;igSRFaNc^^vmPklZZa!3n`H>Y`oCR;B;MVDSJEW zQ!10zaOxwgBBxNx(I-FRp(HRJAF#plqdY46RQN--1{PZ8&+Wccwc0neCcAU$gzwe` z2X}<}iVT+bOdeJi7%9CY0Ex$g$n9PTr3DaJ1%1-+CB#JDIqELc~Ma zYy*OZpi}qB6fTCjmtb&KBkeUF*3#BfiLW=s`|Ln=OF&C~5?}7?D3o4G5BH7Tj(Cb&@)NBk z?b?`uOZ52GOhvx0l3EoX1T#Le$PD9}D1BYvQWWs@piU>Lzhm@CW2E{ct4z7UncyhT zAKpg}TbHAntV{0SFG$HkM_LVfRNmWW>n?b26c*2?*Cwa06*~`2OdeVkI-qZ)zmIM6 z6W#8znfL$xj`YRs1DoEbP^^T=oo^Uup%}d(1w25eAWyQVQG78ehz66Gb2UcT>gQci z*}>_$LjJfsXo-5C_x^UVtHN}{f}}!}H5ax1kUFqJdD;w2WCFx8Riw$lGB+l(z!R z___c3Fr*vnXL{s)yq2pxUQ^1=a$T!M7{Lm8Nzu02#B{7)hBcTLaXsRrjaadMpMlc$ zrxD%tVMtUc2B&;t)FO}9zA@&EQB?7brt2{>N&Dvqp8-+_`b=KFplF2-5=SOf{x+d| z_@W$^bK{}URIU8YB37%nrH{%Vqu1eppr?E zM2;})DD^77R}3u(2<@U1Vdl)j+#c%gOaO_+KR-cc$n@fVxl=Nstm?LJVg}ky=hFg-eSDArX<3Z!V=t2L>1iqVueA^)6gPGPFB4gc5Oa@v>9)A4h_W zBv8$Way5HqrRS+J)5uX#D4ej*ZogRsgl zl1xNOL(-ApmF&sSRVOb%G6!GLKP{Vw3ArBs{JchyIzEm@=KdtmMT1B(A{uaQ2>;ou z)hyM9(?|Ycp?hRANWA@}B#D^A@UfyTW%kt7YB)_D0*~wwtuXUSpGMr4pF!Bz;=}GQ zw({pb1CzC;QS#J315+~Pj*G1#1Sij9p?&FZ{T%Ie#@JoHoF^a1<9)p;|H1dPHSZS>QcS>+e}i0ed#LEmg;ks`tk<|zBa_Ug zDGmpM?AaX65>iTl$-t~6GtoejZidmJXnoqnX!y14K6^oZgc(b%26Fo_s6kE|+y^F# zqhLaVIsn11^+mp-V*-kCJpN9whMnY=r7H^qeiu}iL*J5BGM6^5ULM1Y9rrb`|(MsE#Q$F^>OZ?PQ2d7J*#p&O1DeHJDf6XiwHV>cNd0 zU9HuUYr%2oCqXSsiI~9uAcI4=2);qQxHUeodF~2&I|&HGN>~STj^FqCln4zG<|yL# zoad`jK}vRAn}%-rNT6!JTso$@)-*>ikX4B159tN3kDuo}ybeF@-o ztR+!&VFD(1?}QHiIcU#O*d4~QL(ZruE5wIu7pwED(U2h` z8~cOIl}}0VBtLkcy?HGxQg*WBn|V0ck1e9ZUd5g_X#d@zeav#RcGLg0niV}rTNNSK zT@17#--A}WOm`YoD48b{gcDXI4hdjDVeHG0QL3Hp9=yCA|0v%OQT+&MFCnCeH{%a* z<)o0eR}(!7c95Q#zm6laMc&qmKVbL6M+Od#5#?IyTvcV|n8q2nVO?=OSzPy+Z07lc4eQQ8rq*DzFqa$b2;+SFeSBblvXEfc$r`|41($1AGsm?EPpdfa~>VbmU6B z5+?Nl5UvQTjH&lJ31`WnJSR6dlS&3dtIug71Px2NH-sM>oU0td@ek6e>%}Vi(Z;?% zPBp9W(>B&IXxWf{O&lN7^-}qNE?Gq5ncwBH%`8K<92qKbfXmpw$EENvpI~8LBz0t< zDXmN5O6^JJK|W*r<5_60kgpXm8$3<5&JJMpraS3T)N0mERCphcW)jak_B__ODXl4mR$`cQd1k5gvvDgAq3T?{nzD zb1sb8Vw3;<9H3xK`}LzsnrapqISlj`PuP<=n_xvA?bc5k%NAnGUWICD5{TXW^j`(j($Q(6oEr%w)OL;XH}M8mq|R zOuzidxD@cxe>V2reUGp}xyay9taw6M z2kp2xN_Js*H2brnbNpbZE(o8_>(-@n2SgH}B+ z1Pp6JBB}2FM=gGo-2W4>WTD(Do(NgKK;A2?P@G>+y?!+LUDh;P7lsNTFo~G@ja*tu zHfmQ6fm)Li#(y5cuyP-w9d&`mMuCK*!4f?|AQjXB_?r*x1PSAeF(S}u{2rxoR0;n3 zapJ{9^2*9z!t`sb2ZC@@6cd8J+uHr}kq8(HdYS*9vlL*ZXr)SLe^1=Mo)#|!DNszA zbhx_^{8m)P{bi><(lcCPfc3mEsa=dAQ%n##XyM^gsp90jD7j znUJUD)rMk{qJ`HrU1g29wl{l*?(3{6vR*NU!6a?Z7W|GbN|b@{svpY zlE5wIn%foq^S^HxItqAh@`pe}#^0Ss9%y%r@d<}DW2Mm$@CR%N2&3{cg}hWv1Ft;= zz^|QIO#uzgF8s{jPp|F0HubmuG`&1O#y>z~ z3V3E7Q-|}RUPSzV<4k#?m*B#2{y_nR&YTwN22y*I4w+C2&p&ZuH}Q;0smKKIB|%V1Kj=xJHhs16^uKEx1g&G-Km2q5zwSX?9RsMp znSqwxjp~Cusc@fRE7=Qt^DpU#O}do8Is6mggPR-zVi3tyR#zObaRJPSqe2JP3w?m$ zWet?0(^D;MpAvOU7Wec>1Nm8%r+CTl!Lk2$@JWb44#63q;7$v^6A6Wsl$0cbUltsc z)D1^fw(`@ZIt9RRdrKPZ$ZwAfz>NaZS*;&H#ljP=o*OhE3WqCzkw@iO-5=$_v>V=a zjLNjw{+#7$5#KX;pnaQf`8i4yGZKd_L1@3RyQM++KaWNJ22l>yJCTHLBT1YI%4yod z0!pq);BvvD6#l;Y$*M2*c&~PB!9ijbfi5luSoc45;a%K$j(>bw|ERO<)j``IRox2X61Xg@UIn|Jsds_!uVJ3Vhi0OV zT$OQo#Nlf9<@Oc-1Qi>MntT=YsSB9Sa@tU}zOt_+mH;0ssl={BG}N z=`YXQZ#e+z`t*}9_C{vVs{HQp`jGqKiiCl8(LwrmH-Vk&c8)HJRdS^8Yp-+u1bg2Mu(e@cP|N7K_U29P`ulc~FJpDjL5>;ati>sLCHOz&y-=dR>1e znH|Y7bmvyd%!mB=&N>RxG-)A!kHK3RFg@aqAO))oB4HeRba`Vk2Y zdy@CB5k8e({)o7^u@$WzUGc1r9rONpxak2;8+6KNE*M3aq?3cOSQl?H$F(p1?-wXFQ0P2Epu*r?>TA!(`z6xBJsK>`-(aa~n3&*gwW zKQndhL}>6|-dt|-%8>61Va%lImS}#S;Z9xp3;F!l$rOQ@eE=>n6U`4fGz&T`*F~7& zznP;mW=YlbJM2WCEH~hBB%uBiDgG>(UO)C|LXKwL#~L}=juJGI%>JxGWD*69Q7?K` zww`4ydd`}VKM1BFU{C0}R*E!+9R3Ue3Fd$NV;hrr4y=u7@T@CQ+}*wAYE$fX;+=6v zIO>&=Iz+1D5T2;xGJhm+3^X14f5eGp>m-@3i=B*19Z&0-dF!NxLX^zEwRmTAL0c^^ zAG9gy<}e_r?)m;=Mwox#I@`?jn|=Z?lPHF-n2eBw4Xu!Kdlvs@e$qgK!_WQ{<$(wG z@b8r_XkYJ9K;UrrG3YmRB#^^LyE918=84-nwE1BjqwC zP+A(8T8BlsuPGUg!XD15TV5Qh|3vo1@tVR&91h4&V1F~ne>){>nV=!N8d%R&1QQDL z>m2{H^x-#L-I>hq%z*}x6qrimPPxiZROF}5c}dRz*-(N z=KvMHrj+e-j!wm>gTq6wml^$wf5lW)be66@e!Xz0}UxMVlOrb2UDEXJT@>k zW0MbI<~p$*?ND}EF#d1NjnDut1N<60n0%ZDLOyS&SLB_{uKSAuBb!4(sCPmvyk7;1 zT=7C!WrUN~yHo9+3}c!>+Fmwd70mwL&cFN-M3K8joiDm$JAivA0OR|( zofjT&gV{lIuXFCqV4Bb4zWj%k@k23&@>o{Yz^y+v`zVp7 zfiwI5r4kxp*^*|yL{SV*!1c%e%UYQIeHqS@oSha2jhE>TFdN4RZRh-kyX3ns-zNGg zS}*0m!aqh+YCbFAWbu-bQH=bejk@Jfa?Ye@%uHxB{&hy5vl-fTxjMLHOn)ir$!At5 z!;ElkbJ^Bn5Nxm25OKU9=E$&4hB3hffV-@LR&Ykr zC|gA%OwYO6{SZ?>g|7D)(^&5!z2E6lS(jeUKR~SJ9kI{l(b3WIH{SyVW8=&xjmYV_ z)ZS|e;}k4%(jZYy=!m?AP02=3RA@Un-^%dR?AOt!v>gTzU#7-5fnrqc(MMKP;w&!NAlT(+QUQ? z>NhLmBr~*Q!oOmWj`sKY!9yUaa$bW*icJF9Pp0dg^EuhdGua%b{P4g=wt!}O1+NZ4(R2P1zQ)#_`U#wBLcc_)OxhT@y<*-U2*db9;FINPtta&#OV$NT z&K_s~gAIr9AzD^N`~Xq|U}2Znuh+TeKpP|N6b3`Zhh_isB|~p%j@1o{yFeuE6WfOJ zSRRf<7RZ7eR+I1T;yW_3dZ&zhZ#y=cVA$;wDTD>An|>9cQPC$p3i*@MJ`}q}zIL9$H$-PUp1D`9IuT^_ zQIWi{d%i5@FRtio)|d%SFwGdYIiHo7BWiq`JcI`#VM1xef?`ol7fK(WS2skp{EXH% zGWt+5YQ?@SA^PM(FYlkQ*g6M=L#AddhPNxZ1Biy%fZ+iR6Jh{qCZyP1t)wtg$cDZZ zw@sz1uK3%ek>sLRiV^ z#30TXXGT$aO}0+a^mQz>VFi_Z@=$Uw?)ID1gd?RJKY>I!_%iUwbb9;RdSkDJK->+(#o#O0S;`kNEMNdz1)l+ph{_vA2B?o3uP#)PK$!ot$PxO)qn1_4d#s^7zH#&uf zS~Z#*HXoYQ8_F+D)Jooet6h9|a@c#E(dwA;T`G${^I>Y=;>kltl_iP2pDz3)kAz60 zl{J39WRY#S`oI=m;Z$Z6DGsl3OT|K49Gvg1uz{&ph~o?qUdQAx;2S^*|ylgkEC&Dqci@em_s{y-eBdqIXHC596%&DJ zKK+bLvt&vT$52t}D(kxecE$MBnrmFhBrxP5DmxpZn1nNZ(EfDXM*hgXS7XMPy$KPD zQ7)N#@`xB#Y*1SwpSAluhYn+Xx0JYPRia1|x}JvuHQ=gw41AB3LDJ{!9)jg|J?EVd*;O8h!R>n}EV z0d@bR%v6>j)p@kvd@u-f2f!p!R&KuwSNm@*O&cx{-%NU{OBT6Md0pvlom$7RXomGB-sN?1RIJbAi(?`my;YaWe5bENIfUBLvyH4( zi-~dzzkqYd)vz2L}Ph1{A8175d6o(wB(s2@x$@z8N?<@4`wRYO?jOR(! zbAS~30j~oC=-f}Pu^IYZirqjI3xQv_zo~V3O>WhYua4vr35#`0! zrm(;yw#r$WHFGxzW4~;D_$Bs+r_9i>p*1x?#>br_YJyqvlIhW<&pr?#EE!HS`wv{A zgnxh7^f6ecb(maR^(jgH$QE66WiXB5cN0bqtIvowp5{FCuk9O0;x^;WOq2<6nB`yw zz_-9#|EA4s-?huloHU>s@w*ZINg4%2Jq(B9$#5kW!R%2d>L!38*FSvx=05V>JA^aKxt*ckt%Riz_!sosfN4|iTDa5>a-J5l1}U;$t^t9ckGX+AM6O| zt5$io6=|NGB&M8tbfZUz=&dC?48;?s#Jt}-DC2eieJ}m2%_m+suSv}^sbhQ) zGo;>--y>0#Kh7<=BGu*RGE2=Fp2*cnMhS@MY_u_8Kl@efmKsxF&1t(viSA^3tc`ja z=ux8V%bl(01u@JBddp-vmYtOL9a7HhLE98u=KjEzAFYI6p5hJ7uDrD#P=oCjfynR& zDve&}F~u-d)P1YPp}>j0d$N7!JD27`Pc>afTb{S{3(CDMzSGIy=~lAivh+A1q}7mH z%ul`}Z~4q3+9?Vu8PhSEm1<_o+u&Hy#MC3(zY0z40H6R{IPP{}LAF?+=`Z*(fX(i@ zW9+d7L3d^=U3Q(p{PqTqY~*@TBYxS*6t>Y>3V*3@k&?+9u$;$YsoSrV^Y0|gKr@T( zP>XPsrsOX)KC5N*{kX4P@8_IgqLgwfo9UxIzo~7UDq|!lS+%m}kNnJ01||JCe~AX9)~yxOq(PE3tlg&Sl5y2faSY)Rbg# z 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¬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 AasU7T literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/intro.rst b/tts/NeMo/docs/source/asr/speaker_recognition/intro.rst new file mode 100644 index 0000000..f1709a9 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_recognition/intro.rst @@ -0,0 +1,48 @@ +Speaker Recognition (SR) +======================== + +Speaker Recognition (SR) is a broad research area which solves two major tasks: speaker identification (who is speaking?) and speaker verification (is the speaker who they claim to be?). +We focus on far-field, text-independent speaker recognition when the identity of the speaker is based on how the speech is spoken, not necessarily in what is being said. +Typically such SR systems operate on unconstrained speech utterances, which are converted into vectors of fixed length, called speaker embeddings. +Speaker embeddings can also be used in automatic speech recognition (ASR) and speech synthesis. + +As the goal of most speaker recognition systems is to get good speaker level embeddings that could help distinguish from other speakers, we shall first train these embeddings in end-to-end manner optimizing the QuatzNet based encoder model on cross-entropy loss. +We modify the decoder to get these fixed size embeddings irrespective of the length of the input audio and employ a mean and variance based statistics pooling method to grab these embeddings. + +In Speaker Identification we typically train on a larger training set with cross-entrophy loss and finetune later on your preferred set of labels where one would want to classify only known set of speakers. +And in Speaker verification we train with Angular Softmax loss and compare embedings extracted from one audio file coming from a single speaker with +embeddings extracted from another file of same or another speaker by employing backend scoring techniques like cosine similarity. + + +The full documentation tree is as follows: + +.. toctree:: + :maxdepth: 8 + + models + configs + datasets + results + +Resource and Documentation Guide +-------------------------------- + +Hands-on speaker recognition tutorial notebooks can be found under +`the speaker recognition tutorials folder `_. This and most other tutorials can be run on Google Colab by specifying the link to the notebooks' GitHub pages on Colab. + +If you are looking for information about a particular SpeakerNet model, or would like to find out more about the model +architectures available in the ``nemo_asr`` collection, check out the :doc:`Models <./models>` page. + +Documentation on dataset preprocessing can be found on the :doc:`Datasets <./datasets>` page. +NeMo includes preprocessing and other scripts for speaker_recognition in folder, and this page contains instructions on running +those scripts. It also includes guidance for creating your own NeMo-compatible dataset, if you have your own data. + +Information about how to load model checkpoints (either local files or pretrained ones from NGC), perform inference, as well as a list +of the checkpoints available on NGC are located on the :doc:`Checkpoints <./results>` page. + +Documentation for configuration files specific to the ``nemo_asr`` models can be found on the +:doc:`Configuration Files <./configs>` page. + + +For a clear step-by-step tutorial we advice you to refer tutorials found in `folder `_. + diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/models.rst b/tts/NeMo/docs/source/asr/speaker_recognition/models.rst new file mode 100644 index 0000000..ebfc5ba --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_recognition/models.rst @@ -0,0 +1,52 @@ +Models +====== + +Examples of config files for the following quartznet model can be found in the ``/examples/speaker_recogniton/conf`` directory. + +For more information about the config files and how they should be structured, see the :doc:`./configs` page. + +Pretrained checkpoints for all of these models, as well as instructions on how to load them, can be found on the :doc:`./results` page. +You can use the available checkpoints for immediate inference, or fine-tune them on your own datasets. +The Checkpoints page also contains benchmark results for the available speaker recognition models. + +.. _SpeakerNet_model: + +SpeakerNet +----------- + +The model is based on the QuartzNet ASR architecture :cite:`sr-models-koluguri2020speakernet` +comprising of an encoder and decoder structure. We use the encoder of the QuartzNet model as a top-level feature extractor, and feed the output to the statistics pooling layer, where +we compute the mean and variance across channel dimensions to capture the time-independent utterance-level speaker features. + +The QuartzNet encoder used for speaker embeddings shown in figure below has the following structure: a QuartzNet BxR +model has B blocks, each with R sub-blocks. Each sub-block applies the following operations: a 1D convolution, batch norm, ReLU, and dropout. All sub-blocks in a block have the same number of output channels. These blocks are connected with residual connections. We use QuartzNet with 3 blocks, 2 sub-blocks, and 512 channels, as the Encoder for Speaker Embeddings. All conv layers have stride 1 and dilation 1. + + + .. image:: images/ICASPP_SpeakerNet.png + :align: center + :alt: speakernet model + :scale: 40% + +Top level acoustic Features, obtained from the output of +encoder are used to compute intermediate features that are +then passed to the decoder for getting utterance level speaker +embeddings. The intermediate time-independent features are +computed using a statistics pooling layer, where we compute the mean and standard deviation of features across +time-channels, to get a time-independent feature representation S of size Batch_size × 3000. +The intermediate features, S are passed through the Decoder consisting of two layers each of output size 512 for a +linear transformation from S to the final number of classes +N for the larger (L) model, and a single linear layer of output size 256 to the final number of classes N for the medium +(M) model. We extract q-vectors after the final linear layer +of fixed size 512, 256 for SpeakerNet-L and SpeakerNet-M +models respectively. + +SpeakerNet models can be instantiated using the :class:`~nemo.collections.asr.models.EncDecSpeakerLabelModel` class. + + +References +----------- + +.. bibliography:: ../asr_all.bib + :style: plain + :labelprefix: SR-MODELS + :keyprefix: sr-models- diff --git a/tts/NeMo/docs/source/asr/speaker_recognition/results.rst b/tts/NeMo/docs/source/asr/speaker_recognition/results.rst new file mode 100644 index 0000000..eb2472e --- /dev/null +++ b/tts/NeMo/docs/source/asr/speaker_recognition/results.rst @@ -0,0 +1,85 @@ +Checkpoints +=========== + +There are two main ways to load pretrained checkpoints in NeMo: + +* Using the :code:`restore_from()` method to load a local checkpoint file (`.nemo`), or +* Using the :code:`from_pretrained()` method to download and set up a checkpoint from NGC. + +See the following sections for instructions and examples for each. + +Note that these instructions are for loading fully trained checkpoints for evaluation or fine-tuning. +For resuming an unfinished training experiment, please use the experiment manager to do so by setting the +``resume_if_exists`` flag to True. + +Loading Local Checkpoints +------------------------- + +NeMo will automatically save checkpoints of a model you are training in a `.nemo` format. +You can also manually save your models at any point using :code:`model.save_to(.nemo)`. + +If you have a local ``.nemo`` checkpoint that you'd like to load, simply use the :code:`restore_from()` method: + +.. code-block:: python + + import nemo.collections.asr as nemo_asr + model = nemo_asr.models..restore_from(restore_path="") + +Where the model base class is the ASR model class of the original checkpoint, or the general `ASRModel` class. + + +Inference +---------- + +The audio files should be 16KHz monochannel wav files. + +Write audio files to a ``manifest.json`` file with lines as in format: + +.. code-block:: json + + {"audio_filepath": "/audio_file.wav", "duration": "duration of file in sec", "label": "speaker_id"} + +This python call will download best pretrained model from NGC and writes embeddings pickle file to current working directory + +.. code-block:: bash + + python examples/speaker_recognition/extract_speaker_embeddings.py --manifest=manifest.json + + +NGC Pretrained Checkpoints +-------------------------- + +The SpeakerNet-ASR collection has checkpoints of several models trained on various datasets for a variety of tasks. +`Speaker_Recognition `_ and `Speaker_Verification `_ model cards on NGC contain more information about each of the checkpoints available. + +The tables below list the SpeakerNet models available from NGC, and the models can be accessed via the +:code:`from_pretrained()` method inside the EncDecSpeakerLabelModel Model class. + +.. note:: While loading, remember to use EncDecSpeakerLabelModel for recognition tasks and ExtractSpeakerEmbeddingsModel while extracting embeddings. + +In general, you can load any of these models with code in the following format. + +.. code-block:: python + + import nemo.collections.asr as nemo_asr + model = nemo_asr.models..from_pretrained(model_name="") + +Where the model name is the value under "Model Name" entry in the tables below. + +If you would like to programatically list the models available for a particular base class, you can use the +:code:`list_available_models()` method. + +.. code-block:: python + + nemo_asr.models..list_available_models() + + +Speaker Recognition Models +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :file: data/speaker_results.csv + :align: left + :widths: 30, 30, 40 + :header-rows: 1 + diff --git a/tts/NeMo/docs/source/asr/speech_classification/configs.rst b/tts/NeMo/docs/source/asr/speech_classification/configs.rst new file mode 100644 index 0000000..f0b17c5 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speech_classification/configs.rst @@ -0,0 +1,104 @@ +NeMo Speech Classification Configuration Files +================================================ + +This page covers NeMo configuration file setup that is specific to models in the Speech Classification collection. +For general information about how to set up and run experiments that is common to all NeMo models (e.g. +experiment manager and PyTorch Lightning trainer parameters), see the :doc:`../../core/core` page. + +The model section of NeMo Speech Classification configuration files will generally require information about the dataset(s) being +used, the preprocessor for audio files, parameters for any augmentation being performed, as well as the +model architecture specification. +The sections on this page cover each of these in more detail. + +Example configuration files for all of the NeMo ASR scripts can be found in the +``/examples/asr/conf>``. + + +Dataset Configuration +--------------------- + +Training, validation, and test parameters are specified using the ``train_ds``, ``validation_ds``, and +``test_ds`` sections of your configuration file, respectively. +Depending on the task, you may have arguments specifying the sample rate of your audio files, labels, whether or not to shuffle the dataset, and so on. +You may also decide to leave fields such as the ``manifest_filepath`` blank, to be specified via the command line +at runtime. + +Any initialization parameters that are accepted for the Dataset class used in your experiment +can be set in the config file. +See the `Datasets <../api.html#Datasets>`__ section of the API for a list of Datasets and their respective parameters. + +An example Speech Classification train and validation configuration could look like: + +.. code-block:: yaml + + model: + sample_rate: 16000 + repeat: 2 # number of convolutional sub-blocks within a block, R in _[BxRxC] + dropout: 0.0 + kernel_size_factor: 1.0 + labels: ['bed', 'bird', 'cat', 'dog', 'down', 'eight', 'five', 'four', 'go', 'happy', 'house', 'left', 'marvin', + 'nine', 'no', 'off', 'on', 'one', 'right', 'seven', 'sheila', 'six', 'stop', 'three', 'tree', 'two', 'up', + 'wow', 'yes', 'zero'] + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} # Uses the labels above + batch_size: 128 + shuffle: True + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} # Uses the labels above + batch_size: 128 + shuffle: False # No need to shuffle the validation data + +If you would like to use tarred dataset, have a look at `Datasets Configuration <../configs.html#dataset-configuration>`__. + + +Preprocessor Configuration +-------------------------- +Preprocessor helps to compute MFCC or mel spectrogram features that are given as inputs to model. +For details on how to write this section, refer to `Preprocessor Configuration <../configs.html#preprocessor-configuration>`__ + +Check config yaml files in ``/examples/asr/conf`` to find the processors been used by speech classification models. + + +Augmentation Configurations +--------------------------- + +There are a few on-the-fly spectrogram augmentation options for NeMo ASR, which can be specified by the +configuration file using the ``augmentor`` and ``spec_augment`` section. +For details on how to write this section, refer to `Augmentation Configuration <../configs.html#augmentation-configurations>`__ + +Check config yaml files in ``/tutorials/asr/conf`` to find the processors been used by speech classification models. + + +Model Architecture Configurations +--------------------------------- + +Each configuration file should describe the model architecture being used for the experiment. +Models in the NeMo ASR collection need a ``encoder`` section and a ``decoder`` section, with the ``_target_`` field +specifying the module to use for each. + +The following sections go into more detail about the specific configurations of each model architecture. + +The `MatchboxNet <./models.html#matchboxnet-speech-commands>`__ and `MarbleNet <./models.html#marblenet-vad>`__ models are very similar, and they are based on `QuartzNet <../models.html#quartznet>`__ and as such the components in their +configs are very similar as well. + +Decoder Configurations +------------------------ + +After features have been computed from ConvASREncoder, we pass the features to decoder to compute embeddings and then to compute log_probs +for training models. + +.. code-block:: yaml + + model: + ... + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoderClassification + feat_in: *enc_final_filters + return_logits: true # return logits if true, else return softmax output + pooling_type: 'avg' # AdaptiveAvgPool1d 'avg' or AdaptiveMaxPool1d 'max' \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speech_classification/data/classification_results.csv b/tts/NeMo/docs/source/asr/speech_classification/data/classification_results.csv new file mode 100644 index 0000000..25e3c84 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speech_classification/data/classification_results.csv @@ -0,0 +1,9 @@ +Model Name,Model Base Class,Model Card +vad_marblenet,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:vad_marblenet" +vad_telephony_marblenet,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:vad_telephony_marblenet" +commandrecognition_en_matchboxnet3x1x64_v1,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:commandrecognition_en_matchboxnet3x1x64_v1" +commandrecognition_en_matchboxnet3x2x64_v1,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:commandrecognition_en_matchboxnet3x2x64_v1" +commandrecognition_en_matchboxnet3x1x64_v2,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:commandrecognition_en_matchboxnet3x1x64_v2" +commandrecognition_en_matchboxnet3x2x64_v2,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:commandrecognition_en_matchboxnet3x2x64_v2" +commandrecognition_en_matchboxnet3x1x64_v2_subset_task,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:commandrecognition_en_matchboxnet3x1x64_v2_subset_task" +commandrecognition_en_matchboxnet3x2x64_v2_subset_task,EncDecClassificationModel,"https://ngc.nvidia.com/catalog/models/nvidia:nemo:commandrecognition_en_matchboxnet3x2x64_v2_subset_task" \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speech_classification/datasets.rst b/tts/NeMo/docs/source/asr/speech_classification/datasets.rst new file mode 100644 index 0000000..3198954 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speech_classification/datasets.rst @@ -0,0 +1,131 @@ +Datasets +======== + +NeMo has scripts to convert several common ASR datasets into the format expected by the `nemo_asr` collection. +You can get started with those datasets by following the instructions to run those scripts in the section appropriate to each dataset below. + +If you have your own data and want to preprocess it to use with NeMo ASR models, check out the `Preparing Custom Speech Classification Data`_ section at the bottom of the page. + +.. _Freesound-dataset: + +Freesound +----------- + +`Freesound `_ is a website that aims to create a huge open collaborative database of audio snippets, samples, recordings, bleeps. +Most audio samples are released under Creative Commons licenses that allow their reuse. +Researchers and developers can access Freesound content using the Freesound API to retrieve meaningful sound information such as metadata, analysis files, and the sounds themselves. + +**Instructions** + +Go to ``/scripts/freesound_download_resample`` and follow the below steps to download and convert freedsound data into a format expected by the `nemo_asr` collection. + +1. We will need some required libraries including freesound, requests, requests_oauthlib, joblib, librosa and sox. If they are not installed, please run `pip install -r freesound_requirements.txt` +2. Create an API key for freesound.org at https://freesound.org/help/developers/ +3. Create a python file called `freesound_private_apikey.py` and add lined `api_key = and client_id = ` +4. Authorize by run `python freesound_download.py --authorize` and visit the website and paste response code +5. Feel free to change any arguments in `download_resample_freesound.sh` such as max_samples and max_filesize +6. Run `bash download_resample_freesound.sh ` . For example: + +.. code-block:: bash + + bash download_resample_freesound.sh 4000 ./freesound ./freesound_resampled_background + +Note that downloading this dataset may take hours. Change categories in download_resample_freesound.sh to include other (speech) categories audio files. +Then, you should have 16khz mono wav files in ``. + + +.. _Google-Speech-Commands-Dataset: + +Google Speech Commands Dataset +------------------------------ + +Google released two versions of the dataset with the first version containing 65k samples over 30 classes and the second containing 110k samples over 35 classes. +We refer to these datasets as `v1` and `v2` respectively. + +Run the script `process_speech_commands_data.py` to process Google Speech Commands dataset in order to generate files in the supported format of `nemo_asr`, +which can be found in ``/scripts/dataset_processing/``. +You should set the data folder of Speech Commands using :code:`--data_root` and the version of the dataset using :code:`--data_version` as an int. + +You can further rebalance the train set by randomly oversampling files inside the manifest by passing the `--rebalance` flag. + +.. code-block:: bash + + python process_speech_commands_data.py --data_root= --data_version=<1 or 2> {--rebalance} + + +Then, you should have `train_manifest.json`, `validation_manifest.json` and `test_manifest.json` +in the directory `{data_root}/google_speech_recognition_v{1/2}`. + +.. note:: + You should have at least 4GB or 6GB of disk space available if you use v1 or v2 respectively. + Also, it will take some time to download and process, so go grab a coffee. + +Each line is a training example. + +.. code-block:: bash + + {"audio_filepath": "/two/8aa35b0c_nohash_0.wav", "duration": 1.0, "label": "two"} + {"audio_filepath": "/two/ec5ab5d5_nohash_2.wav", "duration": 1.0, "label": "two"} + + + +Speech Command & Freesound for VAD +------------------------------------ +Speech Command & Freesound (SCF) dataset is used to train MarbleNet in the `paper `_. Here we show how to download and process it. +This script assumes that you already have the Freesound dataset, if not, have a look at :ref:`Freesound-dataset`. +We will use the open-source :ref:`Google-Speech-Commands-Dataset` (we will use V2 of the dataset for SCF dataset, but require very minor changes to support V1 dataset) as our speech data. + +These scripts below will download the Google Speech Commands v2 dataset and convert speech and background data to a format suitable for use with nemo_asr. + +.. note:: + You may additionally pass :code:`--test_size` or :code:`--val_size` flag for splitting train val and test data. + + You may additionally pass :code:`--seg_len` flag for indicating the segment length. Default is 0.63s. + + You may additionally pass a :code:`-rebalance_method='fixed|over|under'` at the end of the script to rebalance the class samples in the manifest. + + + +* `'fixed'`: Fixed number of sample for each class. Train 5000, val 1000, and test 1000. (Change number in script if you want) +* `'over'`: Oversampling rebalance method +* `'under'`: Undersampling rebalance method + + +.. code-block:: bash + + mkdir './google_dataset_v2' + python process_vad_data.py --out_dir='./manifest/' --speech_data_root='./google_dataset_v2'--background_data_root= --log --rebalance_method='fixed' + + +After download and conversion, your `manifest` folder should contain a few json manifest files: + +* `(balanced_)background_testing_manifest.json` +* `(balanced_)background_training_manifest.json` +* `(balanced_)background_validation_manifest.json` +* `(balanced_)speech_testing_manifest.json` +* `(balanced_)speech_training_manifest.json` +* `(balanced_)speech_validation_manifest.json` + +Each line is a training example. `audio_filepath` contains path to the wav file, `duration` is duration in seconds, `offset` is offset in seconds, and `label` is label (class): + +.. code-block:: bash + + {"audio_filepath": "/two/8aa35b0c_nohash_0.wav", "duration": 0.63, "label": "speech", "offset": 0.0} + {"audio_filepath": "/Emergency_vehicle/id_58368 simambulance.wav", "duration": 0.63, "label": "background", "offset": 4.0} + + + +Preparing Custom Speech Classification Data +-------------------------------------------- + +Preparing Custom Speech Classification Data is almost identical to `Preparing Custom ASR Data <../datasets.html#preparing-custom-asr-data>`__. + +Instead of :code:`text` entry in manifest, you need :code:`label` to determine class of this sample + + +Tarred Datasets +--------------- + +Similarly to ASR, you can tar your audio files and use ASR Dataset class ``TarredAudioToClassificationLabelDataset`` (corresponding to the ``AudioToClassificationLabelDataset``) for this case. + +If you would like to use tarred dataset, have a look at `ASR Tarred Datasets <../datasets.html#tarred-datasets>`__. \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speech_classification/images/marblenet_vertical.png b/tts/NeMo/docs/source/asr/speech_classification/images/marblenet_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..3174d1ef5ea56ca36159d7525f2f6acf6c2367b0 GIT binary patch literal 393467 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 *dFV_}t5qIwsa3BeNpoOemrK{{!p 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

bYR~QoBBrfa^W(p#A*lnKTB)f7>uR^;}t<vhL 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ⅆ}zGJfKO>=U(1 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 literal 0 HcmV?d00001 diff --git a/tts/NeMo/docs/source/asr/speech_classification/intro.rst b/tts/NeMo/docs/source/asr/speech_classification/intro.rst new file mode 100644 index 0000000..6a1a2f9 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speech_classification/intro.rst @@ -0,0 +1,47 @@ +Speech Classification +================================== +Speech Classification refers to a set of tasks or problems of getting a program to automatically classify input utterance or audio segment into categories, +such as Speech Command Recognition (multi-class), Voice Activity Detection (binary or multi-class), and Audio Sentiment Classification (typically multi-class), etc. + +**Speech Command Recognition** is the task of classifying an input audio pattern into a discrete set of classes. +It is a subset of Automatic Speech Recognition, sometimes referred to as Key Word Spotting, in which a model is constantly analyzing speech patterns to detect certain "command" classes. +Upon detection of these commands, a specific action can be taken by the system. +It is often the objective of command recognition models to be small and efficient so that they can be deployed onto low-power sensors and remain active for long durations of time. + + +**Voice Activity Detection (VAD)** also known as speech activity detection or speech detection, is the task of predicting which parts of input audio contain speech versus background noise. +It is an essential first step for a variety of speech-based applications including Automatic Speech Recognition. +It serves to determine which samples to be sent to the model and when to close the microphone. + + +The full documentation tree is as follows: + +.. toctree:: + :maxdepth: 8 + + models + datasets + results + configs + + +Resource and Documentation Guide +-------------------------------- + +Hands-on speech classification tutorial notebooks can be found under ``/tutorials/asr/``. +There are training and offline & online microphone inference tutorials for Speech Command Detection and Voice Activity Detection tasks. +This and most other tutorials can be run on Google Colab by specifying the link to the notebooks' GitHub pages on Colab. + +If you are looking for information about a particular Speech Classification model or would like to find out more about the model +architectures available in the `nemo_asr` collection, check out the :doc:`Models <./models>` page. + +Documentation on dataset preprocessing can be found on the :doc:`Datasets <./datasets>` page. +NeMo includes preprocessing scripts for several common ASR datasets, and this page contains instructions on running +those scripts. +It also includes guidance for creating your own NeMo-compatible dataset, if you have your own data. + +Information about how to load model checkpoints (either local files or pretrained ones from NGC), perform inference, as well as a list +of the checkpoints available on NGC are located on the :doc:`Checkpoints <./results>` page. + +Documentation for configuration files specific to the ``nemo_asr`` models can be found on the +:doc:`Configuration Files <./configs>` page. diff --git a/tts/NeMo/docs/source/asr/speech_classification/models.rst b/tts/NeMo/docs/source/asr/speech_classification/models.rst new file mode 100644 index 0000000..b8c0248 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speech_classification/models.rst @@ -0,0 +1,71 @@ +Models +====== + +This page gives a brief overview of the models that NeMo's Speech Classification collection currently supports. +For Speech Classification, we support Speech Command (Keyword) Detection and Voice Activity Detection (VAD). + +Each of these models can be used with the example ASR scripts (in the ``/examples/asr`` directory) by +specifying the model architecture in the config file used. +Examples of config files for each model can be found in the ``/examples/asr/conf`` directory. + +For more information about the config files and how they should be structured, see the :doc:`./configs` page. + +Pretrained checkpoints for all of these models, as well as instructions on how to load them, can be found on the :doc:`./results` page. +You can use the available checkpoints for immediate inference, or fine-tune them on your own datasets. +The Checkpoints page also contains benchmark results for the available ASR models. + +.. _MatchboxNet_model: + +MatchboxNet (Speech Commands) +------------------------------ + +MatchboxNet :cite:`sc-models-matchboxnet` is an end-to-end neural network for speech command recognition based on `QuartzNet <../models.html#QuartzNet>`__. + +Similarly to QuartzNet, the MatchboxNet family of models are denoted as MatchBoxNet_[BxRxC] where B is the number of blocks, and R is the number of convolutional sub-blocks within a block, and C is the number of channels. Each sub-block contains a 1-D *separable* convolution, batch normalization, ReLU, and dropout: + + .. image:: images/matchboxnet_vertical.png + :align: center + :alt: MatchboxNet model + :scale: 50% + +It can reach state-of-the art accuracy on the Google Speech Commands dataset while having significantly fewer parameters than similar models. +The `_v1` and `_v2` are denoted for models trained on `v1` (30-way classification) and `v2` (35-way classification) datasets; +And we use _subset_task to represent (10+2)-way subset (10 specific classes + other remaining classes + silence) classification task. + +MatchboxNet models can be instantiated using the :class:`~nemo.collections.asr.models.EncDecClassificationModel` class. + +.. note:: + For model details and deep understanding about Speech Command Detedction training, inference, finetuning and etc., + please refer to ``/tutorials/asr/03_Speech_Commands.ipynb`` and ``/tutorials/asr/04_Online_Offline_Speech_Commands_Demo.ipynb``. + + + +.. _MarbleNet_model: + +MarbleNet (VAD) +------------------ + +MarbleNet :cite:`sc-models-marblenet` an end-to-end neural network for speech command recognition based on :ref:`MatchboxNet_model`, + +Similarly to MatchboxNet, the MarbleNet family of models are denoted as MarbleNet_[BxRxC] where B is the number of blocks, and R is the number of convolutional sub-blocks within a block, and C is the number of channels. Each sub-block contains a 1-D *separable* convolution, batch normalization, ReLU, and dropout: + + .. image:: images/marblenet_vertical.png + :align: center + :alt: MarbleNet model + :scale: 30% + +It can reach state-of-the art performance on the difficult `AVA speech dataset `_ while having significantly fewer parameters than similar models even training on simple data. +MarbleNet models can be instantiated using the :class:`~nemo.collections.asr.models.EncDecClassificationModel` class. + +.. note:: + For model details and deep understanding about VAD training, inference, postprocessing, threshold tuning and etc., + please refer to ``/tutorials/asr/06_Voice_Activiy_Detection.ipynb`` and ``/tutorials/asr/07_Online_Offline_Microphone_VAD_Demo.ipynb``. + + +References +---------------- + +.. bibliography:: ../asr_all.bib + :style: plain + :labelprefix: SC-MODELS + :keyprefix: sc-models- \ No newline at end of file diff --git a/tts/NeMo/docs/source/asr/speech_classification/results.rst b/tts/NeMo/docs/source/asr/speech_classification/results.rst new file mode 100644 index 0000000..6dd65b9 --- /dev/null +++ b/tts/NeMo/docs/source/asr/speech_classification/results.rst @@ -0,0 +1,105 @@ +Checkpoints +=========== + +There are two main ways to load pretrained checkpoints in NeMo: + +* Using the :code:`restore_from()` method to load a local checkpoint file (`.nemo`), or +* Using the :code:`from_pretrained()` method to download and set up a checkpoint from NGC. + +See the following sections for instructions and examples for each. + +Note that these instructions are for loading fully trained checkpoints for evaluation or fine-tuning. +For resuming an unfinished training experiment, please use the experiment manager to do so by setting the +``resume_if_exists`` flag to True. + +Loading Local Checkpoints +------------------------- + +NeMo will automatically save checkpoints of a model you are training in a `.nemo` format. +You can also manually save your models at any point using :code:`model.save_to(.nemo)`. + +If you have a local ``.nemo`` checkpoint that you'd like to load, simply use the :code:`restore_from()` method: + +.. code-block:: python + + import nemo.collections.asr as nemo_asr + model = nemo_asr.models..restore_from(restore_path="") + +Where the model base class is the ASR model class of the original checkpoint, or the general `ASRModel` class. + + +Transcribing/Inference +----------------------- + +The audio files should be 16KHz monochannel wav files. + +**Transcribe speech command segment:** + +You may perform inference and transcribe a sample of speech after loading the model by using its 'transcribe()' method: + +.. code-block:: python + + mbn_model = nemo_asr.models.EncDecClassificationModel.from_pretrained(model_name="") + mbn_model.transcribe([list of audio files], batch_size=BATCH_SIZE, logprobs=False) + +Setting argument ``logprobs`` to True would return the log probabilities instead of transcriptions. You may find more details in `Modules <../api.html#modules>`__. + +Learn how to fine tune on your own data or on subset classes in ``/tutorials/asr/03_Speech_Commands.ipynb`` +f + +**Run VAD inference:** + +.. code-block:: bash + + python examples/speaker_recognition/vad_infer.py --vad_model="vad_marblenet" --dataset= --out_dir='frame/demo' --time_length=0.63 + +Have a look at scripts under ``/scripts/voice_activity_detection`` for posterior processing and threshold tuning. + + +NGC Pretrained Checkpoints +-------------------------- + +The Speech Classification collection has checkpoints of several models trained on various datasets for a variety of tasks. +These checkpoints are obtainable via NGC `NeMo Automatic Speech Recognition collection `_. +The model cards on NGC contain more information about each of the checkpoints available. + +The tables below list the Speech Classification models available from NGC, and the models can be accessed via the +:code:`from_pretrained()` method inside the ASR Model class. + +In general, you can load any of these models with code in the following format. + +.. code-block:: python + + import nemo.collections.asr as nemo_asr + model = nemo_asr.models.EncDecClassificationModel.from_pretrained(model_name="") + +Where the model name is the value under "Model Name" entry in the tables below. + +For example, to load the MatchboxNet3x2x64_v1 model for speech command detection, run: + +.. code-block:: python + + model = nemo_asr.models.EncDecClassificationModel.from_pretrained(model_name="commandrecognition_en_matchboxnet3x2x64_v1") + +You can also call :code:`from_pretrained()` from the specific model class (such as :code:`EncDecClassificationModel` +for MatchboxNet and MarbleNet) if you will need to access specific model functionality. + +If you would like to programatically list the models available for a particular base class, you can use the +:code:`list_available_models()` method. + +.. code-block:: python + + nemo_asr.models..list_available_models() + + +Speech Classification Models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. tabularcolumns:: 30 30 40 + +.. csv-table:: + :file: data/classification_results.csv + :header-rows: 1 + :class: longtable + :widths: 1 1 1 + diff --git a/tts/NeMo/docs/source/common/intro.rst b/tts/NeMo/docs/source/common/intro.rst new file mode 100644 index 0000000..61d160b --- /dev/null +++ b/tts/NeMo/docs/source/common/intro.rst @@ -0,0 +1,39 @@ +Common Collection +================= + +The common collection contains things that could be used across all collections. + +Tokenizers +---------- +.. automodule:: nemo.collections.common.tokenizers.AutoTokenizer + :special-members: __init__ +.. automodule:: nemo.collections.common.tokenizers.SentencePieceTokenizer + :special-members: __init__ +.. automodule:: nemo.collections.common.tokenizers.TokenizerSpec + :special-members: __init__ + + +Losses +------ +.. automodule:: nemo.collections.common.losses.AggregatorLoss + :special-members: __init__ + +.. automodule:: nemo.collections.common.losses.CrossEntropyLoss + :special-members: __init__ + +.. automodule:: nemo.collections.common.losses.MSELoss + :special-members: __init__ + +.. automodule:: nemo.collections.common.losses.SmoothedCrossEntropyLoss + :special-members: __init__ +.. automodule:: nemo.collections.common.losses.SpanningLoss + :special-members: __init__ + + +Metrics +------- + +.. autoclass:: nemo.collections.common.metrics.Perplexity + :show-inheritance: + :members: + :undoc-members: diff --git a/tts/NeMo/docs/source/conf.py b/tts/NeMo/docs/source/conf.py new file mode 100644 index 0000000..7dfba6e --- /dev/null +++ b/tts/NeMo/docs/source/conf.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import sys +import glob + +import sphinx_rtd_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + +sys.path.insert(0, os.path.abspath("../..")) +sys.path.insert(0, os.path.abspath("../../nemo")) +sys.path.insert(0, os.path.abspath("../../nemo_text_processing")) + +from package_info import __version__ + + +autodoc_mock_imports = [ + 'torch', + 'torch.nn', + 'torch.utils', + 'torch.optim', + 'torch.utils.data', + 'torch.utils.data.sampler', + 'torchvision', + 'torchvision.models', + 'torchtext', + 'ruamel.yaml', # ruamel.yaml has ., which is troublesome for this regex + 'hydra', # hydra-core in requirements, hydra during import + 'dateutil', # part of core python + 'transformers.tokenization_bert', # has ., troublesome for this regex + 'megatron', # megatron-lm in requirements, megatron in import + 'sklearn', + 'nemo_text_processing.inverse_text_normalization', # Not installed automatically + 'nemo_text_processing.text_normalization', # Not installed automatically + 'attr', # attrdict in requirements, attr in import + 'torchmetrics', # inherited from PTL +] + +_skipped_autodoc_mock_imports = ['wrapt', 'numpy'] + +for req_path in sorted(list(glob.glob("../../requirements/*.txt"))): + if "docs.txt" in req_path: + continue + + req_file = os.path.abspath(os.path.expanduser(req_path)) + with open(req_file, 'r') as f: + for line in f: + line = line.replace("\n", "") + req = re.search(r"([a-zA-Z0-9-_]*)", line) + if req: + req = req.group(1) + req = req.replace("-", "_") + + if req not in autodoc_mock_imports: + if req in _skipped_autodoc_mock_imports: + print(f"Skipping req : `{req}` (lib {line})") + continue + + autodoc_mock_imports.append(req) + print(f"Adding req : `{req}` to autodoc mock requirements (lib {line})") + else: + print(f"`{req}` already added to autodoc mock requirements (lib {line})") + +# +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinx.ext.mathjax", + "sphinx.ext.ifconfig", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinx.ext.githubpages", + "sphinxcontrib.bibtex", + "sphinx.ext.inheritance_diagram", + "sphinx.ext.intersphinx", + "sphinx.ext.autosectionlabel", + "sphinxcontrib.bibtex", + "sphinx_rtd_theme", +] + +bibtex_bibfiles = [ + 'asr/asr_all.bib', + 'nlp/nlp_all.bib', + 'tools/tools_all.bib', + 'nemo_text_processing/textprocessing_all.bib', + 'tts_all.bib', +] + +intersphinx_mapping = { + 'pytorch': ('https://pytorch.org/docs/stable', None), + 'pytorch-lightning': ('https://pytorch-lightning.readthedocs.io/en/latest/', None), +} + +# Set default flags for all classes. +autodoc_default_options = {'members': None, 'undoc-members': None, 'show-inheritance': True} + +locale_dirs = ['locale/'] # path is example but recommended. +gettext_compact = False # optional. + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "NVIDIA NeMo" +copyright = "2021-, NVIDIA CORPORATION" +author = "NVIDIA CORPORATION" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + + +# The short X.Y version. +# version = "0.10.0" +version = __version__ +# The full version, including alpha/beta/rc tags. +# release = "0.9.0" +release = __version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "default" + +### Previous NeMo theme +# # NVIDIA theme settings. +# html_theme = 'nvidia_theme' + +# html_theme_path = ["."] + +# html_theme_options = { +# 'display_version': True, +# 'project_version': version, +# 'project_name': project, +# 'logo_path': None, +# 'logo_only': True, +# } +# html_title = 'Introduction' + +# html_logo = html_theme_options["logo_path"] + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = "nemodoc" + +### from TLT conf.py +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# + +# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +html_theme = "sphinx_rtd_theme" +html_logo = os.path.join('nv_logo.png') + +html_theme_options = { + 'logo_only': True, + 'display_version': True, + 'prev_next_buttons_location': 'bottom', + 'style_external_links': False, + 'style_nav_header_background': '#000000', + # Toc options + 'collapse_navigation': False, + 'sticky_navigation': False, + # 'navigation_depth': 10, + 'includehidden': False, + 'titles_only': False, +} + + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". + +html_favicon = 'favicon.ico' + +html_static_path = ['_static'] + +html_last_updated_fmt = '' + + +def setup(app): + app.add_css_file('css/custom.css') + app.add_js_file('js/pk_scripts.js') + + +# html_css_files = [ +# './custom.css', +# ] + +# html_js_files = [ +# './pk_scripts.js', +# ] diff --git a/tts/NeMo/docs/source/core/core.rst b/tts/NeMo/docs/source/core/core.rst new file mode 100644 index 0000000..1e053bd --- /dev/null +++ b/tts/NeMo/docs/source/core/core.rst @@ -0,0 +1,963 @@ +NeMo Models +=========== + +Basics +------ + +NeMo models contain everything needed to train and reproduce Conversational AI models: + +- neural network architectures +- datasets/data loaders +- data preprocessing/postprocessing +- data augmentors +- optimizers and schedulers +- tokenizers +- language models + +NeMo uses `Hydra `_ for configuring both NeMo models and the PyTorch Lightning Trainer. + +.. note:: Every NeMo model has an example configuration file and training script that can be found `here `_. + +The end result of using NeMo, `Pytorch Lightning `_, and Hydra is that NeMo models all have the same look and feel and are also fully compatible with the PyTorch ecosystem. + +Pretrained +---------- + +NeMo comes with many pretrained models for each of our collections: ASR, NLP, and TTS. Every pretrained NeMo model can be downloaded +and used with the ``from_pretrained()`` method. + +As an example, we can instantiate QuartzNet with the following: + +.. code-block:: Python + + import nemo.collections.asr as nemo_asr + + model = nemo_asr.models.EncDecCTCModel.from_pretrained(model_name="QuartzNet15x5Base-En") + +To see all available pretrained models for a specific NeMo model, use the ``list_available_models()`` method. + +.. code-block:: Python + + nemo_asr.model.EncDecCTCModel.list_available_models() + +For detailed information on the available pretrained models, refer to the collections documentation: + +- :ref:`Automatic Speech Recognition (ASR)` +- :ref:`Natural Language Processing (NLP)` +- :ref:`Speech Synthesis (TTS)` + +Training +-------- + +NeMo leverages `PyTorch Lightning `_ for model training. PyTorch Lightning lets NeMo decouple the +conversational AI code from the PyTorch training code. This means that NeMo users can focus on their domain (ASR, NLP, TTS) and +build complex AI applications without having to rewrite boiler plate code for PyTorch training. + +When using PyTorch Lightning, NeMo users can automatically train with: + +- multi-GPU/multi-node +- mixed precision +- model checkpointing +- logging +- early stopping +- and more + +The two main aspects of the Lightning API are the `LightningModule `_ +and the `Trainer `_. + +PyTorch Lightning ``LightningModule`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Every NeMo model is a ``LightningModule`` which is an ``nn.module``. This means that NeMo models are compatible with the PyTorch +ecosystem and can be plugged into existing PyTorch workflows. + +Creating a NeMo model is similar to any other PyTorch workflow. We start by initializing our model architecture, then define the forward pass: + +.. code-block:: python + + class TextClassificationModel(NLPModel, Exportable): + ... + def __init__(self, cfg: DictConfig, trainer: Trainer = None): + """Initializes the BERTTextClassifier model.""" + ... + super().__init__(cfg=cfg, trainer=trainer) + + # instantiate a BERT based encoder + self.bert_model = get_lm_model( + pretrained_model_name=cfg.language_model.pretrained_model_name, + config_file=cfg.language_model.config_file, + config_dict=cfg.language_model.config, + checkpoint_file=cfg.language_model.lm_checkpoint, + vocab_file=cfg.tokenizer.vocab_file, + ) + + # instantiate the FFN for classification + self.classifier = SequenceClassifier( + hidden_size=self.bert_model.config.hidden_size, + num_classes=cfg.dataset.num_classes, + num_layers=cfg.classifier_head.num_output_layers, + activation='relu', + log_softmax=False, + dropout=cfg.classifier_head.fc_dropout, + use_transformer_init=True, + idx_conditioned_on=0, + ) + +.. code-block:: python + + def forward(self, input_ids, token_type_ids, attention_mask): + """ + No special modification required for Lightning, define it as you normally would + in the `nn.Module` in vanilla PyTorch. + """ + hidden_states = self.bert_model( + input_ids=input_ids, token_type_ids=token_type_ids, attention_mask=attention_mask + ) + logits = self.classifier(hidden_states=hidden_states) + return logits + +The ``LightningModule`` organizes PyTorch code so that across all NeMo models we have a similar look and feel. +For example, the training logic can be found in ``training_step``: + +.. code-block:: python + + def training_step(self, batch, batch_idx): + """ + Lightning calls this inside the training loop with the data from the training dataloader + passed in as `batch`. + """ + # forward pass + input_ids, input_type_ids, input_mask, labels = batch + logits = self.forward(input_ids=input_ids, token_type_ids=input_type_ids, attention_mask=input_mask) + + train_loss = self.loss(logits=logits, labels=labels) + + lr = self._optimizer.param_groups[0]['lr'] + + self.log('train_loss', train_loss) + self.log('lr', lr, prog_bar=True) + + return { + 'loss': train_loss, + 'lr': lr, + } + +While validation logic can be found in ``validation_step``: + +.. code-block:: python + + def validation_step(self, batch, batch_idx): + """ + Lightning calls this inside the validation loop with the data from the validation dataloader + passed in as `batch`. + """ + if self.testing: + prefix = 'test' + else: + prefix = 'val' + + input_ids, input_type_ids, input_mask, labels = batch + logits = self.forward(input_ids=input_ids, token_type_ids=input_type_ids, attention_mask=input_mask) + + val_loss = self.loss(logits=logits, labels=labels) + + preds = torch.argmax(logits, axis=-1) + + tp, fn, fp, _ = self.classification_report(preds, labels) + + return {'val_loss': val_loss, 'tp': tp, 'fn': fn, 'fp': fp} + +PyTorch Lightning then handles all of the boiler plate code needed for training. Virtually any aspect of training can be customized +via PyTorch Lightning `hooks `_, +`Plugins `_, +`callbacks `_, or by overriding `methods `_. + +For more domain-specific information, see: + +- :ref:`Automatic Speech Recognition (ASR)` +- :ref:`Natural Language Processing (NLP)` +- :ref:`Speech Synthesis (TTS)` + +PyTorch Lightning Trainer +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since every NeMo model is a ``LightningModule``, we can automatically take advantage of the PyTorch Lightning ``Trainer``. Every NeMo +`example `_ training script uses the ``Trainer`` object to fit the model. + +First, instantiate the model and trainer, then call ``.fit``: + +.. code-block:: python + + # We first instantiate the trainer based on the model configuration. + # See the model configuration documentation for details. + trainer = pl.Trainer(**cfg.trainer) + + # Then pass the model configuration and trainer object into the NeMo model + model = TextClassificationModel(cfg.model, trainer=trainer) + + # Now we can train with by calling .fit + trainer.fit(model) + + # Or we can run the test loop on test data by calling + trainer.test(model=model) + +All `trainer flags `_ can be set from from the +NeMo configuration. + + +Configuration +------------- + +Hydra is an open-source Python framework that simplifies configuration for complex applications that must bring together many different +software libraries. Conversational AI model training is a great example of such an application. To train a conversational AI model, we +must be able to configure: + +- neural network architectures +- training and optimization algorithms +- data pre/post processing +- data augmentation +- experiment logging/visualization +- model checkpointing + +For an introduction to using Hydra, refer to the `Hydra Tutorials `_. + +With Hydra, we can configure everything needed for NeMo with three interfaces: + +- Command Line (CLI) +- Configuration Files (YAML) +- Dataclasses (Python) + +YAML +~~~~ + +NeMo provides YAML configuration files for all of our `example `_ training scripts. +YAML files make it easy to experiment with different model and training configurations. + +Every NeMo example YAML has the same underlying configuration structure: + +- trainer +- exp_manager +- model + +Model configuration always contain ``train_ds``, ``validation_ds``, ``test_ds``, and ``optim``. Model architectures vary across +domains, therefore, refer to the ASR, NLP, and TTS Collections documentation for more detailed information on Model architecture configuration. + +A NeMo configuration file should look similar to the following: + +.. code-block:: yaml + + # PyTorch Lightning Trainer configuration + # any argument of the Trainer object can be set here + trainer: + gpus: 1 # number of gpus per node + num_nodes: 1 # number of nodes + max_epochs: 10 # how many training epochs to run + val_check_interval: 1.0 # run validation after every epoch + + # Experiment logging configuration + exp_manager: + exp_dir: /path/to/my/nemo/experiments + name: name_of_my_experiment + create_tensorboard_logger: True + create_wandb_logger: True + + # Model configuration + # model network architecture, train/val/test datasets, data augmentation, and optimization + model: + train_ds: + manifest_filepath: /path/to/my/train/manifest.json + batch_size: 256 + shuffle: True + validation_ds: + manifest_filepath: /path/to/my/validation/manifest.json + batch_size: 32 + shuffle: False + test_ds: + manifest_filepath: /path/to/my/test/manifest.json + batch_size: 32 + shuffle: False + optim: + name: novograd + lr: .01 + betas: [0.8, 0.5] + weight_decay: 0.001 + # network architecture can vary greatly depending on the domain + encoder: + ... + decoder: + ... + +More specific details about configuration files for each collection can be found on the following pages: + +:ref:`NeMo ASR Configuration Files` + +CLI +~~~ + +With NeMo and Hydra, every aspect of model training can be modified from the command-line. This is extremely helpful for running lots +of experiments on compute clusters or for quickly testing parameters while developing. + +All NeMo `examples `_ come with instructions on how to +run the training/inference script from the command-line (see `here `_ +for an example). + +With Hydra, arguments are set using the ``=`` operator: + +.. code-block:: bash + + python examples/asr/speech_to_text.py \ + model.train_ds.manifest_filepath=/path/to/my/train/manifest.json \ + model.validation_ds.manifest_filepath=/path/to/my/validation/manifest.json \ + trainer.gpus=2 \ + trainer.max_epochs=50 + +We can use the ``+`` operator to add arguments from the CLI: + +.. code-block:: bash + + python examples/asr/speech_to_text.py \ + model.train_ds.manifest_filepath=/path/to/my/train/manifest.json \ + model.validation_ds.manifest_filepath=/path/to/my/validation/manifest.json \ + trainer.gpus=2 \ + trainer.max_epochs=50 \ + +trainer.fast_dev_run=true + +We can use the ``~`` operator to remove configurations: + +.. code-block:: bash + + python examples/asr/speech_to_text.py \ + model.train_ds.manifest_filepath=/path/to/my/train/manifest.json \ + model.validation_ds.manifest_filepath=/path/to/my/validation/manifest.json \ + ~model.test_ds \ + trainer.gpus=2 \ + trainer.max_epochs=50 \ + +trainer.fast_dev_run=true + +We can specify configuration files using the ``--config-path`` and ``--config-name`` flags: + +.. code-block:: bash + + python examples/asr/speech_to_text.py \ + --config-path=conf/quartznet \ + --config-name=quartznet_15x5 \ + model.train_ds.manifest_filepath=/path/to/my/train/manifest.json \ + model.validation_ds.manifest_filepath=/path/to/my/validation/manifest.json \ + ~model.test_ds \ + trainer.gpus=2 \ + trainer.max_epochs=50 \ + +trainer.fast_dev_run=true + +Dataclasses +~~~~~~~~~~~ + +Dataclasses allow NeMo to ship model configurations as part of the NeMo library and also enables pure Python configuration of NeMo models. +With Hydra, dataclasses can be used to create `structured configs `_ for the conversational AI application. + +As an example, refer to the code block below for an *Attenion is All You Need* machine translation model. The model configuration can +be instantiated and modified like any Python `Dataclass `_. + +.. code-block:: Python + + from nemo.collections.nlp.models.machine_translation.mt_enc_dec_config import AAYNBaseConfig + + cfg = AAYNBaseConfig() + + # modify the number of layers in the encoder + cfg.encoder.num_layers = 8 + + # modify the training batch size + cfg.train_ds.tokens_in_batch = 8192 + +.. note:: Configuration with Hydra always has the following precedence CLI > YAML > Dataclass + +Optimization +------------ + +Optimizers and learning rate schedules are configurable across all NeMo models and have their own namespace. Here is a sample YAML +configuration for a Novograd optimizer with Cosine Annealing learning rate schedule. + +.. code-block:: yaml + + optim: + name: novograd + lr: 0.01 + + # optimizer arguments + betas: [0.8, 0.25] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # Optional arguments + max_steps: null # computed at runtime or explicitly set here + monitor: val_loss + reduce_on_plateau: false + + # scheduler config override + warmup_steps: 1000 + warmup_ratio: null + min_lr: 1e-9: + +.. note:: `NeMo Examples `_ has optimizer and scheduler configurations for +every NeMo model. + +Optimizers can be configured from the CLI as well: + +.. code-block:: bash + + python examples/asr/speech_to_text.py \ + --config-path=conf/quartznet \ + --config-name=quartznet_15x5 \ + ... + # train with the adam optimizer + model.optim=adam \ + # change the learning rate + model.optim.lr=.0004 \ + # modify betas + model.optim.betas=[.8, .5] + +Optimizers +~~~~~~~~~~ + +``name`` corresponds to the lowercase name of the optimizer. To view a list of available optimizers, run: + +.. code-block:: Python + + from nemo.core.optim.optimizers import AVAILABLE_OPTIMIZERS + + for name, opt in AVAILABLE_OPTIMIZERS.items(): + print(f'name: {name}, opt: {opt}') + +.. code-block:: bash + + name: sgd opt: + name: adam opt: + name: adamw opt: + name: adadelta opt: + name: adamax opt: + name: adagrad opt: + name: rmsprop opt: + name: rprop opt: + name: novograd opt: + +Optimizer Params +~~~~~~~~~~~~~~~~ + +Optimizer params can vary between optimizers but the ``lr`` param is required for all optimizers. To see the available params for an +optimizer, we can look at its corresponding dataclass. + +.. code-block:: python + + from nemo.core.config.optimizers import NovogradParams + + print(NovogradParams()) + +.. code-block:: bash + + NovogradParams(lr='???', betas=(0.95, 0.98), eps=1e-08, weight_decay=0, grad_averaging=False, amsgrad=False, luc=False, luc_trust=0.001, luc_eps=1e-08) + +``'???'`` indicates that the lr argument is required. + +Register Optimizer +~~~~~~~~~~~~~~~~~~ + +To register a new optimizer to be used with NeMo, run: + +.. autofunction:: nemo.core.optim.optimizers.register_optimizer + +Learning Rate Schedulers +~~~~~~~~~~~~~~~~~~~~~~~~ + +Learning rate schedulers can be optionally configured under the ``optim.sched`` namespace. + +``name`` corresponds to the name of the learning rate schedule. To view a list of available schedulers, run: + +.. code-block:: Python + + from nemo.core.optim.lr_scheduler import AVAILABLE_SCHEDULERS + + for name, opt in AVAILABLE_SCHEDULERS.items(): + print(f'name: {name}, schedule: {opt}') + +.. code-block:: bash + + name: WarmupPolicy, schedule: + name: WarmupHoldPolicy, schedule: + name: SquareAnnealing, schedule: + name: CosineAnnealing, schedule: + name: NoamAnnealing, schedule: + name: WarmupAnnealing, schedule: + name: InverseSquareRootAnnealing, schedule: + name: SquareRootAnnealing, schedule: + name: PolynomialDecayAnnealing, schedule: + name: PolynomialHoldDecayAnnealing, schedule: + name: StepLR, schedule: + name: ExponentialLR, schedule: + name: ReduceLROnPlateau, schedule: + name: CyclicLR, schedule: + +Scheduler Params +~~~~~~~~~~~~~~~~ + +To see the available params for a scheduler, we can look at its corresponding dataclass: + +.. code-block:: Python + + from nemo.core.config.schedulers import CosineAnnealingParams + + print(CosineAnnealingParams()) + +.. code-block:: bash + + CosineAnnealingParams(last_epoch=-1, warmup_steps=None, warmup_ratio=None, min_lr=0.0) + +Register scheduler +~~~~~~~~~~~~~~~~~~ + +To register a new scheduler to be used with NeMo, run: + +.. autofunction:: nemo.core.optim.lr_scheduler.register_scheduler + +Save and Restore +---------------- + +NeMo models all come with ``.save_to`` and ``.restore_from`` methods. + +Save +~~~~ + +To save a NeMo model, run: + +.. code-block:: Python + + model.save_to('/path/to/model.nemo') + +Everything needed to use the trained model is packaged and saved in the ``.nemo`` file. For example, in the NLP domain, ``.nemo`` files +include the necessary tokenizer models and/or vocabulary files, etc. + +.. note:: A ``.nemo`` file is simply an archive like any other ``.tar`` file. + +Restore +~~~~~~~ + +To restore a NeMo model, run: + +.. code-block:: Python + + model.restore_from('/path/to/model.nemo') + +When using the PyTorch Lightning Trainer, a PyTorch Lightning checkpoint is created. These are mainly used within NeMo to auto-resume +training. Since NeMo models are ``LightningModules``, the PyTorch Lightning method ``load_from_checkpoint`` is available. Note that +``load_from_checkpoint`` won't necessarily work out-of-the-box for all models as some models require more artifacts than just the +checkpoint to be restored. For these models, the user will have to override ``load_from_checkpoint`` if they want to use it. + +It's highly recommended to use ``restore_from`` to load NeMo models. + +Register Artifacts +------------------ + +Conversational AI models can be complicated to restore as more information is needed than just the checkpoint weights in order to use the model. +NeMo models can save additional artifacts in the .nemo file by calling ``.register_artifact``. +When restoring NeMo models using ``.restore_from`` or ``.from_pretrained``, any artifacts that were registered will be available automatically. + +As an example, consider an NLP model that requires a trained tokenizer model. +The tokenizer model file can be automatically added to the .nemo file with the following: + +.. code-block:: python + + self.encoder_tokenizer = get_nmt_tokenizer( + ... + tokenizer_model=self.register_artifact(config_path='encoder_tokenizer.tokenizer_model', + src='/path/to/tokenizer.model', + verify_src_exists=True), + ) + +By default, ``.register_artifact`` will always return a path. If the model is being restored from a .nemo file, +then that path will be to the artifact in the .nemo file. Otherwise, ``.register_artifact`` will return the local path specified by the user. + +``config_path`` is the artifact key. It usually corresponds to a model configuration but does not have to. +The model config that is packaged with the .nemo file will be updated according to the ``config_path`` key. +In the above example, the model config will have + +.. code-block:: YAML + + encoder_tokenizer: + ... + tokenizer_model: nemo:4978b28103264263a03439aaa6560e5e_tokenizer.model + +``src`` is the path to the artifact and the base-name of the path will be used when packaging the artifact in the .nemo file. +Each artifact will have a hash prepended to the basename of ``src`` in the .nemo file. This is to prevent collisions with basenames +base-names that are identical (say when there are two or more tokenizers, both called `tokenizer.model`). +The resulting .nemo file will then have the following file: + +.. code-block:: bash + + 4978b28103264263a03439aaa6560e5e_tokenizer.model + +If ``verify_src_exists`` is set to ``False``, then the artifact is optional. This means that ``.register_artifact`` will return ``None`` +if the ``src`` cannot be found. + + + +Experiment Manager +================== + +NeMo's Experiment Manager leverages PyTorch Lightning for model checkpointing, TensorBoard Logging, and Weights and Biases logging. The +Experiment Manager is included by default in all NeMo example scripts. + +To use the experiment manager simply call :class:`~nemo.utils.exp_manager.exp_manager` and pass in the PyTorch Lightning ``Trainer``. + +.. code-block:: python + + exp_manager(trainer, cfg.get("exp_manager", None)) + +And is configurable via YAML with Hydra. + +.. code-block:: bash + + exp_manager: + exp_dir: /path/to/my/experiments + name: my_experiment_name + create_tensorboard_logger: True + create_checkpoint_callback: True + +Optionally, launch TensorBoard to view the training results in ``./nemo_experiments`` (by default). + +.. code-block:: bash + + tensorboard --bind_all --logdir nemo_experiments + +.. + +If ``create_checkpoint_callback`` is set to ``True``, then NeMo automatically creates checkpoints during training +using PyTorch Lightning's `ModelCheckpoint `_. +We can configure the ``ModelCheckpoint`` via YAML or CLI. + +.. code-block:: yaml + + exp_manager: + ... + # configure the PyTorch Lightning ModelCheckpoint using checkpoint_call_back_params + # any ModelCheckpoint argument can be set here + + # save the best checkpoints based on this metric + checkpoint_callback_params.monitor=val_loss + + # choose how many total checkpoints to save + checkpoint_callback_params.save_top_k=5 + +We can auto-resume training as well by configuring the ``exp_manager``. Being able to auto-resume is important when doing long training +runs that are premptible or may be shut down before the training procedure has completed. To auto-resume training, set the following +via YAML or CLI: + +.. code-block:: yaml + + exp_manager: + ... + # resume training if checkpoints already exist + resume_if_exists: True + + # to start training with no existing checkpoints + resume_ignore_no_checkpoint: True + + # by default experiments will be versioned by datetime + # we can set our own version with + exp_manager.version: my_experiment_version + +Neural Modules +============== + +NeMo is built around Neural Modules, conceptual blocks of neural networks that take typed inputs and produce typed outputs. Such +modules typically represent data layers, encoders, decoders, language models, loss functions, or methods of combining activations. +NeMo makes it easy to combine and re-use these building blocks while providing a level of semantic correctness checking via its neural +type system. + +.. note:: *All Neural Modules inherit from ``torch.nn.Module`` and are therefore compatible with the PyTorch ecosystem.* + +There are 3 types on Neural Modules: + + - Regular modules + - Dataset/IterableDataset + - Losses + +Every Neural Module in NeMo must inherit from `nemo.core.classes.module.NeuralModule` class. + +.. autoclass:: nemo.core.classes.module.NeuralModule + +Every Neural Modules inherits the ``nemo.core.classes.common.Typing`` interface and needs to define neural types for its inputs and outputs. +This is done by defining two properties: ``input_types`` and ``output_types``. Each property should return an ordered dictionary of +"port name"->"port neural type" pairs. Here is the example from :class:`~nemo.collections.asr.modules.ConvASREncoder` class: + +.. code-block:: python + + @property + def input_types(self): + return OrderedDict( + { + "audio_signal": NeuralType(('B', 'D', 'T'), SpectrogramType()), + "length": NeuralType(tuple('B'), LengthsType()), + } + ) + + @property + def output_types(self): + return OrderedDict( + { + "outputs": NeuralType(('B', 'D', 'T'), AcousticEncodedRepresentation()), + "encoded_lengths": NeuralType(tuple('B'), LengthsType()), + } + ) + + @typecheck() + def forward(self, audio_signal, length=None): + ... + +The code snippet above means that ``nemo.collections.asr.modules.conv_asr.ConvASREncoder`` expects two arguments: + * First one, named ``audio_signal`` of shape ``[batch, dimension, time]`` with elements representing spectrogram values. + * Second one, named ``length`` of shape ``[batch]`` with elements representing lengths of corresponding signals. + +It also means that ``.forward(...)`` and ``__call__(...)`` methods each produce two outputs: + * First one, of shape ``[batch, dimension, time]`` but with elements representing encoded representation (``AcousticEncodedRepresentation`` class). + * Second one, of shape ``[batch]``, corresponding to their lengths. + +.. tip:: It is a good practice to define types and add ``@typecheck()`` decorator to your ``.forward()`` method after your module is ready for use by others. + +.. note:: The outputs of ``.forward(...)`` method will always be of type ``torch.Tensor`` or container of tensors and will work with any other Pytorch code. The type information is attached to every output tensor. +If tensors without types is passed to your module, it will not fail, however the types will not be checked. Thus, it is recommended to define input/output types for all your modules, starting with +data layers and add ``@typecheck()`` decorator to them. + +.. note:: To temporarily disable typechecking, you can enclose your code in ```with typecheck.disable_checks():``` statement. + +Neural Types +============ + +Motivation +---------- + +Neural Types describe the semantics, axis order, and dimensions of a tensor. The purpose of this type system is to catch semantic and +dimensionality errors during model creation and facilitate module re-use. + +.. image:: whyntypes.gif + :width: 900 + :alt: Neural Types Motivation + +``NeuralType`` class +-------------------- + +Neural Types perform semantic checks for modules and models inputs/outputs. They contain information about: + + - Semantics of what is stored in the tensors. For example, logits, logprobs, audiosignal, embeddings, etc. + - Axes layout, semantic and (optionally) dimensionality. For example: ``[Batch, Time, Channel]`` + +Types are implemented in ``nemo.core.neural_types.NeuralType`` class. When you instantiate an instance of this class, you +are expected to include both *axes* information and *element type* information. + +.. autoclass:: nemo.core.neural_types.NeuralType + +Type Comparison Results +----------------------- + +When comparing two neural types, the following comparison results are generated. + +.. autoclass:: nemo.core.neural_types.NeuralTypeComparisonResult + +Examples +-------- + +Long vs short notation +~~~~~~~~~~~~~~~~~~~~~~ + +NeMo's ``NeuralType`` class allows you to express axis semantics information in long and short form. Consider these two equivalent types. Both encoder 3 dimensional tensors and both contain elements of type ``AcousticEncodedRepresentation`` (this type is a typical output of ASR encoders). + +.. code-block:: python + + long_version = NeuralType( + axes=(AxisType(AxisKind.Batch, None), AxisType(AxisKind.Dimension, None), AxisType(AxisKind.Time, None)), + elements_type=AcousticEncodedRepresentation(), + ) + short_version = NeuralType(('B', 'D', 'T'), AcousticEncodedRepresentation()) + assert long_version.compare(short_version) == NeuralTypeComparisonResult.SAME + +Transpose same +~~~~~~~~~~~~~~ + +Often it is useful to know if a simple transposition will solve type incompatibility. This is the case if the comparison result of two types equals ``nemo.core.neural_types.NeuralTypeComparisonResult.TRANSPOSE_SAME``. + +.. code-block:: python + + type1 = NeuralType(axes=('B', 'T', 'C')) + type2 = NeuralType(axes=('T', 'B', 'C')) + assert type1.compare(type2) == NeuralTypeComparisonResult.TRANSPOSE_SAME + assert type2.compare(type1) == NeuralTypeComparisonResult.TRANSPOSE_SAME + +Note that in this example, we dropped ``elements_type`` argument of ``NeuralType`` constructor. If not supplied, the element type is ``VoidType``. + +``VoidType`` for elements +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes it is useful to express that elements' types don't matter but axes layout do. ``VoidType`` for elements can be used to express this. + +.. note:: ``VoidType`` is compatible with every other elements' type but not the other way around. See the following code snippet below for details. + +.. code-block:: python + + btc_spctr = NeuralType(('B', 'T', 'C'), SpectrogramType()) + btc_spct_bad = NeuralType(('B', 'T'), SpectrogramType()) + # Note the VoidType for elements here + btc_void = NeuralType(('B', 'T', 'C'), VoidType()) + + # This is true because VoidType is compatible with every other element type (SpectrogramType in this case) + # And axes layout between btc_void and btc_spctr is the same + assert btc_void.compare(btc_spctr) == NeuralTypeComparisonResult.SAME + # These two types are incompatible because even though VoidType is used for elements on one side, + # the axes layout is different + assert btc_void.compare(btc_spct_bad) == NeuralTypeComparisonResult.INCOMPATIBLE + # Note that even though VoidType is compatible with every other type, other types are not compatible with VoidType! + # It is one-way compatibility + assert btc_spctr.compare(btc_void) == NeuralTypeComparisonResult.INCOMPATIBLE + +Element type inheritance +~~~~~~~~~~~~~~~~~~~~~~~~ + +Neural types in NeMo support Python inheritance between element types. Consider an example where you want to develop a Neural Module which performs data augmentation for all kinds of spectrograms. +In ASR, two types of spectrograms are frequently used: mel and mfcc. To express this, we will create 3 classes to express +element's types: ``SpectrogramType``, ``MelSpectrogramType(SpectrogramType)``, ``MFCCSpectrogramType(SpectrogramType)``. + +.. code-block:: python + + input = NeuralType(('B', 'D', 'T'), SpectrogramType()) + out1 = NeuralType(('B', 'D', 'T'), MelSpectrogramType()) + out2 = NeuralType(('B', 'D', 'T'), MFCCSpectrogramType()) + + # MelSpectrogram and MFCCSpectrogram are not interchangeable. + assert out1.compare(out2) == NeuralTypeComparisonResult.INCOMPATIBLE + assert out2.compare(out1) == NeuralTypeComparisonResult.INCOMPATIBLE + # Type comparison detects that MFCC/MelSpectrogramType is a kind of SpectrogramType and can be accepted. + assert input.compare(out1) == NeuralTypeComparisonResult.GREATER + assert input.compare(out2) == NeuralTypeComparisonResult.GREATER + +Custom element types +~~~~~~~~~~~~~~~~~~~~ + +It is possible to create user-defined element types to express the semantics of elements in your tensors. To do so, the user will need to inherit and implement abstract methods of the ``nemo.core.neural_types.elements.ElementType`` class + +.. autoclass:: nemo.core.neural_types.elements.ElementType + +Note that element types can be parametrized. Consider this example where it distinguishes between audio sampled at 8Khz and 16Khz. + +.. code-block:: python + + audio16K = NeuralType(axes=('B', 'T'), elements_type=AudioSignal(16000)) + audio8K = NeuralType(axes=('B', 'T'), elements_type=AudioSignal(8000)) + + assert audio8K.compare(audio16K) == NeuralTypeComparisonResult.SAME_TYPE_INCOMPATIBLE_PARAMS + assert audio16K.compare(audio8K) == NeuralTypeComparisonResult.SAME_TYPE_INCOMPATIBLE_PARAMS + +Enforcing dimensions +~~~~~~~~~~~~~~~~~~~~ + +In addition to specifying tensor layout and elements' semantics, neural types also allow you to enforce tensor dimensions. +The user will have to use long notations to specify dimensions. Short notations only allows you to specify axes semantics and assumes +arbitrary dimensions. + +.. code-block:: python + + type1 = NeuralType( + (AxisType(AxisKind.Batch, 64), AxisType(AxisKind.Time, 10), AxisType(AxisKind.Dimension, 128)), + SpectrogramType(), + ) + type2 = NeuralType(('B', 'T', 'C'), SpectrogramType()) + + # type2 will accept elements of type1 because their axes semantics match and type2 does not care about dimensions + assert type2.compare(type1), NeuralTypeComparisonResult.SAME + # type1 will not accept elements of type2 because it need dimensions to match strictly. + assert type1.compare(type2), NeuralTypeComparisonResult.DIM_INCOMPATIBLE + +Generic Axis kind +~~~~~~~~~~~~~~~~~ + +Sometimes (especially in the case of loss modules) it is useful to be able to specify a "generic" axis kind which will make it +compatible with any other kind of axis. This is easy to express with Neural Types by using ``nemo.core.neural_types.axes.AxisKind.Any`` for axes. + +.. code-block:: python + + type1 = NeuralType(('B', 'Any', 'Any'), SpectrogramType()) + type2 = NeuralType(('B', 'T', 'C'), SpectrogramType()) + type3 = NeuralType(('B', 'C', 'T'), SpectrogramType()) + + # type1 will accept elements of type2 and type3 because it only cares about element kind (SpectrogramType) + # number of axes (3) and that first one corresponds to batch + assert type1.compare(type2) == NeuralTypeComparisonResult.SAME + assert type1.compare(type3) == NeuralTypeComparisonResult.INCOMPATIBLE + +Container types +~~~~~~~~~~~~~~~ + +The NeMo-type system understands Python containers (lists). If your module returns a nested list of typed tensors, the way to express it is by +using Python list notation and Neural Types together when defining your input/output types. + +The example below shows how to express that your module returns single output ("out") which is list of lists of two dimensional tensors of shape ``[batch, dimension]`` containing logits. + +.. code-block:: python + + @property + def output_types(self): + return { + "out": [[NeuralType(('B', 'D'), LogitsType())]], + } + +Core APIs +========= + +Base class for all NeMo models +------------------------------ + +.. autoclass:: nemo.core.ModelPT + :show-inheritance: + :members: + :member-order: bysource + :undoc-members: cfg, num_weights + :exclude-members: set_eff_save, use_eff_save, teardown + +Base Neural Module class +------------------------ + +.. autoclass:: nemo.core.NeuralModule + :show-inheritance: + :members: + :member-order: bysource + +Neural Type classes +------------------- + +.. autoclass:: nemo.core.neural_types.NeuralType + :show-inheritance: + :members: + :member-order: bysource + +.. autoclass:: nemo.core.neural_types.axes.AxisType + :show-inheritance: + :members: + :member-order: bysource + +.. autoclass:: nemo.core.neural_types.elements.ElementType + :show-inheritance: + :members: + :member-order: bysource + +.. autoclass:: nemo.core.neural_types.comparison.NeuralTypeComparisonResult + :show-inheritance: + :members: + :member-order: bysource + +Experiment manager +------------------ + +.. autoclass:: nemo.utils.exp_manager.exp_manager + :show-inheritance: + :members: + :member-order: bysource + diff --git a/tts/NeMo/docs/source/core/whyntypes.gif b/tts/NeMo/docs/source/core/whyntypes.gif new file mode 100644 index 0000000000000000000000000000000000000000..56b5ab154391c95d393e5b6d48f2170cba260f07 GIT binary patch literal 309073 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�&2 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 nWL_H` for installation details. + +Additional requirements can be found in `setup.sh `_. + +.. toctree:: + :maxdepth: 1 + + text_normalization + inverse_text_normalization + api + + diff --git a/tts/NeMo/docs/source/nemo_text_processing/inverse_text_normalization.rst b/tts/NeMo/docs/source/nemo_text_processing/inverse_text_normalization.rst new file mode 100644 index 0000000..0e828c7 --- /dev/null +++ b/tts/NeMo/docs/source/nemo_text_processing/inverse_text_normalization.rst @@ -0,0 +1,90 @@ +Inverse Text Normalization +========================== + +Inverse text normalization (ITN) is a part of the Automatic Speech Recognition (ASR) post-processing pipeline. +ITN is the task of converting the raw spoken output of the ASR model into its written form to improve text readability. + +For example, +`"in nineteen seventy"` -> `"in 1975"` +and `"it costs one hundred and twenty three dollars"` -> `"it costs $123"`. + +NeMo ITN :cite:`textprocessing-itn-zhang2021nemo` is based on WFST-grammars :cite:`textprocessing-itn-Mohri2009`. We also provide a deployment route to C++ using `Sparrowhawk `_ :cite:`textprocessing-itn-sparrowhawk` -- an open-source version of Google Kestrel :cite:`textprocessing-itn-ebden2015kestrel`. +See :doc:`Text Procesing Deployment <../tools/text_processing_deployment>` for details. + +.. note:: + + For more details, see the tutorial `NeMo/tutorials/text_processing/Inverse_Text_Normalization.ipynb `__ in `Google's Colab `_. + + + + + + +Classes +---------------------------------- + + +The base class for every grammar is :class:`GraphFst`. +This tool is designed as a two-stage application: 1. `classification` of the input into semiotic tokens and 2. `verbalization` into written form. +For every stage and every semiotic token class there is a corresponding grammar, e.g. :class:`taggers.CardinalFst` +and :class:`verbalizers.CardinalFst`. +Together, they compose the final grammars :class:`ClassifyFst` and +:class:`VerbalizeFinalFst` that are compiled into WFST and used for inference. + + + + + + +.. autoclass:: nemo_text_processing.inverse_text_normalization.ClassifyFst + :show-inheritance: + :members: + +.. autoclass:: nemo_text_processing.inverse_text_normalization.VerbalizeFinalFst + :show-inheritance: + :members: + + +Prediction +---------------------------------- + +Example prediction run: + +.. code:: + + python run_prediction.py --input= --output= [--verbose] + + +The input is expected to be lower-cased. Punctuation are outputted with separating spaces after semiotic tokens, e.g. `"i see, it is ten o'clock..."` -> `"I see, it is 10:00 . . ."`. +Inner-sentence white-space characters in the input are not maintained. + + + +Data Cleaning for Evaluation +---------------------------------- + +.. code:: + + python clean_eval_data.py --input= + + + +Evaluation +---------------------------------- + +Example evaluation run on (cleaned) `Google's text normalization dataset `__ :cite:`textprocessing-itn-sproat2016rnn`: + +.. code:: + + python run_evaluation.py --input=./en_with_types/output-00001-of-00100 [--cat CLASS_CATEGORY] [--filter] + + + + +References +---------- + +.. bibliography:: textprocessing_all.bib + :style: plain + :labelprefix: TEXTPROCESSING-ITN + :keyprefix: textprocessing-itn- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nemo_text_processing/text_normalization.rst b/tts/NeMo/docs/source/nemo_text_processing/text_normalization.rst new file mode 100644 index 0000000..3f225ca --- /dev/null +++ b/tts/NeMo/docs/source/nemo_text_processing/text_normalization.rst @@ -0,0 +1,78 @@ +Text Normalization +================== + +NeMo Text Normalization converts text from written form into its verbalized form. It is used as a preprocessing step before Text to Speech (TTS). It could also be used for preprocessing Automatic Speech Recognition (ASR) training transcripts. + + +For example, +`"at 10:00"` -> `"at ten o'clock"` +and `"it weighs 10kg."` -> `"it weights ten kilograms ."`. + + +NeMo Text Normalization :cite:`textprocessing-norm-zhang2021nemo` is based on WFST-grammars :cite:`textprocessing-norm-Mohri2009`. We also provide a deployment route to C++ using `Sparrowhawk `_ :cite:`textprocessing-norm-sparrowhawk` -- an open-source version of Google Kestrel :cite:`textprocessing-norm-ebden2015kestrel`. +See :doc:`Text Procesing Deployment <../tools/text_processing_deployment>` for details. + + +.. note:: + + For more details, see the tutorial `NeMo/tutorials/text_processing/Text_Normalization.ipynb `__ in `Google's Colab `_. + + + + + + +Classes +---------------------------------- + + +The base class for every grammar is :class:`GraphFst`. +This tool is designed as a two-stage application: 1. `classification` of the input into semiotic tokens and 2. `verbalization` into written form. +For every stage and every semiotic token class there is a corresponding grammar, e.g. :class:`taggers.CardinalFst` +and :class:`verbalizers.CardinalFst`. +Together, they compose the final grammars :class:`ClassifyFst` and +:class:`VerbalizeFinalFst` that are compiled into WFST and used for inference. + + + + +.. autoclass:: nemo_text_processing.text_normalization.ClassifyFst + :show-inheritance: + :members: + +.. autoclass:: nemo_text_processing.text_normalization.VerbalizeFinalFst + :show-inheritance: + :members: + + +Prediction +---------------------------------- + +Example prediction run: + +.. code:: + + python run_prediction.py <--input INPUT_TEXT_FILE> <--output OUTPUT_PATH> [--input_case INPUT_CASE] + +``INPUT_CASE`` specifies whether to treat the input as lower-cased or case sensitive. By default treat the input as cased since this is more informative, especially for abbreviations. Punctuation are outputted with separating spaces after semiotic tokens, e.g. `"I see, it is 10:00..."` -> `"I see, it is ten o'clock . . ."`. +Inner-sentence white-space characters in the input are not maintained. + + +Evaluation +---------------------------------- + +Example evaluation run on `Google's text normalization dataset `__ :cite:`textprocessing-norm-sproat2016rnn`: + +.. code:: + + python run_evaluation.py --input=./en_with_types/output-00001-of-00100 [--cat CLASS_CATEGORY] [--input_case INPUT_CASE] + + + +References +---------- + +.. bibliography:: textprocessing_all.bib + :style: plain + :labelprefix: TEXTPROCESSING-NORM + :keyprefix: textprocessing-norm- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nemo_text_processing/textprocessing_all.bib b/tts/NeMo/docs/source/nemo_text_processing/textprocessing_all.bib new file mode 100644 index 0000000..63eb101 --- /dev/null +++ b/tts/NeMo/docs/source/nemo_text_processing/textprocessing_all.bib @@ -0,0 +1,58 @@ +@article{ebden2015kestrel, + title={The Kestrel TTS text normalization system}, + author={Ebden, Peter and Sproat, Richard}, + journal={Natural Language Engineering}, + volume={21}, + number={3}, + pages={333}, + year={2015}, + publisher={Cambridge University Press} +} + + +@article{sproat2016rnn, + title={RNN approaches to text normalization: A challenge}, + author={Sproat, Richard and Jaitly, Navdeep}, + journal={arXiv preprint arXiv:1611.00068}, + year={2016} +} + +@book{taylor2009text, + title={Text-to-speech synthesis}, + author={Taylor, Paul}, + year={2009}, + publisher={Cambridge university press} +} + +@misc{zhang2021nemo, + title={NeMo Inverse Text Normalization: From Development To Production}, + author={Yang Zhang and Evelina Bakhturina and Kyle Gorman and Boris Ginsburg}, + year={2021}, + eprint={2104.05055}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} + +@Inbook{Mohri2009, +author="Mohri, Mehryar", +editor="Droste, Manfred +and Kuich, Werner +and Vogler, Heiko", +title="Weighted Automata Algorithms", +bookTitle="Handbook of Weighted Automata", +year="2009", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="213--254", +abstract="Weighted automata and transducers are widely used in modern applications in bioinformatics and text, speech, and image processing. This chapter describes several fundamental weighted automata and shortest-distance algorithms including composition, determinization, minimization, and synchronization, as well as single-source and all-pairs shortest distance algorithms over general semirings. It presents the pseudocode of these algorithms, gives an analysis of their running time complexity, and illustrates their use in some simple cases. Many other complex weighted automata and transducer algorithms used in practice can be obtained by combining these core algorithms.", +isbn="978-3-642-01492-5", +doi="10.1007/978-3-642-01492-5_6", +url="https://doi.org/10.1007/978-3-642-01492-5_6" +} + +@inproceedings{sparrowhawk, + title = {TTS for Low Resource Languages: A Bangla Synthesizer}, + author = {Alexander Gutkin and Linne Ha and Martin Jansche and Knot Pipatsrisawat and Richard Sproat}, + booktitle = {10th Language Resources and Evaluation Conference}, + year = {2016}, +} \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/api.rst b/tts/NeMo/docs/source/nlp/api.rst new file mode 100755 index 0000000..18a81d7 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/api.rst @@ -0,0 +1,74 @@ +NeMo NLP collection API +======================= + +Model Classes +------------- + +.. autoclass:: nemo.collections.nlp.models.TextClassificationModel + :show-inheritance: + :members: setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact, classifytext + +.. autoclass:: nemo.collections.nlp.models.GLUEModel + :show-inheritance: + :members: setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + +.. autoclass:: nemo.collections.nlp.models.PunctuationCapitalizationModel + :show-inheritance: + :members: add_punctuation_capitalization, setup_training_data, setup_optimization, setup_validation_data, setup_test_data, multi_validation_epoch_end, register_artifact + +.. autoclass:: nemo.collections.nlp.models.TokenClassificationModel + :show-inheritance: + :members: setup_training_data, setup_optimization, setup_validation_data, setup_test_data, register_artifact + +.. autoclass:: nemo.collections.nlp.models.QAModel + :show-inheritance: + :members: setup_training_data, setup_optimization, setup_validation_data, setup_test_data, inference, validation_epoch_end, test_epoch_end + +.. autoclass:: nemo.collections.nlp.models.BERTLMModel + :show-inheritance: + :members: setup_training_data, setup_optimization + +Modules +------- + +.. autoclass:: nemo.collections.nlp.modules.BertModule + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.MegatronBertEncoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.AlbertEncoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.BertEncoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.DistilBertEncoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.RobertaEncoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.SequenceClassifier + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.SequenceRegression + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.nlp.modules.SequenceTokenClassifier + :show-inheritance: + :members: + +.. autofunction:: nemo.collections.nlp.modules.get_lm_model + +.. autofunction:: nemo.collections.nlp.modules.get_pretrained_lm_models_list + +.. autofunction:: nemo.collections.nlp.modules.get_megatron_lm_models_list \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/bert_pretraining.rst b/tts/NeMo/docs/source/nlp/bert_pretraining.rst new file mode 100755 index 0000000..eee23bd --- /dev/null +++ b/tts/NeMo/docs/source/nlp/bert_pretraining.rst @@ -0,0 +1,133 @@ +.. _bert_pretraining: + +BERT +==== + +BERT is an autoencoding language model with a final loss composed of: + +- masked language model loss +- next sentence prediction + +The model architecture is published in `BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding `__ :cite:`nlp-bert-devlin2018bert`. +The model is originally trained on English Wikipedia and BookCorpus. BERT is often used as a language model encoder for downstream tasks, for example, :ref:`token_classification`, :ref:`text_classification`, :ref:`question_answering`, etc. +Domain-specific BERT models can be advantageous for a wide range of applications. One notable application is the domain-specific BERT in a biomedical setting, +e.g. BioBERT :cite:`nlp-bert-lee2019biobert` or its improved derivative BioMegatron :cite:`nlp-bert-shin2020biomegatron`. For the latter, refer to :ref:`megatron_finetuning`. + +Quick Start Guide +----------------- + +.. code-block:: python + + from nemo.collections.nlp.models import BERTLMModel + + # to get the list of pre-trained models + BERTLMModel.list_available_models() + + # Download and load the pre-trained BERT-based model + model = BERTLMModel.from_pretrained("bertbaseuncased") + +Available Models +^^^^^^^^^^^^^^^^ + +.. list-table:: *Pretrained Models* + :widths: 5 10 + :header-rows: 1 + + * - Model + - Pretrained Checkpoint + * - BERT-base uncased + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:bertbaseuncased + * - BERT-large uncased + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:bertlargeuncased + +.. _dataset_bert_pretraining: + +Data Input for the BERT model +----------------------------- + +Data preprocessing can be either done on-the-fly during training or offline before training. The latter is optimized and recommended +for large text corpora. This was also used in the original paper to train the model on Wikipedia and BookCorpus. For on-the-fly data +processing, provide text files with sentences for training and validation, where words are separated by spaces, i.e.: ``[WORD] [SPACE] [WORD] [SPACE] [WORD]``. +To use this pipeline in training, use the dedicated configuration file `NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_preprocessed_config.yaml`. + +To process data offline in advance, refer to the `BERT Quick Start Guide `__. +To recreate the original Wikipedia and BookCorpus datasets, follow steps 1-5 in the Quick Start Guide and run the script ``./data/create_datasets_from_start.sh`` inside the Docker container. +The ``downloaded`` folder should include two sub folders ``lower_case_[0,1]_seq_len_128_max_pred_20_masked_lm_prob_0.15_random_seed_12345_dupe_factor_5`` +and ``lower_case_[0,1]_seq_len_512_max_pred_80_masked_lm_prob_0.15_random_seed_12345_dupe_factor_5``, containing sequences of length 128 with a maximum of 20 masked tokens +and sequences of length 512 with a maximum of 80 masked tokens respectively. To use this pipeline in training, use the dedicated configuration file ``NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_text_config.yaml`` +and specify the path to the created hd5f files. + + +Training the BERT model +----------------------- + +Example of model configuration for on-the-fly data preprocessing: `NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_text_config.yaml `__. +Example of model configuration for offline data preprocessing: `NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_preprocessed_config.yaml `__. + +The specification can be grouped into three categories: + +- Parameters that describe the training process: **trainer** +- Parameters that describe the datasets: **model.train_ds**, **model.validation_ds** +- Parameters that describe the model: **model**, **model.tokenizer**, **model.language_model** + +More details about parameters in the config file can be found below: + ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.only_mlm_loss** | bool | Only uses masked language model without next sentence prediction. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **train_ds.data_file** | string | Name of the text file or hdf5 data directory. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **train_ds.num_samples** | integer | Number of samples to use from the training dataset, ``-1`` - to use all. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +More details about parameters for offline data preprocessing can be found below: + ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **train_ds.max_predictions_per_seq** | integer | Maximum number of masked tokens in a sequence in the preprocessed data. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +More details about parameters for online data preprocessing can be found below: + ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.max_seq_length** | integer | The maximum total input sequence length after tokenization. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.mask_prob** | float | Probability of masking a token in the input text during data processing. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.short_seq_prob** | float | Probability of having a sequence shorter than the maximum sequence length. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +.. note:: + + For offline data preprocessing, **model.tokenizer** is null. For downstream task, use the same tokenizer that was used for + offline preprocessing. For online data preprocessing, **model.tokenizer** needs to be specified. See also :ref:`nlp_model` for + details. + +Example of the command for training the model: + +.. code:: + + python bert_pretraining.py \ + model.train_ds.data_file= \ + trainer.max_epochs= \ + trainer.gpus=[] + + +Fine-tuning on Downstream Tasks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To use a trained BERT model checkpoint on a NeMo NLP downstream task, e.g. :ref:`question_answering`, specify +:code:`model.language_model.lm_checkpoint=`. + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-BERT + :keyprefix: nlp-bert- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/glue_benchmark.rst b/tts/NeMo/docs/source/nlp/glue_benchmark.rst new file mode 100644 index 0000000..37e0912 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/glue_benchmark.rst @@ -0,0 +1,10 @@ +.. _glue_benchmark: + +GLUE Benchmark +============== + +We recommend you try the GLUE Benchmark model in a Jupyter notebook (can run on `Google's Colab `_): `NeMo/tutorials/nlp/GLUE_Benchmark.ipynb `__. + +Connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for the hardware accelerator). + +An example script on how to train the model can be found here: `NeMo/examples/nlp/glue_benchmark/glue_benchmark.py `__. diff --git a/tts/NeMo/docs/source/nlp/information_retrieval.rst b/tts/NeMo/docs/source/nlp/information_retrieval.rst new file mode 100644 index 0000000..e4c047a --- /dev/null +++ b/tts/NeMo/docs/source/nlp/information_retrieval.rst @@ -0,0 +1,10 @@ +.. _information_retrieval: + +Information Retrieval +===================== + +We recommend you try the Information Retrieval model in a Jupyter notebook (can run on `Google's Colab `_): `NeMo/tutorials/nlp/Information_Retrieval_MSMARCO.ipynb `__. + +Connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for hardware the accelerator), + +An example script on how to train the model can be found here: `NeMo/examples/nlp/information_retrieval `__. diff --git a/tts/NeMo/docs/source/nlp/intro.rst b/tts/NeMo/docs/source/nlp/intro.rst new file mode 100755 index 0000000..7703dd0 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/intro.rst @@ -0,0 +1,15 @@ +Natural Language Processing (NLP) +================================= + +.. toctree:: + :maxdepth: 2 + + models + megatron_finetuning + api + + +Example scripts for the NLP collection can be found under `NeMo/example/nlp/ `__. + +NLP notebook-tutorials are located under `NeMo/tutorials/nlp/ `__. Most NeMo +tutorials can be run on `Google's Colab `_.), with more details in the :ref:`tutorials` section. diff --git a/tts/NeMo/docs/source/nlp/joint_intent_slot.rst b/tts/NeMo/docs/source/nlp/joint_intent_slot.rst new file mode 100644 index 0000000..5dc0043 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/joint_intent_slot.rst @@ -0,0 +1,244 @@ +.. _intent_slot: + +Joint Intent and Slot Classification +==================================== + +Joint Intent and Slot classification is a NLU task for classifying an intent and detecting all +relevant slots (Entities) for the intent in a query. For example, in the query ``What is the weather in Santa Clara tomorrow morning?``, +we would like to classify the query as a ``weather intent``, detect ``Santa Clara`` as a `location slot`, +and ``tomorrow morning`` as a ``date_time slot``. Intent and Slot names are usually task-specific and +defined as labels in the training data. This is a fundamental step that is executed in any +task-driven conversational assistant. + +Our BERT-based model implementation allows you to train and detect both of these tasks together. + +.. note:: + + We recommend you try the Joint Intent and Slot Classification model in a Jupyter notebook (can run on `Google's Colab `_.): `NeMo/tutorials/nlp/Joint_Intent_and_Slot_Classification.ipynb `__. + + Connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for the hardware accelerator). + + An example script on how to train the model can be found here: `NeMo/examples/nlp/intent_slot_classification `__. + + +NeMo Data Format +---------------- + +When training the model, the dataset should be first converted to the required data format, which requires the following files: + +- :code:`dict.intents.csv` - A list of all intent names in the data. One line per an intent name. The index of the intent line + (starting from ``0``) is used to identify the appropriate intent in ``train.tsv`` and ``test.tsv`` files. + +.. code:: + + weather + alarm + meeting + ... + +- :code:`dict.slots.csv` - A list of all slot names in the data. One line per slot name. The index of the slot line + (starting from ``0``) is used to identify the appropriate slots in the queries in ``train_slot.tsv`` and ``test_slot.tsv`` files. + In the last line of this dictionary ``O`` slot name is used to identify all ``out of scope`` slots, which are usually the majority of the tokens + in the queries. + +.. code:: + + date + time + city + ... + O + +- :code:`train.tsv/test.tsv` - A list of original queries, one per line, with the intent number + separated by a tab (e.g. "what alarms do i have set right now 0"). Intent numbers are + set according to the intent line in the intent dictionary file (:code:`dict.intents.csv`), + starting from ``0``. The first line in these files should contain the header line ``sentence + label``. + +- :code:`train_slot.tvs/test_slot.tsv` - A list that contains one line per query, when each word from the original text queries + is replaced by a token number from the slots dictionary file (``dict.slots.csv``), counted starting from ``0``. All the words + which do not contain a relevant slot are replaced by ``out-of scope`` token number, which is also a part of the slot dictionary file, + usually as the last entry there. For example a line from these files should look similar to: "54 0 0 54 54 12 12" (the numbers are + separated by a space). These files do not contain a header line. + + +Dataset Conversion +------------------ + +To convert to the format of the model data, use the ``import_datasets`` utility, which implements +the conversion for the Assistant dataset. Download the dataset `here `_ or you can +write your own converter for the format that you are using for data annotation. + +For a dataset that follows your own annotation format, we recommend using one text file for all +samples of the same intent, with the name of the file as the name of the intent. Use one line per +query, with brackets to define slot names. This is very similar to the assistant format, and you can +adapt this converter utility or your own format with small changes: + +:: + + did i set an alarm to [alarm_type : wake up] in the [timeofday : morning] + +Run the ``dataset_converter`` command: + +.. code:: + + python examples/nlp/intent_slot_classification/data/import_datasets.py + --source_data_dir=`source_data_dir` \ + --target_data_dir=`target_data_dir` \ + --dataset_name=['assistant'|'snips'|'atis'] + +- :code:`source_data_dir`: the directory location of the your dataset +- :code:`target_data_dir`: the directory location where the converted dataset should be saved +- :code:`dataset_name`: one of the implemented dataset names + +After conversion, ``target_data_dir`` should contain the following files: + +.. code:: + + . + |--target_data_dir + |-- dict.intents.csv + |-- dict.slots.csv + |-- train.tsv + |-- train_slots.tsv + |-- test.tsv + |-- test_slots.tsv + +Model Training +-------------- + +This is a pretrained BERT based model with 2 linear classifier heads on the top of it, one for classifying an intent of the query and +another for classifying slots for each token of the query. This model is trained with the combined loss function on the Intent and Slot +classification task on the given dataset. The model architecture is based on the paper `BERT for Joint Intent Classification and Slot Filling `__:cite:`nlp-jis-chen2019bert`. + +For each query, the model classifies it as one the intents from the intent dictionary and for each word of the query it will classify +it as one of the slots from the slot dictionary, including out of scope slot for all the remaining words in the query which does not +fall in another slot category. Out of scope slot (``O``) is a part of slot dictionary that the model is trained on. + +Example of model configuration file for training the model can be found at: `NeMo/examples/nlp/intent_slot_classification/conf/intent_slot_classification.yaml `__. +In the configuration file, define the parameters of the training and the model, although most of the default values will work well. + +The specification can be roughly grouped into three categories: + +- Parameters that describe the training process: **trainer** +- Parameters that describe the model: **model** +- Parameters that describe the datasets: **model.train_ds**, **model.validation_ds**, **model.test_ds**, + +More details about parameters in the spec file can be found below: + ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Default** | **Description** | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.data_dir** | string | -- | The path of the data converted to the specified format. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.class_balancing** | string | ``null`` | Choose from ``[null, weighted_loss]``. The ``weighted_los``s enables weighted class balancing of the loss. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.intent_loss_weight** | float | ``0.6`` | The elation of intent-to-slot loss in the total loss. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.pad_label** | integer | ``-1`` | A value to pad the inputs. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.ignore_extra_tokens** | boolean | ``false`` | A flag that specifies whether to ignore extra tokens. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.ignore_start_end** | boolean | ``true`` | A flag that specifies whether to not use the first and last token for slot training. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.head.num_output_layers** | integer | ``2`` | The number of fully connected layers of the classifier on top of the BERT model. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **model.head.fc_dropout** | float | ``0.1`` | The dropout ratio of the fully connected layers. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.prefix** | string | ``train`` | A prefix for the training file names. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.prefix** | string | ``dev`` | A prefix for the validation file names. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ +| **test_ds.prefix** | string | ``test`` | A prefix for the test file names. | ++-------------------------------------------+-----------------+----------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ + +For additional config parameters common to all NLP models, refer to the `nlp_model doc `__. + +The following is an example of the command for training the model: + +.. code:: + + python examples/nlp/intent_slot_classification/intent_slot_classification.py + model.data_dir= \ + trainer.max_epochs= \ + trainer.gpus=[] + + +Required Arguments for Training +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`model.data_dir`: the dataset directory + + +Optional Arguments +^^^^^^^^^^^^^^^^^^ + +Most of the default parameters in the existing configuration file are already set appropriately, however, there are some parameters +you may want to experiment with. + +- ``trainer.max_epochs``: the number of training epochs (reasonable to be between 10 to 100) +- ``model.class_balancing`` - value ``weighted_loss`` may help to train the model when there is unbalanced set of classes +- ``model.intent_loss_weight`` - a number between 0 to 1 that defines a weight of the intent lost versus a slot loss during training. A +default value 0.6 gives a slight preference for the intent lose optimization. + +Training Procedure +^^^^^^^^^^^^^^^^^^ + +At the start of evaluation, NeMo will print out a log of the experiment specification, a summary of the training dataset, and the +model architecture. + +As the model starts training, you should see a progress bar per epoch. During training, after each epoch, NeMo will display accuracy +metrics on the validation dataset for every intent and slot separately, as well as the total accuracy. You can expect these numbers +to grow up to 50-100 epochs, depending on the size of the trained data. Since this is a joint iIntent and slot training, usually +intent's accuracy will grow first for the initial 10-20 epochs, and after that, slot's accuracy will start improving as well. + +At the end of training, NeMo saves the best checkpoint on the validation dataset at the path specified by the experiment spec file +before finishing. + +.. code:: + + GPU available: True, used: True + TPU available: None, using: 0 TPU cores + LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1,2] + [NeMo W 2021-01-28 14:52:19 exp_manager:299] There was no checkpoint folder at checkpoint_dir :results/checkpoints. Training from scratch. + [NeMo I 2021-01-28 14:52:19 exp_manager:186] Experiments will be logged at results + ... + label precision recall f1 support + weather.weather (label_id: 0) 0.00 0.00 0.00 128 + weather.temperature (label_id: 1) 0.00 0.00 0.00 0 + weather.temperature_yes_no (label_id: 2) 0.00 0.00 0.00 0 + weather.rainfall (label_id: 3) 0.00 0.00 0.00 0 + weather.rainfall_yes_no (label_id: 4) 0.00 0.00 0.00 0 + weather.snow (label_id: 5) 0.00 0.00 0.00 0 + weather.snow_yes_no (label_id: 6) 0.00 0.00 0.00 0 + weather.humidity (label_id: 7) 0.00 0.00 0.00 0 + weather.humidity_yes_no (label_id: 8) 0.00 0.00 0.00 0 + weather.windspeed (label_id: 9) 0.00 0.00 0.00 0 + weather.sunny (label_id: 10) 0.00 0.00 0.00 0 + weather.cloudy (label_id: 11) 0.00 0.00 0.00 0 + weather.alert (label_id: 12) 0.00 0.00 0.00 0 + context.weather (label_id: 13) 0.00 0.00 0.00 0 + context.continue (label_id: 14) 0.00 0.00 0.00 0 + context.navigation (label_id: 15) 0.00 0.00 0.00 0 + context.rating (label_id: 16) 0.00 0.00 0.00 0 + context.distance (label_id: 17) 0.00 0.00 0.00 0 + ------------------- + micro avg 0.00 0.00 0.00 128 + macro avg 0.00 0.00 0.00 128 + weighted avg 0.00 0.00 0.00 128 + +Model Evaluation and Inference +------------------------------ + +There is no separate script for the evaluation and inference of this model in NeMo, however, inside of the example file `examples/nlp/intent_slot_classification/intent_slot_classification.py` +after the training part is finished, you can see the code that evaluates the trained model on an evaluation test set and then an example of doing inference using a list of given queries. + +For the deployment in the production environment, refer to `NVIDIA Jarvis `__ and `NVIDIA TLT documentation `__. + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-JIS + :keyprefix: nlp-jis- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/language_modeling.rst b/tts/NeMo/docs/source/nlp/language_modeling.rst new file mode 100644 index 0000000..5565e5d --- /dev/null +++ b/tts/NeMo/docs/source/nlp/language_modeling.rst @@ -0,0 +1,6 @@ +.. _language_modeling: + +Language Modeling +================= + +An example script on how to train the model can be found here: `NeMo/examples/nlp/language_modeling `__. diff --git a/tts/NeMo/docs/source/nlp/machine_translation.rst b/tts/NeMo/docs/source/nlp/machine_translation.rst new file mode 100644 index 0000000..8f3ed7d --- /dev/null +++ b/tts/NeMo/docs/source/nlp/machine_translation.rst @@ -0,0 +1,466 @@ +.. _machine_translation: + +Machine Translation Models +========================== +Machine translation is the task of translating text from one language to another. For example, from English to Spanish. Models are +based on the Transformer sequence-to-sequence architecture :cite:`nlp-machine_translation-vaswani2017attention`. + +An example script on how to train the model can be found here: `NeMo/examples/nlp/machine_translation/enc_dec_nmt.py `__. +The default configuration file for the model can be found at: `NeMo/examples/nlp/machine_translation/conf/aayn_base.yaml `__. + +Quick Start Guide +----------------- + +.. code-block:: python + + from nemo.collections.nlp.models import MTEncDecModel + + # To get the list of pre-trained models + MTEncDecModel.list_available_models() + + # Download and load the a pre-trained to translate from English to Spanish + model = MTEncDecModel.from_pretrained("nmt_en_es_transformer12x2") + + # Translate a sentence or list of sentences + translations = model.translate(["Hello!"], source_lang="en", target_lang="es") + +Available Models +^^^^^^^^^^^^^^^^ + +.. list-table:: *Pretrained Models* + :widths: 5 10 + :header-rows: 1 + + * - Model + - Pretrained Checkpoint + * - English -> German + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_en_de_transformer12x2 + * - German -> English + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_de_en_transformer12x2 + * - English -> Spanish + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_en_es_transformer12x2 + * - Spanish -> English + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_es_en_transformer12x2 + * - English -> French + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_en_fr_transformer12x2 + * - French -> English + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_fr_en_transformer12x2 + * - English -> Russian + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_en_ru_transformer6x6 + * - Russian -> English + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_ru_en_transformer6x6 + * - English -> Chinese + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_en_zh_transformer6x6 + * - Chinese -> English + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:nmt_zh_en_transformer6x6 + +Data Format +----------- + +Supervised machine translation models require parallel corpora which comprises many examples of sentences in a source language and +their corresponding translation in a target language. We use parallel data formatted as seperate text files for source and target +languages where sentences in corresponding files are aligned like in the table below. + +.. list-table:: *Parallel Coprus* + :widths: 10 10 + :header-rows: 1 + + * - train.english.txt + - train.spanish.txt + * - Hello . + - Hola . + * - Thank you . + - Gracias . + * - You can now translate from English to Spanish in NeMo . + - Ahora puedes traducir del inglés al español en NeMo . + +It is common practice to apply data cleaning, normalization, and tokenization to the data prior to training a translation model and +NeMo expects already cleaned, normalized, and tokenized data. The only data pre-processing NeMo does is subword tokenization with BPE +:cite:`nlp-machine_translation-sennrich2015neural`. + +Data Cleaning, Normalization & Tokenization +------------------------------------------- + +We recommend applying the following steps to clean, normalize, and tokenize your data. All pre-trained models released, apply these data pre-processing steps. + +#. Language ID filtering - This step filters out examples from your training dataset that aren't in the correct language. For example, + many datasets contain examples where source and target sentences are in the same language. You can use a pre-trained language ID + classifier from `fastText `__. You can then run our script using the + ``lid.176.bin`` model downloaded from the fastText website. + + .. code :: + + python NeMo/scripts/neural_machine_translation/filter_by_language.py \ + --input-src train.en \ + --input-tgt train.es \ + --output-src train_lang_filtered.en \ + --output-tgt train_lang_filtered.es \ + --source-lang en \ + --target-lang es \ + --removed-src train_noise.en \ + --removed-tgt train_noise.de \ + --fasttext-model lid.176.bin + +#. Length filtering - We filter out sentences from the data that are below a minimum length (1) or exceed a maximum length (250). We + also filter out sentences where the ratio between source and target lengths exceeds 1.3 except for English <-> Chinese models. + `Moses `__ is a statistical machine translation toolkit that contains many useful + pre-processing scripts. + + .. code :: + + perl mosesdecoder/scripts/training/clean-corpus-n.perl -ratio 1.3 train en es train.filter 1 250 + +#. Data cleaning - While language ID filtering can sometimes help with filtering out noisy sentences that contain too many puncutations, + it does not help in cases where the translations are potentially incorrect, disfluent, or incomplete. We use `bicleaner `__ + a tool to identify such sentences. It trains a classifier based on many features included pre-trained language model fluency, word + alignment scores from a word-alignment model like `Giza++ `__ etc. We use their available + pre-trained models wherever possible and train models ourselves using their framework for remaining languages. The following script + applies a pre-trained bicleaner model to the data and pick sentences that are clean with probability > 0.5. + + .. code :: + + awk '{print "-\t-"}' train.en \ + | paste -d "\t" - train.filter.en train.filter.es \ + | bicleaner-classify - - > train.en-es.bicleaner.score + +#. Data deduplication - We use `bifixer `__ (which uses xxHash) to hash the source and target + sentences based on which we remove duplicate entries from the file. You may want to do something similar to remove training examples + that are in the test dataset. + + .. code :: + + cat train.en-es.bicleaner.score \ + | parallel -j 25 --pipe -k -l 30000 python bifixer.py --ignore-segmentation -q - - en es \ + > train.en-es.bifixer.score + + awk -F awk -F "\t" '!seen[$6]++' train.en-es.bifixer.score > train.en-es.bifixer.dedup.score + +#. Filter out data that bifixer assigns probability < 0.5 to. + + .. code :: + + awk -F "\t" '{ if ($5>0.5) {print $3}}' train.en-es.bifixer.dedup.score > train.cleaned.en + awk -F "\t" '{ if ($5>0.5) {print $4}}' train.en-es.bifixer.dedup.score > train.cleaned.es + +#. Punctuation Normalization - Punctuation, especially things like quotes can be written in different ways. + It's often useful to normalize the way they appear in text. We use the moses punctuation normalizer on all languages except Chinese. + + .. code :: + + perl mosesdecoder/scripts/tokenizer/normalize-punctuation.perl -l es < train.cleaned.es > train.normalized.es + perl mosesdecoder/scripts/tokenizer/normalize-punctuation.perl -l en < train.cleaned.en > train.normalized.en + + For example: + + .. code :: + + Before - Aquí se encuentran joyerías como Tiffany`s entre negocios tradicionales suizos como la confitería Sprüngli. + After - Aquí se encuentran joyerías como Tiffany's entre negocios tradicionales suizos como la confitería Sprüngli. + +#. Tokenization and word segmentation for Chinese - Naturally written text often contains punctuation markers like commas, full-stops + and apostrophes that are attached to words. Tokenization by just splitting a string on spaces will result in separate token IDs for + very similar items like ``NeMo`` and ``NeMo.``. Tokenization splits punctuation from the word to create two separate tokens. In the + previous example ``NeMo.`` becomes ``NeMo .`` which when split by space, results in two tokens and adressess the earlier problem. + + For example: + + .. code :: + + Before - Especialmente porque se enfrentará "a Mathieu (Debuchy), Yohan (Cabaye) y Adil (Rami) ", recuerda. + After - Especialmente porque se enfrentará " a Mathieu ( Debuchy ) , Yohan ( Cabaye ) y Adil ( Rami ) " , recuerda . + + We use the Moses tokenizer for all languages except Chinese. + + .. code :: + + perl mosesdecoder/scripts/tokenizer/tokenizer.perl -l es -no-escape < train.normalized.es > train.tokenized.es + perl mosesdecoder/scripts/tokenizer/tokenizer.perl -l en -no-escape < train.normalized.en > train.tokenized.en + + For languages like Chinese where there is no explicit marker like spaces that separate words, we use `Jieba `__ to segment a string into words that are space separated. + + For example: + + .. code :: + + Before - 同时,卫生局认为有必要接种的其他人员,包括公共部门,卫生局将主动联络有关机构取得名单后由卫生中心安排接种。 + After - 同时 , 卫生局 认为 有 必要 接种 的 其他 人员 , 包括 公共部门 , 卫生局 将 主动 联络 有关 机构 取得 名单 后 由 卫生 中心 安排 接种 。 + +Training a BPE Tokenization +--------------------------- + +Byte-pair encoding (BPE) :cite:`nlp-machine_translation-sennrich2015neural` is a sub-word tokenization algorithm that is commonly used +to reduce the large vocabulary size of datasets by splitting words into frequently occuring sub-words. Currently, mMachine translation +only supports the `YouTokenToMe `__ BPE tokenizer. One can set the tokenization configuration +as follows: + ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Default** | **Description** | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **model.{encoder_tokenizer,decoder_tokenizer}.tokenizer_name** | str | ``yttm`` | BPE library name. Only supports ``yttm`` for now. | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **model.{encoder_tokenizer,decoder_tokenizer}.tokenizer_model** | str | ``null`` | Path to an existing YTTM BPE model. If ``null``, will train one from scratch on the provided data. | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **model.{encoder_tokenizer,decoder_tokenizer}.vocab_size** | int | ``null`` | Desired vocabulary size after BPE tokenization. | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **model.{encoder_tokenizer,decoder_tokenizer}.bpe_dropout** | float | ``null`` | BPE dropout probability. :cite:`nlp-machine_translation-provilkov2019bpe`. | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **model.{encoder_tokenizer,decoder_tokenizer}.vocab_file** | str | ``null`` | Path to pre-computed vocab file if exists. | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ +| **model.shared_tokenizer** | bool | ``True`` | Whether to share the tokenizer between the encoder and decoder. | ++-----------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------+ + + +Applying BPE Tokenization, Batching, Bucketing and Padding +---------------------------------------------------------- + +Given BPE tokenizers, and a cleaned parallel corpus, the following steps are applied to create a `TranslationDataset `__ object. + +#. Text to IDs - This performs subword tokenization with the BPE model on an input string and maps it to a sequence of tokens for the + source and target text. + +#. Bucketing - Sentences vary in length and when creating minibatches, we'd like sentences in them to have roughly the same length to + minimize the number of ```` tokens and to maximize computational efficiency. This step groups sentences roughly the same length + into buckets. + +#. Batching and padding - Creates minibatches with a maximum number of tokens specified by ``model.{train_ds,validation_ds,test_ds}.tokens_in_batch`` + from buckets and pads, so they can be packed into a tensor. + +Datasets can be configured as follows: + ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Default** | **Description** | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.src_file_name** | str | ``null`` | Path to the source language file. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.tgt_file_name** | str | ``null`` | Path to the target language file. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.tokens_in_batch** | int | ``512`` | Maximum number of tokens per minibatch. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.clean** | bool | ``true`` | Whether to clean the dataset by discarding examples that are greater than ``max_seq_length``. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.max_seq_length** | int | ``512`` | Maximum sequence to be used with the ``clean`` argument above. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.shuffle** | bool | ``true`` | Whether to shuffle minibatches in the PyTorch DataLoader. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.num_samples** | int | ``-1`` | Number of samples to use. ``-1`` for the entire dataset. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.drop_last** | bool | ``false`` | Drop last minibatch if it is not of equal size to the others. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.pin_memory** | bool | ``false`` | Whether to pin memory in the PyTorch DataLoader. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.num_workers** | int | ``8`` | Number of workers for the PyTorch DataLoader. | ++-------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------------+ + + +Tarred Datasets for Large Corpora +--------------------------------- + +When training with ``DistributedDataParallel``, each process has its own copy of the dataset. For large datasets, this may not always +fit in CPU memory. `Webdatasets `__ circumvents this problem by efficiently iterating over +tar files stored on disk. Each tar file can contain hundreds to thousands of pickle files, each containing a single minibatch. + +We recommend using this method when working with datasets with > 1 million sentence pairs. + +Tarred datasets can be configured as follows: + ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Default** | **Description** | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.use_tarred_dataset** | bool | ``false`` | Whether to use tarred datasets. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.tar_files** | str | ``null`` | String specifying path to all tar files. Example with 100 tarfiles ``/path/to/tarfiles._OP_1..100_CL_.tar``. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.metadata_file** | str | ``null`` | Path to JSON metadata file that contains only a single entry for the total number of batches in the dataset. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.lines_per_dataset_fragment** | int | ``1000000`` | | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.num_batches_per_tarfile** | int | ``100`` | Maximum sequence to be used with the ``clean`` argument above. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.tar_shuffle_n** | int | ``100`` | Whether to cache IDs to avoid re-tokenizing data. This will be deprecated in favor of tarred datasets. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.{train_ds,validation_ds,test_ds}.shard_strategy** | str | ``scatter`` | Whether to cache IDs in each of the nodes in multi-node training. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ +| **model.preproc_out_dir** | str | ``null`` | Path to folder that contains processed tar files or directory where new tar files are written. | ++-----------------------------------------------------------------------+-----------------+----------------+----------------------------------------------------------------------------------------------------------------+ + +Tarred datasets can be created in two ways: + +#. Using the Hydra config and `training script `__. + + For example: + + .. code :: + + python examples/nlp/machine_translation/enc_dec_nmt.py \ + -cn aayn_base \ + do_training=false \ + model.preproc_out_dir=/path/to/preproc_dir \ + model.train_ds.use_tarred_dataset=true \ + model.train_ds.lines_per_dataset_fragment=1000000 \ + model.train_ds.num_batches_per_tarfile=200 \ + model.train_ds.src_file_name=train.tokenized.en \ + model.train_ds.tgt_file_name=train.tokenized.es \ + model.validation_ds.src_file_name=validation.tokenized.en \ + model.validation_ds.tgt_file_name=validation.tokenized.es \ + model.encoder_tokenizer.vocab_size=32000 \ + model.decoder_tokenizer.vocab_size=32000 \ + ~model.test_ds \ + trainer.gpus=[0,1,2,3] \ + +trainer.fast_dev_run=true \ + exp_manager=null \ + + The above script processes the parallel tokenized text files into tarred datasets that are written to ``/path/to/preproc_dir``. Since + ``do_training`` is set to ``False``, the above script only creates tarred datasets and then exits. If ``do_training`` is set ``True``, + then one of two things happen: + + (a) If no tar files are present in ``model.preproc_out_dir``, the script first creates those files and then commences training. + (b) If tar files are already present in ``model.preproc_out_dir``, the script starts training from the provided tar files. + +#. Using a separate script without Hydra. + + Tarred datasets for parallel corpora can also be created with a script that doesn't require specifying a configs via Hydra and + just uses Python argparse. + + For example: + + .. code :: + + python examples/nlp/machine_translation/create_tarred_parallel_dataset.py \ + --shared_tokenizer \ + --clean \ + --bpe_dropout 0.1 \ + --src_fname train.tokenized.en \ + --tgt_fname train.tokenized.es \ + --out_dir /path/to/preproc_dir \ + --vocab_size 32000 \ + --max_seq_length 512 \ + --min_seq_length 1 \ + --tokens_in_batch 8192 \ + --lines_per_dataset_fragment 1000000 \ + --num_batches_per_tarfile 200 + + You can then set `model.preproc_out_dir=/path/to/preproc_dir` and `model.train_ds.use_tarred_dataset=true` to train with this data. + +Model Configuration and Training +-------------------------------- + +The overall model consists of an encoder, decoder, and classification head. Encoders and decoders have the following configuration +options: + ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Default** | **Description** | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.max_sequence_length** | int | ``512`` | Maximum sequence length of positional encodings. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.embedding_dropout** | float | ``0.1`` | Path to JSON metadata file that contains only a single entry for the total number of batches in the dataset. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.learn_positional_encodings** | bool | ``false`` | If ``True``, this is a regular learnable embedding layer. If ``False``, fixes position encodings to sinusoidal. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.hidden_size** | int | ``512`` | Size of the transformer hidden states. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.num_layers** | int | ``6`` | Number of transformer layers. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.inner_size** | int | ``2048`` | Size of the hidden states within the feedforward layers. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.num_attention_heads** | int | ``8`` | Number of attention heads. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.ffn_dropout** | float | ``0.1`` | Dropout probability within the feedforward layers. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.attn_score_dropout** | float | ``0.1`` | Dropout probability of the attention scores before softmax normalization. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.attn_layer_dropout** | float | ``0.1`` | Dropout probability of the attention query, key, and value projection activations. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.hidden_act** | str | ``relu`` | Activation function throughout the network. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.mask_future** | bool | ``false``, ``true`` | Whether to mask future timesteps for attention. Defaults to ``True`` for decoder and ``False`` for encoder. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +| **model.{encoder,decoder}.pre_ln** | bool | ``false`` | Whether to apply layer-normalization before (``true``) or after (``false``) a sub-layer. | ++-------------------------------------------------------------------+-----------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ + +Our pre-trained models are optimized with Adam, with a maximum learning of 0.0004, beta of (0.9, 0.98), an inverse square root learning +rate schedule from :cite:`nlp-machine_translation-vaswani2017attention`. The **model.optim** section sets the optimization parameters. + +The following script creates tarred datasets based on the provided parallel corpus and train a model based on the ``base`` configuration +from :cite:`nlp-machine_translation-vaswani2017attention`. + +.. code :: + + python examples/nlp/machine_translation/enc_dec_nmt.py \ + -cn aayn_base \ + do_training=true \ + trainer.gpus=8 \ + ~trainer.max_epochs \ + +trainer.max_steps=100000 \ + +trainer.val_check_interval=1000 \ + +exp_manager.exp_dir=/path/to/store/results \ + +exp_manager.create_checkpoint_callback=True \ + +exp_manager.checkpoint_callback_params.monitor=val_sacreBLEU \ + +exp_manager.checkpoint_callback_params.mode=max \ + +exp_manager.checkpoint_callback_params.save_top_k=5 \ + model.preproc_out_dir=/path/to/preproc_dir \ + model.train_ds.use_tarred_dataset=true \ + model.train_ds.lines_per_dataset_fragment=1000000 \ + model.train_ds.num_batches_per_tarfile=200 \ + model.train_ds.src_file_name=train.tokenized.en \ + model.train_ds.tgt_file_name=train.tokenized.es \ + model.validation_ds.src_file_name=validation.tokenized.en \ + model.validation_ds.tgt_file_name=validation.tokenized.es \ + model.encoder_tokenizer.vocab_size=32000 \ + model.decoder_tokenizer.vocab_size=32000 \ + ~model.test_ds \ + +The trainer keeps track of the sacreBLEU score :cite:`nlp-machine_translation-post2018call` on the provided validation set and saves +the checkpoints that had the top 5 (by default) sacreBLEU scores. + +At the end of training, a ``.nemo`` file is written to the result directory which allows to run inference on a test set. + +Multi-Validation +---------------- + +To run validation on multiple datasets, specify ``validation_ds.src_file_name`` and ``validation_ds.tgt_file_name`` with a list of file paths: + +.. code-block:: bash + + model.validation_ds.src_file_name=[/data/wmt13-en-de.src,/data/wmt14-en-de.src] \ + model.validation_ds.tgt_file_name=[/data/wmt13-en-de.ref,/data/wmt14-en-de.ref] \ + +When using ``val_loss`` or ``val_sacreBLEU`` for the ``exp_manager.checkpoint_callback_params.monitor`` +then the 0th indexed dataset will be used as the monitor. + +To use other indexes, append the index: + +.. code-block:: bash + + exp_manager.checkpoint_callback_params.monitor=val_sacreBLEU_dl_index_1 + +Multiple test datasets work exactly the same way as validation datasets, simply replace ``validation_ds`` by ``test_ds`` in the above examples. + +Model Inference +--------------- + +To generate translations on a test set and compute sacreBLEU scores, run the inference script: + +.. code :: + + python examples/nlp/machine_translation/nmt_transformer_infer.py \ + --model /path/to/model.nemo \ + --srctext test.en \ + --tgtout test.en-es.translations \ + --batch_size 128 \ + --source_lang en \ + --target_lang es + +The ``--srctext`` file must be provided before tokenization and normalization. The resulting ``--tgtout`` file is detokenized and +can be used to compute sacreBLEU scores. + +.. code :: + + cat test.en-es.translations | sacrebleu test.es + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: nlp-machine_translation + :keyprefix: nlp-machine_translation- diff --git a/tts/NeMo/docs/source/nlp/megatron_finetuning.rst b/tts/NeMo/docs/source/nlp/megatron_finetuning.rst new file mode 100644 index 0000000..fec82f2 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/megatron_finetuning.rst @@ -0,0 +1,216 @@ +.. _megatron_finetuning: + +Megatron-LM for Downstream Tasks +================================ + +Megatron-LM :cite:`nlp-megatron-shoeybi2019megatron` is a large, powerful transformer developed by the Applied Deep Learning Research +team at NVIDIA. Unlike BERT, the position of the layer normalization and the residual connection in the model architecture (similar to +GPT-2 architucture) are swapped, which allows the models to continue to improve as they were scaled up. This model reaches higher +scores compared to BERT on a range of Natural Language Processing (NLP) tasks. More details on efficient, model-parallel and multi-node +pre-training of GPT and BERT using mixed precision can be found in the `Megatron-LM GitHub repo `_. + + +Fine-tuning +----------- + +Pre-trained Megatron-LM (BERT) can be used for most of the NLP downstream tasks from `NeMo/examples/nlp `_. +Specify the ``model.language_model.pretrained_model_name`` parameter: + +.. code-block:: bash + + model.language_model.pretrained_model_name=megatron-bert-345m-uncased + +Available pre-trained Megatron-LM models: + +- ``megatron-bert-345m-cased`` +- ``megatron-bert-345m-uncased`` +- ``biomegatron-bert-345m-uncased`` +- ``biomegatron-bert-345m-cased`` + +For example, to fine-tune SQuAD v1.1 with Megatron-LM, run: + +.. code-block:: bash + + python question_answering_squad.py \ + model.train_ds.file= \ + model.validation_ds= \ + model.language_model.pretrained_model_name=megatron-bert-345m-uncased + +If you have a different checkpoint or model configuration (pre-trained with `Megatron-LM GitHub repo `_), +use ``model.language_model.pretrained_model_name=megatron-bert-uncased`` or ``model.language_model.pretrained_model_name=megatron-bert-cased`` +and specify ``--bert_config`` and ``--bert_checkpoint`` for your model. + +.. note:: + Megatron-LM has its own set of training arguments (including tokenizer) that are ignored during fine-tuning in NeMo. Use downstream + task training scripts for all NeMo supported arguments. + +BioMegatron +----------- + +BioMegatron has the same network architecture as the Megatron-LM, but is pretrained on a different dataset - `PubMed `_, +a large biomedical text corpus, which achieves better performance in biomedical downstream tasks than the original Megatron-LM. + +Examples of using BioMegatron on biomedical downstream tasks can be found at (can be executed with `Google's Colab `_): +`NeMo/tutorials/nlp/Relation_Extraction-BioMegatron.ipynb `__ and `NeMo/tutorials/nlp/Token_Classification-BioMegatron.ipynb `__. + +Model Parallelism +----------------- + +`Megatron-LM `_ is a highly optimized and efficient library for training large language models. +With Megatron model parallelism, language models can be trained with billions of weights and then used in NeMo for downstream tasks. + +NeMo handles pretrained model parallel checkpoints from Megatron-LM automatically and model parallel models in NeMo have the all +the same features as other NeMo Models. + +.. note:: + + Currently, NeMo only supports tensor model parallelism. + +Training +^^^^^^^^ + +All of the necessary logic to train model parallel models in NeMo with PyTorch Lightning is contained in the ``NLPDDPPlugin``. +The ``NLPDDPPlugin`` subclasses the PyTorch Lightning training type plugin ``DDPPlugin``. +See `plugins `_ for more information on PyTorch Lightning Plugins. + +To enable model parallel training in NeMo: + +.. code-block:: python + + trainer = Trainer(plugins=[NLPDDPPlugin()], **cfg.trainer) + +Megatron-LM checkpoints have a specific format. One checkpoint is saved for each model parallel rank: + +.. code-block:: bash + + iter_0080000/ + ├── mp_rank_00 + │ └── model_optim_rng.pt + └── mp_rank_01 + └── model_optim_rng.pt + + +To start fine-tuning from a Megatron-LM checkpoint, simply pass the path to the Megatron-LM checkpoint +via the language model config: + +.. code-block:: bash + + model.language_model.lm_checkpoint=/raid/megatron/bert/iter_0080000 \ + +We also need to input the model configuration. This can be done via json: + +.. code-block:: json + + { + "hidden-size": 1024, + "num-attention-heads": 16, + "num-layers": 24, + "max-seq-length": 512 + } + +And input via command line: + +.. code-block:: bash + + model.language_model.config_file=/raid/data/megatron/bert/config.json \ + +Or the model configuration can be input via YAML: + +.. code-block:: YAML + + model: + language_model: + config: + hidden_size: 1024 + num_attention_heads: 16 + num_layers: 24 + max_position_embeddings: 512 + +Additionally, Megatron-LM requires a vocab file: + +.. code-block:: bash + + model.tokenizer.vocab_file=/path/to/vocab.txt + +If using the Megatron-LM default tokenizer for training BERT the vocab file can be omitted: + +.. code-block:: bash + + # uncased model + model.tokenizer.tokenizer_name=megatron-bert-uncased + +.. code-block:: bash + + # cased model + model.tokenizer.tokenizer_name=megatron-bert-uncased + +Auto-Resume +^^^^^^^^^^^ + +Resuming training with NeMo experiment manager and PyTorch Lightning works exactly the same as other NeMo models. +While training with PTL, model parallel checkpoint will be saved and loaded properly. + +.. code-block:: bash + + checkpoints/ + ├── mp_rank_00 + │ ├── mp_autoresume-last.ckpt + │ ├── mp_autoresume---val_loss=0.35-epoch=0.ckpt + │ ├── mp_autoresume---val_loss=0.38-epoch=1.ckpt + │ └── mp_autoresume---val_loss=0.39-epoch=2.ckpt + └── mp_rank_01 + ├── mp_autoresume-last.ckpt + ├── mp_autoresume---val_loss=0.35-epoch=0.ckpt + ├── mp_autoresume---val_loss=0.38-epoch=1.ckpt + └── mp_autoresume---val_loss=0.39-epoch=2.ckpt + +Save and Restore +^^^^^^^^^^^^^^^^ + +Model parallel .nemo files behave the same as all other .nemo files. Calling ``.save_to`` will save +a checkpoint for each model parallel rank inside the .nemo file: + +.. code-block:: bash + + text_class_350m + ├── megatron-bert-uncased_encoder_config.json + ├── megatron_checkpoint_version.json + ├── model_config.yaml + ├── mp_rank_00 + │ └── model_weights.ckpt + ├── mp_rank_01 + │ └── model_weights.ckpt + ├── tokenizer_vocab_dict.json + └── tokenizer.vocab_file + +When restoring a model parallel .nemo file, we must pass in the ``Trainer`` as model parallel requires DDP: + +.. code-block:: python + + model = TokenClassificationModel.restore_from(cfg.pretrained_model, trainer=trainer) + +Evaluation +^^^^^^^^^^ + +Since model parallel models always require more than one GPU, the ``Trainer`` is needed for evaluation: + +.. code-block:: python + + trainer = pl.Trainer(plugins=[NLPDDPPlugin()], **cfg.trainer) + + model = TextClassificationModel.restore_from(cfg.model.nemo_path, trainer=trainer) + model.setup_test_data(test_data_config=cfg.model.test_ds) + + trainer.test(model=model, ckpt_path=None) + + + + + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-MEGATRON + :keyprefix: nlp-megatron- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/models.rst b/tts/NeMo/docs/source/nlp/models.rst new file mode 100755 index 0000000..c6b9adb --- /dev/null +++ b/tts/NeMo/docs/source/nlp/models.rst @@ -0,0 +1,22 @@ +.. _nlp_models: + +Models +====== + +NeMo's NLP collection supports the following models: + +.. toctree:: + :maxdepth: 1 + + punctuation_and_capitalization + token_classification + joint_intent_slot + text_classification + bert_pretraining + language_modeling + question_answering + sgd_qa + glue_benchmark + information_retrieval + nlp_model + machine_translation diff --git a/tts/NeMo/docs/source/nlp/nlp_all.bib b/tts/NeMo/docs/source/nlp/nlp_all.bib new file mode 100644 index 0000000..f291310 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/nlp_all.bib @@ -0,0 +1,109 @@ +@article{devlin2018bert, + title={Bert: Pre-training of deep bidirectional transformers for language understanding}, + author={Devlin, Jacob and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina}, + journal={arXiv preprint arXiv:1810.04805}, + year={2018} +} + +@article{shoeybi2019megatron, + title={Megatron-lm: Training multi-billion parameter language models using model parallelism}, + author={Shoeybi, Mohammad and Patwary, Mostofa and Puri, Raul and LeGresley, Patrick and Casper, Jared and Catanzaro, Bryan}, + journal={arXiv preprint arXiv:1909.08053}, + year={2019} +} + +@InProceedings{maas2011, + author = {Maas, Andrew L. and Daly, Raymond E. and Pham, Peter T. and Huang, Dan and Ng, Andrew Y. and Potts, Christopher}, + title = {Learning Word Vectors for Sentiment Analysis}, + booktitle = {Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies}, + month = {June}, + year = {2011}, + address = {Portland, Oregon, USA}, + publisher = {Association for Computational Linguistics}, + pages = {142--150}, + url = {http://www.aclweb.org/anthology/P11-1015} +} + +@inproceedings{socher2013, + title = "Recursive Deep Models for Semantic Compositionality Over a Sentiment Treebank", + author = "Socher, Richard and Perelygin, Alex and Wu, Jean and Chuang, Jason and Manning, Christopher D. and Ng, Andrew and Potts, Christopher", + booktitle = "Proceedings of the 2013 Conference on Empirical Methods in Natural Language Processing", + month = oct, + year = "2013", + address = "Seattle, Washington, USA", + publisher = "Association for Computational Linguistics", + url = "https://www.aclweb.org/anthology/D13-1170", + pages = "1631--1642", +} + +@article{lim2018chemical, + title={Chemical--gene relation extraction using recursive neural network}, + author={Lim, Sangrak and Kang, Jaewoo}, + journal={Database}, + volume={2018}, + year={2018}, + publisher={Oxford Academic} +} + +@inproceedings{li2007scalable, + title={Scalable term selection for text categorization}, + author={Li, Jingyang and Sun, Maosong}, + booktitle={Proceedings of the 2007 Joint Conference on Empirical Methods in Natural Language Processing and Computational Natural Language Learning (EMNLP-CoNLL)}, + pages={774--782}, + year={2007} +} + +@misc{lee2019biobert, + title={BioBERT: a pre-trained biomedical language representation model for biomedical text mining}, + author={Jinhyuk Lee and Wonjin Yoon and Sungdong Kim and Donghyeon Kim and Sunkyu Kim and Chan Ho So and Jaewoo Kang}, + year={2019}, + eprint={1901.08746}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} + +@misc{shin2020biomegatron, + title={BioMegatron: Larger Biomedical Domain Language Model}, + author={Hoo-Chang Shin and Yang Zhang and Evelina Bakhturina and Raul Puri and Mostofa Patwary and Mohammad Shoeybi and Raghav Mani}, + year={2020}, + eprint={2010.06060}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} + +@article{vaswani2017attention, + title={Attention is all you need}, + author={Vaswani, Ashish and Shazeer, Noam and Parmar, Niki and Uszkoreit, Jakob and Jones, Llion and Gomez, Aidan N and Kaiser, Lukasz and Polosukhin, Illia}, + journal={arXiv preprint arXiv:1706.03762}, + year={2017} +} + +@article{sennrich2015neural, + title={Neural machine translation of rare words with subword units}, + author={Sennrich, Rico and Haddow, Barry and Birch, Alexandra}, + journal={arXiv preprint arXiv:1508.07909}, + year={2015} +} + +@article{provilkov2019bpe, + title={Bpe-dropout: Simple and effective subword regularization}, + author={Provilkov, Ivan and Emelianenko, Dmitrii and Voita, Elena}, + journal={arXiv preprint arXiv:1910.13267}, + year={2019} +} + +@article{post2018call, + title={A call for clarity in reporting BLEU scores}, + author={Post, Matt}, + journal={arXiv preprint arXiv:1804.08771}, + year={2018} +} + +@misc{zhang2021sgdqa, + title={SGD-QA: Fast Schema-Guided Dialogue State Tracking for Unseen Services}, + author={Yang Zhang and Vahid Noroozi and Evelina Bakhturina and Boris Ginsburg}, + year={2021}, + eprint={2105.08049}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/nlp_model.rst b/tts/NeMo/docs/source/nlp/nlp_model.rst new file mode 100755 index 0000000..8c47518 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/nlp_model.rst @@ -0,0 +1,43 @@ +.. _nlp_model: + +Model NLP +========= + +The config file for NLP models contain three main sections: + + - ``trainer``: contains the configs for PTL training. For more information, refer to :doc:`../core/core` and `PTL Trainer class API '. + - ``exp_manager``: the configs of the experiment manager. For more information, refer to :doc:`../core/core`. + - ``model``: contains the configs of the datasets, model architecture, tokenizer, optimizer, scheduler, etc. + +The following sub-sections of the model section are shared among most of the NLP models. + + - ``tokenizer``: specifies the tokenizer + - ``language_model``: specifies the underlying model to be used as the encoder + - ``optim``: the configs of the optimizer and scheduler :doc:`../core/core` + +The ``tokenizer`` and ``language_model`` sections have the following parameters: + ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.tokenizer.tokenizer_name** | string | Tokenizer name will be filled automatically based on ``model.language_model.pretrained_model_name``. | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.tokenizer.vocab_file** | string | Path to tokenizer vocabulary. | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.tokenizer.tokenizer_model** | string | Path to tokenizer model (only for sentencepiece tokenizer). | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.language_model.pretrained_model_name** | string | Pre-trained language model name, for example: ``bert-base-cased`` or ``bert-base-uncased``. | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.language_model.lm_checkpoint** | string | Path to the pre-trained language model checkpoint. | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.language_model.config_file** | string | Path to the pre-trained language model config file. | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.language_model.config** | dictionary | Config of the pre-trained language model. | ++------------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +The parameter **model.language_model.pretrained_model_name** can be one of the following: + + - ``megatron-bert-345m-uncased``, ``megatron-bert-345m-cased``, ``biomegatron-bert-345m-uncased``, ``biomegatron-bert-345m-cased``, ``bert-base-uncased``, ``bert-large-uncased``, ``bert-base-cased``, ``bert-large-cased`` + - ``distilbert-base-uncased``, ``distilbert-base-cased`` + - ``roberta-base``, ``roberta-large``, ``distilroberta-base`` + - ``albert-base-v1``, ``albert-large-v1``, ``albert-xlarge-v1``, ``albert-xxlarge-v1``, ``albert-base-v2``, ``albert-large-v2``, ``albert-xlarge-v2``, ``albert-xxlarge-v2`` diff --git a/tts/NeMo/docs/source/nlp/punctuation_and_capitalization.rst b/tts/NeMo/docs/source/nlp/punctuation_and_capitalization.rst new file mode 100755 index 0000000..4cce7b3 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/punctuation_and_capitalization.rst @@ -0,0 +1,300 @@ +.. _punctuation_and_capitalization: + +Punctuation and Capitalization Model +==================================== + +Automatic Speech Recognition (ASR) systems typically generate text with no punctuation and capitalization of the words. +There are two issues with non-punctuated ASR output: + +- it could be difficult to read and understand +- models for some downstream tasks, such as named entity recognition, machine translation, or text-to-speech, are usually trained +on punctuated datasets and using raw ASR output as the input to these models could deteriorate their performance + +Quick Start Guide +----------------- + +.. code-block:: python + + from nemo.collections.nlp.models import PunctuationCapitalizationModel + + # to get the list of pre-trained models + PunctuationCapitalizationModel.list_available_models() + + # Download and load the pre-trained BERT-based model + model = PunctuationCapitalizationModel.from_pretrained("punctuation_en_bert") + + # try the model on a few examples + model.add_punctuation_capitalization(['how are you', 'great how about you']) + +Model Description +----------------- + +For each word in the input text, the Punctuation and Capitalization model: + +- predicts a punctuation mark that should follow the word (if any). By default, the model supports commas, periods, and question marks. +- predicts if the word should be capitalized or not + +In the Punctuation and Capitalization model, we are jointly training two token-level classifiers on top of a pre-trained +language model, such as `BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding `__ :cite:`nlp-punct-devlin2018bert`. + +.. note:: + + We recommend you try this model in a Jupyter notebook (run on `Google's Colab `_.): `NeMo/tutorials/nlp/Punctuation_and_Capitalization.ipynb `__. + + Connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for the hardware accelerator). + + An example script on how to train the model can be found at: `NeMo/examples/nlp/token_classification/punctuation_capitalization_train.py `__. + + An example script on how to run evaluation and inference can be found at: `NeMo/examples/nlp/token_classification/punctuation_capitalization_evaluate.py `__. + + The default configuration file for the model can be found at: `NeMo/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml `__. + +.. _raw_data_format_punct: + +Raw Data Format +--------------- + +The Punctuation and Capitalization model can work with any text dataset, although it is recommended to balance the data, especially +for the punctuation task. Before pre-processing the data to the format expected by the model, the data should be split into ``train.txt`` +and ``dev.txt`` (and optionally ``test.txt``). Each line in the ``train.txt/dev.txt/test.txt`` should represent one or more full +and/or truncated sentences. + +Example of the ``train.txt``/``dev.txt`` file: + +.. code:: + + When is the next flight to New York? + The next flight is ... + .... + + +The ``source_data_dir`` structure should look similar to the following: + +.. code:: + + . + |--sourced_data_dir + |-- dev.txt + |-- train.txt + +NeMo Data Format +---------------- + +The Punctuation and Capitalization model expects the data in the following format: + +The training and evaluation data is divided into 2 files: +- ``text.txt`` +- ``labels.txt`` + +Each line of the ``text.txt`` file contains text sequences, where words are separated with spaces. + +[WORD] [SPACE] [WORD] [SPACE] [WORD], for example: + + :: + + when is the next flight to new york + the next flight is ... + ... + +The ``labels.txt`` file contains corresponding labels for each word in ``text.txt``, the labels are separated with spaces. +Each label in ``labels.txt`` file consists of 2 symbols: + +- the first symbol of the label indicates what punctuation mark should follow the word (where ``O`` means no punctuation needed) +- the second symbol determines if a word needs to be capitalized or not (where ``U`` indicates that the word should be upper cased, +and ``O`` - no capitalization needed) + +By default, the following punctuation marks are considered: commas, periods, and question marks; the remaining punctuation marks were +removed from the data. This can be changed by introducing new labels in the ``labels.txt`` files. + +Each line of the ``labels.txt`` should follow the format: ``[LABEL] [SPACE] [LABEL] [SPACE] [LABEL]`` (for ``labels.txt``). For example, +labels for the above ``text.txt`` file should be: + + :: + + OU OO OO OO OO OO OU ?U + OU OO OO OO ... + ... + +The complete list of all possible labels used in this tutorial are: + +- ``OO`` +- ``O`` +- ``.O`` +- ``?O`` +- ``OU`` +- +- ``U`` +- ``.U`` +- ``?U`` + +Converting Raw Data to NeMo Format +---------------------------------- + +To pre-process the raw text data, stored under :code:`sourced_data_dir` (see the :ref:`raw_data_format_punct` +section), run the following command: + +.. code:: + + python examples/nlp/token_classification/data/prepare_data_for_punctuation_capitalization.py \ + -s + -o + + +Required Argument for Dataset Conversion +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`-s` or :code:`--source_file`: path to the raw file +- :code:`-o` or :code:`--output_dir` - path to the directory to store the converted files + +After the conversion, the :code:`output_dir` should contain :code:`labels_*.txt` and :code:`text_*.txt` files. The default names +for the training and evaluation in the :code:`conf/punctuation_capitalization_config.yaml` are the following: + +.. code:: + + . + |--output_dir + |-- labels_dev.txt + |-- labels_train.txt + |-- text_dev.txt + |-- text_train.txt + +Training Punctuation and Capitalization Model +--------------------------------------------- + +The language model is initialized with the pre-trained model from `HuggingFace Transformers `__, +unless the user provides a pre-trained checkpoint for the language model. Example of model configuration file for training the model can be found at: `NeMo/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml `__. + +The specification is roughly grouped into the following categories: + +- Parameters that describe the training process: **trainer** +- Parameters that describe the datasets: **model.dataset**, **model.train_ds**, **model.validation_ds** +- Parameters that describe the model: **model** + +More details about parameters in the config file can be found below and in the `model's config file `__: + ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **pretrained_model** | string | Path to the pre-trained model ``.nemo`` file or pre-trained model name. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.dataset.data_dir** | string | Path to the data converted to the specified above format. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.punct_head.punct_num_fc_layers** | integer | Number of fully connected layers. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.punct_head.fc_dropout** | float | Activation to use between fully connected layers. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.punct_head.activation** | string | Dropout to apply to the input hidden states. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.punct_head.use_transrormer_init** | bool | Whether to initialize the weights of the classifier head with the same approach used in Transformer. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.capit_head.punct_num_fc_layers** | integer | Number of fully connected layers. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.capit_head.fc_dropout** | float | Dropout to apply to the input hidden states. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.capit_head.activation** | string | Activation function to use between fully connected layers. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.capit_head.use_transrormer_init** | bool | Whether to initialize the weights of the classifier head with the same approach used in Transformer. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.text_file** | string | Name of the text training file located at ``data_dir``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.labels_file** | string | Name of the labels training file located at ``data_dir``, such as ``labels_train.txt``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.num_samples** | integer | Number of samples to use from the training dataset, ``-1`` - to use all. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.text_file** | string | Name of the text file for evaluation, located at ``data_dir``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.labels_file** | string | Name of the labels dev file located at ``data_dir``, such as ``labels_dev.txt``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.num_samples** | integer | Number of samples to use from the dev set, ``-1`` - to use all. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +For more information, refer to the :ref:`nlp_model` section. + +To train the model from scratch, run: + +.. code:: + + python examples/nlp/token_classification/punctuation_and_capitalization_train.py \ + model.dataset.data_dir= \ + trainer.gpus=[0,1] \ + optim.name=adam \ + optim.lr=0.0001 + +The above command will start model training on GPUs 0 and 1 with Adam optimizer and learning rate of 0.0001; and the trained model is +stored in the ``nemo_experiments/Punctuation_and_Capitalization`` folder. + +To train from the pre-trained model, run: + +.. code:: + + python examples/nlp/token_classification/punctuation_and_capitalization_train.py \ + model.dataset.data_dir= \ + pretrained_model= + + +Required Arguments for Training +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* :code:`model.dataset.data_dir`: Path to the `data_dir` with the pre-processed data files. + + +.. note:: + + All parameters defined in the configuration file can be changed with command arguments. For example, the sample config file + mentioned above has :code:`validation_ds.batch_size` set to ``64``. However, if you see that the GPU utilization can be + optimized further by using a larger batch size, you may override to the desired value by adding the field :code:`validation_ds.batch_size=128` + over the command-line. You can repeat this with any of the parameters defined in the sample configuration file. + +Inference +--------- + +An example script on how to run inference on a few examples, can be found at `examples/nlp/token_classification/punctuation_capitalization_evaluate.py `_. + +To start inference with a pre-trained model on a few examples, run: + +.. code:: + + python punctuation_capitalization_evaluate.py \ + pretrained_model= + + +Model Evaluation +---------------- + +An example script on how to evaluate the pre-trained model, can be found at `examples/nlp/token_classification/punctuation_capitalization_evaluate.py `_. + +To start evaluation of the pre-trained model, run: + +.. code:: + + python punctuation_capitalization_evaluate.py \ + model.dataset.data_dir= \ + pretrained_model=punctuation_en_bert \ + model.test_ds.text_file= \ + model.test_ds.labels_file= + + +Required Arguments +^^^^^^^^^^^^^^^^^^ + +- :code:`pretrained_model`: pretrained Punctuation and Capitalization model from ``list_available_models()`` or path to a ``.nemo`` +file. For example: ``punctuation_en_bert`` or ``your_model.nemo``. +- :code:`model.dataset.data_dir`: path to the directory that containes :code:`model.test_ds.text_file` and :code:`model.test_ds.labels_file` + +During evaluation of the :code:`test_ds`, the script generates two classification reports: one for capitalization task and another +one for punctuation task. This classification reports include the following metrics: + +- :code:`Precision` +- :code:`Recall` +- :code:`F1` + +More details about these metrics can be found `here `__. + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-PUNCT + :keyprefix: nlp-punct- + diff --git a/tts/NeMo/docs/source/nlp/question_answering.rst b/tts/NeMo/docs/source/nlp/question_answering.rst new file mode 100644 index 0000000..567be7d --- /dev/null +++ b/tts/NeMo/docs/source/nlp/question_answering.rst @@ -0,0 +1,300 @@ +.. _question_answering: + +Question Answering model +======================== + +With Question Answering, or Reading Comprehension, given a question and a passage of content (context) that may contain an answer for +the question, the model predicts the span within the text with a start and end position indicating the answer to the question. For +datasets like SQuAD 2.0, this model supports cases when the answer is not contained in the content. + +For every word in the context of a given question, the model is trained to predict: + +- The likelihood this word is the start of the span. +- The likelihood this word is the end of the span. + +The model chooses the start and end words with maximal probabilities. When the content does not contain the answer, we would like the +start and end span to be set for the first token. + +A pretrained BERT encoder with two span prediction heads is used for the prediction start and the end position of the answer. The span +predictions are token classifiers consisting of a single linear layer. + +Quick Start Guide +----------------- + +.. code-block:: python + + from nemo.collections.nlp.models import QAModel + + # to get the list of pre-trained models + QAModel.list_available_models() + + # Download and load the pre-trained BERT-based model + model = QAModel.from_pretrained("qa_squadv1.1_bertbase") + + # try the model on a few examples + model.inference(test_file) + + +.. note:: + + We recommend you try Question Answering model in a Jupyter notebook (can run on `Google's Colab `_.): + `NeMo/tutorials/nlp/Question_Answering_Squad.ipynb `__. + + Connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for the hardware accelerator). + + An example script on how to train and evaluate the model can be found here: `NeMo/examples/nlp/question_answering/question_answering_squad.py `__. + + The default configuration file for the model can be found at: `NeMo/examples/nlp/question_answering/conf/question_answering_squad.yaml `__. + + + +Available models +^^^^^^^^^^^^^^^^ + +.. list-table:: *Pretrained Models* + :widths: 5 10 + :header-rows: 1 + + * - Model + - Pretrained Checkpoint + * - qa_squadv1.1_bertbase + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv1_1_bertbase + * - qa_squadv2.0_bertbase + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv2_0_bertbase + * - qa_squadv1.1_bertlarge + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv1_1_bertlarge + * - qa_squadv2.0_bertlarge + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv2_0_bertlarge + * - qa_squadv1.1_megatron_cased + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv1_1_megatron_cased + * - qa_squadv2.0_megatron_cased + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv2_0_megatron_cased + * - qa_squadv1.1_megatron_uncased + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv1_1_megatron_uncased + * - qa_squadv2.0_megatron_uncased + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:qa_squadv2_0_megatron_uncased + + +.. _dataset_question_answering: + +Data Format +----------- + +This model expects the dataset in `SQuAD format`_ (i.e., a JSON file for each dataset split). The code snippet below shows an example +of the training file. Each title has one or multiple paragraph entries, each consisting of the "context" and question-answer entries. +Each question-answer entry has: + +- A question +- A globally unique id +- The Boolean flag ``is_impossible``, which shows whether a question is answerable or not: + - if the question is answerable, one answer entry contains the text span and its starting character index in the context + - if the question is not answerable, an empty ``answers`` list is provided + +.. _SQuAD format: https://rajpurkar.github.io/SQuAD-explorer/ + +The evaluation files (for validation and testing) follow the above format, except that it can provide more than one answer to the +same question. The inference file also follows the above format, except that it does not require the ``answers`` and ``is_impossible`` +keywords. + +The following is an example of the data format (JSON file): + +.. code:: + + { + "data": [ + { + "title": "Super_Bowl_50", + "paragraphs": [ + { + "context": "Super Bowl 50 was an American football game to determine the champion of the National Football League (NFL) for the 2015 season. The American Football Conference (AFC) champion Denver Broncos defeated the National Football Conference (NFC) champion Carolina Panthers 24\u201310 to earn their third Super Bowl title. The game was played on February 7, 2016, at Levi's Stadium in the San Francisco Bay Area at Santa Clara, California. As this was the 50th Super Bowl, the league emphasized the \"golden anniversary\" with various gold-themed initiatives, as well as temporarily suspending the tradition of naming each Super Bowl game with Roman numerals (under which the game would have been known as \"Super Bowl L\"), so that the logo could prominently feature the Arabic numerals 50.", + "qas": [ + { + "question": "Where did Super Bowl 50 take place?", + "is_impossible": "false", + "id": "56be4db0acb8001400a502ee", + "answers": [ + { + "answer_start": "403", + "text": "Santa Clara, California" + } + ] + }, + { + "question": "What was the winning score of the Super Bowl 50?", + "is_impossible": "true", + "id": "56be4db0acb8001400a502ez", + "answers": [ + ] + } + ] + } + ] + } + ] + } + + +Dataset Download +---------------- + +To perform training of the Question Answering model on the SQuAD dataset, you must first download it from `here +`_ or run: + +.. code:: + + python get_squad.py + +There are two versions: + +- SQuAD version 1.1, which does not contain questions without the answer and has 100,000+ question-answer pairs on 500+ articles. +- SQuAD version 2.0, which combines the 100,000 questions from SQuAD 1.1 with over 50,000 unanswerable questions. To do well with + SQuAD 2.0, a system must not only answer questions when possible, but also determine when no answer is supported by the paragraph + and abstain from answering. + +After downloading the files, you should have a :code:`squad` data folder that contains the following four files for training and +evaluation: + +.. code:: + + . + |--squad + |-- v1.1/train-v1.1.json + |-- v1.1/dev-v1.1.json + |-- v2.0/train-v2.0.json + |-- v2.0/dev-v2.0.json + + +.. _model_training_question_answering: + +Model Training +-------------- + +In the Question Answering Model, we are training a span prediction head on top of a pre-trained language model, such as +`BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding `__ :cite:`nlp-qa-devlin2018bert`. +Unless the user provides a pre-trained checkpoint for the language model, the language model is initialized with the pre-trained model +from `HuggingFace Transformers `__. + +Example of model configuration file for training the model can be found at: `NeMo/examples/nlp/question_answering/conf/question_answering_squad_config.yaml `__. + +The specification can be grouped into three categories: + +- Parameters that describe the training process: **trainer** +- Parameters that describe the datasets: **model.dataset**, **model.train_ds**, **model.validation_ds**, **model.test_ds** +- Parameters that describe the model: **model** + +More details about parameters in the spec file can be found below: + ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **pretrained_model** | string | Pretrained QA model model from ``list_available_models()`` or path to a ``.nemo`` file. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **do_training** | bool | If ``true``, starts training, otherwise, skips training and continues with evaluation/inference. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.dataset.version_2_with_negative** | bool | Set to ``true`` to allow examples without an answer, e.g. for SQuAD v2.0. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.dataset.do_lower_case** | bool | If ``true``, converts text to lower case, only import for inference/evaluation. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.dataset.use_cache** | bool | If ``true``, either loads all preprocessed data from cache or saves preprocessed data for future use. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.file** | string | The training file path. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.num_samples** | integer | The number of samples to use from the training dataset (use ``-1`` to specify all samples). | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.file** | string | The validation file path. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.num_samples** | integer | The number of samples to use from the validation dataset (use ``-1`` to specify all samples). | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **test_ds.file** | string | The test file path (optional). | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **test_ds.num_samples** | integer | The number of samples to use from the test dataset (use ``-1`` to specify all samples). | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +Example of the command for training the model: + +.. code:: + + python question_answering_squad.py \ + model.train_ds.file= \ + model.validation_ds.file= \ + model.dataset.version_2_with_negative= \ + model.dataset.do_lower_case= \ + trainer.max_epochs= \ + trainer.gpus=[] + +.. Note:: + + The first time you train, it will take an extra 5-10 minutes to process the dataset. For future training runs, it will use the + processed dataset if :code:`model.dataset.use_cache=true`, which is automatically cached in the files in the same directory as + the data. + +Required Arguments for Training +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`model.train_ds.file`: path to the training file in JSON format +- :code:`model.validation_ds.file`: path to the validation file in JSON format + +Fine-tuning Procedure +^^^^^^^^^^^^^^^^^^^^^ + +Fine-tuning procedure and logs look similar to what's described in the Model Training section, with the addition of the model +that is initially loaded from a previously trained checkpoint, e.g. by specifying :code:`pretrained_model=`. + +Inference +--------- + +An example script on how to run inference can be found at `examples/nlp/question_answering/question_answering_squad.py `_. + +To run inference with the pre-trained model, run: + +.. code:: + + python question_answering_squad.py \ + pretrained_model= \ + model.dataset.version_2_with_negative= \ + model.dataset.do_lower_case= \ + do_training=false \ + model.validation_ds.file= + +Required Arguments for inference: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`pretrained_model`: pretrained QA Model model from ``list_available_models()`` or path to a ``.nemo`` file + +Model Evaluation +---------------- + +An example script on how to evaluate the pre-trained model, can be found at `examples/nlp/question_answering/question_answering_squad.py `_. + +To run evaluation of the pre-trained model, run: + +.. code:: + + python question_answering_squad.py \ + pretrained_model= \ + model.dataset.version_2_with_negative= \ + model.dataset.do_lower_case= \ + do_training=false \ + model.test_ds.file= + + +Required Arguments: +^^^^^^^^^^^^^^^^^^^ + +- :code:`pretrained_model`: pretrained QA model from `list_available_models()`` or path to a ``.nemo`` file +- :code:`model.test_ds.file`: path to test file + +During evaluation of the :code:`test_ds`, the script generates the following metrics: + +- :code:`Exact Match (EM)` +- :code:`F1` + +More details about these metrics can be found `here `__. + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-QA + :keyprefix: nlp-qa- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/sgd_qa.rst b/tts/NeMo/docs/source/nlp/sgd_qa.rst new file mode 100644 index 0000000..351ffe5 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/sgd_qa.rst @@ -0,0 +1,17 @@ +.. _sgd_qa: + +Dialogue State Tracking - SGD-QA Model +====================================== + +More details can be found in the paper +`SGD-QA: Fast Schema-Guided Dialogue State Tracking for Unseen Services `__ :cite:`nlp-sgdqa-zhang2021sgdqa`. +An example script on how to train the model can be found here: `NeMo/examples/nlp/dialogue_state_tracking/sgd_qa.py `__. + + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-SGDQA + :keyprefix: nlp-sgdqa- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nlp/text_classification.rst b/tts/NeMo/docs/source/nlp/text_classification.rst new file mode 100644 index 0000000..ea90c85 --- /dev/null +++ b/tts/NeMo/docs/source/nlp/text_classification.rst @@ -0,0 +1,169 @@ +.. _text_classification: + +Text Classification model +========================= + +Text Classification is a sequence classification model based on BERT-based encoders. It can be used for a +variety of tasks like text classification, sentiment analysis, domain/intent detection for dialogue systems, etc. +The model takes a text input and predicts a label/class for the whole sequence. Megatron-LM and most of the BERT-based encoders +supported by HuggingFace including BERT, RoBERTa, and DistilBERT. + +An example script on how to train the model can be found here: `NeMo/examples/nlp/text_classification/text_classification_with_bert.py `__. +The default configuration file for the model can be found at: `NeMo/examples/nlp/text_classification/conf/text_classification_config.yaml `__. + +There is also a Jupyter notebook which explains how to work with this model. We recommend you try this model in the Jupyter notebook (can run on `Google's Colab `_.): +`NeMo/tutorials/nlp/Text_Classification_Sentiment_Analysis.ipynb `__. +This tutorial shows an example of how run the Text Classification model on a sentiment analysis task. You may connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for the hardware accelerator) to run the notebook. + +Data Format +----------- + +The Text Classification model uses a simple text format as the dataset. It requires the data to be stored in TAB separated files +(``.tsv``) with two columns: sentence and label. Each line of the data file contains text sequences, where words are separated with spaces and the label is separated with ``[TAB]``, i.e.: + +.. code:: + + [WORD][SPACE][WORD][SPACE][WORD][TAB][LABEL] + +Labels need to be integers starting from ``0``. Some examples taken from the SST2 dataset, which is a two-class dataset for sentiment analysis: + +.. code:: + + saw how bad this movie was 0 + lend some dignity to a dumb story 0 + the greatest musicians 1 + +You may need separate files for train, validation, and test with this format. + +Dataset Conversion +------------------ + +If your dataset is stored in another format, you need to convert it to NeMo's format to use this model. There are some conversion +scripts available for the following datasets: + +- SST2 :cite:`nlp-textclassify-socher2013` +- IMDB :cite:`nlp-textclassify-maas2011` +- ChemProt :cite:`nlp-textclassify-lim2018chemical` +- THUCnews :cite:`nlp-textclassify-li2007scalable` + +You can convert them from their original format to NeMo's format. To convert the original datasets to NeMo's format, use the ``examples/text_classification/data/import_datasets.py`` script: + +.. code:: python + + python import_datasets.py \ + --dataset_name DATASET_NAME \ + --target_data_dir TARGET_PATH \ + --source_data_dir SOURCE_PATH + +It reads the dataset specified by ``DATASET_NAME`` from ``SOURCE_PATH`` and converts it to NeMo's format. It then saves the new +dataset at ``TARGET_PATH``. + +Arguments: + +- ``dataset_name``: name of the dataset to convert (``sst-2``, ``chemprot``, ``imdb``, and ``thucnews`` are currently supported) +- ``source_data_dir``: directory of your dataset +- ``target_data_dir``: directory to save the converted dataset + +After the conversion, the ``TARGET_PATH`` should contain the following files: + +.. code:: + + . + |--TARGET_PATH + |-- train.tsv + |-- dev.tsv + |-- test.tsv + +Some datasets do not have the test set or their test set does not have any labels, therefore, the corresponding file may be missing. + +Model Training +-------------- + +You may find an example of a config file to be used for training of the Text Classification model at `NeMo/examples/nlp/text_classification/conf/text_classification_config.yaml `__. +You can change any of these parameters directly from the config file or update them with the command-line arguments. + +The config file of the Text Classification model contains three main sections of ``trainer``, ``exp_manager``, and ``model``. You can +find more details about the ``trainer`` and ``exp_manager`` at :doc:`./nlp_model`. Some sub-sections of the model section including +``tokenizer``, ``language_model``, and ``optim`` are shared among most of the NLP models. The details of these sections can be found +at :doc:`./nlp_model`. + +Example of a command for training a Text Classification model on two GPUs for 50 epochs: + +.. code:: + + python examples/nlp/text_classification/text_classification_with_bert.py \ + model.training_ds.file_path= \ + model.validation_ds.file_path= \ + trainer.max_epochs=50 \ + trainer.gpus=[0,1] \ + optim.name=adam \ + optim.lr=0.0001 \ + model.nemo_path= + +At the start of each training experiment, there is a printed log of the experiment specification including any parameters added or +overridden via the command-line. It also shows additional information, such as which GPUs are available, where logs are saved, +and some samples from the datasets with their corresponding inputs to the model. It also provides some stats on the lengths of +sequences in the dataset. + +After each epoch, you should see a summary table of metrics on the validation set which include the following metrics: + +- :code:`Precision` +- :code:`Recall` +- :code:`F1` + +At the end of training, NeMo saves the last checkpoint at the path specified by ``NEMO_FILE_PATH`` in ``.nemo`` format. + +Model Arguments +^^^^^^^^^^^^^^^ + +The following table lists some of the model's parameters you can use in the config files or set them from the command-line when +training a model: + ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Default** | **Description** | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.class_labels.class_labels_file** | string | ``null`` | Path to an optional file containing the labels; each line is the string label corresponding to a label. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.dataset.num_classes** | int | ``Required`` | Number of the categories or classes, ``0`` < ``Label`` < ``num_classes``. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.dataset.do_lower_case** | boolean | ``true`` for uncased models, ``false`` for cased | Specifies if inputs should be made lower case, would be set automatically if pre-trained model is used. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.dataset.max_seq_length** | int | ``256`` | Maximum length of the input sequences. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.dataset.class_balancing** | string | ``null`` | ``null`` or ``weighted_loss``. ``weighted_loss`` enables the weighted class balancing to handle unbalanced classes. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.dataset.use_cache** | boolean | ``false`` | Uses a cache to store the processed dataset, you can use it for large datasets for speed up. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.classifier_head.num_output_layers** | integer | ``2`` | Number of fully connected layers of the classifier on top of the BERT model. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **model.classifier_head.fc_dropout** | float | ``0.1`` | Dropout ratio of the fully connected layers. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.file_path** | string | ``Required`` | Path of the training ``.tsv`` file. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.batch_size** | integer | ``32`` | Data loader's batch size. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.num_workers** | integer | ``2`` | Number of worker threads for data loader. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.shuffle** | boolean | ``true`` (training), ``false`` (test and validation) | Shuffles data for each epoch. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.drop_last** | boolean | ``false`` | Specifies if last batch of data needs to get dropped if it is smaller than batch size. | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.pin_memory** | boolean | ``false`` | Enables pin_memory of PyTorch's data loader to enhance speed | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| **{training,validation,test}_ds.num_samples** | integer | ``-1`` | Number of samples to be used from the dataset; -1 means all samples | ++-----------------------------------------------+-----------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ + + +Model Evaluation and Inference +------------------------------ + +After saving the model in ``.nemo`` format, you can load the model and perform evaluation or inference on the model. You can find +some examples in the example script: `NeMo/examples/nlp/text_classification/text_classification_with_bert.py `__. + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-TEXTCLASSIFY + :keyprefix: nlp-textclassify- diff --git a/tts/NeMo/docs/source/nlp/token_classification.rst b/tts/NeMo/docs/source/nlp/token_classification.rst new file mode 100755 index 0000000..cab12ed --- /dev/null +++ b/tts/NeMo/docs/source/nlp/token_classification.rst @@ -0,0 +1,219 @@ +.. _token_classification: + +Token Classification (Named Entity Recognition) Model +===================================================== + +Token Classification model supports named entity recognition (NER) and other token level classification tasks, as long as the data +follows the format specified below. + +We're going to use NER task throughout this section. NER, also referred to as entity chunking, identification or extraction, is the +task of detecting and classifying key information (entities) in text. In other words, a NER model takes a piece of text as input and +for each word in the text, the model identifies a category the word belongs to. For example, in a sentence: ``Mary lives in Santa Clara +and works at NVIDIA``, the model should detect that ``Mary`` is a person, ``Santa Clara`` is a location and ``NVIDIA`` is a company. + +Quick Start Guide +----------------- + +.. code-block:: python + + from nemo.collections.nlp.models import TokenClassificationModel + + # to get the list of pre-trained models + TokenClassificationModel.list_available_models() + + # Download and load the pre-trained BERT-based model + model = TokenClassificationModel.from_pretrained("ner_en_bert") + + # try the model on a few examples + model.add_predictions(['we bought four shirts from the nvidia gear store in santa clara.', 'NVIDIA is a company.']) + +.. note:: + + We recommend you try this model in a Jupyter notebook (run on `Google's Colab `_.): + `NeMo/tutorials/nlp/Token_Classification_Named_Entity_Recognition.ipynb `__. + + Connect to an instance with a GPU (**Runtime** -> **Change runtime type** -> select **GPU** for the hardware accelerator). + + An example script on how to train the model can be found here: `NeMo/examples/nlp/token_classification/token_classification_train.py `__. + + An example script on how to run evaluation and inference can be found here: `NeMo/examples/nlp/token_classification/token_classification_evaluate.py `__. + + The default configuration file for the model can be found here: `NeMo/examples/nlp/token_classification/conf/token_classification_config.yaml `__. + +.. _dataset_token_classification: + +Data Input for Token Classification Model +----------------------------------------- + +For pre-training or fine-tuning of the model, the data should be split into 2 files: + +- ``text.txt`` +- ``labels.txt`` + +Each line of the ``text.txt`` file contains text sequences, where words are separated with spaces, i.e.: ``[WORD] [SPACE] [WORD] [SPACE] [WORD]``. +The ``labels.txt`` file contains corresponding labels for each word in ``text.txt``, the labels are separated with spaces, i.e.: ``[LABEL] [SPACE] [LABEL] [SPACE] [LABEL]``. +Example of a ``text.txt`` file: + + Jennifer is from New York City . + She likes ... + ... + +Corresponding ``labels.txt`` file: + + B-PER O O B-LOC I-LOC I-LOC O + O O ... + ... + +Dataset Conversion +------------------ + +To convert an `IOB format `__ (short for inside, outside, beginning) data to the format required for training, use +`examples/nlp/token_classification/data/import_from_iob_format.py `_. + +.. code:: + + # For conversion from IOB format, for example, for CoNLL-2003 dataset: + python import_from_iob_format.py --data_file= + +Convert Dataset Required Arguments +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`--data_file`: path to the file to convert from IOB to NeMo format + +After running the above command, the data directory, where the :code:`--data_file` is stored, should contain :code:`text_*.txt` and :code:`labels_*.txt` files. +The default names for the training and evaluation in the :code:`conf/token_classification_config.yaml` are the following: + +.. code:: + + . + |--data_dir + |-- labels_dev.txt + |-- labels_train.txt + |-- text_dev.txt + |-- text_train.txt + + +Training The Token Classification model +--------------------------------------- + +In the Token Classification model, we are jointly training a classifier on top of a pre-trained language model, such as +`BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding `__ :cite:`nlp-ner-devlin2018bert`. +Unless the user provides a pre-trained checkpoint for the language model, the language model is initialized with the pre-trained model +from `HuggingFace Transformers `__. + +Example of model configuration file for training the model can be found at: `NeMo/examples/nlp/token_classification/conf/token_classification_config.yaml `__. + +The specification can be roughly grouped into three categories: + +- Parameters that describe the training process: **trainer** +- Parameters that describe the datasets: **model.dataset**, **model.train_ds**, **model.validation_ds** +- Parameters that describe the model: **model** + +More details about parameters in the spec file can be found below: + ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Data Type** | **Description** | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.dataset.data_dir** | string | Path to the data converted to the specified above format. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.head.num_fc_layers** | integer | Number of fully connected layers. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.head.fc_dropout** | float | Dropout to apply to the input hidden states. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.head.activation** | string | Activation to use between fully connected layers. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **model.punct_head.use_transrormer_init** | bool | Whether to initialize the weights of the classifier head with the same approach used in Transformer. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.text_file** | string | Name of the text training file located at ``data_dir``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.labels_file** | string | Name of the labels training file located at ``data_dir``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **training_ds.num_samples** | integer | Number of samples to use from the training dataset, ``-1`` - to use all. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.text_file** | string | Name of the text file for evaluation, located at ``data_dir``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.labels_file** | string | Name of the labels dev file located at ``data_dir``. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ +| **validation_ds.num_samples** | integer | Number of samples to use from the dev set, ``-1`` - to use all. | ++-------------------------------------------+-----------------+--------------------------------------------------------------------------------------------------------------+ + +For more information, see :ref:`nlp_model`. + +Example of the command for training the model: + +.. code:: + + python token_classification_train.py \ + model.dataset.data_dir= \ + trainer.max_epochs= \ + trainer.gpus=[] + + +Required Arguments for Training +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`model.dataset.data_dir`: path to the directory with pre-processed data. + +.. note:: + + While the arguments are defined in the spec file, if you want to override these parameter definitions in the spec file and + experiment with them, use the command-line to define the parameter. For example, the sample spec file mentioned above has + :code:`validation_ds.batch_size` set to ``64``. However, if the GPU utilization can be optimized further by + using a larger batch size, override it to the desired value by adding the field :code:`validation_ds.batch_size=128` from + the command-line. You can repeat this with any of the parameters defined in the sample spec file. + +Inference +--------- + +An example script on how to run inference can be found at `examples/nlp/token_classification/token_classification_evaluate.py `_. + +To run inference with the pre-trained model, run: + +.. code:: + + python token_classification_evaluate.py \ + pretrained_model= + +Required Arguments for Inference +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :code:`pretrained_model`: pretrained Token Classification model from ``list_available_models()`` or path to a ``.nemo`` file. For example, ``ner_en_bert`` or ``your_model.nemo`` + +Model Evaluation +---------------- + +An example script on how to evaluate the pre-trained model can be found at `examples/nlp/token_classification/token_classification_evaluate.py `_. + +To start evaluation of the pre-trained model, run: + +.. code:: + + python token_classification_evaluate.py \ + model.dataset.data_dir= \ + pretrained_model=ner_en_bert \ + model.test_ds.text_file= \ + model.test_ds.labels_file= \ + model.dataset.max_seq_length=512 + + +Required Arguments +^^^^^^^^^^^^^^^^^^ + +- :code:`pretrained_model`: pretrained Token Classification model from ``list_available_models()`` or path to a ``.nemo`` file. For example, ``ner_en_bert`` or ``your_model.nemo`` +- :code:`model.dataset.data_dir`: path to the directory that containes :code:`model.test_ds.text_file` and :code:`model.test_ds.labels_file` + +During evaluation of the :code:`test_ds`, the script generates a classification report that includes the following metrics: + +- :code:`Precision` +- :code:`Recall` +- :code:`F1` + +For more information, see `here `__. + +References +---------- + +.. bibliography:: nlp_all.bib + :style: plain + :labelprefix: NLP-NER + :keyprefix: nlp-ner- \ No newline at end of file diff --git a/tts/NeMo/docs/source/nv_logo.png b/tts/NeMo/docs/source/nv_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e764a71852c6f4e22e150621aaf6e1d8b35183a8 GIT binary patch literal 109116 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

-Bu)ej8~;ac=ddSso-fDBvSgIF!}_28|QOWON|^ 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 So>i5C{21t(z-qM}(f`_ as well as +a `Docker container on NGC `_. It's assumed the user has +already installed NeMo by following the :ref:`quick-start-guide` instructions. + +The conversational AI pipeline consists of three major stages: + +- Automatic Speech Recognition (ASR) +- Natural Language Processing (NLP) or Natural Language Understanding (NLU) +- Text-to-Speech (TTS) or voice synthesis + +As you talk to a computer, the ASR phase converts the audio signal into text, the NLP stage interprets the question +and generates a smart response, and finally the TTS phase converts the text into speech signals to generate audio for +the user. The toolkit enables development and training of deep learning models involved in conversational AI and easily +chain them together. + +Why NeMo? +--------- + +Deep learning model development for conversational AI is complex. It involves defining, building, and training several +models in specific domains; experimenting several times to get high accuracy, fine tuning on multiple tasks and domain +specific data, ensuring training performance and making sure the models are ready for deployment to inference applications. +Neural modules are logical blocks of AI applications which take some typed inputs and produce certain typed outputs. By +separating a model into its essential components in a building block manner, NeMo helps researchers develop state-of-the-art +accuracy models for domain specific data faster and easier. + +Collections of modules for core tasks as well as specific to speech recognition, natural language, speech synthesis help +develop modular, flexible, and reusable pipelines. + +A neural module’s inputs/outputs have a neural type, that describes the semantics, the axis order and meaning, and the dimensions +of the input/output tensors. This typing allows neural modules to be safely chained together to build models for applications. + +NeMo can be used to train new models or perform transfer learning on existing pre-trained models. Pre-trained weights per module +(such as encoder, decoder) help accelerate model training for domain specific data. + +ASR, NLP and TTS pre-trained models are trained on multiple datasets (including some languages such as Mandarin) and optimized +for high accuracy. They can be used for transfer learning as well. + +NeMo supports developing models that work with Mandarin Chinese data. Tutorials help users train or fine tune models for +conversational AI with the Mandarin Chinese language. The export method provided in NeMo makes it easy to transform a trained +model into inference ready format for deployment. + +A key area of development in the toolkit is interoperability with other tools used by speech researchers. Data layer for Kaldi +compatibility is one such example. + +NeMo, PyTorch Lightning, And Hydra +---------------------------------- + +Conversational AI architectures are typically very large and require a lot of data and compute for training. NeMo uses +`Pytorch Lightning `_ for easy and performant multi-GPU/multi-node +mixed precision training. + +Pytorch Lightning is a high-performance PyTorch wrapper that organizes PyTorch code, scales model training, and reduces +boilerplate. PyTorch Lightning has two main components, the ``LightningModule`` and the Trainer. The ``LightningModule`` is +used to organize PyTorch code so that deep learning experiments can be easily understood and reproduced. The Pytorch Lightning +Trainer is then able to take the ``LightningModule`` and automate everything needed for deep learning training. + +NeMo models are LightningModules that come equipped with all supporting infrastructure for training and reproducibility. This +includes the deep learning model architecture, data preprocessing, optimizer, check-pointing and experiment logging. NeMo +models, like LightningModules, are also PyTorch modules and are fully compatible with the broader PyTorch ecosystem. Any NeMo +model can be taken and plugged into any PyTorch workflow. + +Configuring conversational AI applications is difficult due to the need to bring together many different Python libraries into +one end-to-end system. NeMo uses Hydra for configuring both NeMo models and the PyTorch Lightning Trainer. `Hydra `_ +is a flexible solution that makes it easy to configure all of these libraries from a configuration file or from the command-line. + +Every NeMo model has an example configuration file and a corresponding script that contains all configurations needed for training +to state-of-the-art accuracy. NeMo models have the same look and feel so that it is easy to do conversational AI research across +multiple domains. + +Using Optimized Pretrained Models With NeMo +------------------------------------------- + +`NVIDIA GPU Cloud (NGC) `_ is a software repository that has containers and models optimized +for deep learning. NGC hosts many conversational AI models developed with NeMo that have been trained to state-of-the-art accuracy +on large datasets. NeMo models on NGC can be automatically downloaded and used for transfer learning tasks. Pretrained models +are the quickest way to get started with conversational AI on your own data. NeMo has many `example scripts `_ +and `Jupyter Notebook tutorials `_ showing step-by-step how to fine-tune pretrained NeMo +models on your own domain-specific datasets. + +For BERT based models, the model weights provided are ready for +downstream NLU tasks. For speech models, it can be helpful to start with a pretrained model and then continue pretraining on your +own domain-specific data. Jasper and QuartzNet base model pretrained weights have been known to be very efficient when used as +base models. For an easy to follow guide on transfer learning and building domain specific ASR models, you can follow this `blog `_. +All pre-trained NeMo models can be found on the `NGC NeMo Collection `_. Everything needed to quickly get started +with NeMo ASR, NLP, and TTS models is there. + +Pre-trained models are packaged as a ``.nemo`` file and contain the PyTorch checkpoint along with everything needed to use the model. +NeMo models are trained to state-of-the-art accuracy and trained on multiple datasets so that they are robust to small differences +in data. NeMo contains a large variety of models such as speaker identification and Megatron BERT and the best models in speech and +language are constantly being added as they become available. NeMo is the premier toolkit for conversational AI model building and +training. + +For a list of supported models, refer to the :ref:`tutorials` section. + +ASR Guidance +------------ + +This section is to help guide your decision making by answering our most asked ASR questions. + +**Q: Is there a way to add domain specific vocabulary in NeMo? If so, how do I do that?** +A: QuartzNet and Jasper models are character-based. So pretrained models we provide for these two output lowercase English +letters and ‘. Users can re-retrain them on vocabulary with upper case letters and punctuation symbols. + +**Q: When training, there are “Reference” lines and “Decoded” lines that are printed out. It seems like the reference line should +be the “truth” line and the decoded line should be what the ASR is transcribing. Why do I see that even the reference lines do not +appear to be correct?** +A: Because our pre-trained models can only output lowercase letters and apostrophe, everything else is dropped. So the model will +transcribe 10 as ten. The best way forward is to prepare the training data first by transforming everything to lowercase and convert +the numbers from digit representation to word representation using a simple library such as `inflect `_. Then, add the uppercase letters +and punctuation back using the NLP punctuation model. Here is an example of how this is incorporated: `NeMo voice swap demo `_. + +**Q: What languages are supported in NeMo currently?** +A: Along with English, we provide pre-trained models for Zh, Es, Fr, De, Ru, It, Ca and Pl languages. +For more information, see `NeMo Speech Models `_. + +Data Augmentation +----------------- + +Data augmentation in ASR is invaluable. It comes at the cost of increased training time if samples are augmented during training +time. To save training time, it is recommended to pre-process the dataset offline for a one time preprocessing cost and then train +the dataset on this augmented training set. + +For example, processing a single sample involves: + +- Speed perturbation +- Time stretch perturbation (sample level) +- Noise perturbation +- Impulse perturbation +- Time stretch augmentation (batch level, neural module) + +A simple tutorial guides users on how to use these utilities provided in `GitHub: NeMo `_. + +Speech Data Explorer +-------------------- + +Speech data explorer is a `Dash-based tool `_ for interactive exploration of ASR/TTS datasets. + +Speech data explorer collects: + +- dataset statistics (alphabet, vocabulary, and duration-based histograms) +- navigation across datasets (sorting and filtering) +- inspections of individual utterances (waveform, spectrogram, and audio player) +- errors analysis (word error rate, character error rate, word match rate, mean word accuracy, and diff) + +In order to use the tool, it needs to be installed separately. Perform the steps `here `_ to install speech data explorer. + +Using Kaldi Formatted Data +-------------------------- + +The `Kaldi Speech Recognition Toolkit `_ project began in 2009 at `Johns Hopkins University `. It is a toolkit written in C++. If +researchers have used Kaldi and have datasets that are formatted to be used with the toolkit; they can use NeMo to develop models +based on that data. + +To load Kaldi-formatted data, you can simply use ``KaldiFeatureDataLayer`` instead of ``AudioToTextDataLayer``. The ``KaldiFeatureDataLayer`` +takes in the argument ``kaldi_dir`` instead of a ``manifest_filepath``. The ``manifest_filepath`` argument should be set to the directory +that contains the files ``feats.scp`` and ``text``. + +Using Speech Command Recognition Task For ASR Models +---------------------------------------------------- + +Speech Command Recognition is the task of classifying an input audio pattern into a set of discrete classes. It is a subset of ASR, +sometimes referred to as Key Word Spotting, in which a model is constantly analyzing speech patterns to detect certain ``action`` classes. + +Upon detection of these commands, a specific action can be taken. An example Jupyter notebook provided in NeMo shows how to train a +QuartzNet model with a modified decoder head trained on a speech commands dataset. + +.. note:: It is preferred that you use absolute paths to ``data_dir`` when preprocessing the dataset. + +NLP Fine-Tuning BERT +-------------------- + +BERT, or Bidirectional Encoder Representations from Transformers, is a neural approach to pre-train language representations which +obtains near state-of-the-art results on a wide array of Natural Language Processing (NLP) tasks, including the GLUE benchmark and +SQuAD Question & Answering dataset. + +BERT model checkpoints (`BERT-large-uncased `_ and `BERT-base-uncased `_) are provided can be used for either fine tuning BERT on your custom +dataset, or fine tuning downstream tasks, including GLUE benchmark tasks, Question & Answering tasks, Joint Intent & Slot detection, +Punctuation and Capitalization, Named Entity Recognition, and Speech Recognition post processing model to correct mistakes. + +.. note:: Almost all NLP examples also support RoBERTa and ALBERT models for downstream fine-tuning tasks (see the list of all +supported models by calling ``nemo.collections.nlp.modules.common.lm_utils.get_pretrained_lm_models_list()``. The user needs to specify +the name of the model desired while running the example scripts. + +BioMegatron Medical BERT +------------------------ + +BioMegatron is a large language model (Megatron-LM) trained on larger domain text corpus (PubMed abstract + full-text-commercial). +It achieves state-of-the-art results for certain tasks such as Relationship Extraction, Named Entity Recognition and Question & +Answering. Follow these tutorials to learn how to train and fine tune BioMegatron; pretrained models are provided on NGC: + +- `Relation Extraction BioMegatron `_ +- `Token Classification BioMegatron `_ + +Efficient Training With NeMo +---------------------------- + +Using Mixed Precision +^^^^^^^^^^^^^^^^^^^^^ + +Mixed precision accelerates training speed while protecting against noticeable loss. Tensor Cores is a specific hardware unit that +comes starting with the Volta and Turing architectures to accelerate large matrix to matrix multiply-add operations by operating them +on half precision inputs and returning the result in full precision. + +Neural networks which usually use massive matrix multiplications can be significantly sped up with mixed precision and Tensor Cores. +However, some neural network layers are numerically more sensitive than others. Apex AMP is an NVIDIA library that maximizes the +benefit of mixed precision and Tensor Cores usage for a given network. + +Multi-GPU Training +^^^^^^^^^^^^^^^^^^ + +This section is to help guide your decision making by answering our most asked multi-GPU training questions. + +**Q: Why is multi-GPU training preferred over other types of training?** +A: Multi-GPU training can reduce the total training time by distributing the workload onto multiple compute instances. This is +particularly important for large neural networks which would otherwise take weeks to train until convergence. Since NeMo supports +multi-GPU training, no code change is needed to move from single to multi-GPU training, only a slight change in your launch command +is required. + +**Q: What are the advantages of mixed precision training?** +A: Mixed precision accelerates training speed while protecting against noticeable loss in precision. Tensor Cores is a specific +hardware unit that comes starting with the Volta and Turing architectures to accelerate large matrix multiply-add operations by +operating on half precision inputs and returning the result in full precision in order to prevent loss in precision. Neural +networks which usually use massive matrix multiplications can be significantly sped up with mixed precision and Tensor Cores. +However, some neural network layers are numerically more sensitive than others. Apex AMP is a NVIDIA library that maximizes the +benefit of mixed precision and Tensor Core usage for a given network. + +**Q: What is the difference between multi-GPU and multi-node training?** +A: Multi-node is an abstraction of multi-GPU training, which requires a distributed compute cluster, where each node can have multiple +GPUs. Multi-node training is needed to scale training beyond a single node to large amounts of GPUs. + +From the framework perspective, nothing changes from moving to multi-node training. However, a master address and port needs to be set +up for inter-node communication. Multi-GPU training will then be launched on each node with passed information. You might also consider +the underlying inter-node network topology and type to achieve full performance, such as HPC-style hardware such as NVLink, InfiniBand +networking, or Ethernet. + + +Recommendations For Optimization And FAQs +----------------------------------------- + +This section is to help guide your decision making by answering our most asked NeMo questions. + +**Q: Are there areas where performance can be increased?** +A: You should try using mixed precision for improved performance. Note that typically when using mixed precision, memory consumption +is decreased and larger batch sizes could be used to further improve the performance. + +When fine-tuning ASR models on your data, it is almost always possible to take advantage of NeMo's pre-trained modules. Even if you +have a different target vocabulary, or even a different language; you can still try starting with pre-trained weights from Jasper or +QuartzNet ``encoder`` and only adjust the ``decoder`` for your needs. + +**Q: What is the recommended sampling rate for ASR?** +A: The released models are based on 16 KHz audio, therefore, ensure you use models with 16 KHz audio. Reduced performance should be +expected for any audio that is up-sampled from a sampling frequency less than 16 KHz data. + +**Q: How do we use this toolkit for audio with different types of compression and frequency than the training domain for ASR?** +A: You have to match the compression and frequency. + +**Q: How do you replace the 6-gram out of the ASR model with a custom language model? What is the language format supported in NeMo?** +A: NeMo’s Beam Search decoder with Levenberg-Marquardt (LM) neural module supports the KenLM language model. + +- You should retrain the KenLM language model on your own dataset. Refer to `KenLM’s documentation `_. +- If you want to use a different language model, other than KenLM, you will need to implement a corresponding decoder module. +- Transformer-XL example is present in OS2S. It would need to be updated to work with NeMo. `Here is the code `_. + +**Q: How do I use text-to-speech (TTS)?** +A: +- Obtain speech data ideally at 22050 Hz or alternatively at a higher sample rate and then down sample to 22050 Hz. + - If less than 22050 Hz and above 16000 Hz: + - Retrain WaveGlow on your own dataset. + - Tweak the spectrogram generation parameters, namely the ``window_size`` and the ``window_stride`` for their fourier + transforms. + - For below 16000 Hz, look into obtaining new data. +- In terms of bitrate/quantization, the general advice is the higher the better. We have not experimented enough to state how much + this impacts quality. +- For the amount of data, again the more the better, and the more diverse in terms of phonemes the better. Aim for around 20 hours + of speech after filtering for silences and non-speech audio. +- Most open speech datasets are in ~10 second format so training Tacotron 2 on audio on the order of 10s - 20s per sample is known + to work. Additionally, the longer the speech samples, the more difficult it will be to train Tacotron 2. +- Audio files should be clean. There should be little background noise or music. Data recorded from a studio mic is likely to be easier + to train compared to data captured using a phone. +- To ensure pronunciation of words are accurate; the technical challenge is related to the dataset, text to phonetic spelling is + required, use phonetic alphabet (notation) that has the name correctly pronounced. +- Here are some example parameters you can use to train Tacotron 2: + - Tacotron 2 requires a single speaker dataset + - Use AMP level O0 + - Trim long silences in the beginning and end + - ``optimizer="adam"`` + - ``beta1 = 0.9`` + - ``beta2 = 0.999`` + - ``lr=0.001 (constant)`` + - ``amp_opt_level="O0"`` + - ``weight_decay=1e-6`` + - ``batch_size=48 (per GPU)`` + - ``trim_silence=True`` + +Resources +--------- + +Ensure you are familiar with the following resources for NeMo. + +- Developer blogs + - `How to Build Domain Specific Automatic Speech Recognition Models on GPUs `_ + - `Develop Smaller Speech Recognition Models with NVIDIA’s NeMo Framework `_ + - `Neural Modules for Fast Development of Speech and Language Models `_ + +- Domain specific, transfer learning, Docker container with Jupyter Notebooks + - `Domain Specific NeMo ASR Application `_ + diff --git a/tts/NeMo/docs/source/starthere/intro.rst b/tts/NeMo/docs/source/starthere/intro.rst new file mode 100644 index 0000000..d80a3df --- /dev/null +++ b/tts/NeMo/docs/source/starthere/intro.rst @@ -0,0 +1,157 @@ +Introduction +============ + +.. # define a hard line break for html +.. |br| raw:: html + +
+ +.. _dummy_header: + +`NVIDIA NeMo `_ is a toolkit for building new state-of-the-art +conversational AI models. NeMo has separate collections for Automatic Speech Recognition (ASR), +Natural Language Processing (NLP), and Text-to-Speech (TTS) models. Each collection consists of +prebuilt modules that include everything needed to train on your data. +Every module can easily be customized, extended, and composed to create new conversational AI +model architectures. + +Conversational AI architectures are typically large and require a lot of data and compute +for training. NeMo uses `PyTorch Lightning `_ for easy and performant multi-GPU/multi-node +mixed-precision training. + +.. raw:: html + +

+ +
+ +For more information and questions, visit the `NVIDIA NeMo Discussion Board `_. + +Prerequisites +------------- + +Before you begin using NeMo, it's assumed you meet the following prerequisites. + +#. You have Python version 3.6, 3.7 or 3.8. + +#. You have Pytorch version 1.8.1. + +#. You have access to an NVIDIA GPU for training. + +.. _quick_start_guide: + +Quick Start Guide +----------------- + +This NeMo Quick Start Guide is a starting point for users who want to try out NeMo; specifically, this guide enables users to quickly get started with the NeMo fundamentals by walking you through an example audio translator and voice swap. + +If you're new to NeMo, the best way to get started is to take a look at the following tutorials: + +* `Text Classification (Sentiment Analysis) `__ - demonstrates the Text Classification model using the NeMo NLP collection. +* `NeMo Primer `__ - introduces NeMo, PyTorch Lightning, and OmegaConf, and shows how to use, modify, save, and restore NeMo models. +* `NeMo Models `__ - explains the fundamental concepts of the NeMo model. +* `NeMo voice swap demo `__ - demonstrates how to swap a voice in the audio fragment with a computer generated one using NeMo. + +Below we is the code snippet of Audio Translator application. + +.. code-block:: python + + # Import NeMo and it's ASR, NLP and TTS collections + import nemo + # Import Speech Recognition collection + import nemo.collections.asr as nemo_asr + # Import Natural Language Processing colleciton + import nemo.collections.nlp as nemo_nlp + # Import Speech Synthesis collection + import nemo.collections.tts as nemo_tts + + # Next, we instantiate all the necessary models directly from NVIDIA NGC + # Speech Recognition model - QuartzNet trained on Russian part of MCV 6.0 + quartznet = nemo_asr.models.EncDecCTCModel.from_pretrained(model_name="stt_ru_quartznet15x5").cuda() + # Neural Machine Translation model + nmt_model = nemo_nlp.models.MTEncDecModel.from_pretrained(model_name='nmt_ru_en_transformer6x6').cuda() + # Spectrogram generator which takes text as an input and produces spectrogram + spectrogram_generator = nemo_tts.models.Tacotron2Model.from_pretrained(model_name="tts_en_tacotron2").cuda() + # Vocoder model which takes spectrogram and produces actual audio + vocoder = nemo_tts.models.WaveGlowModel.from_pretrained(model_name="tts_waveglow_88m").cuda() + # Transcribe an audio file + # IMPORTANT: The audio must be mono with 16Khz sampling rate + # Get example from: https://nemo-public.s3.us-east-2.amazonaws.com/mcv-samples-ru/common_voice_ru_19034087.wav + russian_text = quartznet.transcribe(['Path_to_audio_file']) + print(russian_text) + # You should see russian text here. Let's translate it to English + english_text = nmt_model.translate(russian_text) + print(english_text) + # After this you should see English translation + # Let's convert it into audio + # A helper function which combines Tacotron2 and WaveGlow to go directly from + # text to audio + def text_to_audio(text): + parsed = spectrogram_generator.parse(text) + spectrogram = spectrogram_generator.generate_spectrogram(tokens=parsed) + audio = vocoder.convert_spectrogram_to_audio(spec=spectrogram) + return audio.to('cpu').numpy() + audio = text_to_audio(english_text[0]) + + +Installation +------------ + +Pip +~~~ +Use this installation mode if you want the latest released version. + +.. code-block:: bash + + apt-get update && apt-get install -y libsndfile1 ffmpeg + pip install Cython + pip install nemo_toolkit[all] + +Pip from source +~~~~~~~~~~~~~~~ +Use this installation mode if you want the version from a particular GitHub branch (for example, ``main``). + +.. code-block:: bash + + apt-get update && apt-get install -y libsndfile1 ffmpeg + pip install Cython + python -m pip install git+https://github.com/NVIDIA/NeMo.git@{BRANCH}#egg=nemo_toolkit[all] + # For v1.0.2, replace {BRANCH} with v1.0.2 like so: + # python -m pip install git+https://github.com/NVIDIA/NeMo.git@v1.0.2#egg=nemo_toolkit[all] + +From source +~~~~~~~~~~~ +Use this installation mode if you are contributing to NeMo. + +.. code-block:: bash + + apt-get update && apt-get install -y libsndfile1 ffmpeg + git clone https://github.com/NVIDIA/NeMo + cd NeMo + ./reinstall.sh + +Docker containers +~~~~~~~~~~~~~~~~~ +If you chose to work with the ``main`` branch, we recommend using `NVIDIA's PyTorch container version 21.05-py3 `_, then install from GitHub. + +.. code-block:: bash + + docker run --gpus all -it --rm -v :/NeMo --shm-size=8g \ + -p 8888:8888 -p 6006:6006 --ulimit memlock=-1 --ulimit \ + stack=67108864 --device=/dev/snd nvcr.io/nvidia/pytorch:21.05-py3 + + +FAQ +--- +Have a look at our `discussions board `_ and feel free to post a question or start a discussion. + + +Contributing +------------ + +We welcome community contributions! Refer to the `CONTRIBUTING.md `_ file for the process. + +License +------- + +NeMo is under `Apache 2.0 license `_. \ No newline at end of file diff --git a/tts/NeMo/docs/source/starthere/tutorials.rst b/tts/NeMo/docs/source/starthere/tutorials.rst new file mode 100644 index 0000000..76b4dd7 --- /dev/null +++ b/tts/NeMo/docs/source/starthere/tutorials.rst @@ -0,0 +1,117 @@ +.. _tutorials: + +Tutorials +========= + +The best way to get started with NeMo is to start wtih one of our tutorials. + +Most NeMo tutorials can be run on `Google's Colab `_. + +To run a tutorial: + +#. Click the **Colab** link (see table below). +#. Connect to an instance with a GPU. For example, click **Runtime** > **Change runtime type** and select **GPU** for the hardware accelerator. + +.. list-table:: **Tutorials** + :widths: 15 25 25 + :header-rows: 1 + + * - Domain + - Title + - GitHub URL + * - General + - Getting Started: Exploring Nemo Fundamentals + - `NeMo Fundamentals `_ + * - General + - Getting Started: Sample Conversational AI application + - `Audio translator example `_ + * - General + - Getting Started: Voice swap application + - `Voice swap example `_ + * - General + - Exploring NeMo Model Construction + - `NeMo Models `_ + * - ASR + - ASR with NeMo + - `ASR with NeMo `_ + * - ASR + - ASR with Subword Tokenization + - `ASR with Subword Tokenization `_ + * - ASR + - Offline ASR Inference with Beam Search and External Language Model Rescoring + - `Offline ASR `_ + * - ASR + - Online ASR inference with Microphone + - `Online ASR Microphone `_ + * - ASR + - Fine-tuning CTC Models on New Languages + - `ASR CTC Language Fine-Tuning `_ + * - ASR + - Speech Commands + - `Speech Commands `_ + * - ASR + - Online and Offline Speech Commands Inference + - `Online Offline Microphone Speech Commands `_ + * - ASR + - Voice Activiy Detection (VAD) + - `Voice Activiy Detection `_ + * - ASR + - Online and Offline VAD Inference + - `Online Offline Microphone VAD `_ + * - ASR + - Speaker Recognition and Verification + - `Speaker Recognition and Verification `_ + * - ASR + - Speaker Diarization Inference + - `Speaker Diarization Inference `_ + * - ASR + - ASR with Speaker Diarization + - `ASR with Speaker Diarization `_ + * - ASR + - Online Noise Augmentation + - `Online Noise Augmentation `_ + * - NLP + - Using Pretrained Language Models for Downstream Tasks + - `Pretrained Language Models for Downstream Tasks `_ + * - NLP + - Exploring NeMo NLP Tokenizers + - `NLP Tokenizers `_ + * - NLP + - Text Classification (Sentiment Analysis) with BERT + - `Text Classification (Sentiment Analysis) `_ + * - NLP + - Question Answering with SQuAD + - `Question Answering Squad `_ + * - NLP + - Token Classification (Named Entity Recognition) + - `Token Classification: Named Entity Recognition `_ + * - NLP + - Joint Intent Classification and Slot Filling + - `Joint Intent and Slot Classification `_ + * - NLP + - GLUE Benchmark + - `GLUE Benchmark `_ + * - NLP + - Punctuation and Capitalization + - `Punctuation and Capitalization `_ + * - NLP + - Named Entity Recognition - BioMegatron + - `Named Entity Recognition - BioMegatron `_ + * - NLP + - Relation Extraction - BioMegatron + - `Relation Extraction - BioMegatron `_ + * - TTS + - Speech Synthesis + - `TTS Inference `_ + * - TTS + - Speech Synthesis + - `Tacotron2 Training `_ + * - Tools + - CTC Segmentation + - `CTC Segmentation `_ + * - Text Processing + - Text Normalization for TTS + - `Text Normalization `_ + * - Text Processing + - Inverse Text Normalization for ASR + - `Inverse Text Normalization `_ \ No newline at end of file diff --git a/tts/NeMo/docs/source/tools/ctc_segmentation.rst b/tts/NeMo/docs/source/tools/ctc_segmentation.rst new file mode 100644 index 0000000..80e4f6c --- /dev/null +++ b/tts/NeMo/docs/source/tools/ctc_segmentation.rst @@ -0,0 +1,20 @@ +Dataset Creation Tool Based on CTC-Segmentation +=============================================== + +This tool provides functionality to align long audio files and the corresponding transcripts into shorter fragments +that are suitable for an Automatic Speech Recognition (ASR) model training. + +More details could be found in `NeMo/tutorials/tools/CTC_Segmentation_Tutorial.ipynb `__ (can be executed with `Google's Colab `_). + +The tool is based on the `CTC-Segmentation `__ package and +`CTC-Segmentation of Large Corpora for German End-to-end Speech Recognition +`__ :cite:`tools-kurzinger2020ctc` + + +References +---------- + +.. bibliography:: tools_all.bib + :style: plain + :labelprefix: TOOLS + :keyprefix: tools- diff --git a/tts/NeMo/docs/source/tools/intro.rst b/tts/NeMo/docs/source/tools/intro.rst new file mode 100644 index 0000000..ff7a61f --- /dev/null +++ b/tts/NeMo/docs/source/tools/intro.rst @@ -0,0 +1,14 @@ +Tools +===== + +NeMo provides a set of tools useful for developing Automatic Speech Recognitions (ASR) and Text-to-Speech (TTS) models: \ +`https://github.com/NVIDIA/NeMo/tree/main/tools `__ . + +.. toctree:: + :maxdepth: 1 + + ctc_segmentation + speech_data_explorer + text_processing_deployment + + diff --git a/tts/NeMo/docs/source/tools/speech_data_explorer.rst b/tts/NeMo/docs/source/tools/speech_data_explorer.rst new file mode 100644 index 0000000..92d1d07 --- /dev/null +++ b/tts/NeMo/docs/source/tools/speech_data_explorer.rst @@ -0,0 +1,33 @@ +Speech Data Explorer +==================== + +.. note:: + + The tool could be found under `NeMo/tools/speech_data_explorer `__. + +`Dash `__-based tool for interactive exploration of ASR/TTS datasets. + +Features: + +* dataset's statistics (alphabet, vocabulary, duration-based histograms) +* navigation across dataset (sorting, filtering) +* inspection of individual utterances (waveform, spectrogram, audio player) +* errors' analysis (Word Error Rate, Character Error Rate, Word Match Rate, Mean Word Accuracy, diff) + +Please make sure that requirements are installed. Then run: + +.. code:: + + python data_explorer.py path_to_manifest.json + + +JSON manifest file should contain the following fields: + +* `audio_filepath` (path to audio file) +* `duration` (duration of the audio file in seconds) +* `text` (reference transcript) + +Errors' analysis requires "pred_text" (ASR transcript) for all utterances. + +Any additional field will be parsed and displayed in 'Samples' tab. + diff --git a/tts/NeMo/docs/source/tools/text_processing_deployment.rst b/tts/NeMo/docs/source/tools/text_processing_deployment.rst new file mode 100644 index 0000000..3b277bd --- /dev/null +++ b/tts/NeMo/docs/source/tools/text_processing_deployment.rst @@ -0,0 +1,78 @@ +NeMo Text Processing Deployment +=============================================== + +This tool deploys :doc:`NeMo Inverse Text Normalization (ITN) <../nemo_text_processing/inverse_text_normalization>` and :doc:`NeMo Text Normalization (TN) <../nemo_text_processing/text_normalization>` for production :cite:`tools-itn_deploy-zhang2021nemo`. +It uses `Sparrowhawk `_ :cite:`tools-itn_deploy-sparrowhawk` -- an open-source version of Google Kestrel :cite:`tools-itn_deploy-ebden2015kestrel`. + +Requirements +------------------------ + +:doc:`nemo_text_processing <../nemo_text_processing/intro>` package + + +Usage +------------ + +Starts docker container with production backend with plugged in grammars. This is entry point script. + +Arguments: +^^^^^^^^^ +* ``GRAMMARS`` - ``tn_grammars`` or ``itn_grammars`` to export either TN or ITN grammars from :doc:`nemo_text_processing <../nemo_text_processing/intro>`. +* ``INPUT_CASE`` - ``cased`` or ``lower_cased`` (lower_cased is supported only in TN grammars). +* ``MODE`` - choose ``test`` to run test on the grammars inside the container. + +For example: + + +.. code-block:: bash + + # to export ITN grammars + bash export_grammar.sh --GRAMMARS=itn_grammars + + # to export and test TN grammars + bash export_grammar.sh --GRAMMARS=itn_grammars --INPUT_CASE=cased --MODE=test + +This script runs the following steps in sequence: + +Exports grammar `ClassifyFst` and `VerbalizeFst` from :doc:`nemo_text_processing <../nemo_text_processing/intro>` to `OUTPUT_DIR/classify/tokenize_and_classify.far` and `OUTPUT_DIR/verbalize/verbalize.far` respectively. + +.. code-block:: bash + + python pynini_export.py <--output_dir OUTPUT_DIR> <--grammars GRAMMARS> <--input_case INPUT_CASE> + +Builds C++ production backend docker + +.. code-block:: bash + + bash docker/build.sh + + +Plugs in grammars into production backend by mounting grammar directory `classify/` and `verbalize/` with sparrowhawk grammar directory inside docker. Returns docker prompt + +.. code-block:: bash + + # to launch container with the exported grammars + bash docker/launch.sh + + # to launch container with the exported grammars and run tests on TN grammars + bash docker/launch.sh test_tn_grammars + + # to launch container with the exported grammars and run tests on ITN grammars + bash docker/launch.sh test_itn_grammars + + +Runs TN or ITN in docker container: + +.. code-block:: bash + + echo "two dollars fifty" | ../../src/bin/normalizer_main --config=sparrowhawk_configuration.ascii_proto + +This returns $2.50 for ITN. + +References +---------- + +.. bibliography:: tools_all.bib + :style: plain + :labelprefix: TOOLS-ITN_DEPLOY + :keyprefix: tools-itn_deploy- diff --git a/tts/NeMo/docs/source/tools/tools_all.bib b/tts/NeMo/docs/source/tools/tools_all.bib new file mode 100644 index 0000000..4b86ee2 --- /dev/null +++ b/tts/NeMo/docs/source/tools/tools_all.bib @@ -0,0 +1,49 @@ +@inproceedings{kurzinger2020ctc, + title={CTC-segmentation of large corpora for german end-to-end speech recognition}, + author={K{\"u}rzinger, Ludwig and Winkelbauer, Dominik and Li, Lujun and Watzel, Tobias and Rigoll, Gerhard}, + booktitle={International Conference on Speech and Computer}, + pages={267--278}, + year={2020}, + organization={Springer} +} + +@article{ebden2015kestrel, + title={The Kestrel TTS text normalization system}, + author={Ebden, Peter and Sproat, Richard}, + journal={Natural Language Engineering}, + volume={21}, + number={3}, + pages={333}, + year={2015}, + publisher={Cambridge University Press} +} + +@article{sproat2016rnn, + title={RNN approaches to text normalization: A challenge}, + author={Sproat, Richard and Jaitly, Navdeep}, + journal={arXiv preprint arXiv:1611.00068}, + year={2016} +} + +@book{taylor2009text, + title={Text-to-speech synthesis}, + author={Taylor, Paul}, + year={2009}, + publisher={Cambridge university press} +} + +@misc{zhang2021nemo, + title={NeMo Inverse Text Normalization: From Development To Production}, + author={Yang Zhang and Evelina Bakhturina and Kyle Gorman and Boris Ginsburg}, + year={2021}, + eprint={2104.05055}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} + +@inproceedings{sparrowhawk, + title = {TTS for Low Resource Languages: A Bangla Synthesizer}, + author = {Alexander Gutkin and Linne Ha and Martin Jansche and Knot Pipatsrisawat and Richard Sproat}, + booktitle = {10th Language Resources and Evaluation Conference}, + year = {2016}, +} \ No newline at end of file diff --git a/tts/NeMo/docs/source/tts/api.rst b/tts/NeMo/docs/source/tts/api.rst new file mode 100644 index 0000000..2255af4 --- /dev/null +++ b/tts/NeMo/docs/source/tts/api.rst @@ -0,0 +1,47 @@ +NeMo TTS Collection API +======================= + +TTS Base Classes +---------------- + +The classes below are the base of the TTS pipeline. +To read more about them, see the `Base Classes <./intro.html#Base Classes>`__ section of the intro page. + +.. autoclass:: nemo.collections.tts.models.base.SpectrogramGenerator + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.tts.models.base.Vocoder + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.tts.models.base.TextToWaveform + :show-inheritance: + :members: + +TTS Datasets +------------ + +.. autoclass:: nemo.collections.tts.data.datalayers.AudioDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.tts.data.datalayers.MelAudioDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.tts.data.datalayers.SplicedAudioDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.tts.data.datalayers.NoisySpecsDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.asr.data.audio_to_text.FastPitchDataset + :show-inheritance: + :members: + +.. autoclass:: nemo.collections.tts.data.datalayers.FastSpeech2Dataset + :show-inheritance: + :members: diff --git a/tts/NeMo/docs/source/tts/datasets.rst b/tts/NeMo/docs/source/tts/datasets.rst new file mode 100644 index 0000000..ef3236e --- /dev/null +++ b/tts/NeMo/docs/source/tts/datasets.rst @@ -0,0 +1,187 @@ +TTS Datasets +============ + +Most TTS scripts work out-of-the-box with the LJ Speech dataset. +However, some models may require supplementary data for training and validation. +The following sections contain details of required data formats and instructions for running preprocessing scripts for +such models. + + +FastSpeech 2 +------------ + +The FastSpeech 2 model converts from phonemes to Mel Spectrograms and predicts phoneme durations, pitches, and +energies. +Therefore, in addition to the manifest and audio samples, it requires some supplementary files and data: + +* A **mappings file** for converting from words to phonemes and phonemes to indices +* **Phoneme durations** (for each audio sample) +* **Pitch per frame** (for each training audio sample) +* **Energy per frame** (for each training audio sample) +* (Optional) **Ignore list** for filtering out samples with OOV words + +The ``FastSpeech2Dataset`` uses the manifest format shared with all other NeMo speech tasks. +Each line of the manifest should describe one sample, and should be in the following format: + +.. code:: + + {"audio_filepath": "/data/wavs/audio.wav", "text": "an unused transcription", "duration": 23.147} + +See the documentation on :ref:`Preparing Custom ASR Data` for more details on the NeMo speech manifest format. + +.. note:: + The ``FastSpeech2Dataset`` ignores the ``"text"`` field of the manifest, since the model reads phoneme indices from + the supplementary duration files instead. + +The **mappings file** should be a JSON-formatted file that contains dictionaries ``word2phones`` and ``phone2idx``. +``word2phones`` is a mapping that converts from your vocabulary to phonemes. +For example, one entry in ``word2phones`` might be ``"nemo": ["N", "EH1", "M", "OW0"]``. +``phone2idx`` is an (arbitrary) mapping that converts each phoneme to an index for prediction. +It is also used to determine the ``pad_id``, which is set to the length of ``phone2idx``. + +Together, these two dictionaries are also used for inference, as an input sentence is first normalized, then converted +to phonemes using ``word2phones``, and then converted from phonemes to indices using ``phone2idx``. + +For each audio sample, there should be a corresponding **phoneme durations** file that contains ``token_duration`` +(duration per phoneme in frames) and ``text_encoded`` (index of each phoneme corresponding to ``phone2idx``). + +For each sample, there should also be a **pitch file** that contains the pitches (F0) per frame, and an **energy file** +that contains the energies (L2-norm of STFT frame amplitudes) per frame. + +The **ignore list** is a pickled list of file base names (with no extension) that tells the ``FastSpeech2Dataset`` +which audio samples to discard. +You should use this to exclude samples from your manifest that contain OOV words. + + +Directory Structure +^^^^^^^^^^^^^^^^^^^ + +While the mappings file and ignore list paths are passed in to the ``FastSpeech2Dataset`` directly, the +``FastSpeech2Dataset`` infers the path to the supplementary files corresponding to each audio sample based on the +audio samples' paths found in the manifest. +For each sample, the paths to the corresponding duration, pitch, and energy files are inferred by replacing ``wavs/`` +with ``phoneme_durations/``, ``pitches/``, and ``energies``, and swapping out the file extension (``.wav``) with +``.pt``, ``.npy``, and ``.npy`` respectively. + +For example, given manifest audio path ``/data/LJSpeech/wavs/LJ001-0001.wav``, the inferred duration and phonemes file +path would be ``/data/LJSpeech/phoneme_durations/LJ001-0001.pt``. + +Your directory structure should therefore look something like this: + +.. code:: + + data/ + ├── manifest.json + ├── mappings.json + ├── ignore_file.pkl + ├── energies/ + │   ├── basename_1.npy + │   ├── basename_2.npy + │   ├── ... + │   └── basename_n.npy + ├── phoneme_durations/ + │   ├── basename_1.pt + │   ├── basename_2.pt + │   ├── ... + │   └── basename_n.pt + ├── pitches/ + │   ├── basename_1.npy + │   ├── basename_2.npy + │   ├── ... + │   └── basename_n.npy + └── wavs/ +    ├── basename_1.wav +    ├── basename_2.wav +    ├── ... +    └── basename_n.wav + + +LJ Speech Dataset +^^^^^^^^^^^^^^^^^ + +NeMo comes with scripts for preprocessing the LJ Speech dataset for use with FastSpeech 2, which can be found in the +``/scripts/dataset_processing/ljspeech/`` directory. +These scripts assume that you have downloaded the LJ Speech dataset and extracted it to ````. + +They perform the following dataset preparation steps: + +* Create manifest files and ``.txt`` files with normalized transcripts +* Extract pitches +* Extract energies +* Downloads the `CMU Pronouncing Dictionary `_ to convert normalized + transcripts to phonemes +* Uses the `Montreal Forced Aligner `_ (MFA) to + perform alignment +* Calculates durations based on the alignment +* Generates the mappings file and ignore file for the dataset + +To run the scripts, follow the steps below. + +#. Download and extract the `LJ Speech dataset `_ to ````. + +#. Create the manifest files and normalized text files (for MFA to discover later) by running: + + .. code-block:: bash + + python create_manifests_and_textfiles.py --ljspeech_base= + +#. Extract pitches and energies from the audio files: + + .. code-block:: bash + + python extract_ljspeech_energy_pitch.py --ljspeech_base= + + This will write the extracted pitches and energies to ``/pitches/`` and + ``/energies/``. + +#. Run the phoneme extraction and duration calculation script. + This script will set up a Conda environment to download and install MFA and its dependencies, so make sure that you + have Anaconda or Miniconda before running the script. + + Also note that MFA does sometimes have trouble finding OpenBlas, so you may have to manually install it with the + command ``sudo apt-get install libopenblas-dev``. + + .. code-block:: bash + + ./extract_ljspeech_phonemes_and_durs.sh + + This script takes additional options ``--skip_env_setup`` if you have already set up the ``aligner`` environment, + and ``--g2p_dict=`` if you have already downloaded CMU dict or another G2P dictionary you prefer. + + The alignment step will take a while to run, so be prepared to wait upwards of an hour. + + In addition to alignments and durations, this script will create the mappings and ignore files as well. + It will also generate some intermediate files that you are free to delete, as you only need the files listed above. + +When the following steps are finished, your ```` directory will look like this. +(Starred files and directories indicate files from intermediate steps that are safe to remove, but that you may want +to keep for bookkeeping purposes.) + +.. code:: + + / + ├── alignments/ * + ├── cmudict.dict * + ├── energies/ + │   ├── LJ001-0001.npy + │   └── ... + ├── ljs_audio_text_test_filelist.txt * + ├── ljs_audio_text_train_filelist.txt * + ├── ljs_audio_text_val_filelist.txt * + ├── ljspeech_test.json + ├── ljspeech_train.json + ├── ljspeech_val.json + ├── mappings.json + ├── metadata.csv + ├── phoneme_durations/ + │   ├── LJ001-0001.pt + │   └── ... + ├── pitches/ + │   ├── LJ001-0001.npy + │   └── ... + ├── README + ├── uncommented_cmudict.dict * + ├── wavs/ + │   ├── LJ001-0001.wav + │   └── ... + └── wavs_to_ignore.pkl diff --git a/tts/NeMo/docs/source/tts/intro.rst b/tts/NeMo/docs/source/tts/intro.rst new file mode 100644 index 0000000..7aeb5e1 --- /dev/null +++ b/tts/NeMo/docs/source/tts/intro.rst @@ -0,0 +1,153 @@ +Speech Synthesis (TTS) +====================== + +.. toctree:: + :maxdepth: 4 + :hidden: + + datasets + api + +Speech Synthesis or Text-to-Speech (TTS) involves turning text into human speech. The NeMo TTS collection currently +supports two pipelines for TTS: + +1) The two stage pipeline. First, a model is used to generate a mel spectrogram from text. Second, a model is used +to generate audio from a mel spectrogram. +2) The "end-to-end" approach that uses one model to generate audio straight from text. + +Quick Start: + +.. code-block:: python + + import soundfile as sf + from nemo.collections.tts.models.base import SpectrogramGenerator, Vocoder + + # Download and load the pretrained tacotron2 model + spec_generator = SpectrogramGenerator.from_pretrained("tts_en_tacotron2") + # Download and load the pretrained waveglow model + vocoder = Vocoder.from_pretrained("tts_waveglow_88m") + + # All spectrogram generators start by parsing raw strings to a tokenized version of the string + parsed = spec_generator.parse("You can type your sentence here to get nemo to produce speech.") + # They then take the tokenized string and produce a spectrogram + spectrogram = spec_generator.generate_spectrogram(tokens=parsed) + # Finally, a vocoder converts the spectrogram to audio + audio = vocoder.convert_spectrogram_to_audio(spec=spectrogram) + + # Save the audio to disk in a file called speech.wav + # Note vocoder return a batch of audio. In this example, we just take the first and only sample. + sf.write("speech.wav", audio.to('cpu').detach().numpy()[0], 22050) + +.. note:: + + For an interactive version of the quick start above, refer to the TTS inference notebook that can be found on the + github readme. + +Available Models +################ + +NeMo supports a variety of models that can be used for TTS. For beginners, we recommend starting with the Tacotron2 + +WaveGlow combination. Then we suggest trying using (TalkNet or FastPitch) + HiFiGAN if you want to continue exploring +the two stage pipeline, or the FastPitch_HifiGan_E2E model for the end-to-end pipeline. + +.. list-table:: *TTS Models* + :widths: 5 5 10 25 + :header-rows: 1 + + * - Model + - Base Class + - Pretrained Checkpoint + - Description + * - Tacotron2 + - :class:`SpectrogramGenerator` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_en_tacotron2 + - LSTM encoder decoder based model that generates spectrograms + * - GlowTTS + - :class:`SpectrogramGenerator` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_en_glowtts + - Glow-based spectrogram generator + * - FastSpeech 2 + - :class:`SpectrogramGenerator` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_en_fastspeech_2 + - Non-autoregressive transformer-based spectrogram generator that predicts duration, energy, and pitch + * - FastPitch + - :class:`SpectrogramGenerator` + - (Coming soon) + - Non-autoregressive transformer-based spectrogram generator that predicts duration and pitch + * - TalkNet + - :class:`SpectrogramGenerator` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_en_talknet + - Non-autoregressive convolution-based spectrogram generator + * - WaveGlow + - :class:`Vocoder` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_waveglow_88m + - Glow-based vocoder + * - SqueezeWave + - :class:`Vocoder` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_squeezewave + - Glow-based vocoder based on WaveGlow but with fewer parameters + * - UniGlow + - :class:`Vocoder` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_uniglow + - Glow-based vocoder based on WaveGlow but shares 1 set of parameters across all flow steps + * - MelGAN + - :class:`Vocoder` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_melgan + - GAN-based vocoder + * - HiFiGAN + - :class:`Vocoder` + - https://ngc.nvidia.com/catalog/models/nvidia:nemo:tts_hifigan + - GAN-based vocoder + * - FastPitch_HifiGan_E2E + - :class:`TextToWaveform` + - (Coming soon) + - End-to-end model based on composing FastPitch and HiFiGAN + * - FastSpeech2_HifiGan_E2E + - :class:`TextToWaveform` + - (Coming soon) + - End-to-end model based on composing FastSpeech2 and HiFiGAN + +Base Classes +############ + +Two Stage Pipeline +****************** + +NeMo TTS has two base classes corresponding to the two stage pipeline: + + - :class:`SpectrogramGenerator` + - :class:`Vocoder` + +The :class:`SpectrogramGenerator` class has two important +functions: :py:meth:`parse` which +accepts raw python strings and returns a torch.tensor that represents tokenized text ready to pass to, and +:py:meth:`generate_spectrogram` which +accepts a batch of tokenized text and returns a torch.tensor that represents a batch of spectrograms + +The :class:`Vocoder` class has one important functions +:py:meth:`convert_spectrogram_to_audio` which +accepts a batch of spectrograms and returns a torch.tensor that represents a batch of raw audio. + +End-to-End Pipeline +******************* + +Correspondingly, NeMo TTS has one base class for the end-to-end pipeline: + + - :class:`TextToWaveform` + +Similarly to the SpectrogramGenerator, :class:`TextToWaveform` +implements two functions: :py:meth:`parse` which +accepts raw python strings and returns a torch.tensor that represents tokenized text ready to pass to, and +:py:meth:`generate_spectrogram` which +accepts a batch of tokenized text and returns a torch.tensor that represents a batch of audio. + +TTS Training +############ + +Training of TTS models can be done using the scripts inside the NeMo ``examples/tts folders``. The majority of the TTS +YAML configurations should work out of the box with the LJSpeech dataset. If you want to train on other data, it is +recommended that you walk through the Tacotron 2 Training notebook. Please pay special attention to the sample rate and +FFT parameters for new data. + +Some models, like FastSpeech 2, require supplementary data such as phoneme durations, pitches, and energies. +For more information about how to preprocess datasets for such models, see the `TTS Datasets <./datasets.html>`__ page. diff --git a/tts/NeMo/docs/update_docs_docker.sh b/tts/NeMo/docs/update_docs_docker.sh new file mode 100755 index 0000000..c7a45f8 --- /dev/null +++ b/tts/NeMo/docs/update_docs_docker.sh @@ -0,0 +1,3 @@ +cd ../ +docker run --rm -v $PWD:/workspace python:3.7 /bin/bash -c "cd /workspace && \ +pip install -r requirements/requirements_docs.txt && cd docs/ && rm -rf build && make clean && make html && make html" diff --git a/tts/NeMo/examples/asr/asr_webapp/Dockerfile b/tts/NeMo/examples/asr/asr_webapp/Dockerfile new file mode 100644 index 0000000..8e5ee21 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/Dockerfile @@ -0,0 +1,41 @@ +# syntax=docker/dockerfile:experimental + +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +ARG BASE_IMAGE=nvcr.io/nvidia/nemo:1.0.0rc1 + +# build an image that includes only the nemo dependencies, ensures that dependencies +# are included first for optimal caching, and useful for building a development +# image (by specifying build target as `nemo-deps`) +FROM ${BASE_IMAGE} as nemo-deps + +# copy asr service source into a temp directory +WORKDIR /tmp/nemo-service +COPY . . + +# override nemo installation with dependency from requirements.txt +RUN /bin/echo "export BASE_IMAGE=${BASE_IMAGE}" >> /root/.bashrc +RUN cd /tmp/nemo-service && pip install -r "requirements.txt" + +# copy webapp into container for end user +WORKDIR /workspace/nemo-service +COPY . /workspace/nemo-service/ + +# pre-import some asr dependencies which would take time on each worker +RUN python -c "import nemo.collections.asr as nemo_asr" + +# expose port 8000 and launch gunicorn +EXPOSE 8000 +CMD ["gunicorn", "wsgi:app"] diff --git a/tts/NeMo/examples/asr/asr_webapp/README.rst b/tts/NeMo/examples/asr/asr_webapp/README.rst new file mode 100644 index 0000000..1f05b5f --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/README.rst @@ -0,0 +1,69 @@ +**ASR EVALUATION SERVICE ** +=========================== + +Usage +----- + +A simple service that will load a pre-trained model from NeMo's ASR collection and after uploading some files, will transcribe them. Any pre-trained model (or model which has been uploaded to the service) can be selected and if the local / docker environment supports GPUs then it will be possible to transcribe the audio segments with GPU. + +All uploaded files are immediately deleted after transcriptions are obtained. + + .. note:: + + When using `Gunicorn `_, you might notice that each pretrained checkpoint takes a long time for the first transcription. This is because that worker is instantiating the model into memory and then moving the model onto the GPU. For large models, this step might take a significant amount of time. However, this step is cached, and subsequent transcription requests should be much faster (especially if a GPU is utilized). + +From inside the ``asr_webapp`` directory, there are three options to run the ASR Service to transcribe audio - + +Local Setup +----------- + +1) Install all the dependencies (``pip install -r requirements.txt``). Note : It will utilize the latest branch set in the requirements and will override current nemo installation. + +2) Simply run ``python asr_service.py``. This will launch a single service worker that can be run locally. + +3) The app will run at ``127.0.0.1:5000`` by default. + +Gunicorn Setup +-------------- + +1) Follow Step (1) of the ``Local Setup`` section. + +2) Edit the configuration of ``gunicorn`` inside ``gunicorn.conf.py`` if you wish to change the port or number of workers (though this can be achieved via command line overrides as well). + +3) Simply run ``gunicorn wsgi:app``. This will launch two workers (default) in a gunicorn environment. + +4) The app will run at ``0.0.0.0:8000`` by default. + +Docker Setup +------------ + +The cleanest approach of the three, and requires simply building and running a docker container. + +1) Build the docker by executing ``bash docker_container_build.sh``. This will build a container using the latest branch of nemo. + +2) Run the container by executing ``bash docker_container_run.sh``. This will run a detached container that can be used by visiting ``0.0.0.0:8000`` on a modern browser. + +Note About Uploading Models +--------------------------- + +Uploading models is a useful method to evaluate models quickly without having to write scripts. +By design, models uploaded via the browser are visible to **all** users who have access to the web app - so that there only needs to be one user who uploads the model and everyone else who can access this service will be able to evaluate with that model. + +This also means that models are uploaded indefinitely - and cannot be removed easily without explicitly deleting the ``models`` directory or by shutting down the container (if a container is used). + +There are several reasons this approach was taken - + +* It allows for easy evaluation amongst peers without duplicating model uploads (which may be very big). +* When using ``gunicorn``, every worker has access to a central cache of models which can be loaded into memory. +* Model upload mode is meant to be used in a local, protected environment. + +If you wish to disable model uploading, please open ``templates/main.html`` and comment out the following section: + +.. code-block:: html + + + +
+ NeMo File : + + diff --git a/tts/NeMo/examples/asr/asr_webapp/asr_service.py b/tts/NeMo/examples/asr/asr_webapp/asr_service.py new file mode 100644 index 0000000..1c53d15 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/asr_service.py @@ -0,0 +1,374 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import atexit +import glob +import os +import shutil +import time +from html import unescape +from uuid import uuid4 + +import model_api +import torch +import werkzeug +from flask import Flask, make_response, render_template, request, url_for +from flask_cors import CORS +from werkzeug.utils import secure_filename + +from nemo.utils import logging + +app = Flask(__name__) +CORS(app) + +# Upload folder for audio files; models are stored in permanent cache +# which gets deleted once the container shuts down +app.config[f'UPLOAD_FOLDER'] = f"tmp/" + + +@app.route('/initialize_model', methods=['POST']) +def initialize_model(): + """ + API Endpoint to instantiate a model + + Loads ASR model by its pretrained checkpoint name or upload ASR model that is provided by the user, + then load that checkpoint into the cache. + + Loading of the model into cache is done once per worker. Number of workers should be limited + so as not to exhaust the GPU memory available on device (if GPU is being used). + """ + logging.info("Starting ASR service") + if torch.cuda.is_available(): + logging.info("CUDA is available. Running on GPU") + else: + logging.info("CUDA is not available. Defaulting to CPUs") + + # get form fields + model_name = request.form['model_names_select'] + use_gpu_if_available = request.form.get('use_gpu_ckbx', "off") + + # get nemo model from user (if not none) + nemo_model_file = request.files.get('nemo_model', '') + + # if nemo model is not None, upload it to model cache + if nemo_model_file != '': + model_name = _store_model(nemo_model_file) + + # Alert user that model has been uploaded into the model cache, + # and they should refresh the page to access the model + result = render_template( + 'toast_msg.html', toast_message=f"Model {model_name} has been uploaded. " f"Refresh page !", timeout=5000 + ) + + else: + # Alert user that model has been loaded onto a workers memory + result = render_template( + 'toast_msg.html', toast_message=f"Model {model_name} has been initialized !", timeout=2000 + ) + + # Load model into memory cache + model_api.initialize_model(model_name=model_name) + + # reset file banner + reset_nemo_model_file_script = """ + + """ + + result = result + reset_nemo_model_file_script + result = make_response(result) + + # set cookies + result.set_cookie("model_name", model_name) + result.set_cookie("use_gpu", use_gpu_if_available) + return result + + +def _store_model(nemo_model_file): + """ + Preserve the model supplied by user into permanent cache + This cache needs to be manually deleted (if run locally), or gets deleted automatically + (when the container gets shutdown / killed). + + Args: + nemo_model_file: User path to .nemo checkpoint. + + Returns: + A file name (with a .nemo) at the end - to signify this is an uploaded checkpoint. + """ + filename = secure_filename(nemo_model_file.filename) + file_basename = os.path.basename(filename) + model_dir = os.path.splitext(file_basename)[0] + + model_store = os.path.join('models', model_dir) + if not os.path.exists(model_store): + os.makedirs(model_store) + + # upload model + model_path = os.path.join(model_store, filename) + nemo_model_file.save(model_path) + return file_basename + + +@app.route('/upload_audio_files', methods=['POST']) +def upload_audio_files(): + """ + API Endpoint to upload audio files for inference. + + The uploaded files must be wav files, 16 KHz sample rate, mono-channel audio samples. + """ + # Try to get one or more files from form + try: + f = request.files.getlist('file') + except werkzeug.exceptions.BadRequestKeyError: + f = None + + # If user did not select any file to upload, notify them. + if f is None or len(f) == 0: + toast = render_template('toast_msg.html', toast_message="No file has been selected to upload !", timeout=2000) + result = render_template('updates/upload_files_failed.html', pre_exec=toast, url=url_for('upload_audio_files')) + result = unescape(result) + return result + + # temporary id to store data + uuid = str(uuid4()) + data_store = os.path.join(app.config[f'UPLOAD_FOLDER'], uuid) + + # If the user attempt to upload another set of files without first transcribing them, + # delete the old cache of files and create a new cache entirely + _remove_older_files_if_exists() + + # Save each file into this unique cache + for fn in f: + filename = secure_filename(fn.filename) + if not os.path.exists(data_store): + os.makedirs(data_store) + + fn.save(os.path.join(data_store, filename)) + logging.info(f"Saving file : {fn.filename}") + + # Update user that N files were uploaded. + msg = f"{len(f)} file(s) uploaded. Click to upload more !" + toast = render_template('toast_msg.html', toast_message=f"{len(f)} file(s) uploaded !", timeout=2000) + result = render_template( + 'updates/upload_files_successful.html', pre_exec=toast, msg=msg, url=url_for('upload_audio_files') + ) + result = unescape(result) + + result = make_response(result) + result.set_cookie("uuid", uuid) + return result + + +def _remove_older_files_if_exists(): + """ + Helper method to prevent cache leakage when user attempts to upload another set of files + without first transcribing the files already uploaded. + """ + # remove old data store (if exists) + old_uuid = request.cookies.get('uuid', '') + if old_uuid is not None and old_uuid != '': + # delete old data store + old_data_store = os.path.join(app.config[f'UPLOAD_FOLDER'], old_uuid) + + logging.info("Tried uploading more data without using old uploaded data. Purging data cache.") + shutil.rmtree(old_data_store, ignore_errors=True) + + +@app.route('/remove_audio_files', methods=['POST']) +def remove_audio_files(): + """ + API Endpoint for removing audio files + + # Note: Sometimes data may persist due to set of circumstances: + + - User uploads audio then closes app without transcribing anything + + In such a case, the files will be deleted when gunicorn shutsdown, or container is stopped. + However the data may not be automatically deleted if the flast server is used as is. + """ + # Get the unique cache id from cookie + uuid = request.cookies.get("uuid", "") + data_store = os.path.join(app.config[f'UPLOAD_FOLDER'], uuid) + + # If the data does not exist (cache is empty), notify user + if not os.path.exists(data_store) or uuid == "": + files_dont_exist = render_template( + 'toast_msg.html', toast_message="No files have been uploaded !", timeout=2000 + ) + result = render_template( + 'updates/remove_files.html', pre_exec=files_dont_exist, url=url_for('remove_audio_files') + ) + result = unescape(result) + return result + + else: + # delete data that exists in cache + shutil.rmtree(data_store, ignore_errors=True) + + logging.info("Removed all data") + + # Notify user that cache was deleted. + toast = render_template('toast_msg.html', toast_message="All files removed !", timeout=2000) + result = render_template('updates/remove_files.html', pre_exec=toast, url=url_for('remove_audio_files')) + result = unescape(result) + + result = make_response(result) + result.set_cookie("uuid", '', expires=0) + return result + + +@app.route('/transcribe', methods=['POST']) +def transcribe(): + """ + API Endpoint to transcribe a set of audio files. + + The files are sorted according to their name, so order may not be same as upload order. + + Utilizing the cached info inside the cookies, a model with selected name will be loaded into memory, + and maybe onto a GPU (if it is supported on the device). + + Then the transcription api will be called from the model_api. If all is successful, a template is updated + with results. If some issue occurs (memory ran out, file is invalid format), notify the user. + """ + # load model name from cookie + model_name = request.cookies.get('model_name') + logging.info(f"Model name : {model_name}") + + # If model name is not selected via Load Model, notify user. + if model_name is None or model_name == '': + result = render_template('toast_msg.html', toast_message="Model has not been initialized !", timeout=2000) + return result + + # load whether gpu should be used + use_gpu_if_available = request.cookies.get('use_gpu') == 'on' + gpu_used = torch.cuda.is_available() and use_gpu_if_available + + # Load audio from paths + uuid = request.cookies.get("uuid", "") + data_store = os.path.join(app.config[f'UPLOAD_FOLDER'], uuid) + + files = list(glob.glob(os.path.join(data_store, "*.wav"))) + + # If no files found in cache, notify user + if len(files) == 0: + result = render_template('toast_msg.html', toast_message="No audio files were found !", timeout=2000) + return result + + # transcribe file via model api + t1 = time.time() + transcriptions = model_api.transcribe_all(files, model_name, use_gpu_if_available=use_gpu_if_available) + t2 = time.time() + + # delete all transcribed files immediately + for fp in files: + try: + os.remove(fp) + except FileNotFoundError: + logging.info(f"Failed to delete transcribed file : {os.path.basename(fp)}") + + # delete temporary transcription directory + shutil.rmtree(data_store, ignore_errors=True) + + # If something happened during transcription, and it failed, notify user. + if type(transcriptions) == str and transcriptions == model_api.TAG_ERROR_DURING_TRANSCRIPTION: + toast = render_template( + 'toast_msg.html', + toast_message=f"Failed to transcribe files due to unknown reason. " + f"Please provide 16 KHz Monochannel wav files onle.", + timeout=5000, + ) + transcriptions = ["" for _ in range(len(files))] + + else: + # Transcriptions obtained successfully, notify user. + toast = render_template( + 'toast_msg.html', + toast_message=f"Transcribed {len(files)} files using {model_name} (gpu={gpu_used}), " + f"in {(t2 - t1): 0.2f} s", + timeout=5000, + ) + + # Write results to data table + results = [] + for filename, transcript in zip(files, transcriptions): + results.append(dict(filename=os.path.basename(filename), transcription=transcript)) + + result = render_template('transcripts.html', transcripts=results) + result = toast + result + result = unescape(result) + + result = make_response(result) + result.set_cookie("uuid", "", expires=0) + return result + + +def remove_tmp_dir_at_exit(): + """ + Helper method to attempt a deletion of audio file cache on flask api exit. + Gunicorn and Docker container (based on gunicorn) will delete any remaining files on + shutdown of the gunicorn server or the docker container. + + This is a patch that might not always work for Flask server, but in general should ensure + that local audio file cache is deleted. + + This does *not* impact the model cache. Flask and Gunicorn servers will *never* delete uploaded models. + Docker container will delete models *only* when the container is killed (since models are uploaded to + local storage path inside container). + """ + try: + uuid = request.cookies.get("uuid", "") + + if uuid is not None or uuid != "": + cache_dir = os.path.join(os.path.join(app.config[f'UPLOAD_FOLDER'], uuid)) + logging.info(f"Removing cache file for worker : {os.getpid()}") + + if os.path.exists(cache_dir): + shutil.rmtree(cache_dir, ignore_errors=True) + logging.info(f"Deleted tmp folder : {cache_dir}") + + except RuntimeError: + # Working outside of request context (probably shutdown) + # simply delete entire tmp folder + shutil.rmtree(app.config[f'UPLOAD_FOLDER'], ignore_errors=True) + + +@app.route('/') +def main(): + """ + API Endpoint for ASR Service. + """ + nemo_model_names, local_model_names = model_api.get_model_names() + model_names = [] + model_names.extend(local_model_names) # prioritize local models + model_names.extend(nemo_model_names) # attach all other pretrained models + + # page initializations + result = render_template('main.html', model_names=model_names) + result = make_response(result) + + # Reset cookies + result.set_cookie("model_name", '', expires=0) # model name from pretrained model list + result.set_cookie("use_gpu", '', expires=0) # flag to use gpu (if available) + result.set_cookie("uuid", '', expires=0) # session id + return result + + +# Register hook to delete file cache (for flask server only) +atexit.register(remove_tmp_dir_at_exit) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/tts/NeMo/examples/asr/asr_webapp/docker_container_build.sh b/tts/NeMo/examples/asr/asr_webapp/docker_container_build.sh new file mode 100644 index 0000000..b94987e --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/docker_container_build.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# build container +DOCKER_BUILDKIT=1 docker build -f Dockerfile --progress=plain -t nemo-asr-service:latest . + diff --git a/tts/NeMo/examples/asr/asr_webapp/docker_container_run.sh b/tts/NeMo/examples/asr/asr_webapp/docker_container_run.sh new file mode 100644 index 0000000..6ea348c --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/docker_container_run.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# run container +docker run -d --gpus=all -p 8000:8000 --shm-size=8g --ulimit memlock=-1 --ulimit \ + stack=67108864 nemo-asr-service:latest + diff --git a/tts/NeMo/examples/asr/asr_webapp/gunicorn.conf.py b/tts/NeMo/examples/asr/asr_webapp/gunicorn.conf.py new file mode 100644 index 0000000..1fc0e36 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/gunicorn.conf.py @@ -0,0 +1,36 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# https://docs.gunicorn.org/en/stable/settings.html + +# NOTE: Do not import nemo / torch code here +# Gunicorn creates forked processes - and CUDA cannot be used in forked multiprocessing environment. + +import shutil + +# General config +bind = "0.0.0.0:8000" +workers = 2 + +# Worker specific config +worker_connections = 1000 +timeout = 180 # 3 minutes of timeout + + +def on_exit(server): + # delete tmp dir + print("Shutting down server ...") + print("Deleteing tmp directory ...") + shutil.rmtree('tmp/', ignore_errors=True) + print("Tmp directory deleted !") diff --git a/tts/NeMo/examples/asr/asr_webapp/model_api.py b/tts/NeMo/examples/asr/asr_webapp/model_api.py new file mode 100644 index 0000000..e14bcb3 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/model_api.py @@ -0,0 +1,131 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import contextlib +import glob +import os + +import torch + +import nemo.collections.asr as nemo_asr +from nemo.utils import logging, model_utils + +# setup AMP (optional) +if torch.cuda.is_available() and hasattr(torch.cuda, 'amp') and hasattr(torch.cuda.amp, 'autocast'): + logging.info("AMP enabled!\n") + autocast = torch.cuda.amp.autocast +else: + + @contextlib.contextmanager + def autocast(): + yield + + +MODEL_CACHE = {} + +# Special tags for fallbacks / user notifications +TAG_ERROR_DURING_TRANSCRIPTION = "" + + +def get_model_names(): + # Populate local copy of models + local_model_paths = glob.glob(os.path.join('models', "**", "*.nemo"), recursive=True) + local_model_names = list(sorted([os.path.basename(path) for path in local_model_paths])) + + # Populate with pretrained nemo checkpoint list + nemo_model_names = set() + for model_info in nemo_asr.models.ASRModel.list_available_models(): + for superclass in model_info.class_.mro(): + if 'CTC' in superclass.__name__ or 'RNNT' in superclass.__name__: + nemo_model_names.add(model_info.pretrained_model_name) + break + nemo_model_names = list(sorted(nemo_model_names)) + return nemo_model_names, local_model_names + + +def initialize_model(model_name): + # load model + if model_name not in MODEL_CACHE: + if '.nemo' in model_name: + # use local model + model_name_no_ext = os.path.splitext(model_name)[0] + model_path = os.path.join('models', model_name_no_ext, model_name) + + # Extract config + model_cfg = nemo_asr.models.ASRModel.restore_from(restore_path=model_path, return_config=True) + classpath = model_cfg.target # original class path + imported_class = model_utils.import_class_by_path(classpath) # type: ASRModel + logging.info(f"Restoring local model : {imported_class.__name__}") + + # load model from checkpoint + model = imported_class.restore_from(restore_path=model_path, map_location='cpu') # type: ASRModel + + else: + # use pretrained model + model = nemo_asr.models.ASRModel.from_pretrained(model_name, map_location='cpu') + + model.freeze() + + # cache model + MODEL_CACHE[model_name] = model + + model = MODEL_CACHE[model_name] + return model + + +def transcribe_all(filepaths, model_name, use_gpu_if_available=True): + # instantiate model + if model_name in MODEL_CACHE: + model = MODEL_CACHE[model_name] + else: + model = initialize_model(model_name) + + if torch.cuda.is_available() and use_gpu_if_available: + model = model.cuda() + + # transcribe audio + logging.info("Begin transcribing audio...") + try: + with autocast(): + with torch.no_grad(): + transcriptions = model.transcribe(filepaths, batch_size=32) + + except RuntimeError: + # Purge the cache to clear some memory + MODEL_CACHE.clear() + + logging.info("Ran out of memory on device - performing inference on CPU for now") + + try: + model = model.cpu() + + with torch.no_grad(): + transcriptions = model.transcribe(filepaths, batch_size=32) + + except Exception as e: + logging.info(f"Exception {e} occured while attemting to transcribe audio. Returning error message") + return TAG_ERROR_DURING_TRANSCRIPTION + + logging.info(f"Finished transcribing {len(filepaths)} files !") + + # If RNNT models transcribe, they return a tuple (greedy, beam_scores) + if type(transcriptions[0]) == list and len(transcriptions) == 2: + # get greedy transcriptions only + transcriptions = transcriptions[0] + + # Force onto CPU + model = model.cpu() + MODEL_CACHE[model_name] = model + + return transcriptions diff --git a/tts/NeMo/examples/asr/asr_webapp/requirements.txt b/tts/NeMo/examples/asr/asr_webapp/requirements.txt new file mode 100644 index 0000000..b08f825 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/requirements.txt @@ -0,0 +1,4 @@ +-e git+git://github.com/NVIDIA/NeMo.git@v1.0.2#egg=nemo_toolkit[all] +flask +flask-cors +gunicorn diff --git a/tts/NeMo/examples/asr/asr_webapp/templates/main.html b/tts/NeMo/examples/asr/asr_webapp/templates/main.html new file mode 100644 index 0000000..b6bafcb --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/templates/main.html @@ -0,0 +1,150 @@ + + + + + + + + Automatic Speech Recognition + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/tts/NeMo/examples/asr/asr_webapp/templates/toast_msg.html b/tts/NeMo/examples/asr/asr_webapp/templates/toast_msg.html new file mode 100644 index 0000000..794d0e7 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/templates/toast_msg.html @@ -0,0 +1,28 @@ + + + \ No newline at end of file diff --git a/tts/NeMo/examples/asr/asr_webapp/templates/transcripts.html b/tts/NeMo/examples/asr/asr_webapp/templates/transcripts.html new file mode 100644 index 0000000..5da42c7 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/templates/transcripts.html @@ -0,0 +1,43 @@ + + + + + + + + + + + {% for transcript in transcripts %} + + + + + {% endfor %} + +
FilenameTranscript
+
+ {{ transcript.filename }} +
+
+
+ +
+
\ No newline at end of file diff --git a/tts/NeMo/examples/asr/asr_webapp/templates/updates/remove_files.html b/tts/NeMo/examples/asr/asr_webapp/templates/updates/remove_files.html new file mode 100644 index 0000000..185f5d8 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/templates/updates/remove_files.html @@ -0,0 +1,22 @@ + + +{{ pre_exec }} + \ No newline at end of file diff --git a/tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_failed.html b/tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_failed.html new file mode 100644 index 0000000..61ad36b --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_failed.html @@ -0,0 +1,22 @@ + + +{{ pre_exec }} + \ No newline at end of file diff --git a/tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_successful.html b/tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_successful.html new file mode 100644 index 0000000..c3d15da --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/templates/updates/upload_files_successful.html @@ -0,0 +1,22 @@ + + +{{ pre_exec }} + \ No newline at end of file diff --git a/tts/NeMo/examples/asr/asr_webapp/wsgi.py b/tts/NeMo/examples/asr/asr_webapp/wsgi.py new file mode 100644 index 0000000..6441009 --- /dev/null +++ b/tts/NeMo/examples/asr/asr_webapp/wsgi.py @@ -0,0 +1,18 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from asr_service import app + +if __name__ == '__main__': + app.run() diff --git a/tts/NeMo/examples/asr/conf/citrinet/citrinet_384.yaml b/tts/NeMo/examples/asr/conf/citrinet/citrinet_384.yaml new file mode 100644 index 0000000..1ba7085 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/citrinet/citrinet_384.yaml @@ -0,0 +1,428 @@ +# This config contains the default values for training a Citrinet model with CTC loss and BPE-based vocabulary. +# Default learning parameters in this config are set for effective batch size of 1k on 32 GPUs. +# To train it with smaller batch sizes, you may need to re-tune the learning parameters or use higher accumulate_grad_batches. +# If training for a short time, you can also reduce weight decay to 0. + +# Training Recipe +# This model can be trained using the default settings in this config with FP32 precision. +# When training under AMP, increase `warmup_steps` to 5000 for stable training. +# In order to create Citrinet-C, find-replace `filters: 384` with `filters: C`. +# When reducing the receptive field of these models, it is advised to reduce the amount of augmentation +# for larger models from 10x time masking to 5x or 2x time masking. +# For further details regarding Citrinet, visit - https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#citrinet + +name: &name "Citrinet-384-8x-Stride" + +model: + sample_rate: &sample_rate 16000 + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + trim_silence: false + max_duration: 16.7 + shuffle: true + is_tarred: false + tarred_audio_filepaths: null + use_start_end_token: false + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: false + use_start_end_token: false + + test_ds: + manifest_filepath: null + sample_rate: 16000 + batch_size: 32 + shuffle: false + use_start_end_token: false + + model_defaults: + repeat: 5 + dropout: 0.0 + separable: true + se: true + se_context_size: -1 + kernel_size_factor: 1.0 + + tokenizer: + dir: ??? # path to directory which contains either tokenizer.model (bpe) or vocab.txt (for wpe) + type: ??? # Can be either bpe or wpe + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + sample_rate: *sample_rate + normalize: "per_feature" + window_size: 0.025 + window_stride: 0.01 + window: "hann" + features: &n_mels 80 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + pad_to: 16 + stft_conv: false + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 + time_masks: 2 + freq_width: 27 + time_width: 0.05 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 384 + repeat: 1 + kernel: [5] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [11] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [19] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [21] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [13] + stride: [2] # *stride + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [19] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [21] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [23] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [25] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [25] + stride: [2] # stride + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [27] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [29] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [31] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [33] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [35] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [37] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 384 + repeat: ${model.model_defaults.repeat} + kernel: [39] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: &enc_final 640 + repeat: 1 + kernel: [41] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_final + num_classes: -1 # filled with vocabulary size from tokenizer at runtime + vocabulary: [] # filled with vocabulary from tokenizer at runtime + + optim: + name: novograd + lr: 0.05 + + # optimizer arguments + betas: [0.8, 0.25] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # scheduler config override + warmup_steps: 1000 + warmup_ratio: null + min_lr: 1e-5 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 100 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + log_every_n_steps: 100 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + check_val_every_n_epoch: 1 + precision: 32 + sync_batchnorm: false + benchmark: false + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: true + create_checkpoint_callback: true + checkpoint_callback_params: + monitor: "val_wer" + mode: "min" + save_top_k: 3 + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null + entity: null + resume_if_exists: false + resume_ignore_no_checkpoint: false + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/citrinet/citrinet_512.yaml b/tts/NeMo/examples/asr/conf/citrinet/citrinet_512.yaml new file mode 100644 index 0000000..2aab672 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/citrinet/citrinet_512.yaml @@ -0,0 +1,428 @@ +# This config contains the default values for training a Citrinet model with CTC loss and BPE-based vocabulary. +# Default learning parameters in this config are set for effective batch size of 1k on 32 GPUs. +# To train it with smaller batch sizes, you may need to re-tune the learning parameters or use higher accumulate_grad_batches. +# If training for a short time, you can also reduce weight decay to 0. + +# Training Recipe +# This model can be trained using the default settings in this config with FP32 precision. +# When training under AMP, increase `warmup_steps` to 5000 for stable training. +# In order to create Citrinet-C, find-replace `filters: 384` with `filters: C`. +# When reducing the receptive field of these models, it is advised to reduce the amount of augmentation +# for larger models from 10x time masking to 5x or 2x time masking. +# For further details regarding Citrinet, visit - https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#citrinet + +name: &name "Citrinet-512-8x-Stride" + +model: + sample_rate: &sample_rate 16000 + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + trim_silence: false + max_duration: 16.7 + shuffle: true + is_tarred: false + tarred_audio_filepaths: null + use_start_end_token: false + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: false + use_start_end_token: false + + test_ds: + manifest_filepath: null + sample_rate: 16000 + batch_size: 32 + shuffle: false + use_start_end_token: false + + model_defaults: + repeat: 5 + dropout: 0.1 + separable: true + se: true + se_context_size: -1 + kernel_size_factor: 1.0 + + tokenizer: + dir: ??? # path to directory which contains either tokenizer.model (bpe) or vocab.txt (for wpe) + type: ??? # Can be either bpe or wpe + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + sample_rate: *sample_rate + normalize: "per_feature" + window_size: 0.025 + window_stride: 0.01 + window: "hann" + features: &n_mels 80 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + pad_to: 16 + stft_conv: false + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 + time_masks: 10 + freq_width: 27 + time_width: 0.05 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 512 + repeat: 1 + kernel: [5] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [11] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [19] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [21] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [13] + stride: [2] # *stride + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [19] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [21] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [23] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [25] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [25] + stride: [2] # stride + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [27] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [29] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [31] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [33] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [35] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [37] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: 512 + repeat: ${model.model_defaults.repeat} + kernel: [39] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + - filters: &enc_final 640 + repeat: 1 + kernel: [41] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + kernel_size_factor: ${model.model_defaults.kernel_size_factor} + + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_final + num_classes: -1 # filled with vocabulary size from tokenizer at runtime + vocabulary: [] # filled with vocabulary from tokenizer at runtime + + optim: + name: novograd + lr: 0.05 + + # optimizer arguments + betas: [0.8, 0.25] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # scheduler config override + warmup_steps: 1000 + warmup_ratio: null + min_lr: 1e-5 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 100 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + log_every_n_steps: 100 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + check_val_every_n_epoch: 1 + precision: 32 + sync_batchnorm: false + benchmark: false + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: true + create_checkpoint_callback: true + checkpoint_callback_params: + monitor: "val_wer" + mode: "min" + save_top_k: 3 + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null + entity: null + resume_if_exists: false + resume_ignore_no_checkpoint: false + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/citrinet/config_bpe.yaml b/tts/NeMo/examples/asr/conf/citrinet/config_bpe.yaml new file mode 100644 index 0000000..4b7a7bf --- /dev/null +++ b/tts/NeMo/examples/asr/conf/citrinet/config_bpe.yaml @@ -0,0 +1,183 @@ +name: &name "ContextNet5x1" +sample_rate: &sample_rate 16000 +repeat: &repeat 1 +dropout: &dropout 0.0 +separable: &separable true + +model: + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + trim_silence: True + max_duration: 16.7 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: False + + tokenizer: + dir: ??? # path to directory which contains either tokenizer.model (bpe) or vocab.txt (for wpe) + type: ??? # Can be either bpe or wpe + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [13] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [15] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [17] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [19] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: 1 + kernel: [21] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: *separable + se: true + se_context_size: -1 + + - filters: &enc_feat_out 1024 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: *separable + se: true + se_context_size: -1 + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: 1024 + num_classes: -1 # filled with vocabulary size from tokenizer at runtime + vocabulary: [] # filled with vocabulary from tokenizer at runtime + + optim: + name: adam + # _target_: nemo.core.optim.optimizers.Adam + lr: .1 + + # optimizer arguments + betas: [0.9, 0.999] + weight_decay: 0.0001 + + # scheduler setup + sched: + name: CosineAnnealing + + # scheduler config override + warmup_steps: null + warmup_ratio: 0.05 + min_lr: 1e-6 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/config.yaml b/tts/NeMo/examples/asr/conf/config.yaml new file mode 100644 index 0000000..f18a23f --- /dev/null +++ b/tts/NeMo/examples/asr/conf/config.yaml @@ -0,0 +1,183 @@ +name: &name "QuartzNet15x5" +sample_rate: &sample_rate 16000 +repeat: &repeat 1 +dropout: &dropout 0.0 +separable: &separable true +labels: &labels [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + +model: + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + trim_silence: True + max_duration: 16.7 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + shuffle: False + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + stft_conv: false + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [13] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [15] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [17] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: *repeat + kernel: [19] + stride: [1] + dilation: [1] + dropout: *dropout + residual: true + separable: *separable + se: true + se_context_size: -1 + + - filters: 256 + repeat: 1 + kernel: [21] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: *separable + se: true + se_context_size: -1 + + - filters: &enc_feat_out 1024 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: *separable + se: true + se_context_size: -1 + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: 1024 + num_classes: 28 + vocabulary: *labels + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: .01 + # optimizer arguments + betas: [0.8, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + + # Scheduler params + warmup_steps: null + warmup_ratio: null + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # check once per epoch .25 for 4 times per epoch + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/conformer/conformer_ctc_bpe.yaml b/tts/NeMo/examples/asr/conf/conformer/conformer_ctc_bpe.yaml new file mode 100644 index 0000000..1560fc3 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/conformer/conformer_ctc_bpe.yaml @@ -0,0 +1,189 @@ +# It contains the default values for training a Conformer-CTC ASR model, large size (~120M) with CTC loss and sub-word encoding. + +# Architecture and training config: +# Default learning parameters in this config are set for effective batch size of 2K. To train it with smaller effective +# batch sizes, you may need to re-tune the learning parameters or use higher accumulate_grad_batches. +# Here are the recommended configs for different variants of Conformer-CTC, other parameters are the same as in this config file. +# One extra layer (compared to original paper) is added to the medium and large variants to compensate for replacing the LSTM decoder with a linear one. +# +# +-------------+---------+---------+----------+------------+-----+ +# | Model | d_model | n_heads | n_layers | time_masks | lr | +# +=============+=========+========+===========+============+=====+ +# | Small (13M)| 176 | 4 | 16 | 5 | 5.0 | +# +-------------+---------+--------+-----------+------------+-----+ +# | Medium (30M)| 256 | 4 | 18 | 5 | 5.0 | +# +-------------+---------+--------+-----------+------------+-----+ +# | Large (121M)| 512 | 8 | 18 | 10 | 2.0 | +# +---------------------------------------------------------------+ +# +# If you do not want to train with AMP, you may use weight decay of 0.0 or reduce the number of time maskings to 2 +# with time_width=100. It may help when you want to train for fewer epochs and need faster convergence. +# With weight_decay=0.0, learning rate may need to get reduced to 2.0. + +# You may find more info about Conformer-CTC here: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/stable/asr/models.html#conformer-ctc +# Pre-trained models of Conformer-CTC can be found here: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/stable/asr/results.html +# The checkpoint of the large model trained on LibriSpeech with this recipe can be found here: https://ngc.nvidia.com/catalog/models/nvidia:nemo:stt_en_conformer_ctc_large_ls + +name: "Conformer-CTC-BPE" + +model: + sample_rate: 16000 + log_prediction: true # enables logging sample predictions in the output during training + ctc_reduction: 'mean_batch' + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: true + num_workers: 8 + pin_memory: true + use_start_end_token: false + trim_silence: false + max_duration: 16.7 # it is set for LibriSpeech, you may need to update it for your dataset + min_duration: 0.1 + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: false + num_workers: 8 + pin_memory: true + use_start_end_token: false + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: false + num_workers: 8 + pin_memory: true + use_start_end_token: false + + # recommend small vocab size of 128 or 256 when using 4x sub-sampling + # you may find more detail on how to train a tokenizer at: /scripts/tokenizers/process_asr_text_tokenizer.py + tokenizer: + dir: ??? # path to directory which contains either tokenizer.model (bpe) or vocab.txt (wpe) + type: wpe # Can be either bpe (SentencePiece tokenizer) or wpe (WordPiece tokenizer) + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + sample_rate: ${model.sample_rate} + normalize: "per_feature" + window_size: 0.025 + window_stride: 0.01 + window: "hann" + features: 80 + n_fft: 512 + log: true + frame_splicing: 1 + dither: 0.00001 + pad_to: 0 + pad_value: 0.0 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 # set to zero to disable it + # you may use lower time_masks for smaller models to have a faster convergence + time_masks: 10 # set to zero to disable it + freq_width: 27 + time_width: 0.05 + + encoder: + _target_: nemo.collections.asr.modules.ConformerEncoder + feat_in: ${model.preprocessor.features} + feat_out: -1 # you may set it if you need different output size other than the default d_model + n_layers: 18 + d_model: 512 + + # Sub-sampling params + subsampling: striding # vggnet or striding, vggnet may give better results but needs more memory + subsampling_factor: 4 # must be power of 2 + subsampling_conv_channels: -1 # -1 sets it to d_model + + # Feed forward module's params + ff_expansion_factor: 4 + + # Multi-headed Attention Module's params + self_attention_model: rel_pos # rel_pos or abs_pos + n_heads: 8 # may need to be lower for smaller d_models + # [left, right] specifies the number of steps to be seen from left and right of each step in self-attention + att_context_size: [-1, -1] # -1 means unlimited context + xscaling: true # scales up the input embeddings by sqrt(d_model) + untie_biases: true # unties the biases of the TransformerXL layers + pos_emb_max_len: 5000 + + # Convolution module's params + conv_kernel_size: 31 + + ### regularization + dropout: 0.1 # The dropout used in most of the Conformer Modules + dropout_emb: 0.0 # The dropout used for embeddings + dropout_att: 0.1 # The dropout for multi-headed attention modules + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: null + num_classes: -1 + vocabulary: [] + + optim: + name: adamw + lr: 2.0 + # optimizer arguments + betas: [0.9, 0.98] + # less necessity for weight_decay as we already have large augmentations with SpecAug + # you may need weight_decay for large models, stable AMP training, small datasets, or when lower augmentations are used + # weight decay of 0.0 with lr of 2.0 also works fine + weight_decay: 1e-3 + + # scheduler setup + sched: + name: NoamAnnealing + d_model: ${model.encoder.d_model} + # scheduler config override + warmup_steps: 10000 + warmup_ratio: null + min_lr: 1e-6 + +trainer: + gpus: -1 # number of GPUs, -1 would use all available GPUs + num_nodes: 1 + max_epochs: 1000 + max_steps: null # computed at runtime if not set + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + accelerator: ddp + accumulate_grad_batches: 1 + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP. + log_every_n_steps: 10 # Interval of logging. + progress_bar_refresh_rate: 10 + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + check_val_every_n_epoch: 1 # number of evaluations on validation every n epochs + sync_batchnorm: true + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: true + create_checkpoint_callback: true + checkpoint_callback_params: + # in case of multiple validation sets, first one is used + monitor: "val_wer" + mode: "min" + save_top_k: 3 + + # you need to set these two to True to continue the training + resume_if_exists: false + resume_ignore_no_checkpoint: false + + # You may use this section to create a W&B logger + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null diff --git a/tts/NeMo/examples/asr/conf/conformer/conformer_ctc_char.yaml b/tts/NeMo/examples/asr/conf/conformer/conformer_ctc_char.yaml new file mode 100644 index 0000000..735b075 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/conformer/conformer_ctc_char.yaml @@ -0,0 +1,165 @@ +# It contains the default values for training a Conformer-CTC ASR model, large size (~120M) with CTC loss and char-based vocabulary. +# Char-based encoding may give lower accuracy than sub-word encoding (conformer_ctc_bpe.yaml). + +# You may find more detail on Conformer-CTC at `examples/asr/conf/conformer/conformer_ctc_bpe.yaml` + +name: "Conformer-CTC-Char" + +model: + sample_rate: 16000 + labels: [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + log_prediction: true # enables logging sample predictions in the output during training + ctc_reduction: 'mean_batch' + + train_ds: + manifest_filepath: ??? + labels: ${model.labels} + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: true + num_workers: 8 + pin_memory: true + trim_silence: false + max_duration: 16.7 # it is set for LibriSpeech, you may need to update it for your dataset + min_duration: 0.1 + + validation_ds: + manifest_filepath: ??? + labels: ${model.labels} + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: false + num_workers: 8 + pin_memory: true + + test_ds: + manifest_filepath: null + labels: ${model.labels} + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: false + num_workers: 8 + pin_memory: true + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + sample_rate: ${model.sample_rate} + normalize: "per_feature" + window_size: 0.025 + window_stride: 0.01 + window: "hann" + features: 80 + n_fft: 512 + log: true + frame_splicing: 1 + dither: 0.00001 + pad_to: 0 + pad_value: 0.0 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 # set to zero to disable it + # you may use lower time_masks for smaller models to have a faster convergence + time_masks: 10 # set to zero to disable it + freq_width: 27 + time_width: 0.05 + + encoder: + _target_: nemo.collections.asr.modules.ConformerEncoder + feat_in: ${model.preprocessor.features} + feat_out: -1 # you may set it if you need different output size other than the default d_model + n_layers: 16 + d_model: 256 + + # Sub-sampling params + subsampling: striding # vggnet or striding, vggnet may give better results but needs more memory + subsampling_factor: 4 # must be power of 2 + subsampling_conv_channels: -1 # set to -1 to make it equal to the d_model + + # Feed forward module's params + ff_expansion_factor: 4 + + # Multi-headed Attention Module's params + self_attention_model: rel_pos # rel_pos or abs_pos + n_heads: 8 # may need to be lower for smaller d_models + # [left, right] specifies the number of steps to be seen from left and right of each step in self-attention + att_context_size: [-1, -1] # -1 means unlimited context + xscaling: true # scales up the input embeddings by sqrt(d_model) + untie_biases: true # unties the biases of the TransformerXL layers + pos_emb_max_len: 5000 + + # Convolution module's params + conv_kernel_size: 31 + + ### regularization + dropout: 0.1 # The dropout used in most of the Conformer Modules + dropout_emb: 0.0 # The dropout used for embeddings + dropout_att: 0.1 # The dropout for multi-headed attention modules + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: null + num_classes: -1 + vocabulary: ${model.labels} + + optim: + name: adamw + lr: 2.0 + # optimizer arguments + betas: [0.9, 0.98] + # less necessity for weight_decay as we already have large augmentations with SpecAug + # you may need weight_decay for large models, stable AMP training, small datasets, or when lower augmentations are used + # weight decay of 0.0 with lr of 2.0 also works fine + weight_decay: 1e-3 + + # scheduler setup + sched: + name: NoamAnnealing + d_model: ${model.encoder.d_model} + # scheduler config override + warmup_steps: 10000 + warmup_ratio: null + min_lr: 1e-6 + +trainer: + gpus: -1 # number of GPUs, -1 would use all available GPUs + num_nodes: 1 + max_epochs: 1000 + max_steps: null # computed at runtime if not set + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + accelerator: ddp + accumulate_grad_batches: 1 + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP. + log_every_n_steps: 10 # Interval of logging. + progress_bar_refresh_rate: 10 + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + check_val_every_n_epoch: 1 # number of evaluations on validation every n epochs + sync_batchnorm: true + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: true + create_checkpoint_callback: true + checkpoint_callback_params: + # in case of multiple validation sets, first one is used + monitor: "val_wer" + mode: "min" + save_top_k: 3 + + # you need to set these two to True to continue the training + resume_if_exists: false + resume_ignore_no_checkpoint: false + + # You may use this section to create a W&B logger + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null diff --git a/tts/NeMo/examples/asr/conf/jasper/jasper_10x5dr.yaml b/tts/NeMo/examples/asr/conf/jasper/jasper_10x5dr.yaml new file mode 100644 index 0000000..2f5309a --- /dev/null +++ b/tts/NeMo/examples/asr/conf/jasper/jasper_10x5dr.yaml @@ -0,0 +1,208 @@ +name: &name "Jasper10x5" + +model: + sample_rate: &sample_rate 16000 + labels: &labels [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + trim_silence: True + max_duration: 16.7 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + shuffle: False + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + jasper: + - dilation: [1] + dropout: 0.2 + filters: 256 + kernel: [11] + repeat: 1 + residual: false + stride: [2] + - dilation: [1] + dropout: 0.2 + filters: 256 + kernel: [11] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.2 + filters: 256 + kernel: [11] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.2 + filters: 384 + kernel: [13] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.2 + filters: 384 + kernel: [13] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.2 + filters: 512 + kernel: [17] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.2 + filters: 512 + kernel: [17] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.3 + filters: 640 + kernel: [21] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.3 + filters: 640 + kernel: [21] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.3 + filters: 768 + kernel: [25] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [1] + dropout: 0.3 + filters: 768 + kernel: [25] + repeat: 5 + residual: true + residual_dense: true + stride: [1] + - dilation: [2] + dropout: 0.4 + filters: 896 + kernel: [29] + repeat: 1 + residual: false + stride: [1] + - dilation: [1] + dropout: 0.4 + filters: 1024 + kernel: [1] + repeat: 1 + residual: false + stride: [1] + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: 1024 + num_classes: 28 + vocabulary: *labels + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: .01 + # optimizer arguments + betas: [0.8, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # pytorch lightning args + # monitor: val_loss + # reduce_on_plateau: false + + # Scheduler params + warmup_steps: null + warmup_ratio: null + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/marblenet/marblenet_3x2x64.yaml b/tts/NeMo/examples/asr/conf/marblenet/marblenet_3x2x64.yaml new file mode 100644 index 0000000..e3d34cb --- /dev/null +++ b/tts/NeMo/examples/asr/conf/marblenet/marblenet_3x2x64.yaml @@ -0,0 +1,180 @@ +name: &name "MarbleNet-3x2x64" + +model: + sample_rate: 16000 + repeat: 2 + dropout: 0.0 + kernel_size_factor: 1.0 + + labels: ['background', 'speech'] + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + augmentor: + shift: + prob: 1.0 + min_shift_ms: -5.0 + max_shift_ms: 5.0 + white_noise: + prob: 1.0 + min_level: -90 + max_level: -46 + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: False + val_loss_idx: 0 + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: False + test_loss_idx: 0 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMFCCPreprocessor + window_size: 0.025 + window_stride: 0.01 + window: "hann" + n_mels: &n_mels 64 + n_mfcc: *n_mels + n_fft: 512 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 + time_masks: 2 + freq_width: 15 + time_width: 25 + rect_masks: 5 + rect_time: 25 + rect_freq: 15 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: false + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 128 + repeat: 1 + kernel: [29] + stride: [1] + dilation: [2] + dropout: ${model.dropout} + residual: false + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: &enc_final_filters 128 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: false + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoderClassification + feat_in: *enc_final_filters + return_logits: true + pooling_type: 'avg' + + optim: + name: sgd + lr: 0.01 + # optimizer arguments + weight_decay: 0.001 + momentum: 0.9 + + # scheduler setup + sched: + name: PolynomialHoldDecayAnnealing + # Scheduler params + power: 2.0 + warmup_ratio: 0.05 + hold_ratio: 0.45 + min_lr: 0.001 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 150 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v1.yaml b/tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v1.yaml new file mode 100644 index 0000000..3016539 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v1.yaml @@ -0,0 +1,193 @@ +name: &name "MatchboxNet-3x1x64-v1" + +model: + sample_rate: 16000 + timesteps: 128 + repeat: 1 + dropout: 0.0 + kernel_size_factor: 1.0 + + labels_full: ['bed', 'bird', 'cat', 'dog', 'down', 'eight', 'five', 'four', 'go', 'happy', 'house', 'left', 'marvin', + 'nine', 'no', 'off', 'on', 'one', 'right', 'seven', 'sheila', 'six', 'stop', 'three', 'tree', 'two', 'up', + 'wow', 'yes', 'zero'] + + labels_subset: ["yes", "no", "up", "down", "left", "right", "on", "off", "stop", "go", "unknown", "silence"] + + labels: ${model.labels_full} + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + augmentor: + shift: + prob: 1.0 + min_shift_ms: -5.0 + max_shift_ms: 5.0 + white_noise: + prob: 1.0 + min_level: -90 + max_level: -46 + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: False + val_loss_idx: 0 + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: False + test_loss_idx: 0 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMFCCPreprocessor + window_size: 0.025 + window_stride: 0.01 + window: "hann" + n_mels: &n_mels 64 + n_mfcc: *n_mels + n_fft: 512 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 + time_masks: 2 + freq_width: 15 + time_width: 25 + rect_masks: 5 + rect_time: 25 + rect_freq: 15 + + crop_or_pad_augment: + _target_: nemo.collections.asr.modules.CropOrPadSpectrogramAugmentation + audio_length: ${model.timesteps} + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: false + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 128 + repeat: 1 + kernel: [29] + stride: [1] + dilation: [2] + dropout: ${model.dropout} + residual: false + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: &enc_final_filters 128 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: false + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoderClassification + feat_in: *enc_final_filters + return_logits: true + pooling_type: 'avg' + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: 0.05 + # optimizer arguments + betas: [0.95, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: PolynomialHoldDecayAnnealing + + # Scheduler params + power: 2.0 + warmup_ratio: 0.05 + hold_ratio: 0.45 + min_lr: 0.001 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 200 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v2.yaml b/tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v2.yaml new file mode 100644 index 0000000..5e088b0 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/matchboxnet/matchboxnet_3x1x64_v2.yaml @@ -0,0 +1,193 @@ +name: &name "MatchboxNet-3x1x64-v2" + +model: + sample_rate: 16000 + timesteps: 128 + repeat: 1 + dropout: 0.0 + kernel_size_factor: 1.0 + + labels_full: ['visual', 'wow', 'learn', 'backward', 'dog', 'two', 'left', 'happy', 'nine', 'go', 'up', 'bed', 'stop', + 'one', 'zero', 'tree', 'seven', 'on', 'four', 'bird', 'right', 'eight', 'no', 'six', 'forward', 'house', + 'marvin', 'sheila', 'five', 'off', 'three', 'down', 'cat', 'follow', 'yes'] + + labels_subset: ["yes", "no", "up", "down", "left", "right", "on", "off", "stop", "go", "unknown", "silence"] + + labels: ${model.labels_full} + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + augmentor: + shift: + prob: 1.0 + min_shift_ms: -5.0 + max_shift_ms: 5.0 + white_noise: + prob: 1.0 + min_level: -90 + max_level: -46 + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: False + val_loss_idx: 0 + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + labels: ${model.labels} + batch_size: 128 + shuffle: False + test_loss_idx: 0 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMFCCPreprocessor + window_size: 0.025 + window_stride: 0.01 + window: "hann" + n_mels: &n_mels 64 + n_mfcc: *n_mels + n_fft: 512 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 + time_masks: 2 + freq_width: 15 + time_width: 25 + rect_masks: 5 + rect_time: 25 + rect_freq: 15 + + crop_or_pad_augment: + _target_: nemo.collections.asr.modules.CropOrPadSpectrogramAugmentation + audio_length: ${model.timesteps} + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: false + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 64 + repeat: ${model.repeat} + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: 128 + repeat: 1 + kernel: [29] + stride: [1] + dilation: [2] + dropout: ${model.dropout} + residual: false + separable: true + kernel_size_factor: ${model.kernel_size_factor} + + - filters: &enc_final_filters 128 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: false + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoderClassification + feat_in: *enc_final_filters + return_logits: true + pooling_type: 'avg' + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: 0.05 + # optimizer arguments + betas: [0.95, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: PolynomialHoldDecayAnnealing + + # Scheduler params + power: 2.0 + warmup_ratio: 0.05 + hold_ratio: 0.45 + min_lr: 0.001 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 200 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5.yaml b/tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5.yaml new file mode 100644 index 0000000..ad44ed1 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5.yaml @@ -0,0 +1,281 @@ +name: &name "QuartzNet15x5" + +model: + sample_rate: &sample_rate 16000 + repeat: &repeat 5 + dropout: &dropout 0.0 + separable: &separable true + labels: &labels [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + trim_silence: True + max_duration: 16.7 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + shuffle: False + + test_ds: + manifest_filepath: null + sample_rate: 16000 + labels: *labels + batch_size: 32 + shuffle: False + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: 1 + residual: false + separable: *separable + stride: [2] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [2] + dropout: *dropout + filters: 512 + kernel: [87] + repeat: 1 + residual: false + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: &enc_filters 1024 + kernel: [1] + repeat: 1 + residual: false + stride: [1] + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_filters + num_classes: 28 + vocabulary: *labels + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: .01 + # optimizer arguments + betas: [0.8, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # pytorch lightning args + # monitor: val_loss + # reduce_on_plateau: false + + # Scheduler params + warmup_steps: null + warmup_ratio: null + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_wer" + mode: "min" + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5_zh.yaml b/tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5_zh.yaml new file mode 100644 index 0000000..576ef81 --- /dev/null +++ b/tts/NeMo/examples/asr/conf/quartznet/quartznet_15x5_zh.yaml @@ -0,0 +1,483 @@ +name: &name "QuartzNet15x5" + +model: + sample_rate: &sample_rate 16000 + repeat: &repeat 5 + dropout: &dropout 0.0 + separable: &separable true + labels: &labels [' ', '''', A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, + S, T, U, V, W, X, Y, Z, 㶧, 䶮, 一, 丁, 七, 万, 丈, 三, 上, 下, 不, 与, 丐, 丑, 专, 且, 丕, + 世, 丘, 丙, 业, 丛, 东, 丝, 丞, 丢, 两, 严, 丧, 个, 丫, 中, 丰, 串, 临, 丸, 丹, 为, 主, 丽, 举, 乃, + 久, 么, 义, 之, 乌, 乍, 乎, 乏, 乐, 乒, 乓, 乔, 乖, 乘, 乙, 九, 乞, 也, 习, 乡, 书, 买, 乱, 乳, 乾, + 了, 予, 争, 事, 二, 于, 亏, 云, 互, 五, 井, 亘, 亚, 些, 亟, 亡, 亢, 交, 亥, 亦, 产, 亨, 亩, 享, 京, + 亭, 亮, 亲, 亳, 亵, 人, 亿, 什, 仁, 仄, 仅, 仆, 仇, 今, 介, 仍, 从, 仑, 仓, 仔, 仕, 他, 仗, 付, 仙, + 仞, 仟, 仡, 代, 令, 以, 仨, 仪, 们, 仰, 仲, 件, 价, 任, 份, 仿, 企, 伉, 伊, 伍, 伎, 伏, 伐, 休, 众, + 优, 伙, 会, 伞, 伟, 传, 伢, 伤, 伦, 伪, 伫, 伯, 估, 伴, 伶, 伸, 伺, 似, 伽, 佃, 但, 位, 低, 住, 佐, + 佑, 体, 何, 佗, 佘, 余, 佚, 佛, 作, 佝, 佟, 你, 佣, 佩, 佬, 佯, 佰, 佳, 佶, 佻, 佼, 使, 侃, 侄, 侈, + 例, 侍, 侏, 侑, 侗, 供, 依, 侠, 侣, 侥, 侦, 侧, 侨, 侬, 侮, 侯, 侵, 便, 促, 俄, 俊, 俎, 俏, 俐, 俑, + 俗, 俘, 俚, 保, 俞, 俟, 信, 俨, 俩, 俪, 俭, 修, 俯, 俱, 俸, 俺, 俾, 倌, 倍, 倒, 倔, 倘, 候, 倚, 倜, + 借, 倡, 倦, 倩, 倪, 倭, 债, 值, 倾, 偃, 假, 偈, 偌, 偎, 偏, 偓, 偕, 做, 停, 健, 偶, 偷, 偻, 偿, 傀, + 傅, 傍, 傣, 傥, 储, 催, 傲, 傻, 像, 僚, 僧, 僮, 僵, 僻, 儋, 儒, 儡, 儿, 兀, 允, 元, 兄, 充, 兆, 先, + 光, 克, 免, 兑, 兔, 兖, 党, 兜, 兢, 入, 全, 八, 公, 六, 兮, 兰, 共, 关, 兴, 兵, 其, 具, 典, 兹, 养, + 兼, 兽, 冀, 内, 冈, 冉, 册, 再, 冒, 冕, 冗, 写, 军, 农, 冠, 冢, 冤, 冥, 冬, 冯, 冰, 冲, 决, 况, 冶, + 冷, 冻, 冼, 冽, 净, 凄, 准, 凇, 凉, 凋, 凌, 减, 凑, 凛, 凝, 几, 凡, 凤, 凭, 凯, 凰, 凳, 凶, 凸, 凹, + 出, 击, 函, 凿, 刀, 刁, 刃, 分, 切, 刊, 刍, 刎, 刑, 划, 列, 刘, 则, 刚, 创, 初, 删, 判, 刨, 利, 别, + 刮, 到, 制, 刷, 券, 刹, 刺, 刻, 刽, 剁, 剂, 剃, 削, 剌, 前, 剐, 剑, 剔, 剖, 剜, 剥, 剧, 剩, 剪, 副, + 割, 剽, 剿, 劈, 力, 劝, 办, 功, 加, 务, 劣, 动, 助, 努, 劫, 劭, 励, 劲, 劳, 劵, 劾, 势, 勃, 勇, 勉, + 勋, 勐, 勒, 勘, 募, 勤, 勺, 勾, 勿, 匀, 包, 匆, 匈, 匏, 匕, 化, 北, 匙, 匝, 匠, 匡, 匣, 匪, 匮, 匹, + 区, 医, 匾, 匿, 十, 千, 升, 午, 卉, 半, 华, 协, 卑, 卒, 卓, 单, 卖, 南, 博, 卜, 卞, 占, 卡, 卢, 卤, + 卦, 卧, 卫, 卯, 印, 危, 卲, 即, 却, 卵, 卷, 卸, 卿, 厂, 厄, 厅, 历, 厉, 压, 厌, 厕, 厘, 厚, 厝, 原, + 厢, 厥, 厦, 厨, 厩, 厮, 去, 县, 叁, 参, 又, 叉, 及, 友, 双, 反, 发, 叔, 取, 受, 变, 叙, 叛, 叠, 口, + 古, 句, 另, 叨, 叩, 只, 叫, 召, 叭, 叮, 可, 台, 叱, 史, 右, 叵, 叶, 号, 司, 叹, 叼, 叽, 吁, 吃, 各, + 吆, 合, 吉, 吊, 吋, 同, 名, 后, 吏, 吐, 向, 吒, 吓, 吕, 吖, 吗, 君, 吝, 吞, 吟, 吠, 否, 吧, 吨, 吩, + 含, 听, 吭, 吮, 启, 吱, 吴, 吵, 吸, 吹, 吻, 吼, 吾, 呀, 呃, 呆, 呈, 告, 呐, 呕, 呗, 员, 呛, 呜, 呢, + 呦, 周, 呱, 呲, 味, 呵, 呷, 呸, 呻, 呼, 命, 咀, 咂, 咄, 咆, 咋, 和, 咎, 咏, 咐, 咒, 咔, 咕, 咖, 咘, + 咙, 咚, 咝, 咣, 咤, 咦, 咧, 咨, 咩, 咪, 咫, 咬, 咭, 咯, 咱, 咳, 咸, 咻, 咽, 哀, 品, 哂, 哄, 哆, 哇, + 哈, 哉, 响, 哎, 哐, 哑, 哒, 哔, 哕, 哗, 哟, 哥, 哦, 哨, 哩, 哪, 哭, 哮, 哲, 哺, 哼, 哽, 唁, 唆, 唇, + 唉, 唏, 唐, 唑, 唛, 唠, 唢, 唤, 唧, 唬, 售, 唯, 唰, 唱, 唳, 唷, 唾, 啃, 啄, 商, 啊, 啕, 啖, 啜, 啡, + 啤, 啥, 啦, 啧, 啪, 啬, 啰, 啲, 啵, 啶, 啸, 啼, 啾, 喀, 喁, 喂, 喃, 善, 喆, 喇, 喉, 喊, 喋, 喔, 喘, + 喜, 喝, 喟, 喧, 喱, 喳, 喵, 喷, 喻, 喽, 嗄, 嗅, 嗑, 嗒, 嗓, 嗔, 嗖, 嗜, 嗝, 嗡, 嗣, 嗤, 嗦, 嗨, 嗪, + 嗫, 嗬, 嗯, 嗲, 嗷, 嗽, 嘀, 嘈, 嘉, 嘎, 嘏, 嘘, 嘛, 嘞, 嘟, 嘣, 嘭, 嘱, 嘲, 嘴, 嘶, 嘹, 嘻, 嘿, 噌, + 噎, 噗, 噘, 噙, 噜, 噢, 噤, 器, 噩, 噪, 噬, 噱, 噶, 噻, 噼, 嚎, 嚏, 嚓, 嚣, 嚷, 嚼, 囊, 囍, 囔, 囗, + 囚, 四, 回, 因, 团, 囤, 囧, 囫, 园, 囯, 困, 囱, 围, 囵, 囹, 固, 国, 图, 圃, 圄, 圆, 圈, 土, 圣, 在, + 圩, 圪, 圭, 地, 圳, 圹, 场, 圻, 圾, 址, 坂, 均, 坊, 坍, 坎, 坏, 坐, 坑, 块, 坚, 坛, 坝, 坞, 坟, 坠, + 坡, 坤, 坦, 坨, 坩, 坪, 坭, 坯, 坳, 坷, 坻, 垂, 垃, 垄, 垅, 型, 垌, 垒, 垚, 垛, 垡, 垢, 垣, 垤, 垦, + 垩, 垫, 垭, 垮, 埂, 埃, 埇, 埋, 城, 埔, 埕, 埚, 埝, 域, 埠, 埭, 埸, 培, 基, 堀, 堂, 堃, 堆, 堇, 堕, + 堡, 堤, 堪, 堰, 堵, 堺, 塌, 塍, 塑, 塔, 塘, 塞, 填, 塬, 塾, 境, 墅, 墉, 墓, 増, 墙, 增, 墟, 墨, 墩, + 壁, 壑, 壕, 壤, 士, 壬, 壮, 声, 壳, 壶, 壹, 处, 备, 复, 夏, 夔, 夕, 外, 夙, 多, 夜, 够, 大, 天, 太, + 夫, 夭, 央, 夯, 失, 头, 夷, 夸, 夹, 夺, 奁, 奂, 奄, 奇, 奈, 奉, 奋, 奎, 奏, 契, 奔, 奕, 奖, 套, 奘, + 奚, 奠, 奢, 奥, 女, 奴, 奶, 奸, 她, 好, 如, 妃, 妄, 妆, 妇, 妈, 妊, 妍, 妒, 妓, 妖, 妙, 妞, 妤, 妥, + 妨, 妩, 妪, 妫, 妮, 妯, 妲, 妹, 妻, 妾, 姆, 姊, 始, 姐, 姑, 姓, 委, 姗, 姚, 姜, 姝, 姣, 姥, 姨, 姬, + 姻, 姿, 威, 娃, 娄, 娅, 娆, 娇, 娈, 娉, 娌, 娓, 娘, 娜, 娟, 娠, 娣, 娥, 娩, 娱, 娲, 娴, 娶, 娼, 婀, + 婆, 婉, 婊, 婕, 婚, 婢, 婧, 婪, 婴, 婵, 婶, 婷, 婺, 婿, 媒, 媚, 媛, 媞, 媲, 媳, 嫁, 嫂, 嫉, 嫌, 嫒, + 嫔, 嫖, 嫚, 嫡, 嫣, 嫦, 嫩, 嫫, 嬅, 嬉, 嬗, 嬛, 嬴, 嬷, 孀, 子, 孑, 孔, 孕, 字, 存, 孙, 孚, 孛, 孜, + 孝, 孟, 孢, 季, 孤, 学, 孩, 孪, 孬, 孰, 孱, 孳, 孵, 孺, 孽, 宁, 它, 宅, 宇, 守, 安, 宋, 完, 宏, 宓, + 宕, 宗, 官, 宙, 定, 宛, 宜, 宝, 实, 宠, 审, 客, 宣, 室, 宥, 宦, 宪, 宫, 宰, 害, 宴, 宵, 家, 宸, 容, + 宽, 宾, 宿, 寂, 寄, 寅, 密, 寇, 富, 寐, 寒, 寓, 寝, 寞, 察, 寡, 寥, 寨, 寮, 寰, 寸, 对, 寺, 寻, 导, + 寿, 封, 射, 尅, 将, 尉, 尊, 小, 少, 尔, 尕, 尖, 尘, 尚, 尝, 尤, 尧, 尬, 就, 尴, 尸, 尹, 尺, 尼, 尽, + 尾, 尿, 局, 屁, 层, 居, 屈, 屉, 届, 屋, 屌, 屎, 屏, 屐, 屑, 展, 属, 屠, 屡, 履, 屯, 山, 屹, 屿, 岁, + 岂, 岌, 岐, 岑, 岔, 岖, 岗, 岚, 岛, 岩, 岬, 岭, 岱, 岳, 岷, 岸, 峁, 峋, 峒, 峙, 峡, 峥, 峦, 峨, 峪, + 峭, 峰, 峻, 崂, 崃, 崆, 崇, 崎, 崔, 崖, 崛, 崧, 崩, 崭, 崮, 崴, 崽, 嵇, 嵊, 嵋, 嵌, 嵘, 嵛, 嵩, 嵬, + 嶂, 嶙, 嶝, 巅, 巍, 川, 州, 巡, 巢, 工, 左, 巧, 巨, 巩, 巫, 差, 己, 已, 巳, 巴, 巷, 巾, 币, 市, 布, + 帅, 帆, 师, 希, 帐, 帕, 帖, 帘, 帚, 帛, 帜, 帝, 带, 帧, 席, 帮, 帷, 常, 帼, 帽, 幂, 幄, 幅, 幌, 幔, + 幕, 幡, 幢, 干, 平, 年, 并, 幸, 幺, 幻, 幼, 幽, 广, 庄, 庆, 庇, 床, 序, 庐, 库, 应, 底, 庖, 店, 庙, + 庚, 府, 庞, 废, 度, 座, 庭, 庵, 庶, 康, 庸, 庹, 庾, 廉, 廊, 廓, 廖, 延, 廷, 建, 开, 异, 弃, 弄, 弈, + 弊, 弋, 式, 弑, 弓, 引, 弗, 弘, 弛, 弟, 张, 弥, 弦, 弧, 弩, 弭, 弯, 弱, 弹, 强, 弼, 归, 当, 录, 彗, + 彝, 形, 彤, 彦, 彩, 彪, 彬, 彭, 彰, 影, 彷, 役, 彻, 彼, 往, 征, 径, 待, 徇, 很, 徉, 徊, 律, 徐, 徒, + 得, 徘, 徙, 徜, 御, 徨, 循, 微, 德, 徽, 心, 必, 忆, 忌, 忍, 忏, 忐, 忑, 忒, 忖, 志, 忘, 忙, 忠, 忡, + 忤, 忧, 忪, 快, 忱, 念, 忻, 忽, 忿, 怀, 态, 怂, 怄, 怅, 怆, 怎, 怒, 怕, 怖, 怜, 思, 怠, 怡, 急, 怦, + 性, 怨, 怪, 怫, 怯, 怵, 总, 怼, 怿, 恁, 恃, 恋, 恍, 恐, 恒, 恕, 恙, 恢, 恣, 恤, 恨, 恩, 恪, 恬, 恭, + 息, 恰, 恳, 恶, 恸, 恺, 恻, 恼, 恿, 悄, 悉, 悌, 悍, 悔, 悖, 悚, 悟, 悠, 患, 悦, 您, 悬, 悭, 悯, 悱, + 悲, 悴, 悸, 悻, 悼, 情, 惆, 惊, 惋, 惑, 惕, 惚, 惜, 惟, 惠, 惦, 惧, 惨, 惩, 惫, 惬, 惭, 惮, 惯, 惰, + 想, 惶, 惹, 惺, 愁, 愈, 愉, 意, 愕, 愚, 感, 愣, 愤, 愧, 愫, 愿, 慈, 慌, 慎, 慑, 慕, 慢, 慧, 慨, 慰, + 慵, 慷, 憋, 憎, 憔, 憧, 憨, 憩, 憬, 憷, 憾, 懂, 懈, 懊, 懋, 懑, 懒, 懦, 懵, 懿, 戈, 戊, 戌, 戍, 戎, + 戏, 成, 我, 戒, 或, 戗, 战, 戚, 戛, 戟, 截, 戬, 戮, 戳, 戴, 户, 戾, 房, 所, 扁, 扇, 扈, 扉, 手, 才, + 扎, 扑, 扒, 打, 扔, 托, 扛, 扞, 扣, 扦, 执, 扩, 扪, 扫, 扬, 扭, 扮, 扯, 扰, 扳, 扶, 批, 扼, 找, 承, + 技, 抄, 抉, 把, 抑, 抒, 抓, 投, 抖, 抗, 折, 抚, 抛, 抠, 抡, 抢, 护, 报, 抨, 披, 抬, 抱, 抵, 抹, 押, + 抽, 抿, 拂, 拄, 担, 拆, 拇, 拈, 拉, 拌, 拍, 拎, 拐, 拒, 拓, 拔, 拖, 拗, 拘, 拙, 拚, 招, 拜, 拟, 拢, + 拣, 拥, 拦, 拧, 拨, 择, 括, 拭, 拮, 拯, 拱, 拳, 拴, 拷, 拼, 拽, 拾, 拿, 持, 挂, 指, 按, 挎, 挑, 挖, + 挚, 挛, 挝, 挞, 挟, 挠, 挡, 挣, 挤, 挥, 挨, 挪, 挫, 振, 挺, 挽, 捂, 捅, 捆, 捉, 捋, 捌, 捍, 捎, 捏, + 捐, 捕, 捞, 损, 捡, 换, 捣, 捧, 据, 捶, 捷, 捺, 捻, 掀, 掂, 掇, 授, 掉, 掌, 掏, 掐, 排, 掖, 掘, 掠, + 探, 掣, 接, 控, 推, 掩, 措, 掬, 掮, 掰, 掳, 掴, 掷, 掸, 掺, 揄, 揉, 揍, 描, 提, 插, 握, 揣, 揩, 揪, + 揭, 援, 揶, 揽, 搀, 搁, 搂, 搅, 搏, 搐, 搓, 搔, 搜, 搞, 搡, 搧, 搪, 搬, 搭, 携, 搽, 摁, 摄, 摆, 摇, + 摈, 摊, 摒, 摔, 摘, 摞, 摧, 摩, 摸, 摹, 撂, 撅, 撇, 撑, 撒, 撕, 撞, 撤, 撩, 撬, 播, 撮, 撰, 撵, 撸, + 撺, 撼, 擀, 擂, 擅, 操, 擎, 擒, 擘, 擞, 擢, 擦, 攀, 攒, 攘, 攥, 攫, 支, 收, 攸, 改, 攻, 放, 政, 故, + 效, 敌, 敏, 救, 敕, 敖, 教, 敛, 敝, 敞, 敢, 散, 敦, 敬, 数, 敲, 整, 敷, 文, 斋, 斌, 斐, 斑, 斓, 斗, + 料, 斛, 斜, 斟, 斡, 斤, 斥, 斧, 斩, 断, 斯, 新, 方, 施, 旁, 旅, 旋, 旌, 族, 旖, 旗, 无, 既, 日, 旦, + 旧, 旨, 早, 旬, 旭, 旮, 旯, 旱, 时, 旷, 旺, 旻, 昀, 昂, 昆, 昊, 昌, 明, 昏, 易, 昔, 昕, 昙, 昝, 星, + 映, 春, 昧, 昨, 昭, 是, 昱, 昴, 昵, 昶, 昼, 显, 晃, 晋, 晌, 晏, 晒, 晓, 晔, 晕, 晖, 晗, 晚, 晞, 晟, + 晤, 晦, 晨, 普, 景, 晰, 晴, 晶, 晷, 智, 晾, 暂, 暄, 暇, 暌, 暑, 暖, 暗, 暧, 暨, 暮, 暴, 暹, 暾, 曈, + 曙, 曜, 曝, 曦, 曰, 曲, 曳, 更, 曹, 曼, 曾, 替, 最, 月, 有, 朋, 服, 朐, 朔, 朕, 朗, 望, 朝, 期, 朦, + 木, 未, 末, 本, 札, 术, 朱, 朴, 朵, 机, 朽, 杀, 杂, 权, 杆, 杈, 杉, 李, 杏, 材, 村, 杓, 杖, 杜, 杞, + 束, 杠, 条, 来, 杨, 杭, 杯, 杰, 杳, 杵, 杷, 松, 板, 极, 构, 枇, 枉, 枋, 析, 枕, 林, 枚, 果, 枝, 枞, + 枢, 枣, 枥, 枪, 枫, 枭, 枯, 枰, 枳, 架, 枷, 枸, 柃, 柄, 柏, 某, 柑, 柒, 染, 柔, 柘, 柚, 柜, 柞, 柠, + 查, 柩, 柬, 柯, 柱, 柳, 柴, 柿, 栀, 栅, 标, 栈, 栋, 栌, 栎, 栏, 树, 栓, 栖, 栗, 校, 栩, 株, 样, 核, + 根, 格, 栽, 栾, 桁, 桂, 桃, 框, 案, 桉, 桌, 桎, 桐, 桑, 桓, 桔, 桠, 桢, 档, 桥, 桦, 桨, 桩, 桴, 桶, + 桷, 梁, 梅, 梆, 梏, 梓, 梗, 梢, 梦, 梧, 梨, 梭, 梯, 械, 梳, 梵, 检, 棂, 棉, 棋, 棍, 棒, 棕, 棘, 棚, + 棠, 棣, 森, 棱, 棵, 棺, 椁, 椅, 椋, 植, 椎, 椒, 椟, 椤, 椭, 椰, 椴, 椹, 椿, 楂, 楔, 楚, 楞, 楠, 楣, + 楷, 楸, 楼, 概, 榄, 榆, 榈, 榉, 榔, 榕, 榛, 榜, 榨, 榫, 榭, 榴, 榷, 榻, 槃, 槌, 槎, 槐, 槛, 槟, 槭, + 槽, 槿, 樊, 樟, 模, 樨, 横, 樯, 樱, 樵, 樽, 樾, 橄, 橇, 橐, 橘, 橙, 橡, 橱, 檀, 檐, 檗, 檬, 欠, 次, + 欢, 欣, 欧, 欲, 欸, 欺, 款, 歆, 歇, 歉, 歌, 歙, 止, 正, 此, 步, 武, 歧, 歩, 歪, 歹, 死, 歼, 殁, 殃, + 殆, 殇, 殉, 殊, 残, 殒, 殓, 殖, 殚, 殡, 殴, 段, 殷, 殿, 毁, 毂, 毅, 毋, 母, 每, 毒, 毓, 比, 毕, 毗, + 毙, 毛, 毡, 毫, 毯, 毽, 氏, 民, 氓, 气, 氚, 氛, 氟, 氢, 氤, 氦, 氧, 氨, 氪, 氮, 氯, 氰, 氲, 水, 永, + 汀, 汁, 求, 汇, 汉, 汊, 汐, 汕, 汗, 汛, 汝, 汞, 江, 池, 污, 汤, 汨, 汩, 汪, 汰, 汲, 汴, 汶, 汹, 汽, + 汾, 沁, 沂, 沃, 沅, 沈, 沉, 沌, 沏, 沐, 沓, 沙, 沛, 沟, 没, 沢, 沣, 沥, 沦, 沧, 沪, 沫, 沭, 沮, 沱, + 河, 沸, 油, 治, 沼, 沽, 沾, 沿, 泄, 泉, 泊, 泌, 泓, 泔, 法, 泖, 泗, 泛, 泞, 泠, 泡, 波, 泣, 泥, 注, + 泪, 泫, 泮, 泯, 泰, 泱, 泳, 泵, 泷, 泸, 泺, 泻, 泼, 泽, 泾, 洁, 洋, 洒, 洗, 洙, 洛, 洞, 津, 洪, 洮, + 洱, 洲, 洵, 洹, 洺, 活, 洼, 洽, 派, 流, 浃, 浅, 浆, 浇, 浈, 浊, 测, 济, 浏, 浐, 浑, 浒, 浓, 浔, 浙, + 浚, 浜, 浠, 浣, 浦, 浩, 浪, 浮, 浴, 海, 浸, 涂, 涅, 消, 涉, 涌, 涎, 涑, 涓, 涕, 涛, 涝, 涞, 涟, 涠, + 涡, 涣, 涤, 润, 涧, 涨, 涩, 涪, 涮, 涯, 液, 涵, 涸, 涿, 淀, 淄, 淅, 淆, 淇, 淋, 淌, 淑, 淖, 淘, 淝, + 淞, 淡, 淤, 淦, 淫, 淬, 淮, 深, 淳, 混, 淹, 添, 淼, 清, 渊, 渌, 渍, 渎, 渐, 渑, 渔, 渗, 渚, 渝, 渠, + 渡, 渣, 渤, 渥, 温, 渭, 港, 渲, 渴, 游, 渺, 湃, 湄, 湉, 湍, 湎, 湖, 湘, 湛, 湫, 湾, 湿, 溃, 溅, 溆, + 溉, 溏, 源, 溜, 溟, 溢, 溥, 溧, 溪, 溯, 溶, 溺, 滁, 滇, 滋, 滑, 滔, 滕, 滘, 滚, 滞, 满, 滢, 滤, 滥, + 滦, 滨, 滩, 滴, 滹, 漂, 漆, 漉, 漏, 漓, 演, 漕, 漠, 漩, 漪, 漫, 漭, 漯, 漱, 漳, 漾, 潆, 潇, 潋, 潍, + 潘, 潜, 潞, 潢, 潦, 潭, 潮, 潸, 潺, 潼, 澄, 澈, 澍, 澎, 澜, 澡, 澧, 澳, 澶, 激, 濂, 濑, 濒, 濠, 濡, + 濮, 濯, 瀑, 瀚, 瀛, 灌, 灏, 灞, 火, 灭, 灯, 灰, 灵, 灶, 灸, 灼, 灾, 灿, 炀, 炅, 炉, 炊, 炎, 炒, 炔, + 炕, 炖, 炙, 炜, 炫, 炬, 炭, 炮, 炯, 炳, 炷, 炸, 点, 炼, 炽, 烀, 烁, 烂, 烃, 烈, 烊, 烘, 烙, 烛, 烟, + 烤, 烦, 烧, 烨, 烩, 烫, 烬, 热, 烯, 烷, 烹, 烽, 焉, 焊, 焓, 焕, 焖, 焗, 焘, 焙, 焚, 焦, 焯, 焰, 焱, + 然, 煊, 煌, 煎, 煜, 煞, 煤, 煦, 照, 煨, 煮, 煲, 煳, 煽, 熄, 熊, 熏, 熔, 熙, 熟, 熠, 熨, 熬, 熵, 熹, + 燃, 燊, 燎, 燕, 燥, 燮, 爆, 爪, 爬, 爱, 爵, 父, 爷, 爸, 爹, 爽, 片, 版, 牌, 牍, 牒, 牙, 牛, 牟, 牠, + 牡, 牢, 牧, 物, 牲, 牵, 特, 牺, 牾, 犀, 犁, 犄, 犇, 犊, 犒, 犟, 犬, 犯, 状, 犷, 犸, 犹, 狂, 狄, 狈, + 狐, 狒, 狗, 狙, 狞, 狠, 狡, 狩, 独, 狭, 狮, 狰, 狱, 狸, 狼, 猁, 猎, 猖, 猛, 猜, 猝, 猥, 猩, 猪, 猫, + 猬, 献, 猴, 猷, 猹, 猾, 猿, 獒, 獗, 獭, 獾, 玄, 率, 玉, 王, 玑, 玖, 玛, 玟, 玥, 玩, 玫, 玮, 环, 现, + 玲, 玳, 玷, 玹, 玺, 玻, 珀, 珂, 珈, 珉, 珊, 珍, 珏, 珑, 珙, 珞, 珠, 珥, 班, 珮, 珲, 珺, 球, 琅, 理, + 琉, 琊, 琏, 琐, 琛, 琢, 琤, 琥, 琦, 琨, 琪, 琬, 琮, 琰, 琳, 琴, 琵, 琶, 琼, 瑁, 瑄, 瑕, 瑙, 瑚, 瑛, + 瑜, 瑞, 瑟, 瑠, 瑭, 瑰, 瑶, 瑷, 瑾, 璀, 璃, 璇, 璋, 璐, 璞, 璟, 璧, 璨, 瓜, 瓢, 瓣, 瓦, 瓮, 瓯, 瓶, + 瓷, 甄, 甘, 甚, 甜, 生, 甥, 用, 甩, 甫, 甬, 甭, 田, 由, 甲, 申, 电, 男, 甸, 町, 画, 畅, 畈, 畊, 界, + 畏, 畔, 留, 畜, 略, 番, 畴, 畸, 畿, 疃, 疆, 疏, 疑, 疖, 疗, 疙, 疚, 疝, 疟, 疡, 疣, 疤, 疫, 疮, 疯, + 疱, 疲, 疴, 疵, 疸, 疹, 疼, 疽, 疾, 病, 症, 痉, 痊, 痍, 痒, 痔, 痕, 痘, 痛, 痞, 痢, 痣, 痧, 痨, 痪, + 痫, 痰, 痱, 痴, 痹, 痼, 瘀, 瘁, 瘙, 瘟, 瘠, 瘢, 瘤, 瘦, 瘩, 瘪, 瘫, 瘳, 瘴, 瘸, 瘾, 癌, 癖, 癜, 癞, + 癣, 癫, 登, 白, 百, 皂, 的, 皆, 皇, 皋, 皎, 皑, 皓, 皖, 皙, 皮, 皱, 皿, 盂, 盅, 盆, 盈, 益, 盎, 盏, + 盐, 监, 盒, 盔, 盖, 盗, 盘, 盛, 盟, 目, 盯, 盱, 盲, 直, 相, 盹, 盼, 盾, 省, 眈, 眉, 看, 眙, 真, 眠, + 眨, 眩, 眬, 眯, 眶, 眷, 眸, 眺, 眼, 着, 睁, 睇, 睐, 睑, 睛, 睡, 睢, 督, 睦, 睫, 睬, 睹, 睽, 睾, 睿, + 瞄, 瞅, 瞌, 瞎, 瞑, 瞒, 瞟, 瞠, 瞥, 瞧, 瞩, 瞪, 瞬, 瞭, 瞰, 瞳, 瞻, 瞿, 矍, 矗, 矛, 矜, 矢, 矣, 知, + 矩, 矫, 矬, 短, 矮, 石, 矶, 矸, 矽, 矾, 矿, 砀, 码, 砂, 砌, 砍, 砒, 研, 砖, 砚, 砝, 砣, 砥, 砭, 砰, + 破, 砷, 砸, 砺, 砼, 砾, 础, 硅, 硌, 硒, 硕, 硖, 硚, 硝, 硫, 硬, 确, 硼, 碉, 碌, 碍, 碎, 碑, 碓, 碗, + 碘, 碚, 碜, 碟, 碣, 碧, 碰, 碱, 碳, 碴, 碾, 磁, 磅, 磊, 磋, 磐, 磕, 磨, 磴, 磷, 磺, 礁, 示, 礼, 社, + 祀, 祁, 祈, 祉, 祎, 祐, 祖, 祚, 祛, 祝, 神, 祟, 祠, 祢, 祥, 票, 祭, 祯, 祷, 祸, 祺, 禀, 禁, 禄, 禅, + 福, 禧, 禹, 禺, 离, 禽, 禾, 秀, 私, 秃, 秆, 秉, 秋, 种, 科, 秒, 秘, 租, 秣, 秤, 秦, 秧, 秩, 积, 称, + 秸, 移, 秽, 稀, 程, 稍, 税, 稔, 稚, 稞, 稠, 稣, 稳, 稷, 稹, 稻, 稼, 稽, 稿, 穆, 穗, 穴, 究, 穷, 穹, + 空, 穿, 突, 窃, 窄, 窈, 窍, 窑, 窒, 窕, 窖, 窗, 窘, 窜, 窝, 窟, 窠, 窥, 窦, 窨, 窿, 立, 竖, 站, 竞, + 竟, 章, 竣, 童, 竭, 端, 竹, 竺, 竽, 竿, 笃, 笆, 笈, 笋, 笑, 笔, 笙, 笛, 笠, 符, 笨, 第, 笳, 笸, 笼, + 等, 筋, 筏, 筐, 筑, 筒, 答, 策, 筛, 筝, 筠, 筱, 筵, 筷, 筹, 签, 简, 箍, 箔, 箕, 算, 管, 箩, 箫, 箭, + 箱, 箴, 篁, 篆, 篇, 篑, 篓, 篝, 篡, 篦, 篪, 篮, 篱, 篷, 篼, 簇, 簋, 簧, 簪, 簸, 簿, 籁, 籍, 米, 类, + 籼, 籽, 粉, 粑, 粒, 粕, 粗, 粘, 粟, 粤, 粥, 粪, 粮, 粱, 粲, 粳, 粹, 粼, 粽, 精, 糊, 糕, 糖, 糗, 糙, + 糟, 糠, 糯, 系, 紊, 素, 索, 紧, 紫, 累, 絮, 綦, 繁, 纂, 纠, 纡, 红, 纣, 纤, 约, 级, 纨, 纪, 纫, 纬, + 纭, 纯, 纰, 纱, 纲, 纳, 纵, 纶, 纷, 纸, 纹, 纺, 纽, 纾, 线, 绀, 练, 组, 绅, 细, 织, 终, 绉, 绊, 绋, + 绌, 绍, 绎, 经, 绑, 绒, 结, 绔, 绕, 绘, 给, 绚, 绛, 络, 绝, 绞, 统, 绢, 绣, 绥, 继, 绩, 绪, 绫, 续, + 绮, 绯, 绰, 绳, 维, 绵, 绷, 绸, 绻, 综, 绽, 绿, 缀, 缄, 缅, 缆, 缇, 缉, 缎, 缓, 缔, 缕, 编, 缘, 缙, + 缚, 缛, 缜, 缝, 缠, 缢, 缤, 缨, 缩, 缪, 缬, 缭, 缮, 缰, 缱, 缴, 缸, 缺, 罂, 罄, 罐, 网, 罔, 罕, 罗, + 罚, 罡, 罢, 罩, 罪, 置, 署, 罹, 羁, 羊, 羌, 美, 羔, 羚, 羞, 羡, 群, 羧, 羯, 羲, 羸, 羹, 羽, 羿, 翁, + 翅, 翊, 翌, 翎, 翔, 翘, 翟, 翠, 翡, 翩, 翰, 翱, 翻, 翼, 耀, 老, 考, 耄, 者, 耆, 耋, 而, 耍, 耐, 耒, + 耕, 耗, 耘, 耙, 耜, 耪, 耳, 耶, 耷, 耸, 耻, 耽, 耿, 聂, 聆, 聊, 聋, 职, 联, 聘, 聚, 聪, 肃, 肆, 肇, + 肉, 肋, 肌, 肖, 肘, 肚, 肛, 肝, 肠, 股, 肢, 肤, 肥, 肩, 肪, 肮, 肯, 肱, 育, 肴, 肺, 肾, 肿, 胀, 胁, + 胃, 胆, 背, 胎, 胖, 胗, 胚, 胛, 胜, 胞, 胡, 胤, 胥, 胧, 胫, 胭, 胯, 胰, 胱, 胳, 胶, 胸, 胺, 能, 脂, + 脆, 脉, 脊, 脍, 脏, 脐, 脑, 脓, 脖, 脚, 脯, 脱, 脸, 脾, 腆, 腈, 腊, 腋, 腌, 腐, 腑, 腓, 腔, 腕, 腥, + 腩, 腭, 腮, 腰, 腱, 腴, 腹, 腺, 腻, 腼, 腾, 腿, 膀, 膈, 膊, 膏, 膑, 膛, 膜, 膝, 膨, 膳, 膺, 臀, 臂, + 臃, 臆, 臊, 臣, 臧, 自, 臬, 臭, 至, 致, 臻, 臼, 舀, 舅, 舆, 舌, 舍, 舐, 舒, 舔, 舛, 舜, 舞, 舟, 航, + 舫, 般, 舰, 舱, 舵, 舶, 舷, 舸, 船, 艇, 艋, 艘, 艮, 良, 艰, 色, 艳, 艺, 艾, 艿, 节, 芊, 芋, 芍, 芒, + 芗, 芙, 芜, 芝, 芥, 芦, 芩, 芪, 芬, 芭, 芮, 芯, 花, 芳, 芷, 芸, 芹, 芽, 芾, 苇, 苋, 苍, 苏, 苑, 苓, + 苔, 苗, 苛, 苞, 苟, 苡, 苣, 若, 苦, 苫, 苯, 英, 苷, 苹, 茁, 茂, 范, 茄, 茅, 茆, 茉, 茌, 茎, 茗, 茛, + 茜, 茧, 茨, 茫, 茬, 茯, 茱, 茳, 茴, 茵, 茶, 茸, 茹, 茼, 荀, 荃, 荆, 荇, 草, 荏, 荐, 荒, 荔, 荚, 荛, + 荞, 荟, 荠, 荡, 荣, 荤, 荧, 荨, 荫, 药, 荷, 荸, 荻, 荼, 莅, 莆, 莉, 莎, 莒, 莓, 莘, 莜, 莞, 莠, 莪, + 莫, 莱, 莲, 莴, 获, 莹, 莺, 莽, 菀, 菁, 菅, 菇, 菊, 菌, 菏, 菖, 菘, 菜, 菠, 菡, 菩, 菱, 菲, 萃, 萄, + 萋, 萌, 萍, 萎, 萝, 萤, 营, 萦, 萧, 萨, 萱, 萸, 落, 葆, 著, 葚, 葛, 葡, 董, 葩, 葫, 葬, 葱, 葳, 葵, + 葺, 蒂, 蒋, 蒙, 蒜, 蒯, 蒲, 蒸, 蒿, 蓁, 蓄, 蓉, 蓓, 蓝, 蓟, 蓥, 蓦, 蓬, 蓼, 蔑, 蔓, 蔗, 蔚, 蔡, 蔫, + 蔬, 蔷, 蔺, 蔻, 蔼, 蔽, 蕃, 蕉, 蕊, 蕙, 蕨, 蕲, 蕴, 蕾, 薄, 薇, 薏, 薛, 薪, 薯, 薰, 薷, 藁, 藉, 藏, + 藐, 藓, 藕, 藜, 藠, 藤, 藩, 藻, 藿, 蘑, 蘸, 虎, 虏, 虐, 虑, 虔, 虚, 虞, 虫, 虱, 虹, 虻, 虽, 虾, 蚀, + 蚁, 蚂, 蚊, 蚌, 蚓, 蚕, 蚝, 蚣, 蚤, 蚪, 蚬, 蚯, 蚱, 蚴, 蛀, 蛆, 蛇, 蛉, 蛊, 蛋, 蛎, 蛐, 蛔, 蛙, 蛛, + 蛟, 蛤, 蛮, 蛰, 蛳, 蛹, 蛾, 蜀, 蜂, 蜃, 蜇, 蜈, 蜊, 蜍, 蜒, 蜓, 蜕, 蜗, 蜘, 蜚, 蜜, 蜡, 蜢, 蜥, 蜱, + 蜴, 蜷, 蜻, 蜿, 蝇, 蝈, 蝉, 蝌, 蝎, 蝗, 蝙, 蝠, 蝮, 蝴, 蝶, 蝽, 螂, 螃, 螈, 融, 螨, 螳, 螺, 蟀, 蟆, + 蟊, 蟋, 蟑, 蟒, 蟠, 蟹, 蟾, 蠊, 蠕, 蠡, 蠢, 血, 衅, 行, 衍, 衔, 街, 衙, 衡, 衢, 衣, 补, 表, 衩, 衫, + 衬, 衮, 衰, 衲, 衷, 袁, 袂, 袄, 袅, 袈, 袋, 袍, 袒, 袖, 袜, 被, 袭, 袱, 裁, 裂, 装, 裆, 裔, 裕, 裘, + 裙, 裟, 裤, 裨, 裱, 裳, 裴, 裸, 裹, 褂, 褐, 褒, 褓, 褔, 褚, 褛, 褥, 褪, 褴, 褶, 襁, 襄, 襟, 西, 要, + 覃, 覆, 见, 观, 规, 觅, 视, 览, 觉, 觊, 觎, 觐, 觑, 角, 觞, 解, 觥, 触, 言, 訾, 詹, 誉, 誓, 警, 譬, + 计, 订, 讣, 认, 讥, 讧, 讨, 让, 讪, 训, 议, 讯, 记, 讲, 讳, 讴, 讶, 讷, 许, 讹, 论, 讼, 讽, 设, 访, + 诀, 证, 诃, 评, 诅, 识, 诈, 诉, 诊, 诋, 词, 诏, 译, 诓, 试, 诗, 诘, 诙, 诚, 诛, 话, 诞, 诟, 诠, 诡, + 询, 诣, 诤, 该, 详, 诧, 诩, 诫, 诬, 语, 误, 诱, 诲, 说, 诵, 诶, 请, 诸, 诹, 诺, 读, 诽, 课, 诿, 谀, + 谁, 调, 谅, 谆, 谈, 谊, 谋, 谌, 谍, 谎, 谏, 谐, 谑, 谓, 谕, 谖, 谘, 谙, 谚, 谛, 谜, 谟, 谢, 谣, 谤, + 谦, 谧, 谨, 谩, 谬, 谭, 谮, 谯, 谱, 谴, 谶, 谷, 豁, 豆, 豇, 豉, 豌, 豚, 象, 豢, 豪, 豫, 豹, 豺, 貂, + 貅, 貉, 貌, 貔, 贝, 贞, 负, 贡, 财, 责, 贤, 败, 账, 货, 质, 贩, 贪, 贫, 贬, 购, 贮, 贯, 贰, 贱, 贲, + 贴, 贵, 贷, 贸, 费, 贺, 贻, 贼, 贾, 贿, 赁, 赂, 赃, 资, 赅, 赈, 赉, 赊, 赋, 赌, 赎, 赏, 赐, 赓, 赔, + 赖, 赘, 赚, 赛, 赝, 赞, 赠, 赡, 赢, 赣, 赤, 赦, 赫, 走, 赳, 赴, 赵, 赶, 起, 趁, 超, 越, 趋, 趟, 趣, + 足, 趴, 趵, 趸, 趺, 趾, 跃, 跄, 跆, 跋, 跌, 跎, 跑, 跚, 跛, 距, 跟, 跤, 跨, 跪, 跬, 路, 跳, 践, 跶, + 跷, 跹, 跺, 跻, 踉, 踊, 踌, 踏, 踝, 踞, 踢, 踩, 踪, 踮, 踯, 踱, 踵, 踹, 踺, 蹁, 蹂, 蹄, 蹈, 蹉, 蹊, + 蹋, 蹒, 蹚, 蹦, 蹩, 蹬, 蹭, 蹲, 蹴, 蹶, 蹼, 蹿, 躁, 躅, 躇, 躏, 身, 躬, 躯, 躲, 躺, 车, 轧, 轨, 轩, + 轫, 转, 轮, 软, 轰, 轱, 轲, 轳, 轴, 轶, 轸, 轻, 轼, 载, 轿, 较, 辄, 辅, 辆, 辈, 辉, 辊, 辍, 辐, 辑, + 输, 辕, 辖, 辗, 辘, 辙, 辛, 辜, 辞, 辟, 辣, 辨, 辩, 辫, 辰, 辱, 边, 辽, 达, 迁, 迂, 迄, 迅, 过, 迈, + 迎, 运, 近, 返, 还, 这, 进, 远, 违, 连, 迟, 迢, 迥, 迦, 迩, 迪, 迫, 迭, 述, 迷, 迸, 迹, 追, 退, 送, + 适, 逃, 逅, 逆, 选, 逊, 逋, 逍, 透, 逐, 逑, 递, 途, 逗, 通, 逛, 逝, 逞, 速, 造, 逡, 逢, 逮, 逯, 逵, + 逸, 逻, 逼, 逾, 遁, 遂, 遇, 遍, 遏, 遐, 遑, 道, 遗, 遛, 遢, 遣, 遥, 遨, 遭, 遮, 遴, 遵, 避, 邀, 邂, + 邃, 邋, 邑, 邓, 邕, 邙, 邛, 邝, 邡, 邢, 那, 邦, 邪, 邬, 邮, 邯, 邰, 邱, 邳, 邵, 邸, 邹, 邺, 邻, 郁, + 郅, 郇, 郊, 郎, 郑, 郓, 郜, 郝, 郡, 郧, 部, 郫, 郭, 郯, 郴, 郸, 都, 鄂, 鄙, 鄞, 鄢, 鄱, 酉, 酊, 酋, + 酌, 配, 酐, 酒, 酗, 酚, 酝, 酞, 酣, 酥, 酩, 酪, 酬, 酮, 酯, 酰, 酱, 酵, 酶, 酷, 酸, 酿, 醇, 醉, 醋, + 醍, 醐, 醒, 醛, 醺, 采, 釉, 释, 里, 重, 野, 量, 金, 釜, 鉴, 銮, 鏖, 鑫, 钇, 针, 钉, 钊, 钎, 钏, 钐, + 钒, 钓, 钗, 钙, 钛, 钜, 钝, 钞, 钟, 钠, 钢, 钣, 钥, 钦, 钧, 钨, 钩, 钮, 钯, 钰, 钱, 钲, 钳, 钴, 钵, + 钻, 钼, 钾, 钿, 铀, 铁, 铂, 铃, 铄, 铅, 铆, 铉, 铋, 铍, 铎, 铐, 铑, 铖, 铛, 铜, 铝, 铟, 铠, 铡, 铣, + 铤, 铧, 铨, 铩, 铬, 铭, 铮, 铰, 铲, 银, 铷, 铸, 铺, 链, 铿, 销, 锁, 锂, 锄, 锅, 锆, 锈, 锉, 锋, 锌, + 锏, 锐, 锑, 锒, 错, 锚, 锟, 锡, 锢, 锣, 锤, 锥, 锦, 锨, 锭, 键, 锯, 锰, 锲, 锴, 锵, 锷, 锹, 锻, 镀, + 镁, 镂, 镇, 镉, 镊, 镌, 镍, 镏, 镐, 镑, 镔, 镕, 镖, 镜, 镣, 镭, 镯, 镰, 镳, 镶, 长, 门, 闩, 闪, 闫, + 闭, 问, 闯, 闰, 闲, 闳, 间, 闵, 闷, 闸, 闹, 闺, 闻, 闽, 闾, 阀, 阁, 阂, 阄, 阅, 阆, 阉, 阎, 阐, 阑, + 阔, 阕, 阖, 阙, 阚, 阜, 队, 阡, 阪, 阮, 阱, 防, 阳, 阴, 阵, 阶, 阻, 阿, 陀, 陂, 附, 际, 陆, 陇, 陈, + 陉, 陋, 陌, 降, 限, 陕, 陛, 陡, 院, 除, 陨, 险, 陪, 陬, 陵, 陶, 陷, 隅, 隆, 隋, 隍, 随, 隐, 隔, 隗, + 隘, 隙, 障, 隧, 隶, 隼, 隽, 难, 雀, 雁, 雄, 雅, 集, 雇, 雉, 雌, 雍, 雏, 雒, 雕, 雨, 雪, 雯, 雳, 零, + 雷, 雹, 雾, 需, 霁, 霄, 霆, 震, 霈, 霉, 霍, 霎, 霏, 霓, 霖, 霜, 霞, 霪, 露, 霸, 霹, 霾, 靑, 青, 靓, + 靖, 静, 靛, 非, 靠, 靡, 面, 革, 靳, 靴, 靶, 鞅, 鞋, 鞍, 鞑, 鞘, 鞠, 鞭, 韦, 韧, 韩, 韫, 韬, 韭, 音, + 韵, 韶, 页, 顶, 顷, 项, 顺, 须, 顽, 顾, 顿, 颀, 颁, 颂, 预, 颅, 领, 颇, 颈, 颊, 颌, 颍, 颐, 频, 颓, + 颖, 颗, 题, 颚, 颜, 额, 颠, 颢, 颤, 颦, 颧, 风, 飒, 飓, 飘, 飙, 飚, 飞, 食, 飧, 餍, 餐, 餮, 饕, 饥, + 饨, 饪, 饭, 饮, 饯, 饰, 饱, 饲, 饴, 饵, 饶, 饷, 饺, 饼, 饽, 饿, 馀, 馁, 馄, 馅, 馆, 馈, 馊, 馋, 馍, + 馏, 馑, 馒, 馕, 首, 馗, 香, 馥, 馨, 马, 驭, 驮, 驯, 驰, 驱, 驳, 驴, 驶, 驷, 驸, 驹, 驻, 驼, 驾, 驿, + 骁, 骂, 骄, 骅, 骆, 骇, 骈, 骊, 骋, 验, 骏, 骐, 骑, 骓, 骗, 骚, 骛, 骜, 骝, 骞, 骠, 骡, 骤, 骥, 骨, + 骰, 骷, 骸, 骺, 骼, 髂, 髅, 髋, 髌, 髓, 高, 髦, 髯, 鬃, 鬓, 鬟, 鬼, 魁, 魂, 魄, 魅, 魇, 魉, 魍, 魏, + 魔, 魟, 鱼, 鱿, 鲁, 鲅, 鲈, 鲍, 鲑, 鲜, 鲟, 鲠, 鲢, 鲤, 鲨, 鲫, 鲭, 鲳, 鲶, 鲷, 鲸, 鲼, 鳃, 鳄, 鳅, + 鳌, 鳍, 鳕, 鳖, 鳗, 鳝, 鳞, 鳟, 鸟, 鸠, 鸡, 鸢, 鸣, 鸥, 鸦, 鸩, 鸪, 鸫, 鸭, 鸯, 鸳, 鸵, 鸽, 鸾, 鸿, + 鹁, 鹂, 鹃, 鹅, 鹉, 鹊, 鹌, 鹏, 鹑, 鹜, 鹞, 鹤, 鹦, 鹧, 鹫, 鹭, 鹰, 鹳, 鹿, 麂, 麋, 麒, 麓, 麝, 麟, + 麦, 麸, 麻, 麾, 黄, 黍, 黎, 黏, 黑, 黔, 默, 黛, 黝, 黟, 黯, 鼎, 鼓, 鼠, 鼬, 鼹, 鼻, 鼾, 齐, 齿, 龃, + 龄, 龅, 龈, 龉, 龊, 龌, 龙, 龚, 龟, "\U0002B5AF", "\U0002B689"] + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + trim_silence: True + normalize: False + max_duration: 16.7 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + normalize: False + labels: *labels + batch_size: 32 + shuffle: False + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: 1 + residual: false + separable: *separable + stride: [2] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [2] + dropout: *dropout + filters: 512 + kernel: [87] + repeat: 1 + residual: false + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: &enc_filters 1024 + kernel: [1] + repeat: 1 + residual: false + stride: [1] + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_filters + num_classes: 5206 + vocabulary: *labels + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: .01 + # optimizer arguments + betas: [0.8, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # pytorch lightning args + # monitor: val_loss + # reduce_on_plateau: false + + # Scheduler params + warmup_steps: null + warmup_ratio: null + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_wer" + mode: "min" + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/experimental/conformer/conformer_rnnt_bpe.yaml b/tts/NeMo/examples/asr/experimental/conformer/conformer_rnnt_bpe.yaml new file mode 100644 index 0000000..e7c2bea --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/conformer/conformer_rnnt_bpe.yaml @@ -0,0 +1,201 @@ +# It contains the default values for training a Conformer ASR model medium size with RNNT loss and BPE-based vocabulary. +# Default learning parameters in this config are set for effective batch size of 2K. +# To train it with smaller batch sizes, you may need to re-tune the learning parameters or use higher accumulate_grad_batches. + +# You may find more info about Conformer-CTC here: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/stable/asr/models.html#conformer-ctc +# Pre-trained models of Conformer-CTC can be found here: https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/stable/asr/results.html + +name: "Conformer-RNNT-BPE" + +model: + sample_rate: &sample_rate 16000 + compute_eval_loss: false # disables loss evaluation for validation and test data + log_prediction: true # enables logging sample predictions in the output during training + ctc_reduction: 'mean_batch' + + model_defaults: + se: true + se_context_size: -1 + # encoder / decoder / joint values + enc_hidden: ${model.encoder.d_model} + pred_hidden: 640 + joint_hidden: 640 + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 16 # you may increase batch_size if your memory allows + shuffle: true + num_workers: 8 + pin_memory: false + use_start_end_token: true + trim_silence: false + max_duration: 16.7 # it is set for LibriSpeech, you may need to update it for your dataset + min_duration: 0.1 + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 16 + shuffle: false + num_workers: 8 + pin_memory: false + use_start_end_token: true + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + batch_size: 16 + shuffle: false + num_workers: 8 + pin_memory: false + use_start_end_token: true + + # you may find more detail on how to train a tokenizer at: /scripts/tokenizers/process_asr_text_tokenizer.py + tokenizer: + dir: ??? # path to directory which contains either tokenizer.model (bpe) or vocab.txt (for wpe) + type: wpe # Can be either bpe (SentencePiece tokenizer) or wpe (WordPiece tokenizer) + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + sample_rate: *sample_rate + normalize: "per_feature" + window_size: 0.025 + window_stride: 0.01 + window: "hann" + features: 80 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + pad_to: 0 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + freq_masks: 2 # set to zero to disable it + time_masks: 10 # set to zero to disable it + freq_width: 27 + time_width: 0.05 + + encoder: + _target_: nemo.collections.asr.modules.ConformerEncoder + feat_in: ${model.preprocessor.features} + feat_out: -1 # you may set it if you need different output size other than the default d_model + n_layers: 16 + d_model: 256 + + # Sub-sampling params + subsampling: striding # vggnet or striding + subsampling_factor: 4 # must be power of 2 + subsampling_conv_channels: -1 # set to -1 to make it equal to the d_model + + # Feed forward module's params + ff_expansion_factor: 4 + + # Multi-headed Attention Module's params + self_attention_model: rel_pos # rel_pos or abs_pos + n_heads: 4 + xscaling: true # scales up the inputs by sqrt(d_model) + untie_biases: true # unties the biases of the TransformerXL layers + pos_emb_max_len: 5000 + + # Convolution module's params + conv_kernel_size: 31 + + ### regularization + dropout: 0.1 # The dropout used in most of the Conformer Modules + dropout_emb: 0.0 # The dropout used for embeddings + dropout_att: 0.1 # The dropout for multi-headed attention modules + + decoder: + _target_: nemo.collections.asr.modules.RNNTDecoder + normalization_mode: null + random_state_sampling: false + blank_as_pad: true + + prednet: + pred_hidden: ${model.model_defaults.pred_hidden} + pred_rnn_layers: 1 + t_max: null + dropout: 0.1 + + joint: + _target_: nemo.collections.asr.modules.RNNTJoint + log_softmax: null # 'null' would set it automatically according to CPU/GPU device + + # fused mode + experimental_fuse_loss_wer: true + fused_batch_size: 16 + + jointnet: + joint_hidden: ${model.model_defaults.joint_hidden} + activation: "relu" + dropout: 0.1 + + decoding: + strategy: "greedy_batch" + + # greedy strategy config + greedy: + max_symbols: 30 + + # beam strategy config + beam: + beam_size: 2 + score_norm: true + tsd_max_sym_exp: 50 # for Time Synchronous Decoding + alsd_max_target_len: 2.0 # for Alignment-Length Synchronous Decoding + + optim: + name: adam + lr: 5.0 + # optimizer arguments + betas: [0.9, 0.98] + weight_decay: 1e-6 + + # scheduler setup + sched: + name: NoamAnnealing + d_model: ${model.encoder.d_model} + # scheduler config override + warmup_steps: 10000 + warmup_ratio: null + min_lr: 1e-6 + +trainer: + gpus: -1 # number of GPUs, -1 would use all available GPUs + num_nodes: 1 + max_epochs: 1000 + max_steps: null # computed at runtime if not set + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + accelerator: ddp + accumulate_grad_batches: 1 + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP. + log_every_n_steps: 10 # Interval of logging. + progress_bar_refresh_rate: 10 + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + check_val_every_n_epoch: 1 # number of evaluations on validation every n epochs + sync_batchnorm: true + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: true + create_checkpoint_callback: true + checkpoint_callback_params: + # in case of multiple validation sets, first one is used + monitor: "val_wer" + mode: "min" + save_top_k: 3 + resume_if_exists: false + resume_ignore_no_checkpoint: false + + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null diff --git a/tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt.yaml b/tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt.yaml new file mode 100644 index 0000000..306ffe0 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt.yaml @@ -0,0 +1,237 @@ +name: &name "ConvRNNT5x1" + +model: + sample_rate: 16000 + compute_eval_loss: true + + labels: [ " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'" ] + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 32 + trim_silence: true + max_duration: 16.7 + labels: ${model.labels} + shuffle: true + is_tarred: false + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 32 + shuffle: false + labels: ${model.labels} + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + batch_size: 32 + shuffle: false + labels: ${model.labels} + + model_defaults: + repeat: 5 + dropout: 0.0 + separable: true + se: true + se_context_size: -1 + # encoder / decoder / joint values + enc_hidden: 1024 + pred_hidden: 320 + joint_hidden: 320 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: ${model.sample_rate} + window_stride: 0.01 + window: "hann" + features: &n_mels 80 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [13] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [17] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [19] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 256 + repeat: 1 + kernel: [21] + stride: [2] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + - filters: ${model.model_defaults.enc_hidden} + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + decoder: + _target_: nemo.collections.asr.modules.RNNTDecoder + normalization_mode: null + random_state_sampling: false + blank_as_pad: true + + prednet: + pred_hidden: ${model.model_defaults.pred_hidden} + pred_rnn_layers: 1 + t_max: null + dropout: 0.0 + + joint: + _target_: nemo.collections.asr.modules.RNNTJoint + log_softmax: null # sets it according to cpu/gpu device + + # fused mode + experimental_fuse_loss_wer: false + fused_batch_size: 1 + + jointnet: + joint_hidden: ${model.model_defaults.joint_hidden} + activation: "relu" + dropout: 0.0 + + decoding: + strategy: "greedy_batch" + + # greedy strategy config + greedy: + max_symbols: 30 + + # beam strategy config + beam: + beam_size: 2 + score_norm: true + tsd_max_sym_exp: 50 # for Time Synchronous Decoding + alsd_max_target_len: 2.0 # for Alignment-Length Synchronous Decoding + + optim: + name: adam + # _target_: nemo.core.optim.optimizers.Adam + lr: .1 + + # optimizer arguments + betas: [0.9, 0.999] + weight_decay: 0.0001 + + # scheduler setup + sched: + name: CosineAnnealing + + # scheduler config override + warmup_steps: null + warmup_ratio: 0.05 + min_lr: 1e-6 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + precision: 32 + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_wer" + mode: "min" + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null diff --git a/tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt_bpe.yaml b/tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt_bpe.yaml new file mode 100644 index 0000000..c259ba5 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/contextnet_rnnt/config_rnnt_bpe.yaml @@ -0,0 +1,238 @@ +name: &name "ConvRNNTBPE5x1" + +model: + sample_rate: 16000 + compute_eval_loss: true + + tokenizer: + dir: ??? # path to directory which contains either tokenizer.model (bpe) or vocab.txt (for wpe) + type: ??? # Can be either bpe or wpe + + train_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 32 + trim_silence: true + max_duration: 16.7 + labels: [] + shuffle: true + is_tarred: false + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: ${model.sample_rate} + batch_size: 32 + shuffle: false + labels: [] + + test_ds: + manifest_filepath: null + sample_rate: ${model.sample_rate} + batch_size: 32 + shuffle: false + labels: [] + + model_defaults: + repeat: 5 + dropout: 0.0 + separable: true + se: true + se_context_size: -1 + # encoder / decoder / joint values + enc_hidden: 1024 + pred_hidden: 320 + joint_hidden: 320 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: ${model.sample_rate} + window_stride: 0.01 + window: "hann" + features: &n_mels 80 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: 128 + repeat: 1 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [13] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [17] + stride: [2] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + - filters: 256 + repeat: ${model.model_defaults.repeat} + kernel: [19] + stride: [1] + dilation: [1] + dropout: ${model.model_defaults.dropout} + residual: true + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + - filters: 256 + repeat: 1 + kernel: [21] + stride: [2] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + stride_last: true + residual_mode: "stride_add" + + - filters: ${model.model_defaults.enc_hidden} + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: ${model.model_defaults.separable} + se: ${model.model_defaults.se} + se_context_size: ${model.model_defaults.se_context_size} + + decoder: + _target_: nemo.collections.asr.modules.RNNTDecoder + normalization_mode: null + random_state_sampling: false + blank_as_pad: true + + prednet: + pred_hidden: ${model.model_defaults.pred_hidden} + pred_rnn_layers: 1 + t_max: null + dropout: 0.0 + + joint: + _target_: nemo.collections.asr.modules.RNNTJoint + log_softmax: null # sets it according to cpu/gpu device + + # fused mode + experimental_fuse_loss_wer: false + fused_batch_size: 1 + + jointnet: + joint_hidden: ${model.model_defaults.joint_hidden} + activation: "relu" + dropout: 0.0 + + decoding: + strategy: "greedy_batch" + + # greedy strategy config + greedy: + max_symbols: 30 + + # beam strategy config + beam: + beam_size: 2 + score_norm: true + tsd_max_sym_exp: 50 # for Time Synchronous Decoding + alsd_max_target_len: 2.0 # for Alignment-Length Synchronous Decoding + + optim: + name: adam + # _target_: nemo.core.optim.optimizers.Adam + lr: .1 + + # optimizer arguments + betas: [0.9, 0.999] + weight_decay: 0.0001 + + # scheduler setup + sched: + name: CosineAnnealing + + # scheduler config override + warmup_steps: null + warmup_ratio: 0.05 + min_lr: 1e-6 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + precision: 32 + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_wer" + mode: "min" + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null diff --git a/tts/NeMo/examples/asr/experimental/quartznet/quartznet_15x5_aug.yaml b/tts/NeMo/examples/asr/experimental/quartznet/quartznet_15x5_aug.yaml new file mode 100644 index 0000000..8ebc2f4 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/quartznet/quartznet_15x5_aug.yaml @@ -0,0 +1,290 @@ +name: &name "QuartzNet15x5" + +model: + sample_rate: &sample_rate 16000 + repeat: &repeat 5 + dropout: &dropout 0.0 + separable: &separable true + labels: &labels [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + trim_silence: True + max_duration: 16.7 + shuffle: True + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + augmentor: + rir_noise_aug: + prob: 0.5 + rir_manifest_path: ??? + rir_tar_filepaths: ??? + rir_prob: 0.5 + noise_manifest_paths: ??? + noise_tar_filepaths: ??? + min_snr_db: [0,0] + max_snr_db: [30,30] + orig_sample_rate: ??? + bg_noise_manifest_paths: ??? + bg_noise_tar_filepaths: ??? + bg_min_snr_db: [10,10] + bg_max_snr_db: [40,40] + bg_orig_sample_rate: ??? + transcode_aug: + prob: 0.1 + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: *labels + batch_size: 32 + shuffle: False + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + stft_conv: false + + spec_augment: + _target_: nemo.collections.asr.modules.SpectrogramAugmentation + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: 1 + residual: false + separable: *separable + stride: [2] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [2] + dropout: *dropout + filters: 512 + kernel: [87] + repeat: 1 + residual: false + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: &enc_filters 1024 + kernel: [1] + repeat: 1 + residual: false + stride: [1] + + decoder: + _target_: nemo.collections.asr.modules.ConvASRDecoder + feat_in: *enc_filters + num_classes: 28 + vocabulary: *labels + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: .01 + # optimizer arguments + betas: [0.8, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # pytorch lightning args + # monitor: val_loss + # reduce_on_plateau: false + + # Scheduler params + warmup_steps: null + warmup_ratio: null + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True + create_wandb_logger: False + wandb_logger_kwargs: + name: null + project: null + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/asr/experimental/sclite/speech_to_text_sclite.py b/tts/NeMo/examples/asr/experimental/sclite/speech_to_text_sclite.py new file mode 100644 index 0000000..b902582 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/sclite/speech_to_text_sclite.py @@ -0,0 +1,158 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script is based on speech_to_text_infer.py and allows you to score the hypotheses +with sclite. A local installation from https://github.com/usnistgov/SCTK is required. +Hypotheses and references are first saved in trn format and are scored after applying a glm +file (if provided). +""" + +import errno +import json +import os +import subprocess +from argparse import ArgumentParser + +import torch + +from nemo.collections.asr.metrics.wer import WER +from nemo.collections.asr.models import EncDecCTCModel +from nemo.utils import logging + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +def score_with_sctk(sctk_dir, ref_fname, hyp_fname, out_dir, glm=""): + sclite_path = os.path.join(sctk_dir, "bin", "sclite") + if not os.path.exists(sclite_path): + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), sclite_path) + # apply glm + if os.path.exists(glm): + rfilter_path = os.path.join(sctk_dir, "bin", "rfilter1") + if not os.path.exists(rfilter_path): + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), rfilter_path) + hypglm = os.path.join(out_dir, os.path.basename(hyp_fname)) + ".glm" + rfilt_cmd = [rfilter_path] + [glm] + with open(hypglm, "w") as hypf, open(hyp_fname, "r") as hyp_in: + subprocess.run(rfilt_cmd, stdin=hyp_in, stdout=hypf) + refglm = os.path.join(out_dir, os.path.basename(ref_fname)) + ".glm" + with open(refglm, "w") as reff, open(ref_fname, "r") as ref_in: + subprocess.run(rfilt_cmd, stdin=ref_in, stdout=reff) + else: + refglm = ref_fname + hypglm = hyp_fname + + _ = subprocess.check_output(f"{sclite_path} -h {hypglm} -r {refglm} -i wsj -o all", shell=True) + + +can_gpu = torch.cuda.is_available() + + +def get_utt_info(manifest_path): + info_list = [] + with open(manifest_path, "r") as utt_f: + for line in utt_f: + utt = json.loads(line) + info_list.append(utt) + + return info_list + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--asr_model", type=str, default="QuartzNet15x5Base-En", required=False, help="Pass: 'QuartzNet15x5Base-En'", + ) + parser.add_argument("--dataset", type=str, required=True, help="path to evaluation data") + parser.add_argument("--batch_size", type=int, default=4) + parser.add_argument( + "--dont_normalize_text", + default=False, + action='store_true', + help="Turn off trasnscript normalization. Recommended for non-English.", + ) + parser.add_argument("--out_dir", type=str, required=True, help="Destination dir for output files") + parser.add_argument("--sctk_dir", type=str, required=False, default="", help="Path to sctk root dir") + parser.add_argument("--glm", type=str, required=False, default="", help="Path to glm file") + args = parser.parse_args() + torch.set_grad_enabled(False) + + if not os.path.exists(args.out_dir): + os.makedirs(args.out_dir) + + use_sctk = os.path.exists(args.sctk_dir) + + if args.asr_model.endswith('.nemo'): + logging.info(f"Using local ASR model from {args.asr_model}") + asr_model = EncDecCTCModel.restore_from(restore_path=args.asr_model) + else: + logging.info(f"Using NGC cloud ASR model {args.asr_model}") + asr_model = EncDecCTCModel.from_pretrained(model_name=args.asr_model) + asr_model.setup_test_data( + test_data_config={ + 'sample_rate': 16000, + 'manifest_filepath': args.dataset, + 'labels': asr_model.decoder.vocabulary, + 'batch_size': args.batch_size, + 'normalize_transcripts': not args.dont_normalize_text, + } + ) + if can_gpu: + asr_model = asr_model.cuda() + asr_model.eval() + labels_map = dict([(i, asr_model.decoder.vocabulary[i]) for i in range(len(asr_model.decoder.vocabulary))]) + + wer = WER(vocabulary=asr_model.decoder.vocabulary) + hypotheses = [] + references = [] + all_log_probs = [] + for test_batch in asr_model.test_dataloader(): + if can_gpu: + test_batch = [x.cuda() for x in test_batch] + with autocast(): + log_probs, encoded_len, greedy_predictions = asr_model( + input_signal=test_batch[0], input_signal_length=test_batch[1] + ) + for r in log_probs.cpu().numpy(): + all_log_probs.append(r) + hypotheses += wer.ctc_decoder_predictions_tensor(greedy_predictions) + for batch_ind in range(greedy_predictions.shape[0]): + reference = ''.join([labels_map[c] for c in test_batch[2][batch_ind].cpu().detach().numpy()]) + references.append(reference) + del test_batch + + info_list = get_utt_info(args.dataset) + hypfile = os.path.join(args.out_dir, "hyp.trn") + reffile = os.path.join(args.out_dir, "ref.trn") + with open(hypfile, "w") as hyp_f, open(reffile, "w") as ref_f: + for i in range(len(hypotheses)): + utt_id = os.path.splitext(os.path.basename(info_list[i]['audio_filepath']))[0] + # rfilter in sctk likes each transcript to have a space at the beginning + hyp_f.write(" " + hypotheses[i] + " (" + utt_id + ")" + "\n") + ref_f.write(" " + references[i] + " (" + utt_id + ")" + "\n") + + if use_sctk: + score_with_sctk(args.sctk_dir, reffile, hypfile, args.out_dir, glm=args.glm) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/experimental/structured/conf/quartznet_15x5.yaml b/tts/NeMo/examples/asr/experimental/structured/conf/quartznet_15x5.yaml new file mode 100644 index 0000000..5bb9925 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/structured/conf/quartznet_15x5.yaml @@ -0,0 +1,235 @@ +name: &name "QuartzNet15x5" + +model: + sample_rate: &sample_rate 16000 + repeat: &repeat 5 + dropout: &dropout 0.0 + separable: &separable true + labels: &labels [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"] + + train_ds: + manifest_filepath: ??? + sample_rate: *sample_rate + labels: *labels + batch_size: 32 + max_duration: 16.7 + is_tarred: False + tarred_audio_filepaths: null + + validation_ds: + labels: *labels + manifest_filepath: ??? + sample_rate: *sample_rate + batch_size: 32 + + preprocessor: + sample_rate: *sample_rate + window_size: 0.02 + window_stride: 0.01 + features: &n_mels 64 + + spec_augment: + rect_freq: 50 + rect_masks: 5 + rect_time: 120 + + encoder: + feat_in: *n_mels + activation: relu + + jasper: + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: 1 + residual: false + separable: *separable + stride: [2] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [33] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 256 + kernel: [39] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [51] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [63] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: 512 + kernel: [75] + repeat: *repeat + residual: true + separable: *separable + stride: [1] + + - dilation: [2] + dropout: *dropout + filters: 512 + kernel: [87] + repeat: 1 + residual: false + separable: *separable + stride: [1] + + - dilation: [1] + dropout: *dropout + filters: &enc_filters 1024 + kernel: [1] + repeat: 1 + residual: false + stride: [1] + + decoder: + feat_in: *enc_filters + num_classes: 28 + vocabulary: *labels + + optim: + name: novograd + lr: .01 + + # optimizer arguments + betas: [0.8, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + + # Scheduler params + warmup_steps: null + warmup_ratio: null + min_lr: 0.0 + +trainer: + gpus: 0 # number of gpus + max_epochs: 5 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + name: *name diff --git a/tts/NeMo/examples/asr/experimental/structured/speech_to_text_hybrid.py b/tts/NeMo/examples/asr/experimental/structured/speech_to_text_hybrid.py new file mode 100644 index 0000000..e396c44 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/structured/speech_to_text_hybrid.py @@ -0,0 +1,56 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.asr.models import EncDecCTCModel, configs +from nemo.core.config import hydra_runner +from nemo.utils.config_utils import update_model_config +from nemo.utils.exp_manager import exp_manager + + +""" +python speech_to_text_hybrid.py \ + --config-path="conf/quartznet" \ + --config-name="quartznet_15x5" \ + model.train_ds.manifest_filepath="/home/smajumdar/PycharmProjects/NeMo-som/examples/asr/an4/train_manifest.json" \ + model.validation_ds.manifest_filepath="/home/smajumdar/PycharmProjects/NeMo-som/examples/asr/an4/test_manifest.json" \ + trainer.gpus=1 +""" + + +@hydra_runner(config_path="conf/quartznet", config_name="quartznet_15x5") +def main(cfg): + # Generate default asr model config + asr_model_config = configs.EncDecCTCModelConfig() + + # Merge hydra updates with model config + # `drop_missing_subconfig=True` is necessary here. Without it, while the data class will instantiate and be added + # to the config, it contains test_ds.sample_rate = MISSING and test_ds.labels = MISSING. + # This will raise a OmegaConf MissingMandatoryValue error when processing the dataloaders inside + # model_utils.resolve_test_dataloaders(model=self) (used for multi data loader support). + # In general, any operation that tries to use a DictConfig with MISSING in it will fail, + # other than explicit update operations to change MISSING to some actual value. + asr_model_config = update_model_config(asr_model_config, cfg, drop_missing_subconfigs=True) + + # From here on out, its a general OmegaConf DictConfig, directly usable by our code. + trainer = pl.Trainer(**asr_model_config.trainer) + exp_manager(trainer, asr_model_config.get("exp_manager", None)) + asr_model = EncDecCTCModel(cfg=asr_model_config.model, trainer=trainer) + + trainer.fit(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured.py b/tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured.py new file mode 100644 index 0000000..23f33f0 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured.py @@ -0,0 +1,146 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from dataclasses import asdict + +import pytorch_lightning as pl + +import nemo.collections.asr as nemo_asr +from nemo.collections.asr.models import EncDecCTCModel, configs +from nemo.utils.exp_manager import exp_manager + +""" +python speech_to_text_structured.py +""" + +# Generate default asr model config +cfg = configs.EncDecCTCModelConfig() + +# set global values +cfg.model.repeat = 5 +cfg.model.separable = True + +# fmt: off +LABELS = [ + " ", "a", "b", "c", "d", "e", + "f", "g", "h", "i", "j", "k", + "l", "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", "w", + "x", "y", "z", "'", +] +# fmt: on + +qn_15x5 = [ + nemo_asr.modules.conv_asr.JasperEncoderConfig( + filters=256, + repeat=1, + kernel=[33], + stride=[2], + separable=cfg.model.separable, + dilation=[1], + dropout=cfg.model.dropout, + residual=False, + ), + nemo_asr.modules.conv_asr.JasperEncoderConfig( + filters=256, + repeat=1, + kernel=[33], + stride=[1], + separable=cfg.model.separable, + dilation=[1], + dropout=cfg.model.dropout, + residual=True, + ), + # ... repeat 14 more times + nemo_asr.modules.conv_asr.JasperEncoderConfig( + filters=1024, repeat=1, kernel=[1], stride=[1], dilation=[1], dropout=cfg.model.dropout, residual=False, + ), +] + + +def main(): + # Update values + # MODEL UPDATES + cfg.name = "Mini QuartzNet" + cfg.model.labels = LABELS + + # train ds + cfg.model.train_ds.manifest_filepath = "" + cfg.model.train_ds.labels = LABELS + cfg.model.train_ds.sample_rate = cfg.model.sample_rate + + # validation ds + cfg.model.validation_ds.manifest_filepath = "" + cfg.model.validation_ds.labels = LABELS + cfg.model.validation_ds.sample_rate = cfg.model.sample_rate + + # del `test_ds` does not work! + # Refer - https://stackoverflow.com/questions/58119758/how-to-remove-dataclass-attributes + # Hydra/OmegaConf dont allow custom .asdict() methods either + # For now, explicitly set parameters + cfg.model.test_ds.sample_rate = cfg.model.sample_rate + cfg.model.test_ds.labels = cfg.model.labels + + # preprocessor + cfg.model.preprocessor.sample_rate = cfg.model.sample_rate + + # spec aug + cfg.model.spec_augment.rect_masks = 5 + cfg.model.spec_augment.rect_freq = 50 + cfg.model.spec_augment.rect_time = 120 + + # encoder + cfg.model.encoder.feat_in = cfg.model.preprocessor.features + cfg.model.encoder.activation = 'relu' + cfg.model.encoder.jasper = qn_15x5 + + # decoder + cfg.model.decoder.feat_in = qn_15x5[-1].filters + cfg.model.decoder.num_classes = len(LABELS) + cfg.model.decoder.vocabulary = LABELS + + # optim + cfg.model.optim.name = 'novograd' + cfg.model.optim.lr = 0.01 + + # `betas` dont exist inside the base config, + # so they cannot be added as such! + # Same for `weight_decay`. + cfg.model.optim.betas = [0.8, 0.5] + cfg.model.optim.weight_decay = 0.001 + + # sched + # As parameters such as warmup_steps and warmup_ratio + # dont exist inside the shell config, these values are not added! + cfg.model.optim.sched.name = "CosineAnnealing" + cfg.model.optim.sched.warmup_steps = None + cfg.model.optim.sched.warmup_ratio = 0.01 + + # Trainer config + cfg.trainer.gpus = 1 + cfg.trainer.max_epochs = 5 + + # Exp Manager config + cfg.exp_manager.name = cfg.name + + # Note usage of asdict + trainer = pl.Trainer(**asdict(cfg.trainer)) + exp_manager(trainer, asdict(cfg.exp_manager)) + asr_model = EncDecCTCModel(cfg=cfg.model, trainer=trainer) + + trainer.fit(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured_v2.py b/tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured_v2.py new file mode 100644 index 0000000..1fc9cc8 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/structured/speech_to_text_structured_v2.py @@ -0,0 +1,90 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from dataclasses import asdict + +import pytorch_lightning as pl + +from nemo.collections.asr.models import EncDecCTCModel, configs +from nemo.core.config import modelPT, optimizers, schedulers +from nemo.utils.exp_manager import exp_manager + +""" +python speech_to_text_structured_v2.py +""" + +# fmt: off +LABELS = [ + " ", "a", "b", "c", "d", "e", + "f", "g", "h", "i", "j", "k", + "l", "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", "w", + "x", "y", "z", "'", +] + +optim_cfg = optimizers.NovogradParams( + lr=0.01, + betas=(0.8, 0.5), + weight_decay=0.001 +) + +sched_cfg = schedulers.CosineAnnealingParams( + warmup_steps=None, + warmup_ratio=None, + min_lr=0.0, +) +# fmt: on + + +def main(): + # NeMo Model config + cfg = modelPT.NemoConfig(name='Custom QuartzNet') + + # Generate default asr model config + builder = configs.EncDecCTCModelConfigBuilder(name='quartznet_15x5') + + # set model global values + builder.set_labels(LABELS) + builder.set_optim(cfg=optim_cfg, sched_cfg=sched_cfg) + + model_cfg = builder.build() + + # set the model config to the NeMo Model + cfg.model = model_cfg + + # Update values + # MODEL UPDATES + # train ds + model_cfg.train_ds.manifest_filepath = "" + + # validation ds + model_cfg.validation_ds.manifest_filepath = "" + + # Trainer config + cfg.trainer.gpus = 1 + cfg.trainer.max_epochs = 5 + + # Exp Manager config + cfg.exp_manager.name = cfg.name + + # Note usage of asdict + trainer = pl.Trainer(**asdict(cfg.trainer)) + exp_manager(trainer, asdict(cfg.exp_manager)) + asr_model = EncDecCTCModel(cfg=cfg.model, trainer=trainer) + + trainer.fit(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain.yaml b/tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain.yaml new file mode 100644 index 0000000..00268fc --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain.yaml @@ -0,0 +1,123 @@ +name: &name "Wav2vec_Pretrain" +# For more details on the model parameters, see nemo/collections/asr/models/wav2vec/wav2vec_config.py +# These parameters are based off the FairSeq implementation. +# See here: https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml +model: + transformer_encoder: + dropout: 0.1 # Dropout probability for the transformer + conv: # Config for convolutional model that generates positional embeddings required for attention layer + conv_pos: 128 # Number of filters for convolutional positional embeddings + conv_pos_groups: 16 # Number of groups for convolutional positional embeddings + encoder: + encoder_layers: 12 # Number of encoder layers in transformer model + encoder_layerdrop: 0.05 # Probability of dropping transformer layers + embedding_dim: 768 # Encoder embedding dim + ffn_embedding_dim: 3072 # Encoder embedding dim for feed forward + num_attention_heads: 8 # Number of encoder attention heads + dropout: 0.1 # Dropout probability for transformer encoder + activation_fn: gelu # Activation for transformer + layer_norm_first: False # Apply layer norm first within the transformer + loss: + prob_ppl_weight: 0.1 # Weight applied to quantized prob perplexity loss + feature_loss_weight: 0 # Weight applied to feature L2 Norm + quantizer: + quantize_targets: True # Quantize targets + quantize_input: False # Quantize inputs + same_quantizer: False # Use the same quantizer for inputs and targets (If both enabled) + latent_vars: 320 # Number of latent variables in each group of the codebook + latent_groups: 2 # Number of groups within the codebook + latent_dim: 0 # If greater than 0, use the dim for latest variables else inferred by final dim / latent groups + latent_temp: [2, 0.5, 0.999995] # Quantize temperature (start, stop, decay factor) + conv_feature_encoder: # Config for feature extractor taking raw audio waveform and converting to features + extractor_mode: default # Mode for feature extractor. [Default, layer_norm] + conv_bias: False # Include bias in convolution feature extractor model + masking: + mask_prob: 0.65 # Probability of replacing token with mask + mask_type: static # Used to select configuration to compute mask lengths [static, uniform, normal, poisson] + mask_other: 0 # Secondary mask used for complex distributions (see help in compute_mask_indices) + mask_length: 10 # Length of mask when masking time steps + no_mask_overlap: False # Whether to allow masks to overlap + mask_min_space: 1 # Minimum space beetween spans (if no overlap is enabled) + mask_channel_prob: 0 # Probability of replacing a feature with 0 + mask_channel_type: static # Used to select configuration to compute mask channel lengths [static, uniform, normal, poisson] + mask_channel_other: 0 # Secondary mask argument (used for more complex distributions (see help in compute_mask_indices) + mask_channel_length: 10 # Length of masks for features (channels) + no_mask_channel_overlap: False # Whether to allow channel masks to overlap + mask_channel_min_space: 1 # Minimum space between spans (if no overlap is enabled) + dropout_input: 0.1 # Dropout applied to input raw features + dropout_features: 0.1 # Dropout applied to the features generator by convolutions + final_dim: 0 # Project final representations and targets to this dimension + n_negatives: 100 # Number of negatives to sample from the same audio sample + cross_sample_negatives: 0 # Number of negatives to sample from any sample in the batch + codebook_negatives: 0 # Number of negative examples in codebook + negatives_from_everywhere: False # Sample negatives from everywhere, not just masked states + logit_temp: 0.1 # Temperature to divide logits by + target_glu: False # Adds project and applies GLU to targets + feature_grad_mult: 0.1 # Multiply extracted feature gradients + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: True + num_workers: 4 + labels: [ ] # No vocab needed for pre-training + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: False + num_workers: 1 + labels: [ ] + test_ds: + manifest_filepath: null + sample_rate: 16000 + batch_size: 32 + shuffle: False + num_workers: 4 + labels: [ ] + optim: + name: adamw + lr: 0.0005 + eps: 1e-06 + # optimizer arguments + betas: [ 0.9, 0.98 ] + weight_decay: 0.01 + + # scheduler setup + sched: + name: PolynomialDecayAnnealing + min_lr: 0.000 + # Scheduler params + warmup_steps: null + warmup_ratio: 0.1 +trainer: + gpus: 0 # number of gpus + num_nodes: 1 + max_epochs: 100 + max_steps: null # computed at runtime if not set + val_check_interval: 0.5 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + accelerator: ddp + accumulate_grad_batches: 1 + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP. + log_every_n_steps: 10 # Interval of logging. + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + check_val_every_n_epoch: 1 # number of evaluations on validation every n epochs + sync_batchnorm: true + + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: true + create_checkpoint_callback: true + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null + resume_if_exists: false + resume_ignore_no_checkpoint: false \ No newline at end of file diff --git a/tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain_large.yaml b/tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain_large.yaml new file mode 100644 index 0000000..4a92a28 --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/wav2vec/configs/wav2vec_pretrain_large.yaml @@ -0,0 +1,123 @@ +name: &name "Wav2vec_large_Pretrain" +# For more details on the model parameters, see nemo/collections/asr/models/wav2vec/wav2vec_config.py +# These parameters are based off the FairSeq implementation. +# See here: https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml +model: + transformer_encoder: + dropout: 0.0 # Dropout probability for the transformer + conv: # Config for convolutional model that generates positional embeddings required for attention layer + conv_pos: 128 # Number of filters for convolutional positional embeddings + conv_pos_groups: 16 # Number of groups for convolutional positional embeddings + encoder: + encoder_layers: 24 # Number of encoder layers in transformer model + encoder_layerdrop: 0.0 # Probability of dropping transformer layers + embedding_dim: 1024 # Encoder embedding dim + ffn_embedding_dim: 4096 # Encoder embedding dim for feed forward + num_attention_heads: 16 # Number of encoder attention heads + dropout: 0.0 # Dropout probability for transformer encoder + activation_fn: gelu # Activation for transformer + layer_norm_first: True # Apply layer norm first within the transformer + loss: + prob_ppl_weight: 0.1 # Weight applied to quantized prob perplexity loss + feature_loss_weight: 0 # Weight applied to feature L2 Norm + quantizer: + quantize_targets: True # Quantize targets + quantize_input: False # Quantize inputs + same_quantizer: False # Use the same quantizer for inputs and targets (If both enabled) + latent_vars: 320 # Number of latent variables in each group of the codebook + latent_groups: 2 # Number of groups within the codebook + latent_dim: 0 # If greater than 0, use the dim for latest variables else inferred by final dim / latent groups + latent_temp: [2, 0.1, 0.999995] # Quantize temperature (start, stop, decay factor) + conv_feature_encoder: # Config for feature extractor taking raw audio waveform and converting to features + extractor_mode: layer_norm # Mode for feature extractor. [default, layer_norm] + conv_bias: True # Include bias in convolution feature extractor model + masking: + mask_prob: 0.65 # Probability of replacing token with mask + mask_type: static # Used to select configuration to compute mask lengths [static, uniform, normal, poisson] + mask_other: 0 # Secondary mask used for complex distributions (see help in compute_mask_indices) + mask_length: 10 # Length of mask when masking time steps + no_mask_overlap: False # Whether to allow masks to overlap + mask_min_space: 1 # Minimum space beetween spans (if no overlap is enabled) + mask_channel_prob: 0 # Probability of replacing a feature with 0 + mask_channel_type: static # Used to select configuration to compute mask channel lengths [static, uniform, normal, poisson] + mask_channel_other: 0 # Secondary mask argument (used for more complex distributions (see help in compute_mask_indices) + mask_channel_length: 10 # Length of masks for features (channels) + no_mask_channel_overlap: False # Whether to allow channel masks to overlap + mask_channel_min_space: 1 # Minimum space between spans (if no overlap is enabled) + dropout_input: 0.0 # Dropout applied to input raw features + dropout_features: 0.0 # Dropout applied to the features generator by convolutions + final_dim: 768 # Project final representations and targets to this dimension + n_negatives: 100 # Number of negatives to sample from the same audio sample + cross_sample_negatives: 0 # Number of negatives to sample from any sample in the batch + codebook_negatives: 0 # Number of negative examples in codebook + negatives_from_everywhere: False # Sample negatives from everywhere, not just masked states + logit_temp: 0.1 # Temperature to divide logits by + target_glu: False # Adds project and applies GLU to targets + feature_grad_mult: 1.0 # Multiply extracted feature gradients + + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: True + num_workers: 4 + labels: [ ] # No vocab needed for pre-training + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + batch_size: 32 + shuffle: False + num_workers: 1 + labels: [ ] + test_ds: + manifest_filepath: null + sample_rate: 16000 + batch_size: 32 + shuffle: False + num_workers: 4 + labels: [ ] + optim: + name: adamw + lr: 0.0005 + eps: 1e-06 + # optimizer arguments + betas: [ 0.9, 0.98 ] + weight_decay: 0.01 + + # scheduler setup + sched: + name: PolynomialDecayAnnealing + min_lr: 0.000 + # Scheduler params + warmup_steps: null + warmup_ratio: 0.1 +trainer: + gpus: 0 # number of gpus + num_nodes: 1 + max_epochs: 100 + max_steps: null # computed at runtime if not set + val_check_interval: 0.5 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + accelerator: ddp + accumulate_grad_batches: 1 + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP. + log_every_n_steps: 10 # Interval of logging. + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + check_val_every_n_epoch: 1 # number of evaluations on validation every n epochs + sync_batchnorm: true + + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: true + create_checkpoint_callback: true + create_wandb_logger: false + wandb_logger_kwargs: + name: null + project: null + resume_if_exists: false + resume_ignore_no_checkpoint: false \ No newline at end of file diff --git a/tts/NeMo/examples/asr/experimental/wav2vec/wav2vec_pretrain.py b/tts/NeMo/examples/asr/experimental/wav2vec/wav2vec_pretrain.py new file mode 100644 index 0000000..2e5c1db --- /dev/null +++ b/tts/NeMo/examples/asr/experimental/wav2vec/wav2vec_pretrain.py @@ -0,0 +1,97 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.asr.models.wav2vec.wav2vec_model import Wav2VecEncoderModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +""" +Pre-train a wav2vec 2.0 transformer model on audio. Uses a contrastive loss function to pre-train on unlabelled audio, +using a task similar to masked language modeling in NLP. In wav2vec, we mask portions of the audio +and the model is trained by minimising the distance of the ground truth for the masked section, +using the ground truth quantized codebook representation. Distractors are obtained from other time steps. +See :class:`Wav2VecCriterion` for more information. + +Reference: https://arxiv.org/abs/2006.11477 + + python examples/asr/experimental/wav2vec/wav2vec_pretrain.py \ + model.train_ds.manifest_filepath="./examples/asr/train.tsv" \ + model.validation_ds.manifest_filepath="./examples/asr/valid.tsv" \ + trainer.gpus=1 \ + trainer.max_epochs=100 + +Basic run (on CPU for 50 epochs): + python examples/asr/experimental/wav2vec/wav2vec_pretrain.py \ + model.train_ds.manifest_filepath="./examples/asr/train.tsv" \ + model.validation_ds.manifest_filepath="./examples/asr/valid.tsv" \ + trainer.gpus=1 \ + trainer.max_epochs=50 + +Using wav2vec-large with mixed precision: + python examples/asr/experimental/wav2vec/wav2vec_pretrain.py \ + --config-name=wav2vec_pretrain_large \ + model.train_ds.manifest_filepath="./examples/asr/train.tsv" \ + model.validation_ds.manifest_filepath="./examples/asr/valid.tsv" \ + trainer.gpus=1 \ + trainer.max_epochs=100 \ + trainer.precision=16 + +Add PyTorch Lightning Trainer arguments from CLI: + python wav2vec.py \ + ... \ + +trainer.fast_dev_run=true + +Hydra logs will be found in "$(./outputs/$(date +"%y-%m-%d")/$(date +"%H-%M-%S")/.hydra)" +PTL logs will be found in "$(./outputs/$(date +"%y-%m-%d")/$(date +"%H-%M-%S")/lightning_logs)" + +Override some args of optimizer: + python examples/asr/experimental/wav2vec/wav2vec_pretrain.py \ + model.train_ds.manifest_filepath="./examples/asr/train.tsv" \ + model.validation_ds.manifest_filepath="./examples/asr/valid.tsv" \ + trainer.gpus=2 \ + trainer.max_epochs=2 \ + model.optim.args.params.betas=[0.8,0.5] \ + model.optim.args.params.weight_decay=0.0001 + +Override optimizer entirely + python examples/asr/experimental/wav2vec/wav2vec_pretrain.py \ + model.train_ds.manifest_filepath="./examples/asr/train.tsv" \ + model.validation_ds.manifest_filepath="./examples/asr/valid.tsv" \ + trainer.gpus=2 \ + trainer.max_epochs=2 \ + ~model.optim.args \ + +model.optim.args.betas=[0.8,0.5]\ + +model.optim.args.weight_decay=0.0005 + +""" + + +@hydra_runner(config_path="configs", config_name="wav2vec_pretrain") +def main(cfg: DictConfig): + logging.info("Application config\n" + OmegaConf.to_yaml(cfg)) + + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + wav2vec_encoder_model = Wav2VecEncoderModel(cfg=cfg.model, trainer=trainer) + trainer.fit(wav2vec_encoder_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/quantization/speech_to_text_calibrate.py b/tts/NeMo/examples/asr/quantization/speech_to_text_calibrate.py new file mode 100644 index 0000000..264806c --- /dev/null +++ b/tts/NeMo/examples/asr/quantization/speech_to_text_calibrate.py @@ -0,0 +1,160 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Script for calibrating a pretrained ASR model for quantization +""" + +from argparse import ArgumentParser + +import torch +from omegaconf import open_dict + +from nemo.collections.asr.models import EncDecCTCModel +from nemo.utils import logging + +try: + from pytorch_quantization import calib + from pytorch_quantization import nn as quant_nn + from pytorch_quantization import quant_modules + from pytorch_quantization.tensor_quant import QuantDescriptor +except ImportError: + raise ImportError( + "pytorch-quantization is not installed. Install from " + "https://github.com/NVIDIA/TensorRT/tree/master/tools/pytorch-quantization." + ) + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +can_gpu = torch.cuda.is_available() + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--asr_model", type=str, default="QuartzNet15x5Base-En", required=True, help="Pass: 'QuartzNet15x5Base-En'", + ) + parser.add_argument("--dataset", type=str, required=True, help="path to evaluation data") + parser.add_argument("--batch_size", type=int, default=256) + parser.add_argument( + "--dont_normalize_text", + default=False, + action='store_false', + help="Turn off trasnscript normalization. Recommended for non-English.", + ) + parser.add_argument('--num_calib_batch', default=1, type=int, help="Number of batches for calibration.") + parser.add_argument('--calibrator', type=str, choices=["max", "histogram"], default="max") + parser.add_argument('--percentile', nargs='+', type=float, default=[99.9, 99.99, 99.999, 99.9999]) + parser.add_argument("--amp", action="store_true", help="Use AMP in calibration.") + parser.set_defaults(amp=False) + + args = parser.parse_args() + torch.set_grad_enabled(False) + + # Initialize quantization + quant_desc_input = QuantDescriptor(calib_method=args.calibrator) + quant_nn.QuantConv2d.set_default_quant_desc_input(quant_desc_input) + quant_nn.QuantConvTranspose2d.set_default_quant_desc_input(quant_desc_input) + quant_nn.QuantLinear.set_default_quant_desc_input(quant_desc_input) + + if args.asr_model.endswith('.nemo'): + logging.info(f"Using local ASR model from {args.asr_model}") + asr_model_cfg = EncDecCTCModel.restore_from(restore_path=args.asr_model, return_config=True) + with open_dict(asr_model_cfg): + asr_model_cfg.encoder.quantize = True + asr_model = EncDecCTCModel.restore_from(restore_path=args.asr_model, override_config_path=asr_model_cfg) + + else: + logging.info(f"Using NGC cloud ASR model {args.asr_model}") + asr_model_cfg = EncDecCTCModel.from_pretrained(model_name=args.asr_model, return_config=True) + with open_dict(asr_model_cfg): + asr_model_cfg.encoder.quantize = True + asr_model = EncDecCTCModel.from_pretrained(model_name=args.asr_model, override_config_path=asr_model_cfg) + + asr_model.setup_test_data( + test_data_config={ + 'sample_rate': 16000, + 'manifest_filepath': args.dataset, + 'labels': asr_model.decoder.vocabulary, + 'batch_size': args.batch_size, + 'normalize_transcripts': args.dont_normalize_text, + 'shuffle': True, + } + ) + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + if can_gpu: + asr_model = asr_model.cuda() + asr_model.eval() + + # Enable calibrators + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer): + if module._calibrator is not None: + module.disable_quant() + module.enable_calib() + else: + module.disable() + + for i, test_batch in enumerate(asr_model.test_dataloader()): + if can_gpu: + test_batch = [x.cuda() for x in test_batch] + if args.amp: + with autocast(): + _ = asr_model(input_signal=test_batch[0], input_signal_length=test_batch[1]) + else: + _ = asr_model(input_signal=test_batch[0], input_signal_length=test_batch[1]) + if i >= args.num_calib_batch: + break + + # Save calibrated model(s) + model_name = args.asr_model.replace(".nemo", "") if args.asr_model.endswith(".nemo") else args.asr_model + if not args.calibrator == "histogram": + compute_amax(asr_model, method="max") + asr_model.save_to(F"{model_name}-max-{args.num_calib_batch*args.batch_size}.nemo") + else: + for percentile in args.percentile: + print(F"{percentile} percentile calibration") + compute_amax(asr_model, method="percentile") + asr_model.save_to(F"{model_name}-percentile-{percentile}-{args.num_calib_batch*args.batch_size}.nemo") + + for method in ["mse", "entropy"]: + print(F"{method} calibration") + compute_amax(asr_model, method=method) + asr_model.save_to(F"{model_name}-{method}-{args.num_calib_batch*args.batch_size}.nemo") + + +def compute_amax(model, **kwargs): + for name, module in model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer): + if module._calibrator is not None: + if isinstance(module._calibrator, calib.MaxCalibrator): + module.load_calib_amax() + else: + module.load_calib_amax(**kwargs) + print(F"{name:40}: {module}") + if can_gpu: + model.cuda() + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer.py b/tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer.py new file mode 100644 index 0000000..b072fe8 --- /dev/null +++ b/tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer.py @@ -0,0 +1,216 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Script for post training quantization of ASR models +""" + +import collections +from argparse import ArgumentParser +from pprint import pprint + +import torch +from omegaconf import open_dict + +from nemo.collections.asr.metrics.wer import WER, word_error_rate +from nemo.collections.asr.models import EncDecCTCModel +from nemo.utils import logging + +try: + from pytorch_quantization import nn as quant_nn + from pytorch_quantization import quant_modules +except ImportError: + raise ImportError( + "pytorch-quantization is not installed. Install from " + "https://github.com/NVIDIA/TensorRT/tree/master/tools/pytorch-quantization." + ) + + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +can_gpu = torch.cuda.is_available() + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--asr_model", type=str, default="QuartzNet15x5Base-En", required=True, help="Pass: 'QuartzNet15x5Base-En'", + ) + parser.add_argument("--dataset", type=str, required=True, help="path to evaluation data") + parser.add_argument("--wer_target", type=float, default=None, help="used by test") + parser.add_argument("--batch_size", type=int, default=4) + parser.add_argument("--wer_tolerance", type=float, default=1.0, help="used by test") + parser.add_argument( + "--dont_normalize_text", + default=False, + action='store_false', + help="Turn off trasnscript normalization. Recommended for non-English.", + ) + parser.add_argument( + "--use_cer", default=False, action='store_true', help="Use Character Error Rate as the evaluation metric" + ) + parser.add_argument('--sensitivity', action="store_true", help="Perform sensitivity analysis") + parser.add_argument('--onnx', action="store_true", help="Export to ONNX") + parser.add_argument('--quant-disable-keyword', type=str, nargs='+', help='disable quantizers by keyword') + args = parser.parse_args() + torch.set_grad_enabled(False) + + quant_modules.initialize() + + if args.asr_model.endswith('.nemo'): + logging.info(f"Using local ASR model from {args.asr_model}") + asr_model_cfg = EncDecCTCModel.restore_from(restore_path=args.asr_model, return_config=True) + with open_dict(asr_model_cfg): + asr_model_cfg.encoder.quantize = True + asr_model = EncDecCTCModel.restore_from(restore_path=args.asr_model, override_config_path=asr_model_cfg) + + else: + logging.info(f"Using NGC cloud ASR model {args.asr_model}") + asr_model_cfg = EncDecCTCModel.from_pretrained(model_name=args.asr_model, return_config=True) + with open_dict(asr_model_cfg): + asr_model_cfg.encoder.quantize = True + asr_model = EncDecCTCModel.from_pretrained(model_name=args.asr_model, override_config_path=asr_model_cfg) + asr_model.setup_test_data( + test_data_config={ + 'sample_rate': 16000, + 'manifest_filepath': args.dataset, + 'labels': asr_model.decoder.vocabulary, + 'batch_size': args.batch_size, + 'normalize_transcripts': args.dont_normalize_text, + } + ) + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + if can_gpu: + asr_model = asr_model.cuda() + asr_model.eval() + + if args.quant_disable_keyword: + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer): + for keyword in args.quant_disable_keyword: + if keyword in name: + logging.warning(F"Disable {name}") + module.disable() + + labels_map = dict([(i, asr_model.decoder.vocabulary[i]) for i in range(len(asr_model.decoder.vocabulary))]) + wer = WER(vocabulary=asr_model.decoder.vocabulary, use_cer=args.use_cer) + wer_quant = evaluate(asr_model, labels_map, wer) + logging.info(f'Got WER of {wer_quant}. Tolerance was {args.wer_tolerance}') + + if args.sensitivity: + if wer_quant < args.wer_tolerance: + logging.info("Tolerance is already met. Skip sensitivity analyasis.") + return + quant_layer_names = [] + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer): + module.disable() + layer_name = name.replace("._input_quantizer", "").replace("._weight_quantizer", "") + if layer_name not in quant_layer_names: + quant_layer_names.append(layer_name) + logging.info(F"{len(quant_layer_names)} quantized layers found.") + + # Build sensitivity profile + quant_layer_sensitivity = {} + for i, quant_layer in enumerate(quant_layer_names): + logging.info(F"Enable {quant_layer}") + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer) and quant_layer in name: + module.enable() + logging.info(F"{name:40}: {module}") + + # Eval the model + wer_value = evaluate(asr_model, labels_map, wer) + logging.info(F"WER: {wer_value}") + quant_layer_sensitivity[quant_layer] = args.wer_tolerance - wer_value + + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer) and quant_layer in name: + module.disable() + logging.info(F"{name:40}: {module}") + + # Skip most sensitive layers until WER target is met + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer): + module.enable() + quant_layer_sensitivity = collections.OrderedDict(sorted(quant_layer_sensitivity.items(), key=lambda x: x[1])) + pprint(quant_layer_sensitivity) + skipped_layers = [] + for quant_layer, _ in quant_layer_sensitivity.items(): + for name, module in asr_model.named_modules(): + if isinstance(module, quant_nn.TensorQuantizer): + if quant_layer in name: + logging.info(F"Disable {name}") + if not quant_layer in skipped_layers: + skipped_layers.append(quant_layer) + module.disable() + wer_value = evaluate(asr_model, labels_map, wer) + if wer_value <= args.wer_tolerance: + logging.info( + F"WER tolerance {args.wer_tolerance} is met by skipping {len(skipped_layers)} sensitive layers." + ) + print(skipped_layers) + export_onnx(args, asr_model) + return + raise ValueError(f"WER tolerance {args.wer_tolerance} can not be met with any layer quantized!") + + export_onnx(args, asr_model) + + +def export_onnx(args, asr_model): + if args.onnx: + if args.asr_model.endswith("nemo"): + onnx_name = args.asr_model.replace(".nemo", ".onnx") + else: + onnx_name = args.asr_model + logging.info(F"Export to {onnx_name}") + quant_nn.TensorQuantizer.use_fb_fake_quant = True + asr_model.export(onnx_name, onnx_opset_version=13) + quant_nn.TensorQuantizer.use_fb_fake_quant = False + + +def evaluate(asr_model, labels_map, wer): + # Eval the model + hypotheses = [] + references = [] + for test_batch in asr_model.test_dataloader(): + if can_gpu: + test_batch = [x.cuda() for x in test_batch] + with autocast(): + log_probs, encoded_len, greedy_predictions = asr_model( + input_signal=test_batch[0], input_signal_length=test_batch[1] + ) + hypotheses += wer.ctc_decoder_predictions_tensor(greedy_predictions) + for batch_ind in range(greedy_predictions.shape[0]): + seq_len = test_batch[3][batch_ind].cpu().detach().numpy() + seq_ids = test_batch[2][batch_ind].cpu().detach().numpy() + reference = ''.join([labels_map[c] for c in seq_ids[0:seq_len]]) + references.append(reference) + del test_batch + wer_value = word_error_rate(hypotheses=hypotheses, references=references, use_cer=wer.use_cer) + + return wer_value + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer_trt.py b/tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer_trt.py new file mode 100644 index 0000000..747bd5b --- /dev/null +++ b/tts/NeMo/examples/asr/quantization/speech_to_text_quant_infer_trt.py @@ -0,0 +1,226 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Script for inference ASR models using TensorRT +""" + +import collections +import os +import time +from argparse import ArgumentParser +from pprint import pprint + +import numpy as np +import pycuda.autoinit +import pycuda.driver as cuda +import tensorrt as trt +import torch +from omegaconf import open_dict + +from nemo.collections.asr.metrics.wer import WER, word_error_rate +from nemo.collections.asr.models import EncDecCTCModel +from nemo.utils import logging + +TRT_LOGGER = trt.Logger() + + +can_gpu = torch.cuda.is_available() + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--asr_model", type=str, default="QuartzNet15x5Base-En", required=True, help="Pass: 'QuartzNet15x5Base-En'", + ) + parser.add_argument( + "--asr_onnx", + type=str, + default="./QuartzNet15x5Base-En-max-32.onnx", + help="Pass: 'QuartzNet15x5Base-En-max-32.onnx'", + ) + parser.add_argument("--dataset", type=str, required=True, help="path to evaluation data") + parser.add_argument("--batch_size", type=int, default=4) + parser.add_argument( + "--dont_normalize_text", + default=False, + action='store_false', + help="Turn off trasnscript normalization. Recommended for non-English.", + ) + parser.add_argument( + "--use_cer", default=False, action='store_true', help="Use Character Error Rate as the evaluation metric" + ) + parser.add_argument('--qat', action="store_true", help="Use onnx file exported from QAT tools") + args = parser.parse_args() + torch.set_grad_enabled(False) + + if args.asr_model.endswith('.nemo'): + logging.info(f"Using local ASR model from {args.asr_model}") + asr_model_cfg = EncDecCTCModel.restore_from(restore_path=args.asr_model, return_config=True) + with open_dict(asr_model_cfg): + asr_model_cfg.encoder.quantize = True + asr_model = EncDecCTCModel.restore_from(restore_path=args.asr_model, override_config_path=asr_model_cfg) + + else: + logging.info(f"Using NGC cloud ASR model {args.asr_model}") + asr_model_cfg = EncDecCTCModel.from_pretrained(model_name=args.asr_model, return_config=True) + with open_dict(asr_model_cfg): + asr_model_cfg.encoder.quantize = True + asr_model = EncDecCTCModel.from_pretrained(model_name=args.asr_model, override_config_path=asr_model_cfg) + asr_model.setup_test_data( + test_data_config={ + 'sample_rate': 16000, + 'manifest_filepath': args.dataset, + 'labels': asr_model.decoder.vocabulary, + 'batch_size': args.batch_size, + 'normalize_transcripts': args.dont_normalize_text, + } + ) + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + if can_gpu: + asr_model = asr_model.cuda() + asr_model.eval() + labels_map = dict([(i, asr_model.decoder.vocabulary[i]) for i in range(len(asr_model.decoder.vocabulary))]) + wer = WER(vocabulary=asr_model.decoder.vocabulary, use_cer=args.use_cer) + wer_result = evaluate(asr_model, args.asr_onnx, labels_map, wer, args.qat) + logging.info(f'Got WER of {wer_result}.') + + +def get_min_max_input_shape(asr_model): + max_shape = (1, 64, 1) + min_shape = (64, 64, 99999) + for test_batch in asr_model.test_dataloader(): + test_batch = [x.cuda() for x in test_batch] + processed_signal, processed_signal_length = asr_model.preprocessor( + input_signal=test_batch[0], length=test_batch[1] + ) + shape = processed_signal.cpu().numpy().shape + if shape[0] > max_shape[0]: + max_shape = (shape[0], *max_shape[1:]) + if shape[0] < min_shape[0]: + min_shape = (shape[0], *min_shape[1:]) + if shape[2] > max_shape[2]: + max_shape = (*max_shape[0:2], shape[2]) + if shape[2] < min_shape[2]: + min_shape = (*min_shape[0:2], shape[2]) + return min_shape, max_shape + + +def build_trt_engine(asr_model, onnx_path, qat): + trt_engine_path = "{}.trt".format(onnx_path) + if os.path.exists(trt_engine_path): + return trt_engine_path + + min_input_shape, max_input_shape = get_min_max_input_shape(asr_model) + workspace_size = 512 + with trt.Builder(TRT_LOGGER) as builder: + network_flags = 1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH) + if qat: + network_flags |= 1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_PRECISION) + with builder.create_network(flags=network_flags) as network, trt.OnnxParser( + network, TRT_LOGGER + ) as parser, builder.create_builder_config() as builder_config: + parser.parse_from_file(onnx_path) + builder_config.max_workspace_size = workspace_size * (1024 * 1024) + if qat: + builder_config.set_flag(trt.BuilderFlag.INT8) + + profile = builder.create_optimization_profile() + profile.set_shape("audio_signal", min=min_input_shape, opt=max_input_shape, max=max_input_shape) + builder_config.add_optimization_profile(profile) + + engine = builder.build_engine(network, builder_config) + serialized_engine = engine.serialize() + with open(trt_engine_path, "wb") as fout: + fout.write(serialized_engine) + return trt_engine_path + + +def trt_inference(stream, trt_ctx, d_input, d_output, input_signal, input_signal_length): + print("infer with shape: {}".format(input_signal.shape)) + + trt_ctx.set_binding_shape(0, input_signal.shape) + assert trt_ctx.all_binding_shapes_specified + + h_output = cuda.pagelocked_empty(tuple(trt_ctx.get_binding_shape(1)), dtype=np.float32) + + h_input_signal = cuda.register_host_memory(np.ascontiguousarray(input_signal.cpu().numpy().ravel())) + cuda.memcpy_htod_async(d_input, h_input_signal, stream) + trt_ctx.execute_async_v2(bindings=[int(d_input), int(d_output)], stream_handle=stream.handle) + cuda.memcpy_dtoh_async(h_output, d_output, stream) + stream.synchronize() + + greedy_predictions = torch.tensor(h_output).argmax(dim=-1, keepdim=False) + return greedy_predictions + + +def evaluate(asr_model, asr_onnx, labels_map, wer, qat): + # Eval the model + hypotheses = [] + references = [] + stream = cuda.Stream() + vocabulary_size = len(labels_map) + 1 + engine_file_path = build_trt_engine(asr_model, asr_onnx, qat) + with open(engine_file_path, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: + trt_engine = runtime.deserialize_cuda_engine(f.read()) + trt_ctx = trt_engine.create_execution_context() + + profile_shape = trt_engine.get_profile_shape(profile_index=0, binding=0) + print("profile shape min:{}, opt:{}, max:{}".format(profile_shape[0], profile_shape[1], profile_shape[2])) + max_input_shape = profile_shape[2] + input_nbytes = trt.volume(max_input_shape) * trt.float32.itemsize + d_input = cuda.mem_alloc(input_nbytes) + max_output_shape = [max_input_shape[0], vocabulary_size, (max_input_shape[-1] + 1) // 2] + output_nbytes = trt.volume(max_output_shape) * trt.float32.itemsize + d_output = cuda.mem_alloc(output_nbytes) + + for test_batch in asr_model.test_dataloader(): + if can_gpu: + test_batch = [x.cuda() for x in test_batch] + processed_signal, processed_signal_length = asr_model.preprocessor( + input_signal=test_batch[0], length=test_batch[1] + ) + + greedy_predictions = trt_inference( + stream, + trt_ctx, + d_input, + d_output, + input_signal=processed_signal, + input_signal_length=processed_signal_length, + ) + hypotheses += wer.ctc_decoder_predictions_tensor(greedy_predictions) + for batch_ind in range(greedy_predictions.shape[0]): + seq_len = test_batch[3][batch_ind].cpu().detach().numpy() + seq_ids = test_batch[2][batch_ind].cpu().detach().numpy() + reference = ''.join([labels_map[c] for c in seq_ids[0:seq_len]]) + references.append(reference) + del test_batch + wer_value = word_error_rate(hypotheses=hypotheses, references=references, use_cer=wer.use_cer) + + return wer_value + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/speech_to_label.py b/tts/NeMo/examples/asr/speech_to_label.py new file mode 100644 index 0000000..369b0f0 --- /dev/null +++ b/tts/NeMo/examples/asr/speech_to_label.py @@ -0,0 +1,146 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +# Task 1: Speech Command + +## Preparing the dataset +Use the `process_speech_commands_data.py` script under /scripts/dataset_processing in order to prepare the dataset. + +```sh +python /scripts/dataset_processing/process_speech_commands_data.py \ + --data_root= \ + --data_version= \ + --class_split= \ + --rebalance \ + --log +``` + +## Train to convergence +```sh +python speech_to_label.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath=["",""] \ + trainer.gpus=2 \ + trainer.accelerator="ddp" \ + trainer.max_epochs=200 \ + exp_manager.create_wandb_logger=True \ + exp_manager.wandb_logger_kwargs.name="MatchboxNet-3x1x64-v1" \ + exp_manager.wandb_logger_kwargs.project="MatchboxNet-v1" \ + +trainer.precision=16 \ + +trainer.amp_level=O1 # needed if using PyTorch < 1.6 +``` + + +# Task 2: Voice Activity Detection + +## Preparing the dataset +Use the `process_vad_data.py` script under /scripts/dataset_processing in order to prepare the dataset. + +```sh +python process_vad_data.py \ + --out_dir= \ + --speech_data_root= \ + --background_data_root= \ + --rebalance_method=<'under' or 'over' of 'fixed'> \ + --log + (Optional --demo (for demonstration in tutorial). If you want to use your own background noise data, make sure to delete --demo) +``` + +## Train to convergence +```sh +python speech_to_label.py \ + --config-path= + --config-name= \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath=["",""] \ + trainer.gpus=2 \ + trainer.accelerator="ddp" \ + trainer.max_epochs=200 \ + exp_manager.create_wandb_logger=True \ + exp_manager.wandb_logger_kwargs.name="MatchboxNet-3x1x64-vad" \ + exp_manager.wandb_logger_kwargs.project="MatchboxNet-vad" \ + +trainer.precision=16 \ + +trainer.amp_level=O1 # needed if using PyTorch < 1.6 +``` + +# Optional: Use tarred dataset to speed up data loading. Apply to both tasks. +## Prepare tarred dataset. + Prepare ONE manifest that contains all training data you would like to include. Validation should use non-tarred dataset. + Note that it's possible that tarred datasets impacts validation scores because it drop values in order to have same amount of files per tarfile; + Scores might be off since some data is missing. + + Use the `convert_to_tarred_audio_dataset.py` script under /scripts/speech_recognition in order to prepare tarred audio dataset. + For details, please see TarredAudioToClassificationLabelDataset in /nemo/collections/asr/data/audio_to_label.py + +python speech_to_label.py \ + --config-path= + --config-name= \ + model.train_ds.manifest_filepath= \ + model.train_ds.is_tarred=True \ + model.train_ds.tarred_audio_filepaths= \ + +model.train_ds.num_worker= \ + model.validation_ds.manifest_filepath=\ + trainer.gpus=2 \ + trainer.accelerator="ddp" \ + trainer.max_epochs=200 \ + exp_manager.create_wandb_logger=True \ + exp_manager.wandb_logger_kwargs.name="MatchboxNet-3x1x64-vad" \ + exp_manager.wandb_logger_kwargs.project="MatchboxNet-vad" \ + +trainer.precision=16 \ + +trainer.amp_level=O1 # needed if using PyTorch < 1.6 + +# Fine-tune a model + +For documentation on fine-tuning this model, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#fine-tuning-configurations + +# Pretrained Models + +For documentation on existing pretrained models, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/speech_classification/results.html# + +""" +import pytorch_lightning as pl +from omegaconf import OmegaConf + +from nemo.collections.asr.models import EncDecClassificationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf/matchboxnet", config_name="matchboxnet_3x1x64_v1") +def main(cfg): + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + asr_model = EncDecClassificationModel(cfg=cfg.model, trainer=trainer) + + # Initialize the weights of the model from another model, if provided via config + asr_model.maybe_init_from_pretrained_checkpoint(cfg) + + trainer.fit(asr_model) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + trainer = pl.Trainer(gpus=gpu) + if asr_model.prepare_test(trainer): + trainer.test(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/speech_to_text.py b/tts/NeMo/examples/asr/speech_to_text.py new file mode 100644 index 0000000..ced4cb8 --- /dev/null +++ b/tts/NeMo/examples/asr/speech_to_text.py @@ -0,0 +1,105 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +# Training the model + +Basic run (on CPU for 50 epochs): + python examples/asr/speech_to_text.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath="" \ + trainer.gpus=0 \ + trainer.max_epochs=50 + + +Add PyTorch Lightning Trainer arguments from CLI: + python speech_to_text.py \ + ... \ + +trainer.fast_dev_run=true + +Hydra logs will be found in "$(./outputs/$(date +"%y-%m-%d")/$(date +"%H-%M-%S")/.hydra)" +PTL logs will be found in "$(./outputs/$(date +"%y-%m-%d")/$(date +"%H-%M-%S")/lightning_logs)" + +Override some args of optimizer: + python speech_to_text.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath="./an4/train_manifest.json" \ + model.validation_ds.manifest_filepath="./an4/test_manifest.json" \ + trainer.gpus=2 \ + trainer.max_epochs=2 \ + model.optim.args.betas=[0.8,0.5] \ + model.optim.args.weight_decay=0.0001 + +Override optimizer entirely + python speech_to_text.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath="./an4/train_manifest.json" \ + model.validation_ds.manifest_filepath="./an4/test_manifest.json" \ + trainer.gpus=2 \ + trainer.max_epochs=2 \ + model.optim.name=adamw \ + model.optim.lr=0.001 \ + ~model.optim.args \ + +model.optim.args.betas=[0.8,0.5]\ + +model.optim.args.weight_decay=0.0005 + +# Fine-tune a model + +For documentation on fine-tuning this model, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#fine-tuning-configurations + +# Pretrained Models + +For documentation on existing pretrained models, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/results.html + +""" + +import pytorch_lightning as pl +from omegaconf import OmegaConf + +from nemo.collections.asr.models import EncDecCTCModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="config") +def main(cfg): + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + asr_model = EncDecCTCModel(cfg=cfg.model, trainer=trainer) + + # Initialize the weights of the model from another model, if provided via config + asr_model.maybe_init_from_pretrained_checkpoint(cfg) + + trainer.fit(asr_model) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + test_trainer = pl.Trainer( + gpus=gpu, + precision=trainer.precision, + amp_level=trainer.accelerator_connector.amp_level, + amp_backend=cfg.trainer.get("amp_backend", "native"), + ) + if asr_model.prepare_test(test_trainer): + test_trainer.test(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/speech_to_text_bpe.py b/tts/NeMo/examples/asr/speech_to_text_bpe.py new file mode 100644 index 0000000..090535f --- /dev/null +++ b/tts/NeMo/examples/asr/speech_to_text_bpe.py @@ -0,0 +1,101 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +# Preparing the Tokenizer for the dataset +Use the `process_asr_text_tokenizer.py` script under /scripts/tokenizers/ in order to prepare the tokenizer. + +```sh +python /scripts/tokenizers/process_asr_text_tokenizer.py \ + --manifest= + OR + --data_file= \ + --data_root="" \ + --vocab_size= \ + --tokenizer=<"spe" or "wpe"> \ + --no_lower_case \ + --spe_type=<"unigram", "bpe", "char" or "word"> \ + --spe_character_coverage=1.0 \ + --log +``` + +# Training the model +```sh +python speech_to_text_bpe.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath= \ + model.validation_ds.manifest_filepath= \ + model.tokenizer.dir= \ + model.tokenizer.type= \ + trainer.gpus=-1 \ + trainer.accelerator="ddp" \ + trainer.max_epochs=100 \ + model.optim.name="adamw" \ + model.optim.lr=0.001 \ + model.optim.betas=[0.9,0.999] \ + model.optim.weight_decay=0.0001 \ + model.optim.sched.warmup_steps=2000 + exp_manager.create_wandb_logger=True \ + exp_manager.wandb_logger_kwargs.name="" \ + exp_manager.wandb_logger_kwargs.project="" +``` + +# Fine-tune a model + +For documentation on fine-tuning this model, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#fine-tuning-configurations + +# Pretrained Models + +For documentation on existing pretrained models, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/results.html + +""" + +import pytorch_lightning as pl +from omegaconf import OmegaConf + +from nemo.collections.asr.models.ctc_bpe_models import EncDecCTCModelBPE +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf/citrinet/", config_name="config_bpe") +def main(cfg): + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + asr_model = EncDecCTCModelBPE(cfg=cfg.model, trainer=trainer) + + # Initialize the weights of the model from another model, if provided via config + asr_model.maybe_init_from_pretrained_checkpoint(cfg) + + trainer.fit(asr_model) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + test_trainer = pl.Trainer( + gpus=gpu, + precision=trainer.precision, + amp_level=trainer.accelerator_connector.amp_level, + amp_backend=cfg.trainer.get("amp_backend", "native"), + ) + if asr_model.prepare_test(test_trainer): + test_trainer.test(asr_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/asr/speech_to_text_infer.py b/tts/NeMo/examples/asr/speech_to_text_infer.py new file mode 100644 index 0000000..bbba1a6 --- /dev/null +++ b/tts/NeMo/examples/asr/speech_to_text_infer.py @@ -0,0 +1,114 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script serves three goals: + (1) Demonstrate how to use NeMo Models outside of PytorchLightning + (2) Shows example of batch ASR inference + (3) Serves as CI test for pre-trained checkpoint +""" + +from argparse import ArgumentParser + +import torch + +from nemo.collections.asr.metrics.wer import WER, word_error_rate +from nemo.collections.asr.models import EncDecCTCModel +from nemo.utils import logging + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +can_gpu = torch.cuda.is_available() + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--asr_model", type=str, default="QuartzNet15x5Base-En", required=True, help="Pass: 'QuartzNet15x5Base-En'", + ) + parser.add_argument("--dataset", type=str, required=True, help="path to evaluation data") + parser.add_argument("--batch_size", type=int, default=4) + parser.add_argument("--wer_tolerance", type=float, default=1.0, help="used by test") + parser.add_argument( + "--dont_normalize_text", + default=False, + action='store_true', + help="Turn off trasnscript normalization. Recommended for non-English.", + ) + parser.add_argument( + "--use_cer", default=False, action='store_true', help="Use Character Error Rate as the evaluation metric" + ) + args = parser.parse_args() + torch.set_grad_enabled(False) + + if args.asr_model.endswith('.nemo'): + logging.info(f"Using local ASR model from {args.asr_model}") + asr_model = EncDecCTCModel.restore_from(restore_path=args.asr_model) + else: + logging.info(f"Using NGC cloud ASR model {args.asr_model}") + asr_model = EncDecCTCModel.from_pretrained(model_name=args.asr_model) + + asr_model.preprocessor.featurizer.pad_to = 0 + asr_model.preprocessor.featurizer.dither = 0.0 + + asr_model.setup_test_data( + test_data_config={ + 'sample_rate': 16000, + 'manifest_filepath': args.dataset, + 'labels': asr_model.decoder.vocabulary, + 'batch_size': args.batch_size, + 'normalize_transcripts': not args.dont_normalize_text, + } + ) + if can_gpu: + asr_model = asr_model.cuda() + asr_model.eval() + labels_map = dict([(i, asr_model.decoder.vocabulary[i]) for i in range(len(asr_model.decoder.vocabulary))]) + wer = WER(vocabulary=asr_model.decoder.vocabulary) + hypotheses = [] + references = [] + for test_batch in asr_model.test_dataloader(): + if can_gpu: + test_batch = [x.cuda() for x in test_batch] + with autocast(): + log_probs, encoded_len, greedy_predictions = asr_model( + input_signal=test_batch[0], input_signal_length=test_batch[1] + ) + hypotheses += wer.ctc_decoder_predictions_tensor(greedy_predictions) + for batch_ind in range(greedy_predictions.shape[0]): + seq_len = test_batch[3][batch_ind].cpu().detach().numpy() + seq_ids = test_batch[2][batch_ind].cpu().detach().numpy() + reference = ''.join([labels_map[c] for c in seq_ids[0:seq_len]]) + references.append(reference) + del test_batch + + wer_value = word_error_rate(hypotheses=hypotheses, references=references, use_cer=args.use_cer) + if not args.use_cer: + if wer_value > args.wer_tolerance: + raise ValueError(f"got wer of {wer_value}. it was higher than {args.wer_tolerance}") + logging.info(f'Got WER of {wer_value}. Tolerance was {args.wer_tolerance}') + else: + logging.info(f'Got CER of {wer_value}') + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/speech_to_text_rnnt.py b/tts/NeMo/examples/asr/speech_to_text_rnnt.py new file mode 100644 index 0000000..39d3be9 --- /dev/null +++ b/tts/NeMo/examples/asr/speech_to_text_rnnt.py @@ -0,0 +1,104 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +# Training the model + +Basic run (on CPU for 50 epochs): + python examples/asr/speech_to_text_rnnt.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath="" \ + model.validation_ds.manifest_filepath="" \ + trainer.gpus=0 \ + trainer.max_epochs=50 + + +Add PyTorch Lightning Trainer arguments from CLI: + python speech_to_text_rnnt.py \ + ... \ + +trainer.fast_dev_run=true + +Hydra logs will be found in "$(./outputs/$(date +"%y-%m-%d")/$(date +"%H-%M-%S")/.hydra)" +PTL logs will be found in "$(./outputs/$(date +"%y-%m-%d")/$(date +"%H-%M-%S")/lightning_logs)" + +Override some args of optimizer: + python speech_to_text_rnnt.py \ + --config-path="experimental/contextnet_rnnt" \ + --config-name="config_rnnt" \ + model.train_ds.manifest_filepath="./an4/train_manifest.json" \ + model.validation_ds.manifest_filepath="./an4/test_manifest.json" \ + trainer.gpus=2 \ + trainer.precision=16 \ + trainer.max_epochs=2 \ + model.optim.betas=[0.8,0.5] \ + model.optim.weight_decay=0.0001 + +Override optimizer entirely + python speech_to_text_rnnt.py \ + --config-path="experimental/contextnet_rnnt" \ + --config-name="config_rnnt" \ + model.train_ds.manifest_filepath="./an4/train_manifest.json" \ + model.validation_ds.manifest_filepath="./an4/test_manifest.json" \ + trainer.gpus=2 \ + trainer.precision=16 \ + trainer.max_epochs=2 \ + model.optim.name=adamw \ + model.optim.lr=0.001 \ + ~model.optim.args \ + +model.optim.args.betas=[0.8,0.5]\ + +model.optim.args.weight_decay=0.0005 + +# Fine-tune a model + +For documentation on fine-tuning this model, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#fine-tuning-configurations + +""" + +import pytorch_lightning as pl +from omegaconf import OmegaConf + +from nemo.collections.asr.models import EncDecRNNTModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="experimental/contextnet_rnnt", config_name="config_rnnt") +def main(cfg): + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + asr_model = EncDecRNNTModel(cfg=cfg.model, trainer=trainer) + + # Initialize the weights of the model from another model, if provided via config + asr_model.maybe_init_from_pretrained_checkpoint(cfg) + + trainer.fit(asr_model) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + test_trainer = pl.Trainer( + gpus=gpu, + precision=trainer.precision, + amp_level=trainer.accelerator_connector.amp_level, + amp_backend=cfg.trainer.get("amp_backend", "native"), + ) + if asr_model.prepare_test(test_trainer): + test_trainer.test(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/speech_to_text_rnnt_bpe.py b/tts/NeMo/examples/asr/speech_to_text_rnnt_bpe.py new file mode 100644 index 0000000..91e41de --- /dev/null +++ b/tts/NeMo/examples/asr/speech_to_text_rnnt_bpe.py @@ -0,0 +1,96 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +# Preparing the Tokenizer for the dataset +Use the `process_asr_text_tokenizer.py` script under /scripts/tokenizers/ in order to prepare the tokenizer. + +```sh +python /scripts/tokenizers/process_asr_text_tokenizer.py \ + --manifest= + OR + --data_file= \ + --data_root="" \ + --vocab_size= \ + --tokenizer=<"spe" or "wpe"> \ + --no_lower_case \ + --spe_type=<"unigram", "bpe", "char" or "word"> \ + --spe_character_coverage=1.0 \ + --log +``` + +# Training the model +```sh +python speech_to_text_rnnt_bpe.py \ + # (Optional: --config-path= --config-name=) \ + model.train_ds.manifest_filepath= \ + model.validation_ds.manifest_filepath= \ + model.tokenizer.dir= \ + model.tokenizer.type= \ + trainer.gpus=-1 \ + trainer.accelerator="ddp" \ + trainer.max_epochs=100 \ + model.optim.name="adamw" \ + model.optim.lr=0.001 \ + model.optim.betas=[0.9,0.999] \ + model.optim.weight_decay=0.0001 \ + model.optim.sched.warmup_steps=2000 + exp_manager.create_wandb_logger=True \ + exp_manager.wandb_logger_kwargs.name="" \ + exp_manager.wandb_logger_kwargs.project="" +``` + +# Fine-tune a model + +For documentation on fine-tuning this model, please visit - +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/configs.html#fine-tuning-configurations + +""" + +import pytorch_lightning as pl +from omegaconf import OmegaConf + +from nemo.collections.asr.models import EncDecRNNTBPEModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="experimental/contextnet_rnnt", config_name="config_rnnt_bpe") +def main(cfg): + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + asr_model = EncDecRNNTBPEModel(cfg=cfg.model, trainer=trainer) + + # Initialize the weights of the model from another model, if provided via config + asr_model.maybe_init_from_pretrained_checkpoint(cfg) + + trainer.fit(asr_model) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + test_trainer = pl.Trainer( + gpus=gpu, + precision=trainer.precision, + amp_level=trainer.accelerator_connector.amp_level, + amp_backend=cfg.trainer.get("amp_backend", "native"), + ) + if asr_model.prepare_test(test_trainer): + test_trainer.test(asr_model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/transcribe_speech.py b/tts/NeMo/examples/asr/transcribe_speech.py new file mode 100644 index 0000000..b186c22 --- /dev/null +++ b/tts/NeMo/examples/asr/transcribe_speech.py @@ -0,0 +1,167 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import contextlib +import glob +import json +import os +from dataclasses import dataclass +from typing import Optional + +import pytorch_lightning as pl +import torch +from omegaconf import OmegaConf + +from nemo.collections.asr.metrics.rnnt_wer import RNNTDecodingConfig +from nemo.collections.asr.models import ASRModel +from nemo.core.config import hydra_runner +from nemo.utils import logging, model_utils + + +""" +# Transcribe audio +# Arguments +# model_path: path to .nemo ASR checkpoint +# pretrained_name: name of pretrained ASR model (from NGC registry) +# audio_dir: path to directory with audio files +# dataset_manifest: path to dataset JSON manifest file (in NeMo format) +# +# ASR model can be specified by either "model_path" or "pretrained_name". +# Data for transcription can be defined with either "audio_dir" or "dataset_manifest". +# Results are returned in a JSON manifest file. + +python transcribe_speech.py \ + model_path=null \ + pretrained_name=null \ + audio_dir="" \ + dataset_manifest="" \ + output_filename="" +""" + + +@dataclass +class TranscriptionConfig: + # Required configs + model_path: Optional[str] = None # Path to a .nemo file + pretrained_name: Optional[str] = None # Name of a pretrained model + audio_dir: Optional[str] = None # Path to a directory which contains audio files + dataset_manifest: Optional[str] = None # Path to dataset's JSON manifest + + # General configs + output_filename: Optional[str] = None + batch_size: int = 32 + cuda: Optional[bool] = None # will switch to cuda if available, defaults to CPU otherwise + amp: bool = False + audio_type: str = "wav" + + # decoding strategy for RNNT models + rnnt_decoding: RNNTDecodingConfig = RNNTDecodingConfig() + + +@hydra_runner(config_name="TranscriptionConfig", schema=TranscriptionConfig) +def main(cfg: TranscriptionConfig): + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + + if cfg.model_path is None and cfg.pretrained_name is None: + raise ValueError("Both cfg.model_path and cfg.pretrained_name cannot be None!") + if cfg.audio_dir is None and cfg.dataset_manifest is None: + raise ValueError("Both cfg.audio_dir and cfg.dataset_manifest cannot be None!") + + # setup GPU + if cfg.cuda is None: + cfg.cuda = torch.cuda.is_available() + + if type(cfg.cuda) == int: + device_id = int(cfg.cuda) + else: + device_id = 0 + + device = torch.device(f'cuda:{device_id}' if cfg.cuda else 'cpu') + + # setup model + if cfg.model_path is not None: + # restore model from .nemo file path + model_cfg = ASRModel.restore_from(restore_path=cfg.model_path, return_config=True) + classpath = model_cfg.target # original class path + imported_class = model_utils.import_class_by_path(classpath) # type: ASRModel + logging.info(f"Restoring model : {imported_class.__name__}") + asr_model = imported_class.restore_from(restore_path=cfg.model_path, map_location=device) # type: ASRModel + model_name = os.path.splitext(os.path.basename(cfg.model_path))[0] + else: + # restore model by name + asr_model = ASRModel.from_pretrained(model_name=cfg.pretrained_name, map_location=device) # type: ASRModel + model_name = cfg.pretrained_name + + trainer = pl.Trainer(gpus=int(cfg.cuda)) + asr_model.set_trainer(trainer) + asr_model = asr_model.eval() + + # Setup decoding strategy + if hasattr(asr_model, 'change_decoding_strategy'): + asr_model.change_decoding_strategy(cfg.rnnt_decoding) + + # get audio filenames + if cfg.audio_dir is not None: + filepaths = list(glob.glob(os.path.join(cfg.audio_dir, f"*.{cfg.audio_type}"))) + else: + # get filenames from manifest + filepaths = [] + with open(cfg.dataset_manifest, 'r') as f: + for line in f: + item = json.loads(line) + filepaths.append(item['audio_filepath']) + logging.info(f"\nTranscribing {len(filepaths)} files...\n") + + # setup AMP (optional) + if cfg.amp and torch.cuda.is_available() and hasattr(torch.cuda, 'amp') and hasattr(torch.cuda.amp, 'autocast'): + logging.info("AMP enabled!\n") + autocast = torch.cuda.amp.autocast + else: + + @contextlib.contextmanager + def autocast(): + yield + + # transcribe audio + with autocast(): + with torch.no_grad(): + transcriptions = asr_model.transcribe(filepaths, batch_size=cfg.batch_size) + logging.info(f"Finished transcribing {len(filepaths)} files !") + + if cfg.output_filename is None: + # create default output filename + if cfg.audio_dir is not None: + cfg.output_filename = os.path.dirname(os.path.join(cfg.audio_dir, '.')) + '.json' + else: + cfg.output_filename = cfg.dataset_manifest.replace('.json', f'_{model_name}.json') + + logging.info(f"Writing transcriptions into file: {cfg.output_filename}") + + with open(cfg.output_filename, 'w', encoding='utf-8') as f: + if cfg.audio_dir is not None: + for idx, text in enumerate(transcriptions): + item = {'audio_filepath': filepaths[idx], 'pred_text': text} + f.write(json.dumps(item) + "\n") + else: + with open(cfg.dataset_manifest, 'r') as fr: + for idx, line in enumerate(fr): + item = json.loads(line) + item['pred_text'] = transcriptions[idx] + f.write(json.dumps(item) + "\n") + + logging.info("Finished writing predictions !") + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/asr/vad_infer.py b/tts/NeMo/examples/asr/vad_infer.py new file mode 100644 index 0000000..ba03602 --- /dev/null +++ b/tts/NeMo/examples/asr/vad_infer.py @@ -0,0 +1,171 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +During inference, we perform frame-level prediction by two approaches: + 1) shift the window of length time_length (e.g. 0.63s) by shift_length (e.g. 10ms) to generate the frame and use the prediction of the window to represent the label for the frame; + [this script demonstrate how to do this approach] + 2) generate predictions with overlapping input segments. Then a smoothing filter is applied to decide the label for a frame spanned by multiple segments. + [get frame level prediction by this script and use vad_overlap_posterior.py in NeMo/scripts/voice_activity_detection + One can also find posterior about converting frame level prediction + to speech/no-speech segment in start and end times format in that script.] + + Image https://raw.githubusercontent.com/NVIDIA/NeMo/main/tutorials/asr/images/vad_post_overlap_diagram.png + will help you understand this method. + +Usage: +python vad_infer.py --vad_model="vad_marblenet" --dataset= --out_dir='frame/demo' --time_length=0.63 + +""" + + +import json +import logging +import os +from argparse import ArgumentParser + +import torch + +from nemo.collections.asr.models import EncDecClassificationModel +from nemo.collections.asr.parts.utils.vad_utils import get_vad_stream_status, prepare_manifest +from nemo.utils import logging + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--vad_model", type=str, default="MatchboxNet-VAD-3x2", required=False, help="Pass: 'MatchboxNet-VAD-3x2'" + ) + parser.add_argument( + "--dataset", + type=str, + required=True, + help="Path of json file of evaluation data. Audio files should have unique names.", + ) + parser.add_argument("--out_dir", type=str, default="vad_frame", help="Dir of your vad outputs") + parser.add_argument("--time_length", type=float, default=0.63) + parser.add_argument("--shift_length", type=float, default=0.01) + parser.add_argument("--normalize_audio", type=bool, default=False) + parser.add_argument("--num_workers", type=float, default=20) + parser.add_argument("--split_duration", type=float, default=400) + parser.add_argument( + "--dont_auto_split", + default=False, + action='store_true', + help="Whether to automatically split manifest entry by split_duration to avoid potential CUDA out of memory issue.", + ) + + args = parser.parse_args() + + torch.set_grad_enabled(False) + + if args.vad_model.endswith('.nemo'): + logging.info(f"Using local VAD model from {args.vad_model}") + vad_model = EncDecClassificationModel.restore_from(restore_path=args.vad_model) + else: + logging.info(f"Using NGC cloud VAD model {args.vad_model}") + vad_model = EncDecClassificationModel.from_pretrained(model_name=args.vad_model) + + if not os.path.exists(args.out_dir): + os.mkdir(args.out_dir) + + # Prepare manifest for streaming VAD + manifest_vad_input = args.dataset + if not args.dont_auto_split: + logging.info("Split long audio file to avoid CUDA memory issue") + logging.debug("Try smaller split_duration if you still have CUDA memory issue") + config = { + 'manifest_filepath': manifest_vad_input, + 'time_length': args.time_length, + 'split_duration': args.split_duration, + 'num_workers': args.num_workers, + } + manifest_vad_input = prepare_manifest(config) + else: + logging.warning( + "If you encounter CUDA memory issue, try splitting manifest entry by split_duration to avoid it." + ) + + # setup_test_data + vad_model.setup_test_data( + test_data_config={ + 'vad_stream': True, + 'sample_rate': 16000, + 'manifest_filepath': manifest_vad_input, + 'labels': ['infer',], + 'num_workers': args.num_workers, + 'shuffle': False, + 'time_length': args.time_length, + 'shift_length': args.shift_length, + 'trim_silence': False, + 'normalize_audio': args.normalize_audio, + } + ) + + vad_model = vad_model.to(device) + vad_model.eval() + + time_unit = int(args.time_length / args.shift_length) + trunc = int(time_unit / 2) + trunc_l = time_unit - trunc + all_len = 0 + + data = [] + for line in open(args.dataset, 'r'): + file = json.loads(line)['audio_filepath'].split("/")[-1] + data.append(file.split(".wav")[0]) + logging.info(f"Inference on {len(data)} audio files/json lines!") + + status = get_vad_stream_status(data) + for i, test_batch in enumerate(vad_model.test_dataloader()): + test_batch = [x.to(device) for x in test_batch] + with autocast(): + log_probs = vad_model(input_signal=test_batch[0], input_signal_length=test_batch[1]) + probs = torch.softmax(log_probs, dim=-1) + pred = probs[:, 1] + + if status[i] == 'start': + to_save = pred[:-trunc] + elif status[i] == 'next': + to_save = pred[trunc:-trunc_l] + elif status[i] == 'end': + to_save = pred[trunc_l:] + else: + to_save = pred + + all_len += len(to_save) + outpath = os.path.join(args.out_dir, data[i] + ".frame") + with open(outpath, "a") as fout: + for f in range(len(to_save)): + fout.write('{0:0.4f}\n'.format(to_save[f])) + del test_batch + if status[i] == 'end' or status[i] == 'single': + logging.debug(f"Overall length of prediction of {data[i]} is {all_len}!") + all_len = 0 + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/cv/mnist_lenet5_image_classification_pure_lightning.py b/tts/NeMo/examples/cv/mnist_lenet5_image_classification_pure_lightning.py new file mode 100644 index 0000000..ff03a9e --- /dev/null +++ b/tts/NeMo/examples/cv/mnist_lenet5_image_classification_pure_lightning.py @@ -0,0 +1,65 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from dataclasses import dataclass + +# from hydra.utils import instantiate +import pytorch_lightning as ptl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.cv.models import MNISTLeNet5, MNISTLeNet5Config +from nemo.core.config import Config, TrainerConfig, hydra_runner +from nemo.utils import logging + + +@dataclass +class AppConfig(Config): + """ + This is structured config for this application. + + Args: + name: Description of the application. + trainer: configuration of the trainer. + model: configuation of the model. + """ + + name: str = "Training of a LeNet-5 Model using a pure PyTorchLightning approach - using DDP on 2 GPUs." + trainer: TrainerConfig = TrainerConfig(gpus=2, accelerator="ddp") + model: MNISTLeNet5Config = MNISTLeNet5Config() + + +@hydra_runner(schema=AppConfig, config_name="AppConfig") +def main(cfg: DictConfig): + # Show configuration - user can modify every parameter from command line! + logging.info("Application config\n" + OmegaConf.to_yaml(cfg)) + + # The "model" - with dataloader/dataset inside of it. + lenet5 = MNISTLeNet5(cfg.model) + + # Setup train data loader and optimizer + lenet5.setup_training_data() + + # Setup optimizer and scheduler + lenet5.setup_optimization() + + # Create trainer. + trainer = ptl.Trainer(**(cfg.trainer)) + # trainer = instantiate(cfg.trainer) + + # Train. + trainer.fit(model=lenet5) + + +if __name__ == "__main__": + main() # TODO: No cfg in function call, and no hydra runner diff --git a/tts/NeMo/examples/nlp/dialogue_state_tracking/conf/sgdqa_config.yaml b/tts/NeMo/examples/nlp/dialogue_state_tracking/conf/sgdqa_config.yaml new file mode 100644 index 0000000..7ecc565 --- /dev/null +++ b/tts/NeMo/examples/nlp/dialogue_state_tracking/conf/sgdqa_config.yaml @@ -0,0 +1,115 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + + +pretrained_model: null # pretrained QAModel model from list_available_models() +do_training: true # training mode, for testing change to false +trainer: + gpus: 8 # number of GPUs (0 for CPU), or list of the GPUs to use e.g. [0, 1] + num_nodes: 1 + max_epochs: 3 + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + gradient_clip_val: 1.0 + amp_level: O1 # O1/O2 for mixed precision + precision: 16 # Should be set to 16 for O1 and O2 to enable the AMP. + accelerator: ddp + log_every_n_steps: 5 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + +model: + nemo_path: null # filename to save the model and associated artifacts to .nemo file + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null + + language_model: + pretrained_model_name: bert-base-cased + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null + + encoder: + dropout: 0.1 + + dataset: + max_seq_length: 128 # the maximum length BERT supports is 512 + max_num_cat_slot: 6 # maximum number of different categorical slots per service in dataset + max_num_noncat_slot: 12 # maximum number of different non-categorical slots per service in dataset + max_value_per_cat_slot: 12 # maximum number of different categorical slot values per service in dataset + max_num_intent: 4 # maximum number of different intents per service in dataset + task_name: sgd_single_domain # or from [sgd_all, sgd_all_single, sgd_multi_domain, debug_sample] + state_tracker: nemotracker # or baseline + data_dir: ??? + dialogues_example_dir: ??? # cache location to store or load preprocessed data from. To use cache, specify `use_cache` + subsample: false # balances negative and positive training examples for improved performance + use_cache: false # uses a cache to store the processed dataset, you may use it for large datasets for speed up + use_fuzzy_match: true # Whether to use fuzzy string matching when comparing non-categorical slot values. Should be set to False when conducting multiwoz style evaluation. + joint_acc_across_turn: false # Whether to compute joint goal accuracy across turn instead of across service. Should be set to True when conducting multiwoz style evaluation. + + train_ds: + ds_item: "train" + batch_size: 128 + shuffle: true + num_workers: 3 + drop_last: false + pin_memory: false + + validation_ds: + ds_item: ["dev"] # ["dev", "test"] + batch_size: 8 + shuffle: false + num_workers: 3 + drop_last: false + pin_memory: false + + test_ds: + ds_item: ["test"] + batch_size: 8 + shuffle: false + num_workers: 3 + drop_last: false + pin_memory: false + + optim: + name: adamw + lr: 1e-4 + # optimizer arguments + betas: [0.9, 0.999] + weight_decay: 0.01 + + # scheduler setup + sched: + name: PolynomialDecayAnnealing + # Scheduler params + warmup_steps: null + warmup_ratio: 0.02 + last_epoch: -1 + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + +exp_manager: + exp_dir: null # exp_dir for your experiment, if None, defaults to "./nemo_experiments" + name: "SGDQA" # The name of your model + create_tensorboard_logger: True # Whether you want exp_manger to create a tb logger + create_checkpoint_callback: True # Whether you want exp_manager to create a modelcheckpoint callback + resume_if_exists: false + resume_ignore_no_checkpoint: false diff --git a/tts/NeMo/examples/nlp/dialogue_state_tracking/sgd_qa.py b/tts/NeMo/examples/nlp/dialogue_state_tracking/sgd_qa.py new file mode 100644 index 0000000..85dbae1 --- /dev/null +++ b/tts/NeMo/examples/nlp/dialogue_state_tracking/sgd_qa.py @@ -0,0 +1,145 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# Copyright 2019 The Google Research Authors. +# +# 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. + +""" +This script contains an example of how to train and test the NeMo SGD-QA Model (https://arxiv.org/abs/2105.08049). +The SGD-QA model is a fast multi-pass schema-guided state-tracking model, that is trained on the Google schema-guided state tracking dataset (https://arxiv.org/abs/1909.05855). +The model takes dialogue as input and outputs the dialogue state, which includes slot-value pairs. +The model consists of two components: a neural natural language understanding model (NLU), and a rule-based state tracker. +The NLU takes in a dialogue turn and different schema (entity) information options and outputs their match score. The state tracker takes the highest rated entities and composes +the dialogue state across turns. + +***Data format*** +The SGD-QA requires a JSON schema and dialogue files for each dataset split. +In the following we will show an example for a service entry in the schema file. +* service_name +* description +* slots + * name + * description + * is_categorical + * possible values +* intents + * name + * description + * required_slots (not used) + * is_transactional (not used) + * optional_slots (not used) + * result_slots (not used) + + +In the following we will show an example for a dialogue. More information at https://arxiv.org/abs/1909.05855 +* dialogue_id +* services +* turns + * frames + * actions + * act + * slot + * values + * service + * slots + * exclusive_end + * slot + * start + * state + * active_intent + * requeste_slots + * slot_values + * speaker - [USER, SYSTEM] + * utterance + + +***Downloading the dataset*** +# git clone https://github.com/google-research-datasets/dstc8-schema-guided-dialogue.git + +***Setting the configs*** +The model and the PT trainer are defined in a config file that declares multiple important sections. +The most important ones are: + model: All arguments that are related to the Model - language model, SGD-QA encoder and decoder, loss, optimizer, + schedulers, and datasets/data loaders. + trainer: Any argument to be passed to PyTorch Lightning including number of epochs, number of GPUs, + precision level, etc. + +This script uses the `/examples/nlp/dialogue_state_tracking/conf/sgdqa_config.yaml` config file +by default. You may update the config file from the file directly. The other option is to set another config file via command-line arguments by `--config-name=CONFIG_FILE_PATH'. + + +***Model Training*** +# python sgd_qa.py + do_training=True + model.dataset.data_dir= + model.dataset.dialogues_example_dir= + model.validation_ds.ds_item= + trainer.max_epochs= + trainer.gpus=[] + + +***Model Evaluation*** +# python sgd_qa.py + do_training=False + model.test_ds.ds_item= + +To load a pretrained checkpoint from the cloud prior to training (e.g. for fine-tuning) or evaluation you can set cfg.from_pretrained=. You can find all pretrained model names by using +SGDQAModel.list_available_models(). To load a local checkpoint use model.restore_from() + +""" + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.dialogue_state_tracking.sgdqa_model import SGDQAModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="sgdqa_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + if cfg.pretrained_model or (cfg.model.nemo_path and os.path.exists(cfg.model.nemo_path)): + if cfg.pretrained_model: + logging.info(f'Loading pretrained model {cfg.pretrained_model}') + model = SGDQAModel.from_pretrained(cfg.pretrained_model) + else: + logging.info(f'Restoring model from {cfg.model.nemo_path}') + model = SGDQAModel.restore_from(cfg.model.nemo_path) + if cfg.do_training: + model.setup_training_data(train_data_config=cfg.model.train_ds) + model.setup_multiple_validation_data(val_data_config=cfg.model.validation_ds) + else: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + model = SGDQAModel(cfg.model, trainer=trainer) + + if cfg.do_training: + trainer.fit(model) + if cfg.model.nemo_path: + model.save_to(cfg.model.nemo_path) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.ds_item is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + trainer = pl.Trainer(gpus=gpu) + model.setup_multiple_test_data(test_data_config=cfg.model.test_ds) + if model.prepare_test(trainer): + trainer.test(model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/entity_linking/build_index.py b/tts/NeMo/examples/nlp/entity_linking/build_index.py new file mode 100644 index 0000000..eeba5c8 --- /dev/null +++ b/tts/NeMo/examples/nlp/entity_linking/build_index.py @@ -0,0 +1,201 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pickle as pkl +import random +from argparse import ArgumentParser + +import h5py +import numpy as np +import torch +from omegaconf import DictConfig, OmegaConf +from sklearn.decomposition import PCA +from tqdm import tqdm + +from nemo.collections.nlp.models import EntityLinkingModel +from nemo.utils import logging + +try: + import faiss +except ModuleNotFoundError: + logging.warning("Faiss is required for building the index. Please install faiss-gpu") + +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + +def build_index(cfg: DictConfig, model: object): + """ + Builds faiss index from index dataset specified in the config. + + Args: + cfg (DictConfig): Config file specifying index parameters + model (object): Encoder model + """ + + # Get index dataset embeddings + # PCA model exists and index embeddings have already been PCAed, no need to re-extract/PCA them + if cfg.apply_pca and os.path.isfile(cfg.pca.pca_save_name) and os.path.isfile(cfg.pca_embeddings_save_name): + logging.info("Loading reduced dimensionality embeddings") + embeddings = h5py.File(cfg.pca_embeddings_save_name, "r") + embeddings = embeddings[cfg.index_ds.name][:] + + elif os.path.isfile(cfg.embedding_save_name): + logging.info("Loading previously extracted index dataset embeddings") + embeddings = h5py.File(cfg.embedding_save_name, "r") + embeddings = embeddings[cfg.index_ds.name][:] + + else: + logging.info("Encoding index dataset, this may take a while") + index_dataloader = model.setup_dataloader(cfg.index_ds, is_index_data=True) + embeddings, concept_ids = get_index_embeddings(cfg, index_dataloader, model) + + # Create pca model to reduce dimensionality of index dataset and decrease memory footprint + if cfg.apply_pca: + + # Need to train PCA model and apply PCA transformation with newly trained model + if not os.path.isfile(cfg.pca.pca_save_name): + logging.info("Fitting PCA model for embedding dimensionality reduction") + pca_train_set = random.sample(list(embeddings), k=int(len(embeddings) * cfg.pca.sample_fraction)) + pca = PCA(n_components=cfg.pca.output_dim) + pca.fit(pca_train_set) + pkl.dump(pca, open(cfg.pca.pca_save_name, "wb")) + embeddings = reduce_embedding_dim(pca, embeddings, cfg) + + # PCA model already trained, just need to reduce dimensionality of all embeddings + elif not os.path.isfile(cfg.pca_embeddings_save_name): + pca = pkl.load(open(cfg.pca.pca_save_name, "rb")) + embeddings = reduce_embedding_dim(pca, embeddings, cfg) + + # Build faiss index from embeddings + logging.info(f"Training index with embedding dim size {cfg.dims} using {faiss.get_num_gpus()} gpus") + quantizer = faiss.IndexFlatL2(cfg.dims) + index = faiss.IndexIVFFlat(quantizer, cfg.dims, cfg.nlist) + index = faiss.index_cpu_to_all_gpus(index) + index.train(embeddings) + + logging.info("Adding dataset embeddings to index") + for i in tqdm(range(0, embeddings.shape[0], cfg.index_batch_size)): + index.add(embeddings[i : i + cfg.index_batch_size]) + + logging.info("Saving index") + faiss.write_index(faiss.index_gpu_to_cpu(index), cfg.index_save_name) + logging.info("Index built and saved") + + +def reduce_embedding_dim(pca, embeddings, cfg): + """Apply PCA transformation to index dataset embeddings""" + + logging.info("Applying PCA transformation to entire index dataset") + embeddings = np.array(pca.transform(embeddings), dtype=np.float32) + emb_file = h5py.File(cfg.pca_embeddings_save_name, "w") + emb_file.create_dataset(cfg.index_ds.name, data=embeddings) + emb_file.close() + + return embeddings + + +def get_index_embeddings(cfg: DictConfig, dataloader: object, model: object): + """Use entity linking encoder to get embeddings for full index dataset""" + embeddings = [] + concept_ids = [] + + with torch.no_grad(): + for batch in tqdm(dataloader): + input_ids, token_type_ids, input_mask, batch_concept_ids = batch + input_ids = input_ids.to(device) + token_type_ids = token_type_ids.to(device) + input_mask = input_mask.to(device) + batch_embeddings = model.forward( + input_ids=input_ids, token_type_ids=token_type_ids, attention_mask=input_mask + ) + + embeddings.extend(batch_embeddings.detach().cpu().numpy()) + concept_ids.extend(batch_concept_ids.numpy()) + + emb_file = h5py.File(cfg.embedding_save_name, "w") + emb_file.create_dataset(cfg.index_ds.name, data=embeddings) + emb_file.close() + + pkl.dump(concept_ids, open(cfg.concept_id_save_name, "wb")) + + return embeddings, concept_ids + + +def load_model(cfg: DictConfig, restore: bool): + """ + Loads encoder model. + + Args: + cfg: Config file specifying model parameters + restore: Whether to restore model weights trained + by the user. Otherwise will load weights + used before self alignment pretraining. + """ + + if restore: + model = EntityLinkingModel.restore_from(cfg.nemo_path) + else: + cfg.train_ds = None + cfg.validation_ds = None + cfg.test_ds = None + model = EntityLinkingModel(cfg) + + model = model.to(device) + + return model + + +def main(cfg: DictConfig, restore: bool): + """ + Builds new index if one hasn't been built yet. + + Args: + cfg: Config file specifying index parameters + restore: Whether to restore model weights trained + by the user. Otherwise will load weights + used before self alignment pretraining. + """ + + logging.info("Loading entity linking encoder model") + model = load_model(cfg.model, restore) + + if not os.path.isfile(cfg.index.index_save_name) or ( + cfg.apply_pca and not os.path.isfile(cfg.index.pca.pca_save_name) + ): + logging.info("Building index") + build_index(cfg.index, model) + else: + logging.info("Index and pca model (if required) already exists. Skipping build index step.") + + if not os.path.isfile(cfg.index.idx_to_id): + logging.info("Mapping entity index postions to ids") + map_idx_to_ids(cfg.index) + else: + logging.info("Map from concept index to id already exists. Skipping mapping step.") + + +if __name__ == '__main__': + parser = ArgumentParser() + parser.add_argument( + "--restore", action="store_true", help="Whether to restore encoder model weights from nemo path" + ) + parser.add_argument("--project_dir", required=False, type=str, default=".") + parser.add_argument("--cfg", required=False, type=str, default="./conf/umls_medical_entity_linking_config.yaml") + args = parser.parse_args() + + cfg = OmegaConf.load(args.cfg) + cfg.project_dir = args.project_dir + + main(cfg, args.restore) diff --git a/tts/NeMo/examples/nlp/entity_linking/conf/tiny_example_entity_linking_config.yaml b/tts/NeMo/examples/nlp/entity_linking/conf/tiny_example_entity_linking_config.yaml new file mode 100644 index 0000000..36a0273 --- /dev/null +++ b/tts/NeMo/examples/nlp/entity_linking/conf/tiny_example_entity_linking_config.yaml @@ -0,0 +1,90 @@ +project_dir: null +name: SelfAlignmentPretrainingForMedicalEntityLinking +trainer: + gpus: 1 + num_nodes: 1 + max_epochs: 2 + max_steps: null + accumulate_grad_batches: 1 + precision: 16 + amp_level: O1 + accelerator: ddp + gradient_clip_val: 0.0 + log_every_n_steps: 1 + val_check_interval: 2 + checkpoint_callback: false + logger: false +model: + nemo_path: ??? + max_seq_length: 128 + language_model: + pretrained_model_name: bert-base-uncased + config_file: null + config: null + lm_checkpoint: null + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} + vocab_file: null + tokenizer_model: null + do_lower_case: true + loss_params: null + train_ds: + data_file: ??? + max_seq_length: ${model.max_seq_length} + batch_size: 8 + shuffle: true + num_workers: 2 + pin_memory: false + drop_last: false + validation_ds: + data_file: ??? + max_seq_length: ${model.max_seq_length} + batch_size: 8 + shuffle: false + num_workers: 2 + pin_memory: false + drop_last: false + optim: + name: adam + lr: 3.0e-05 + weight_decay: 0.0 + sched: + name: CosineAnnealing + warmup_steps: null + warmup_ratio: 0.1 + min_lr: 0.0 + last_epoch: -1 +index: + dims: 768 + nlist: 2 + top_n: 3 + query_num_factor: 20 + index_save_name: ??? + index_batch_size: 10 + index_ds: + name: tiny_example + data_file: ??? + max_seq_length: ${model.max_seq_length} + batch_size: 100 + shuffle: false + num_workers: 2 + pin_memory: false + drop_last: false + idx_to_id: ${project_dir}/idx_to_id.pkl + id_to_string: ${project_dir}/id_to_string.pkl + concept_id_save_name: ${project_dir}/tiny_example_concept_ids.pkl + embedding_save_name: ${project_dir}/tiny_example_concept_embeddings.hdf5 + pca_embeddings_save_name: null + apply_pca: false + pca: null +exp_manager: + exp_dir: . + name: ${project_dir}/SelfAlignmentPretrainingTinyExample + create_tensorboard_logger: true + create_checkpoint_callback: true +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/nlp/entity_linking/conf/umls_medical_entity_linking_config.yaml b/tts/NeMo/examples/nlp/entity_linking/conf/umls_medical_entity_linking_config.yaml new file mode 100644 index 0000000..5b6709e --- /dev/null +++ b/tts/NeMo/examples/nlp/entity_linking/conf/umls_medical_entity_linking_config.yaml @@ -0,0 +1,95 @@ +project_dir: ??? +name: SelfAlignmentPretrainingForMedicalEntityLinking +trainer: + gpus: 1 + num_nodes: 1 + max_epochs: 2 + max_steps: null + accumulate_grad_batches: 1 + precision: 16 + amp_level: O1 + accelerator: ddp + gradient_clip_val: 0.0 + log_every_n_steps: 1 + val_check_interval: 1000 + checkpoint_callback: false + logger: false +model: + nemo_path: ${project_dir}/sap_bert_umls.nemo + raw_data: ${project_dir}/data/MRCONSO.RRF + max_seq_length: 128 + language_model: + pretrained_model_name: bert-base-uncased + config_file: null + config: null + lm_checkpoint: null + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} + vocab_file: null + tokenizer_model: null + do_lower_case: true + train_ds: + data_file: ${project_dir}/data/umls_train_pairs.tsv + max_seq_length: ${model.max_seq_length} + batch_size: 128 + shuffle: true + num_workers: 2 + pin_memory: false + drop_last: false + validation_ds: + data_file: ${project_dir}/data/umls_validation_pairs.tsv + max_seq_length: ${model.max_seq_length} + batch_size: 128 + shuffle: false + num_workers: 2 + pin_memory: false + drop_last: false + optim: + name: adam + lr: 3.0e-05 + weight_decay: 0.0 + sched: + name: CosineAnnealing + warmup_steps: null + warmup_ratio: 0.1 + min_lr: 0.0 + last_epoch: -1 +index: + dims: 256 + nlist: 300 + top_n: 5 + query_num_factor: 20 + index_save_name: ${project_dir}/medical_entity_linking_index + index_batch_size: 1000 + raw_data: ${model.raw_data} + index_ds: + name: umls + data_file: ${project_dir}/data/umls_index_concepts.tsv + max_seq_length: ${model.max_seq_length} + batch_size: 128 + shuffle: false + num_workers: 2 + pin_memory: false + drop_last: false + idx_to_id: ${project_dir}/data/idx_to_id.pkl + id_to_string: ${project_dir}/data/id_to_string.pkl + concept_id_save_name: ${project_dir}/data/concept_ids.pkl + embedding_save_name: ${project_dir}/data/medical_concept_embeddings.hdf5 + pca_embeddings_save_name: ${project_dir}/data/medical_concept_reduced_${index.dims}dim_embeddings.hdf5 + apply_pca: true + pca: + input_dim: 756 + output_dim: ${index.dims} + sample_fraction: 0.5 + pca_save_name: ${project_dir}/${index.pca.input_dim}_to_${index.pca.output_dim}_pca_model.pkl +exp_manager: + exp_dir: ${project_dir}/medical_entity_linking_experiments + name: sap_bert_umls + create_tensorboard_logger: true + create_checkpoint_callback: true +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/nlp/entity_linking/data/umls_dataset_processing.py b/tts/NeMo/examples/nlp/entity_linking/data/umls_dataset_processing.py new file mode 100644 index 0000000..03a17da --- /dev/null +++ b/tts/NeMo/examples/nlp/entity_linking/data/umls_dataset_processing.py @@ -0,0 +1,189 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +import pickle as pkl +import random +from argparse import ArgumentParser + +import pandas as pd +from omegaconf import OmegaConf +from tqdm import tqdm + +# Info on these headers can be found here on the UMLS website https://www.ncbi.nlm.nih.gov/books/NBK9685/ +# section 3.3.4 Table 1 +HEADERS = [ + 'CUI', + 'LAT', + 'TS', + 'LUI', + 'STT', + 'SUI', + 'ISPREF', + 'AUI', + 'SAUI', + 'SCUI', + 'SDUI', + 'SAB', + 'TTY', + 'CODE', + 'STR', + 'SRL', + 'SUPPRESS', + 'CVF', +] + + +def process_umls_training_dataset(data_path, train_save_name, val_save_name, max_pairs, train_split, headers): + """ + Generates and saves UMLS self alignment pretraining train and validation data. Takes the raw .RRF UMLS + data file and creates different pair combinations for entities with the same CUI. Each row in the output + will be formatted as 'CUI EntitySynonym1 EntitySynonym2' with each item in a row separated by tabs. + Saves two .tsv output files, one for the train split and one for the validation split. + Only data marked as English is added to the train and val splits. + + Arguments: + data_path (str): path to MRCONSO.RRF UMLS data file + train_save_name (str): path to where training data will be saved + val_save_name (str): path to where validation data will be saved + max_pairs (int): max number of pairs for any one CUI added to the train + or validation splits + train_split (float): precentage of raw data to be added to train set split + headers (list): column lables within MRCONSO.RRF + """ + + print("Loading training data file...") + df = pd.read_table(data_path, names=headers, index_col=False, delimiter='|') + train_file = open(train_save_name, 'w') + val_file = open(val_save_name, 'w') + + cui = df["CUI"].iloc[0] + names = [] + random.seed(2021) + + for idx in tqdm(range(len(df))): + # Address incorrectly formatted data + if type(df["STR"].iloc[idx]) != str or "|" in df["STR"].iloc[idx]: + continue + + # Collect all english concept strings matching the current CUI + if df["CUI"].iloc[idx] == cui and df["LAT"].iloc[idx] == "ENG": + concept_string = df["STR"].iloc[idx] + names.append(concept_string) + + else: + # Pair off concept synonyms to make training and val sets + pairs = list(itertools.combinations(names, 2)) + + if len(pairs) == 0: + # Not enough concepts gathered to make a pair + cui = df["CUI"].iloc[idx] + names = [df["STR"].iloc[idx]] + continue + + # Removing leading C to convert label string to int + cui = int(cui[1:]) + random.shuffle(pairs) + + # Keep up to max pairs number pairs for any one concept + for pair in pairs[:max_pairs]: + + # Want concepts in train and val splits to be randomly selected and mutually exclusive + add_to_train = random.random() + + if add_to_train <= train_split: + train_file.write(f'{cui}\t{pair[0]}\t{pair[1]}\n') + else: + val_file.write(f'{cui}\t{pair[0]}\t{pair[1]}\n') + + # Switch to next concept + cui = df["CUI"].iloc[idx] + names = [df["STR"].iloc[idx]] + + train_file.close() + val_file.close() + print("Finished making training and validation data") + + +def process_umls_index_dataset(data_path, data_savename, id2string_savename, headers): + """ + Generates data file needed to build a UMLS index and a hash table mapping each + CUI to one canonical concept string. Takes the raw .RRF data file and saves + a .tsv indec concept file as well as the a .pkl file of cui to concept string + mappings. Only data marked as English is added to the index data file. + + Arguments: + data_path (str): path to MRCONSO.RRF UMLS data file + data_savename (str): path to where .tsv index data will be saved + id2string_savename (str): path to where .pkl cui to string mapping will + be saved + headers (list): column lables within MRCONSO.RRF + """ + + print("Loading index data file...") + df = pd.read_table(data_path, names=headers, index_col=False, delimiter='|') + id2string = {} + + with open(data_savename, "w") as outfile: + for idx, row in tqdm(df.iterrows(), total=df.shape[0]): + # Address incorrectly formatted data + if type(row["STR"]) != str or "|" in row["STR"]: + continue + + cui = row["CUI"] + sent = row["STR"] + + # Removing leading C to convert label string to int + cui = int(cui[1:]) + + # Only keeping english concepts + if row["LAT"] == "ENG": + outfile.write(f'{cui}\t{sent}\n') + + # Matching each cui to one canonical string represention + if cui not in id2string and ":" not in sent: + id2string[cui] = sent + + outfile.close() + pkl.dump(id2string, open(id2string_savename, "wb")) + print("Finished saving index data and id to concept mapping") + + +if __name__ == '__main__': + parser = ArgumentParser() + parser.add_argument("--index", action="store_true", help="Whether to process data for building an index") + parser.add_argument("--project_dir", required=False, type=str, default=".") + parser.add_argument("--cfg", required=False, type=str, default="conf/umls_medical_entity_linking_config.yaml") + parser.add_argument( + "--max_pairs", required=False, type=int, default=50, help="Max number of train pairs for a single concepts" + ) + parser.add_argument( + "--train_split", required=False, type=float, default=0.99, help="Precentage of data to add to train set" + ) + + args = parser.parse_args() + cfg = OmegaConf.load(args.cfg) + cfg.project_dir = args.project_dir + + if args.index: + process_umls_index_dataset(cfg.index.raw_data, cfg.index.index_ds.data_file, cfg.index.id_to_string, HEADERS) + else: + process_umls_training_dataset( + cfg.model.raw_data, + cfg.model.train_ds.data_file, + cfg.model.validation_ds.data_file, + args.max_pairs, + args.train_split, + HEADERS, + ) diff --git a/tts/NeMo/examples/nlp/entity_linking/query_index.py b/tts/NeMo/examples/nlp/entity_linking/query_index.py new file mode 100644 index 0000000..6cb51a7 --- /dev/null +++ b/tts/NeMo/examples/nlp/entity_linking/query_index.py @@ -0,0 +1,166 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pickle as pkl +from argparse import ArgumentParser +from collections import OrderedDict +from typing import Dict + +import numpy as np +import torch +from build_index import load_model +from omegaconf import DictConfig, OmegaConf + +from nemo.utils import logging + +try: + import faiss +except ModuleNotFoundError: + logging.warning("Faiss is required for building the index. Please install faiss-gpu") + +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + +def get_query_embedding(query, model): + """Use entity linking encoder to get embedding for index query""" + model_input = model.tokenizer( + query, + add_special_tokens=True, + padding=True, + truncation=True, + max_length=512, + return_token_type_ids=True, + return_attention_mask=True, + ) + + query_emb = model.forward( + input_ids=torch.LongTensor([model_input["input_ids"]]).to(device), + token_type_ids=torch.LongTensor([model_input["token_type_ids"]]).to(device), + attention_mask=torch.LongTensor([model_input["attention_mask"]]).to(device), + ) + + return query_emb + + +def query_index( + query: str, cfg: DictConfig, model: object, index: object, pca: object, idx2id: dict, id2string: dict, +) -> Dict: + + """ + Query the nearest neighbor index of entities to find the + concepts in the index dataset that are most similar to the + query. + + Args: + query (str): entity to look up in the index + cfg (DictConfig): config object to specifiy query parameters + model (EntityLinkingModel): entity linking encoder model + index (object): faiss index + pca (object): sklearn pca transformation to be applied to queries + idx2id (dict): dictionary mapping unique concept dataset index to + its CUI + id2string (dict): dictionary mapping each unqiue CUI to a + representative english description of + the concept + Returns: + A dictionary with the concept ids of the index's most similar + entities as the keys and a tuple containing the string + representation of that concept and its cosine similarity to + the query as the values. + """ + query_emb = get_query_embedding(query, model).detach().cpu().numpy() + + if cfg.apply_pca: + query_emb = pca.transform(query_emb) + + dist, neighbors = index.search(query_emb.astype(np.float32), cfg.query_num_factor * cfg.top_n) + dist, neighbors = dist[0], neighbors[0] + unique_ids = OrderedDict() + neighbor_idx = 0 + + # Many of nearest neighbors could map to the same concept id, their idx is their unique identifier + while len(unique_ids) < cfg.top_n and neighbor_idx < len(neighbors): + concept_id_idx = neighbors[neighbor_idx] + concept_id = idx2id[concept_id_idx] + + # Only want one instance of each unique concept + if concept_id not in unique_ids: + concept = id2string[concept_id] + unique_ids[concept_id] = (concept, 1 - dist[neighbor_idx]) + + neighbor_idx += 1 + + unique_ids = dict(unique_ids) + + return unique_ids + + +def main(cfg: DictConfig, restore: bool): + """ + Loads faiss index and allows commandline queries + to the index. Builds new index if one hasn't been built yet. + + Args: + cfg: Config file specifying index parameters + restore: Whether to restore model weights trained + by the user. Otherwise will load weights + used before self alignment pretraining. + """ + + if not os.path.isfile(cfg.index.index_save_name) or ( + cfg.apply_pca and not os.path.isfile(cfg.index.pca.pca_save_name) or not os.path.isfile(cfg.index.idx_to_id) + ): + logging.warning("Either no index and/or no mapping from entity idx to ids exists. Please run `build_index.py`") + return + + logging.info("Loading entity linking encoder model") + model = load_model(cfg.model, restore) + + logging.info("Loading index and associated files") + index = faiss.read_index(cfg.index.index_save_name) + idx2id = pkl.load(open(cfg.index.idx_to_id, "rb")) + id2string = pkl.load(open(cfg.index.id_to_string, "rb")) # Should be created during dataset prep + + if cfg.index.apply_pca: + pca = pkl.load(open(cfg.index.pca.pca_save_name, "rb")) + + while True: + query = input("enter index query: ") + output = query_index(query, cfg.top_n, cfg.index, model, index, pca, idx2id, id2string) + + if query == "exit": + break + + for concept_id in output: + concept_details = output[concept_id] + concept_id = "C" + str(concept_id).zfill(7) + print(concept_id, concept_details) + + print("----------------\n") + + +if __name__ == '__main__': + parser = ArgumentParser() + parser.add_argument( + "--restore", action="store_true", help="Whether to restore encoder model weights from nemo path" + ) + parser.add_argument("--project_dir", required=False, type=str, default=".") + parser.add_argument("--cfg", required=False, type=str, default="./conf/umls_medical_entity_linking_config.yaml") + args = parser.parse_args() + + cfg = OmegaConf.load(args.cfg) + cfg.project_dir = args.project_dir + + main(cfg, args.restore) diff --git a/tts/NeMo/examples/nlp/entity_linking/self_alignment_pretraining.py b/tts/NeMo/examples/nlp/entity_linking/self_alignment_pretraining.py new file mode 100644 index 0000000..0d0e0d3 --- /dev/null +++ b/tts/NeMo/examples/nlp/entity_linking/self_alignment_pretraining.py @@ -0,0 +1,49 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + + +# Please see tutorial at Nemo/tutorials/nlp/Entity_Linking_Medical.ipynb for +# more information on entity linking and self alignment pretraining. + +from omegaconf import DictConfig, OmegaConf +from pytorch_lightning import Trainer + +from nemo.collections.nlp.models import EntityLinkingModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="umls_medical_entity_linking_config.yaml") +def main(cfg: DictConfig) -> None: + logging.info(f"\nConfig Params:\n{OmegaConf.to_yaml(cfg)}") + trainer = Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + logging.info(f"Loading weights from pretrained model {cfg.model.language_model.pretrained_model_name}") + model = EntityLinkingModel(cfg=cfg.model, trainer=trainer) + logging.info("===========================================================================================") + logging.info('Starting training...') + trainer.fit(model) + logging.info('Training finished!') + logging.info("===========================================================================================") + + if cfg.model.nemo_path: + # '.nemo' file contains the last checkpoint and the params to initialize the model + model.save_to(cfg.model.nemo_path) + logging.info(f'Model is saved into `.nemo` file: {cfg.model.nemo_path}') + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark.py b/tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark.py new file mode 100644 index 0000000..3242986 --- /dev/null +++ b/tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark.py @@ -0,0 +1,73 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +## Tasks +This script works with all GLUE Benchmark tasks, more details about the GLUE Benchmark could be found at +https://gluebenchmark.com/ + +More details on how to use this script could be found in tutorials/nlp/GLUE_Benchmark.ipynb + +## Model Training + +To train GLUEModel with the default config file, run: + python glue_benchmark.py \ + model.dataset.data_dir= \ + model.task_name=TASK_NAME \ + trainer.max_epochs= \ + trainer.gpus="[] + +Supported task names: +["cola", "sst-2", "mrpc", "sts-b", "qqp", "mnli", "qnli", "rte", "wnli"] +Note, MNLI task includes both matched and mismatched dev sets +""" + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import GLUEModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_name="glue_benchmark_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_manager_cfg = cfg.get("exp_manager", None) + + if exp_manager_cfg: + exp_manager_cfg.name = cfg.model.task_name + logging.info(f'Setting task_name to {exp_manager_cfg.name} in exp_manager') + exp_manager(trainer, exp_manager_cfg) + + if cfg.model.nemo_path and os.path.exists(cfg.model.nemo_path): + model = GLUEModel.restore_from(cfg.model.nemo_path) + logging.info(f'Restoring model from {cfg.model.nemo_path}') + model.update_data_dir(data_dir=cfg.model.dataset.data_dir) + model.setup_training_data() + model.setup_multiple_validation_data() + trainer.fit(model) + else: + model = GLUEModel(cfg.model, trainer=trainer) + trainer.fit(model) + if cfg.model.nemo_path: + model.save_to(cfg.model.nemo_path) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark_config.yaml b/tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark_config.yaml new file mode 100644 index 0000000..23b5522 --- /dev/null +++ b/tts/NeMo/examples/nlp/glue_benchmark/glue_benchmark_config.yaml @@ -0,0 +1,82 @@ +# GLUE Benchmark with pre-trained BERT models +supported_tasks: &supported_tasks ['cola', 'sst-2', 'mrpc', 'sts-b', 'qqp', 'mnli', 'qnli', 'rte', 'wnli'] + +trainer: + gpus: 1 # the number of gpus, 0 for CPU + num_nodes: 1 + max_epochs: 3 + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + amp_level: O0 # O1/O2 for mixed precision + precision: 16 + accelerator: ddp + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + +model: + task_name: &task_name mrpc # choose from: ["cola", "sst-2", "mrpc", "sts-b", "qqp", "mnli", "qnli", "rte", "wnli"] GLUE task name, MNLI includes both matched and mismatched dev sets + supported_tasks: *supported_tasks + output_dir: null # dir to write write predictions + nemo_path: null # filename to save the model and associated artifacts to .nemo file + dataset: + data_dir: ??? # /path/to/data + max_seq_length: 128 + use_cache: true + + # shared across dataloaders: + num_workers: 2 + pin_memory: false + drop_last: false + + train_ds: + ds_item: 'train.tsv' + shuffle: true + num_samples: -1 + batch_size: 32 + + validation_ds: + ds_item: 'dev.tsv' # for MNLI 'dev_matched.tsv' and 'dev_mismatched.tsv' will de used + shuffle: false + num_samples: -1 + batch_size: 32 + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null # only necessary for adding transformer/bert-specific special tokens to tokenizer if the tokenizer does not already have these inherently. + + language_model: + pretrained_model_name: bert-base-uncased + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null + + optim: + name: adam + lr: 5e-5 + weight_decay: 0.00 + + sched: + name: WarmupAnnealing + # Scheduler params + warmup_steps: null + warmup_ratio: 0.1 + last_epoch: -1 + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + +exp_manager: + exp_dir: null # exp_dir for your experiment, if None, defaults to "./NeMo_experiments" + name: *task_name # The name of your model + create_tensorboard_logger: True # Whether you want exp_manger to create a tb logger + create_checkpoint_callback: True # Whether you want exp_manager to create a modelcheckpoint callback + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/nlp/information_retrieval/bert_dpr.py b/tts/NeMo/examples/nlp/information_retrieval/bert_dpr.py new file mode 100644 index 0000000..2d9cd96 --- /dev/null +++ b/tts/NeMo/examples/nlp/information_retrieval/bert_dpr.py @@ -0,0 +1,35 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import BertDPRModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="bert_ir_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + bert_dpr_model = BertDPRModel(cfg.model, trainer=trainer) + trainer.fit(bert_dpr_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/information_retrieval/bert_joint_ir.py b/tts/NeMo/examples/nlp/information_retrieval/bert_joint_ir.py new file mode 100644 index 0000000..1bb164e --- /dev/null +++ b/tts/NeMo/examples/nlp/information_retrieval/bert_joint_ir.py @@ -0,0 +1,35 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import BertJointIRModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="bert_ir_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + bert_joint_ir_model = BertJointIRModel(cfg.model, trainer=trainer) + trainer.fit(bert_joint_ir_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/information_retrieval/conf/bert_ir_config.yaml b/tts/NeMo/examples/nlp/information_retrieval/conf/bert_ir_config.yaml new file mode 100644 index 0000000..e4fe72b --- /dev/null +++ b/tts/NeMo/examples/nlp/information_retrieval/conf/bert_ir_config.yaml @@ -0,0 +1,99 @@ +# Fine-tuning BERT model for information retrieval +name: &name BertIR +trainer: + gpus: 1 # the number of gpus, 0 for CPU, or list with gpu indices + num_nodes: 1 + max_epochs: 2 # the number of training epochs + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + precision: 16 # 16 to use AMP + amp_level: O1 # O1 or O2 if using AMP + accelerator: ddp + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 0.05 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + checkpoint_callback: false # provided by exp_manager + logger: false # provided by exp_manager + +model: + nemo_path: null # exported .nemo path + + language_model: + pretrained_model_name: bert-base-uncased + sim_score_dropout: 0.1 + lm_checkpoint: null + config: + attention_probs_dropout_prob: 0.1 + hidden_act: gelu + hidden_dropout_prob: 0.1 + hidden_size: 768 + initializer_range: 0.02 + intermediate_size: 3072 + max_position_embeddings: 512 + num_attention_heads: 12 + num_hidden_layers: 12 + type_vocab_size: 2 + vocab_size: 30522 + config_file: null # json file, precedence over config + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # tokenizer that inherits from TokenizerSpec + vocab_file: null # path to vocab file + tokenizer_model: null # tokenizer model for sentencepiece + special_tokens: null + + train_ds: + passages: null # path to file with passages and their indices + queries: null # path to file with training queries and their indices + query_to_passages: null + # path to file with training examples which have the form of + # (query_id, relevant_passage_id, irrelevant_passage_1_id, ..., irrelevant_passage_n_id) + num_negatives: 10 + batch_size: 6 + psg_cache_format: npz + shuffle: true + num_samples: -1 # number of samples to be considered, -1 means all the dataset + num_workers: 1 + drop_last: false + pin_memory: false + + validation_ds: + passages: null # path to file with passages and their indices + queries: null # path to file with validation queries and their indices + query_to_passages: null # path to file with passages to re-rank for each validation query + num_negatives: 10 + batch_size: 6 + psg_cache_format: pkl + shuffle: false + num_samples: -1 # number of samples to be considered, -1 means all the dataset + num_workers: 1 + drop_last: false + pin_memory: false + + optim: + name: adam + lr: 1e-5 + betas: [0.9, 0.999] + weight_decay: 0 + + sched: + name: WarmupAnnealing + warmup_steps: null + warmup_ratio: 0.05 + last_epoch: -1 + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + +exp_manager: + exp_dir: null # where to store logs and checkpoints + name: *name # name of experiment + create_tensorboard_logger: True + create_checkpoint_callback: True + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/nlp/information_retrieval/construct_random_negatives.py b/tts/NeMo/examples/nlp/information_retrieval/construct_random_negatives.py new file mode 100644 index 0000000..36da96f --- /dev/null +++ b/tts/NeMo/examples/nlp/information_retrieval/construct_random_negatives.py @@ -0,0 +1,49 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse + +import numpy as np +import pandas as pd + + +def construct_negatives(input_file, output_file, num_passages, num_negatives): + qrels = pd.read_csv(input_file, delimiter="\t", header=None) + with open(output_file, "w") as f: + for i in range(len(qrels)): + query_id, rel_passage_id = qrels[0][i], qrels[2][i] + negatives = np.random.randint(num_passages, size=num_negatives) + output_ids = [query_id, rel_passage_id] + negatives.tolist() + output_str = [str(id_) for id_ in output_ids] + print("\t".join(output_str), file=f) + + +def main(): + parser = argparse.ArgumentParser(description="Negative passages construction") + parser.add_argument("--data", type=str, default="msmarco_dataset", help="path to folder with data") + parser.add_argument("--num_passages", type=int, default=8841823, help="total number of passages") + parser.add_argument("--num_negatives", type=int, default=10, help="number of negatives per positive") + args = parser.parse_args() + + for mode in ["train", "dev"]: + construct_negatives( + input_file=f"{args.data}/qrels.{mode}.tsv", + output_file=f"{args.data}/query2passages.{mode}.tsv", + num_passages=args.num_passages, + num_negatives=args.num_negatives, + ) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/information_retrieval/get_msmarco.sh b/tts/NeMo/examples/nlp/information_retrieval/get_msmarco.sh new file mode 100644 index 0000000..0bf286c --- /dev/null +++ b/tts/NeMo/examples/nlp/information_retrieval/get_msmarco.sh @@ -0,0 +1,22 @@ +echo "=== Acquiring MSMARCO dataset ===" +echo "---" + +mkdir -p msmarco_dataset +cd msmarco_dataset + +echo "- Downloading passages" +wget --quiet --continue https://msmarco.blob.core.windows.net/msmarcoranking/collection.tar.gz +tar -xzvf collection.tar.gz +rm collection.tar.gz + +echo "- Downloading queries" +wget --quiet --continue https://msmarco.blob.core.windows.net/msmarcoranking/queries.tar.gz +tar -xzvf queries.tar.gz +rm queries.tar.gz +rm queries.eval.tsv + +echo "- Downloading relevance labels" +wget --quiet --continue https://msmarco.blob.core.windows.net/msmarcoranking/qrels.train.tsv +wget --quiet --continue https://msmarco.blob.core.windows.net/msmarcoranking/qrels.dev.tsv + +echo "---" \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/intent_slot_classification/conf/intent_slot_classification_config.yaml b/tts/NeMo/examples/nlp/intent_slot_classification/conf/intent_slot_classification_config.yaml new file mode 100644 index 0000000..502458c --- /dev/null +++ b/tts/NeMo/examples/nlp/intent_slot_classification/conf/intent_slot_classification_config.yaml @@ -0,0 +1,111 @@ +# Intent and Slot classification with pretrained BERT models + +trainer: + gpus: 1 # the number of gpus, 0 for CPU + num_nodes: 1 + max_epochs: 50 + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 amp_level to enable the AMP. + accelerator: ddp + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + +model: + nemo_path: null # filename to save the model and associated artifacts to .nemo file + data_dir: ??? # /path/to/data + class_labels: + intent_labels_file: intent_labels.csv + slot_labels_file: slot_labels.csv + class_balancing: null # or weighted_loss + intent_loss_weight: 0.6 # relation of intent to slot loss in total loss (between 0 to 1) + pad_label: -1 # if -1 not slot token will be used + ignore_extra_tokens: false + ignore_start_end: true # do not use first and last token for slot training + + train_ds: + prefix: train + batch_size: 32 + shuffle: true + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + validation_ds: + prefix: test + batch_size: 32 + shuffle: false + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + test_ds: + prefix: test + batch_size: 32 + shuffle: false + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null + + language_model: + max_seq_length: 50 + pretrained_model_name: bert-base-uncased + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null + + head: + num_output_layers: 2 + fc_dropout: 0.1 + + optim: + name: adam + lr: 2e-5 + args: + name: auto + params: + weight_decay: 0.01 + + sched: + name: WarmupAnnealing + iters_per_batch: null # computed at runtime + max_steps: null # computed at runtime or explicitly set here + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + + # scheduler config override + args: + name: auto + params: + warmup_steps: null + warmup_ratio: 0.1 + last_epoch: -1 + +exp_manager: + exp_dir: null # exp_dir for your experiment, if None, defaults to "./nemo_experiments" + name: "IntentSlot" # The name of your model + create_tensorboard_logger: true # Whether you want exp_manger to create a tb logger + create_checkpoint_callback: true # Whether you want exp_manager to create a modelcheckpoint callback + +hydra: + run: + dir: . + job_logging: + root: + handlers: null \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/intent_slot_classification/data/assistant_utils.py b/tts/NeMo/examples/nlp/intent_slot_classification/data/assistant_utils.py new file mode 100644 index 0000000..f47094e --- /dev/null +++ b/tts/NeMo/examples/nlp/intent_slot_classification/data/assistant_utils.py @@ -0,0 +1,151 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import shutil + +from nemo.collections.nlp.data.data_utils.data_preprocessing import DATABASE_EXISTS_TMP, if_exist, write_files +from nemo.utils import logging + + +def copy_input_files(infold): + """ Put training files in convenient place for conversion to our format. """ + our_infold = infold + "/dataset" + + if os.path.exists(our_infold + "/trainset") and os.path.exists(our_infold + "/testset"): + logging.info("Input folders exists") + return + + logging.info(f"Copying files to input folder: {our_infold}") + os.makedirs(infold, exist_ok=True) + + old_infold = ( + infold + '/CrossValidation/autoGeneFromRealAnno/autoGene_2018_03_22-13_01_25_169/CrossValidation/KFold_1' + ) + if not os.path.exists(our_infold + "/trainset"): + shutil.copytree(old_infold + '/trainset', our_infold + '/trainset') + + if not os.path.exists(our_infold + "/testset"): + shutil.copytree(old_infold + '/testset/csv', our_infold + '/testset') + + +def get_intents(infold): + """ Get list of intents from file names. """ + intents = [f[:-4] for f in os.listdir(infold)] + intents.sort() + print(f'Found {len(intents)} intents') + return intents + + +def get_intent_queries(infold, intent_names, mode): + """ Get list of queries with their corresponding intent number. """ + intent_queries = ['sentence\tlabel\n'] + + for index, intent in enumerate(intent_names): + queries = open(f'{infold}/{mode}set/{intent}.csv', 'r').readlines() + for query in queries[1:]: + phrases = query.split(";") + intent_query = phrases[4][1:-1] + "\t" + str(index) + intent_queries.append(intent_query) + + return intent_queries + + +def get_slots(infold, modes): + """ + Find a lost of unique slot types in training and testing data. + We use a single slot type name both for starting and continuation tokes (not using B-, I- notation). + """ + slots = set() + + for mode in modes: + path = f'{infold}/{mode}set' + for filename in os.listdir(path): + lines = open(f'{path}/{filename}', 'r').readlines() + for line in lines[1:]: + query = line.split(";")[3] + slot_phrases = re.findall('\[.*?\]', query) + for slot_phrase in slot_phrases: + slot = slot_phrase.split(" : ")[0][1:] + slots.add(slot) + + slots = sorted(slots) + slots.append("O") + print(f'Found {len(slots)} slot types') + return slots + + +def get_slot_queries(infold, slot_dict, mode, intent_names): + """ Convert each word in a query to corresponding slot number. """ + slot_queries = [] + outside_slot = len(slot_dict) - 1 + + # keep the same order of files/queries as for intents + for intent in intent_names: + lines = open(f'{infold}/{mode}set/{intent}.csv', 'r').readlines() + for line in lines[1:]: + slot_query = "" + query = line.split(";")[3] + words = query.split(" ") + current_slot = outside_slot + for word in words: + if word[0] == "[": + current_slot = slot_dict[word[1:]] + elif word[0] == ":": + continue + else: + slot_query += str(current_slot) + " " + if word[-1] == ']': + current_slot = outside_slot + + slot_queries.append(slot_query.strip()) + + return slot_queries + + +def process_assistant(infold, outfold, modes=['train', 'test']): + """ + https://github.com/xliuhw/NLU-Evaluation-Data - this dataset includes + about 25 thousand examples with 66 various multi-domain intents and 57 entity types. + """ + if if_exist(outfold, [f'{mode}_slots.tsv' for mode in modes]): + logging.info(DATABASE_EXISTS_TMP.format('robot', outfold)) + return outfold + + logging.info(f'Processing assistant commands dataset and store at {outfold}') + os.makedirs(outfold, exist_ok=True) + + # copy train/test files to the convenient directory to work with + copy_input_files(infold) + infold += "/dataset" + + # get list of intents from train folder (test folder supposed to be the same) + intent_names = get_intents(infold + "/trainset") + write_files(intent_names, f'{outfold}/dict.intents.csv') + + # get all train and test queries with their intent + for mode in modes: + intent_queries = get_intent_queries(infold, intent_names, mode) + write_files(intent_queries, f'{outfold}/{mode}.tsv') + + # get list of all unique slots in training and testing files + slot_types = get_slots(infold, modes) + write_files(slot_types, f'{outfold}/dict.slots.csv') + + # create files of slot queries + slot_dict = {k: v for v, k in enumerate(slot_types)} + for mode in modes: + slot_queries = get_slot_queries(infold, slot_dict, mode, intent_names) + write_files(slot_queries, f'{outfold}/{mode}_slots.tsv') diff --git a/tts/NeMo/examples/nlp/intent_slot_classification/data/import_datasets.py b/tts/NeMo/examples/nlp/intent_slot_classification/data/import_datasets.py new file mode 100755 index 0000000..9c58ded --- /dev/null +++ b/tts/NeMo/examples/nlp/intent_slot_classification/data/import_datasets.py @@ -0,0 +1,265 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os +import shutil +from os.path import exists + +from assistant_utils import process_assistant + +from nemo.collections.nlp.data.data_utils.data_preprocessing import ( + DATABASE_EXISTS_TMP, + MODE_EXISTS_TMP, + create_dataset, + get_dataset, + get_vocab, + if_exist, +) +from nemo.utils import logging + + +def ids2text(ids, vocab): + return ' '.join([vocab[int(id_)] for id_ in ids]) + + +def process_atis(infold, outfold, modes=['train', 'test'], do_lower_case=False): + """ MSFT's dataset, processed by Kaggle + https://www.kaggle.com/siddhadev/atis-dataset-from-ms-cntk + """ + vocab = get_vocab(f'{infold}/atis.dict.vocab.csv') + + if if_exist(outfold, [f'{mode}.tsv' for mode in modes]): + logging.info(DATABASE_EXISTS_TMP.format('ATIS', outfold)) + return outfold + logging.info(f'Processing ATIS dataset and storing at {outfold}.') + + os.makedirs(outfold, exist_ok=True) + + outfiles = {} + for mode in modes: + outfiles[mode] = open(os.path.join(outfold, mode + '.tsv'), 'w') + outfiles[mode].write('sentence\tlabel\n') + outfiles[mode + '_slots'] = open(f'{outfold}/{mode}_slots.tsv', 'w') + + queries = open(f'{infold}/atis.{mode}.query.csv', 'r').readlines() + intents = open(f'{infold}/atis.{mode}.intent.csv', 'r').readlines() + slots = open(f'{infold}/atis.{mode}.slots.csv', 'r').readlines() + + for i, query in enumerate(queries): + sentence = ids2text(query.strip().split()[1:-1], vocab) + if do_lower_case: + sentence = sentence.lower() + outfiles[mode].write(f'{sentence}\t{intents[i].strip()}\n') + slot = ' '.join(slots[i].strip().split()[1:-1]) + outfiles[mode + '_slots'].write(slot + '\n') + + shutil.copyfile(f'{infold}/atis.dict.intent.csv', f'{outfold}/dict.intents.csv') + shutil.copyfile(f'{infold}/atis.dict.slots.csv', f'{outfold}/dict.slots.csv') + for mode in modes: + outfiles[mode].close() + + +def process_snips(infold, outfold, do_lower_case, modes=['train', 'test'], dev_split=0.1): + if not os.path.exists(infold): + link = 'https://github.com/snipsco/spoken-language-understanding-research-datasets' + raise ValueError(f'Data not found at {infold}. ' f'You may request to download the SNIPS dataset from {link}.') + + exist = True + for dataset in ['light', 'speak', 'all']: + if if_exist(f'{outfold}/{dataset}', [f'{mode}.tsv' for mode in modes]): + logging.info(DATABASE_EXISTS_TMP.format('SNIPS-' + dataset, outfold)) + else: + exist = False + if exist: + return outfold + + logging.info(f'Processing SNIPS dataset and storing at folders "speak", "light" and "all" under {outfold}.') + logging.info( + f'Processing and importing "smart-speaker-en-close-field" -> "speak" and "smart-speaker-en-close-field" -> "light".' + ) + + os.makedirs(outfold, exist_ok=True) + + speak_dir = 'smart-speaker-en-close-field' + light_dir = 'smart-lights-en-close-field' + + light_files = [f'{infold}/{light_dir}/dataset.json'] + speak_files = [f'{infold}/{speak_dir}/training_dataset.json'] + speak_files.append(f'{infold}/{speak_dir}/test_dataset.json') + + light_train, light_dev, light_slots, light_intents = get_dataset(light_files, dev_split) + speak_train, speak_dev, speak_slots, speak_intents = get_dataset(speak_files) + + create_dataset(light_train, light_dev, light_slots, light_intents, do_lower_case, f'{outfold}/light') + create_dataset(speak_train, speak_dev, speak_slots, speak_intents, do_lower_case, f'{outfold}/speak') + create_dataset( + light_train + speak_train, + light_dev + speak_dev, + light_slots | speak_slots, + light_intents | speak_intents, + do_lower_case, + f'{outfold}/all', + ) + + +def process_jarvis_datasets( + infold, outfold, modes=['train', 'test', 'dev'], do_lower_case=False, ignore_prev_intent=False +): + """ process and convert Jarvis datasets into NeMo's BIO format + """ + dataset_name = "jarvis" + if if_exist(outfold, ['dict.intents.csv', 'dict.slots.csv']): + logging.info(DATABASE_EXISTS_TMP.format(dataset_name, outfold)) + return outfold + + logging.info(f'Processing {dataset_name} dataset and storing at {outfold}') + + os.makedirs(outfold, exist_ok=True) + + outfiles = {} + intents_list = {} + slots_list = {} + slots_list_all = {} + + outfiles['dict_intents'] = open(f'{outfold}/dict.intents.csv', 'w') + outfiles['dict_slots'] = open(f'{outfold}/dict.slots.csv', 'w') + + outfiles['dict_slots'].write('O\n') + slots_list["O"] = 0 + slots_list_all["O"] = 0 + + for mode in modes: + if if_exist(outfold, [f'{mode}.tsv']): + logging.info(MODE_EXISTS_TMP.format(mode, dataset_name, outfold, mode)) + continue + + if not if_exist(infold, [f'{mode}.tsv']): + logging.info(f'{mode} mode of {dataset_name}' f' is skipped as it was not found.') + continue + + outfiles[mode] = open(os.path.join(outfold, mode + '.tsv'), 'w') + outfiles[mode].write('sentence\tlabel\n') + outfiles[mode + '_slots'] = open(f'{outfold}/{mode}_slots.tsv', 'w') + + queries = open(f'{infold}/{mode}.tsv', 'r').readlines() + + for i, query in enumerate(queries): + line_splits = query.strip().split("\t") + if len(line_splits) == 3: + intent_str, slot_tags_str, sentence = line_splits + else: + intent_str, sentence = line_splits + slot_tags_str = "" + + if intent_str not in intents_list: + intents_list[intent_str] = len(intents_list) + outfiles['dict_intents'].write(f'{intent_str}\n') + + if ignore_prev_intent: + start_token = 2 + else: + start_token = 1 + + if do_lower_case: + sentence = sentence.lower() + sentence_cld = " ".join(sentence.strip().split()[start_token:-1]) + outfiles[mode].write(f'{sentence_cld}\t' f'{str(intents_list[intent_str])}\n') + + slot_tags_list = [] + if slot_tags_str.strip(): + slot_tags = slot_tags_str.strip().split(",") + for st in slot_tags: + if not st.strip(): + continue + [start_i, end_i, slot_name] = st.strip().split(":") + slot_tags_list.append([int(start_i), int(end_i), slot_name]) + if slot_name not in slots_list: + slots_list[slot_name] = len(slots_list) + slots_list_all[f'B-{slot_name}'] = len(slots_list_all) + slots_list_all[f'I-{slot_name}'] = len(slots_list_all) + outfiles['dict_slots'].write(f'B-{slot_name}\n') + outfiles['dict_slots'].write(f'I-{slot_name}\n') + + slot_tags_list.sort(key=lambda x: x[0]) + slots = [] + processed_index = 0 + for tag_start, tag_end, tag_str in slot_tags_list: + if tag_start > processed_index: + words_list = sentence[processed_index:tag_start].strip().split() + slots.extend([str(slots_list_all['O'])] * len(words_list)) + words_list = sentence[tag_start:tag_end].strip().split() + slots.append(str(slots_list_all[f'B-{tag_str}'])) + slots.extend([str(slots_list_all[f'I-{tag_str}'])] * (len(words_list) - 1)) + processed_index = tag_end + + if processed_index < len(sentence): + words_list = sentence[processed_index:].strip().split() + slots.extend([str(slots_list_all['O'])] * len(words_list)) + + slots = slots[1:-1] + slot = ' '.join(slots) + outfiles[mode + '_slots'].write(slot + '\n') + + outfiles[mode + '_slots'].close() + outfiles[mode].close() + + outfiles['dict_slots'].close() + outfiles['dict_intents'].close() + + return outfold + + +if __name__ == "__main__": + # Parse the command-line arguments. + parser = argparse.ArgumentParser(description="Process and convert datasets into NeMo\'s format.") + parser.add_argument( + "--dataset_name", required=True, type=str, choices=['atis', 'snips', 'jarvis', 'assistant'], + ) + parser.add_argument( + "--source_data_dir", required=True, type=str, help='path to the folder containing the dataset files' + ) + parser.add_argument("--target_data_dir", required=True, type=str, help='path to save the processed dataset') + parser.add_argument("--do_lower_case", action='store_true') + parser.add_argument( + "--ignore_prev_intent", + action='store_true', + help='ignores previous intent while importing datasets in jarvis\'s format', + ) + + args = parser.parse_args() + + dataset_name = args.dataset_name + source_dir = args.source_data_dir + target_dir = args.target_data_dir + + if not exists(source_dir): + raise FileNotFoundError(f"{source_dir} does not exist.") + + if dataset_name == 'atis': + process_atis(infold=source_dir, outfold=target_dir, do_lower_case=args.do_lower_case) + elif dataset_name == 'snips': + process_snips(infold=source_dir, outfold=target_dir, do_lower_case=args.do_lower_case) + elif dataset_name == 'jarvis': + process_jarvis_datasets( + infold=source_dir, + outfold=target_dir, + modes=["train", "test", "dev"], + do_lower_case=args.do_lower_case, + ignore_prev_intent=args.ignore_prev_intent, + ) + elif dataset_name == 'assistant': + process_assistant(infold=source_dir, outfold=target_dir) + else: + raise ValueError(f'Dataset {dataset_name} is not supported.') diff --git a/tts/NeMo/examples/nlp/intent_slot_classification/intent_slot_classification.py b/tts/NeMo/examples/nlp/intent_slot_classification/intent_slot_classification.py new file mode 100644 index 0000000..39b4b7c --- /dev/null +++ b/tts/NeMo/examples/nlp/intent_slot_classification/intent_slot_classification.py @@ -0,0 +1,85 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import IntentSlotClassificationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="intent_slot_classification_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config Params:\n {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + # initialize the model using the config file + model = IntentSlotClassificationModel(cfg.model, trainer=trainer) + + # training + logging.info("================================================================================================") + logging.info('Starting training...') + trainer.fit(model) + logging.info('Training finished!') + + # Stop further testing as fast_dev_run does not save checkpoints + if trainer.fast_dev_run: + return + + # after model training is done, you can load the model from the saved checkpoint + # and evaluate it on a data file or on given queries. + logging.info("================================================================================================") + logging.info("Starting the testing of the trained model on test set...") + logging.info("We will load the latest model saved checkpoint from the training...") + + # for evaluation and inference you can load the previously trained model saved in .nemo file + # like this in your code, but we will just reuse the trained model here + # eval_model = IntentSlotClassificationModel.restore_from(restore_path=checkpoint_path) + eval_model = model + + # we will setup testing data reusing the same config (test section) + eval_model.update_data_dir_for_testing(data_dir=cfg.model.data_dir) + eval_model.setup_test_data(test_data_config=cfg.model.test_ds) + + trainer.test(model=eval_model, ckpt_path=None, verbose=False) + logging.info("Testing finished!") + + # run an inference on a few examples + logging.info("======================================================================================") + logging.info("Evaluate the model on the given queries...") + + # this will work well if you train the model on Assistant dataset + # for your own dataset change the examples appropriately + queries = [ + 'set alarm for seven thirty am', + 'lower volume by fifty percent', + 'what is my schedule for tomorrow', + ] + + pred_intents, pred_slots = eval_model.predict_from_examples(queries, cfg.model.test_ds) + + logging.info('The prediction results of some sample queries with the trained model:') + for query, intent, slots in zip(queries, pred_intents, pred_slots): + logging.info(f'Query : {query}') + logging.info(f'Predicted Intent: {intent}') + logging.info(f'Predicted Slots: {slots}') + + logging.info("Inference finished!") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/language_modeling/bert_pretraining.py b/tts/NeMo/examples/nlp/language_modeling/bert_pretraining.py new file mode 100644 index 0000000..7760b73 --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/bert_pretraining.py @@ -0,0 +1,38 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf +from pytorch_lightning.plugins import DDPPlugin + +from nemo.collections.nlp.models.language_modeling import BERTLMModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="bert_pretraining_from_text_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config:\n {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(plugins=[DDPPlugin(find_unused_parameters=True)], **cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + bert_model = BERTLMModel(cfg.model, trainer=trainer) + trainer.fit(bert_model) + if cfg.model.nemo_path: + bert_model.save_to(cfg.model.nemo_path) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_preprocessed_config.yaml b/tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_preprocessed_config.yaml new file mode 100644 index 0000000..cc516c1 --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_preprocessed_config.yaml @@ -0,0 +1,80 @@ +# BERT Pretraining from Preprocessed (tokenized) data +name: &name PretrainingBERTFromPreprocessed +trainer: + gpus: 8 # the number of gpus, 0 for CPU, or list with gpu indices + num_nodes: 1 + max_steps: 2285714 # precedence over max_epochs + num_sanity_val_steps: 0 # needed for bert pretraining from preproc + replace_sampler_ddp: false # needed for bert pretraining from preproc + accumulate_grad_batches: 1 # accumulates grads every k batches + precision: 16 # 16 to use AMP + amp_level: O1 # O1 or O2 if using AMP + accelerator: ddp + gradient_clip_val: 1.0 + log_every_n_steps: 1 + val_check_interval: 1.0 # check once per epoch .25 for 4 times per epoch + checkpoint_callback: false # provided by exp_manager + logger: false # provided by exp_manager + +model: + nemo_path: null # exported .nemo path + only_mlm_loss: true # only use masked language model without next sentence prediction + num_tok_classification_layers: 1 # number of token classification head output layers + num_seq_classification_layers: 2 # number of sequence classification head output layers + + + language_model: + pretrained_model_name: bert-base-uncased # huggingface model name + lm_checkpoint: null + config: + attention_probs_dropout_prob: 0.1 + hidden_act: gelu + hidden_dropout_prob: 0.1 + hidden_size: 768 + initializer_range: 0.02 + intermediate_size: 3072 + max_position_embeddings: 512 + num_attention_heads: 12 + num_hidden_layers: 12 + type_vocab_size: 2 + vocab_size: 30522 + config_file: null # json file, precedence over config + + tokenizer: null + + train_ds: + data_file: null # path to hdf5 file (or directory) + max_predictions_per_seq: 80 + batch_size: 16 + shuffle: true + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + optim: + name: adamw + lr: 0.4375e-4 + weight_decay: 0.01 + + sched: + name: SquareRootAnnealing + warmup_steps: null + warmup_ratio: 0.01 + min_lr: 0.0 + last_epoch: -1 + + +exp_manager: + exp_dir: null # where to store logs and checkpoints + name: *name # name of experiment + create_tensorboard_logger: True + create_checkpoint_callback: True + + +hydra: + run: + dir: . + job_logging: + root: + handlers: null \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_text_config.yaml b/tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_text_config.yaml new file mode 100644 index 0000000..02df49e --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/conf/bert_pretraining_from_text_config.yaml @@ -0,0 +1,109 @@ +# BERT Pretraining from Text +name: &name PretrainingBERTFromText +trainer: + gpus: 1 # the number of gpus, 0 for CPU, or list with gpu indices + num_nodes: 1 + max_epochs: 2 # the number of training epochs + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + precision: 16 # 16 to use AMP + amp_level: O1 # O1 or O2 if using AMP + accelerator: ddp + gradient_clip_val: 0.0 + log_every_n_steps: 1 + val_check_interval: 1.0 # check once per epoch .25 for 4 times per epoch + checkpoint_callback: false # provided by exp_manager + logger: false # provided by exp_manager + +model: + nemo_path: null # exported .nemo path + only_mlm_loss: false # only use masked language model without next sentence prediction + num_tok_classification_layers: 1 # number of token classification head output layers + num_seq_classification_layers: 2 # number of sequence classification head output layers + max_seq_length: 128 + # The maximum total input sequence length after tokenization. Sequences longer than this + # will be truncated, and sequences shorter than this will be padded. + mask_prob: 0.15 + # Probability of masking a token in the input text during data processing. + short_seq_prob: 0.1 + # Probability of having a sequence shorter than the maximum sequence length `max_seq_length` in data processing.", + + language_model: + pretrained_model_name: bert-base-uncased + lm_checkpoint: null + config: + attention_probs_dropout_prob: 0.1 + hidden_act: gelu + hidden_dropout_prob: 0.1 + hidden_size: 768 + initializer_range: 0.02 + intermediate_size: 3072 + max_position_embeddings: 512 + num_attention_heads: 12 + num_hidden_layers: 12 + type_vocab_size: 2 + vocab_size: 30522 + config_file: null # json file, precedence over config + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # tokenizer that inherits from TokenizerSpec + vocab_file: null # path to vocab file + tokenizer_model: null # tokenizer model for sentencepiece + special_tokens: # only necessary for adding transformer/bert-specific special tokens to tokenizer if the tokenizer does not already have these inherently. + unk_token: '[UNK]' + sep_token: '[SEP]' + pad_token: '[PAD]' + bos_token: '[CLS]' + mask_token: '[MASK]' + eos_token: '[SEP]' + cls_token: '[CLS]' + + train_ds: + data_file: null # path to data file + max_seq_length: ${model.max_seq_length} + mask_prob: ${model.mask_prob} + short_seq_prob: ${model.short_seq_prob} + batch_size: 16 # per GPU + shuffle: true + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + validation_ds: + data_file: null # path to data file + max_seq_length: ${model.max_seq_length} + mask_prob: ${model.mask_prob} + short_seq_prob: ${model.short_seq_prob} + batch_size: 16 # per GPU + shuffle: false + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + optim: + name: adamw + lr: 3e-5 + weight_decay: 0.0 + + sched: + name: CosineAnnealing + warmup_steps: null + warmup_ratio: 0.1 + min_lr: 0.0 + last_epoch: -1 + + +exp_manager: + exp_dir: null # where to store logs and checkpoints + name: *name # name of experiment + create_tensorboard_logger: True + create_checkpoint_callback: True + +hydra: + run: + dir: . + job_logging: + root: + handlers: null \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/language_modeling/conf/transformer_lm_config.yaml b/tts/NeMo/examples/nlp/language_modeling/conf/transformer_lm_config.yaml new file mode 100644 index 0000000..cb968bd --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/conf/transformer_lm_config.yaml @@ -0,0 +1,96 @@ +name: TransformerLanguageModel +do_training: True # set to False if only preprocessing data + +model: + label_smoothing: 0.0 + preproc_out_dir: null # path to store data preprocessing outputs + + train_ds: + use_tarred_dataset: true + tar_files: ??? # path to tarred files + metadata_file: ??? # metadata for tarred dataset + shard_strategy: scatter + tokens_in_batch: 4096 + tar_shuffle_n: 256 + + validation_ds: + file_name: ??? # path to file with validation data + tokens_in_batch: 512 + clean: false + shuffle: false + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + test_ds: + file_name: ??? # path to file with test data + tokens_in_batch: 512 + clean: false + shuffle: false + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + optim: + name: adam + lr: 0.001 + betas: + - 0.9 + - 0.98 + weight_decay: 0.0 + sched: + name: InverseSquareRootAnnealing + min_lr: 0.0 + last_epoch: -1 + warmup_ratio: 0.1 + + tokenizer: + tokenizer_name: yttm + tokenizer_model: ??? + vocab_file: null + special_tokens: null + training_sample_size: null # valid for sentencepiece tokenizer + + encoder: + library: nemo + model_name: null + pretrained: false + max_sequence_length: 512 + num_token_types: 0 + embedding_dropout: 0.1 + learn_positional_encodings: false + hidden_size: 512 + num_layers: 6 + inner_size: 2048 + num_attention_heads: 8 + ffn_dropout: 0.1 + attn_score_dropout: 0.1 + attn_layer_dropout: 0.1 + hidden_act: relu + mask_future: true + pre_ln: false + + head: + num_layers: 1 + activation: relu + log_softmax: true + dropout: 0.0 + use_transformer_init: true + +trainer: + gpus: 4 + num_nodes: 1 + max_epochs: 200 + amp_level: O2 # O1/O2 for mixed precision + precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0 + accelerator: ddp + checkpoint_callback: False + logger: False + log_every_n_steps: 50 # Interval of logging. + check_val_every_n_epoch: 1 + +exp_manager: + name: TransformerLM + files_to_copy: [] \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/language_modeling/convert_weights_to_nemo1.0.py b/tts/NeMo/examples/nlp/language_modeling/convert_weights_to_nemo1.0.py new file mode 100644 index 0000000..b58b339 --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/convert_weights_to_nemo1.0.py @@ -0,0 +1,61 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Converts BERT NeMo0.* checkpoints to NeMo1.0 format. +""" + +from argparse import ArgumentParser + +import torch + +parser = ArgumentParser() +parser.add_argument("--bert_encoder", required=True, help="path to BERT encoder, e.g. /../BERT-STEP-2285714.pt") +parser.add_argument( + "--bert_token_classifier", + required=True, + help="path to BERT token classifier, e.g. /../BertTokenClassifier-STEP-2285714.pt", +) +parser.add_argument( + "--bert_sequence_classifier", + required=False, + default=None, + help="path to BERT sequence classifier, e.g /../SequenceClassifier-STEP-2285714.pt", +) +parser.add_argument( + "--output_path", required=False, default="converted_model.pt", help="output path to newly converted model" +) +args = parser.parse_args() + +bert_in = torch.load(args.bert_encoder) +tok_in = torch.load(args.bert_token_classifier) +if args.bert_sequence_classifier: + seq_in = torch.load(args.bert_sequence_classifier) + +new_dict = {} +new_model = {"state_dict": new_dict} +for k in bert_in: + new_name = k.replace("bert.", "bert_model.") + new_dict[new_name] = bert_in[k] + +for k in tok_in: + new_name = "mlm_classifier." + k + new_dict[new_name] = tok_in[k] + +if args.bert_sequence_classifier: + for k in seq_in: + new_name = "nsp_classifier." + k + new_dict[new_name] = seq_in[k] + +torch.save(new_model, args.output_path) diff --git a/tts/NeMo/examples/nlp/language_modeling/get_wkt2.sh b/tts/NeMo/examples/nlp/language_modeling/get_wkt2.sh new file mode 100644 index 0000000..33b55b2 --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/get_wkt2.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +""" +This file is adapted from +https://github.com/salesforce/awd-lstm-lm/blob/master/getdata.sh +Copyright by the AWD LSTM authors. +""" +DATA_DIR=$1 +echo "- Downloading WikiText-2" + +wget --continue -P $DATA_DIR https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-2-v1.zip +unzip -q $DATA_DIR/wikitext-2-v1.zip -d $DATA_DIR +cd $DATA_DIR/wikitext-2 +mv wiki.train.tokens train.txt +sed -i -e "s//[UNK]/g" train.txt +mv wiki.valid.tokens valid.txt +sed -i -e "s//[UNK]/g" valid.txt +mv wiki.test.tokens test.txt +sed -i -e "s//[UNK]/g" test.txt +cd .. +rm wikitext-2-v1.zip + +echo "- WikiText-2 saved at $DATA_DIR/wikitext-2" diff --git a/tts/NeMo/examples/nlp/language_modeling/transformer_lm.py b/tts/NeMo/examples/nlp/language_modeling/transformer_lm.py new file mode 100644 index 0000000..caaa0e0 --- /dev/null +++ b/tts/NeMo/examples/nlp/language_modeling/transformer_lm.py @@ -0,0 +1,35 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.language_modeling import TransformerLMModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="transformer_lm_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + transformer_lm = TransformerLMModel(cfg.model, trainer=trainer) + trainer.fit(transformer_lm) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/machine_translation/conf/aayn_base.yaml b/tts/NeMo/examples/nlp/machine_translation/conf/aayn_base.yaml new file mode 100644 index 0000000..a932f63 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/conf/aayn_base.yaml @@ -0,0 +1,156 @@ +name: AttentionIsAllYouNeed +do_training: True # set to False if only preprocessing data +do_testing: False # set to True to run evaluation on test data after training + +model: + beam_size: 4 + len_pen: 0.6 + multilingual: False + max_generation_delta: 5 + label_smoothing: 0.1 + shared_tokenizer: True # train tokenizer model across src and tgt train data + preproc_out_dir: null # path to store data preprocessing outputs + src_language: 'en' + tgt_language: 'de' + + train_ds: + src_file_name: null + tgt_file_name: null + use_tarred_dataset: False # if true tar_file_name and meta_file_name will be used (or created automatically) + # config for preprocessing training data and creating a tarred datset automatically + tar_file_prefix: parallel # prefix for tar file names + tar_files: null # if data has already been preprocessed (rest of config ignored) + metadata_file: null # metadata for tarred dataset + lines_per_dataset_fragment: 1000000 # Number of lines to consider for bucketing and padding + num_batches_per_tarfile: 100 # Number of batches (pickle files) within each tarfile + tar_shuffle_n: 100 # How many samples to look ahead and load to be shuffled + shard_strategy: scatter # tarred dataset shard distribution strategy + n_preproc_jobs: -2 # number of processes to use for data preprocessing (-2 means all but 2) + tokens_in_batch: 512 + clean: true + max_seq_length: 512 + shuffle: true + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + concat_sampling_technique: temperature # only used with ConcatTranslationDataset + concat_sampling_temperature: 5 # only used with ConcatTranslationDataset + concat_sampling_probabilities: null # only used with ConcatTranslationDataset + + validation_ds: + src_file_name: ??? + tgt_file_name: ??? + tokens_in_batch: 512 + clean: false + max_seq_length: 512 + shuffle: false + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + test_ds: + src_file_name: ??? + tgt_file_name: ??? + tokens_in_batch: 512 + clean: false + max_seq_length: 512 + shuffle: false + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + optim: + name: adam + lr: 0.001 + betas: + - 0.9 + - 0.98 + weight_decay: 0.0 + sched: + name: InverseSquareRootAnnealing + min_lr: 0.0 + last_epoch: -1 + warmup_ratio: 0.1 + + encoder_tokenizer: + library: yttm + tokenizer_model: null + vocab_size: null # vocab size for training bpe + bpe_dropout: null + vocab_file: null + special_tokens: null + training_sample_size: null # valid for sentencepiece tokenizer + + decoder_tokenizer: + library: yttm + tokenizer_model: null + vocab_size: null # vocab size for training bpe + bpe_dropout: null + vocab_file: null + special_tokens: null + training_sample_size: null # valid for sentencepiece tokenizer + + encoder: + library: nemo + model_name: null + pretrained: false + max_sequence_length: 512 + num_token_types: 0 + embedding_dropout: 0.1 + learn_positional_encodings: false + hidden_size: 512 + num_layers: 6 + inner_size: 2048 + num_attention_heads: 8 + ffn_dropout: 0.1 + attn_score_dropout: 0.1 + attn_layer_dropout: 0.1 + hidden_act: relu + mask_future: false + pre_ln: false + pre_ln_final_layer_norm: true + + decoder: + library: nemo + model_name: null + pretrained: false + max_sequence_length: 512 + num_token_types: 0 + embedding_dropout: 0.1 + learn_positional_encodings: false + hidden_size: 512 + inner_size: 2048 + num_layers: 6 + num_attention_heads: 8 + ffn_dropout: 0.1 + attn_score_dropout: 0.1 + attn_layer_dropout: 0.1 + hidden_act: relu + pre_ln: false + pre_ln_final_layer_norm: true + + head: + num_layers: 1 + activation: relu + log_softmax: true + dropout: 0.0 + use_transformer_init: true + +trainer: + gpus: 4 + num_nodes: 1 + max_epochs: 200 + amp_level: O2 # O1/O2 for mixed precision + precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0 + accelerator: ddp + checkpoint_callback: False + logger: False + log_every_n_steps: 50 # Interval of logging. + check_val_every_n_epoch: 1 + +exp_manager: + name: AAYNBase + files_to_copy: [] \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/machine_translation/conf/huggingface.yaml b/tts/NeMo/examples/nlp/machine_translation/conf/huggingface.yaml new file mode 100644 index 0000000..abb5e9a --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/conf/huggingface.yaml @@ -0,0 +1,132 @@ +name: HuggingFaceEncoder +do_training: True # set to False if only preprocessing data +do_testing: False # set to True to run evaluation on test data after training + +model: + beam_size: 4 + len_pen: 0.6 + max_generation_delta: 5 + label_smoothing: 0.1 + shared_tokenizer: false + preproc_out_dir: null + src_language: 'en' + tgt_language: 'de' + + train_ds: + src_file_name: null + tgt_file_name: null + use_tarred_dataset: False # if true tar_file_name and meta_file_name will be used (or created automatically) + # config for preprocessing training data and creating a tarred datset automatically + tar_file_prefix: parallel # prefix for tar file names + tar_files: null # if data has already been preprocessed (rest of config ignored) + metadata_file: null # metadata for tarred dataset + lines_per_dataset_fragment: 1000000 # Number of lines to consider for bucketing and padding + num_batches_per_tarfile: 100 # Number of batches (pickle files) within each tarfile + tar_shuffle_n: 100 # How many samples to look ahead and load to be shuffled + shard_strategy: scatter # tarred dataset shard distribution strategy + n_preproc_jobs: -2 # number of processes to use for data preprocessing (-2 means all but 2) + tokens_in_batch: 512 + clean: true + max_seq_length: 512 + shuffle: true + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + validation_ds: + src_file_name: null + tgt_file_name: null + tokens_in_batch: 512 + clean: false + max_seq_length: 512 + shuffle: false + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + test_ds: + src_file_name: null + tgt_file_name: null + tokens_in_batch: 512 + clean: false + max_seq_length: 512 + shuffle: false + num_samples: -1 + drop_last: false + pin_memory: false + num_workers: 8 + + optim: + name: adam + lr: 0.001 + betas: + - 0.9 + - 0.98 + weight_decay: 0.0 + sched: + name: InverseSquareRootAnnealing + min_lr: 0.0 + last_epoch: -1 + warmup_ratio: 0.1 + + encoder_tokenizer: + library: huggingface + tokenizer_model: null + vocab_file: null + special_tokens: null + vocab_size: null + + decoder_tokenizer: + library: yttm + tokenizer_model: null + vocab_file: null + special_tokens: null + vocab_size: null + + encoder: + library: huggingface + model_name: bert-base-uncased + pretrained: false + + decoder: + library: nemo + model_name: null + pretrained: false + max_sequence_length: 512 + num_token_types: 2 + embedding_dropout: 0.1 + learn_positional_encodings: false + hidden_size: 512 + inner_size: 2048 + num_layers: 6 + num_attention_heads: 8 + ffn_dropout: 0.1 + attn_score_dropout: 0.1 + attn_layer_dropout: 0.1 + hidden_act: relu + pre_ln: false + + head: + num_layers: 1 + activation: relu + log_softmax: true + dropout: 0.0 + use_transformer_init: true + +trainer: + gpus: 4 + num_nodes: 1 + max_epochs: 200 + amp_level: O2 # O1/O2 for mixed precision + precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0 + accelerator: ddp + checkpoint_callback: False + logger: False + log_every_n_steps: 50 # Interval of logging. + check_val_every_n_epoch: 1 + +exp_manager: + name: HuggingFaceEncoder + files_to_copy: [] \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/machine_translation/create_tarred_monolingual_dataset.py b/tts/NeMo/examples/nlp/machine_translation/create_tarred_monolingual_dataset.py new file mode 100644 index 0000000..5ad5f78 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/create_tarred_monolingual_dataset.py @@ -0,0 +1,68 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os + +from nemo.collections.nlp.data.machine_translation.preproc_mt_data import MTDataPreproc + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='NMT dataset pre-processing') + parser.add_argument('--tokenizer_model', type=str, required=True, help='Path to tokenizer model') + parser.add_argument('--tokenizer_name', type=str, default='yttm', help='BPE Tokenizer Name, Options: [yttm]') + parser.add_argument('--bpe_droput', type=float, default=0.0, help='BPE dropout to use') + parser.add_argument('--clean', action="store_true", help='Whether to clean dataset based on length diff') + parser.add_argument('--pkl_file_prefix', type=str, default='parallel', help='Prefix for tar and pickle files') + parser.add_argument('--fname', type=str, required=True, help='Path to monolingual data file') + parser.add_argument('--out_dir', type=str, required=True, help='Path to store dataloader and tokenizer models') + parser.add_argument('--max_seq_length', type=int, default=512, help='Max Sequence Length') + parser.add_argument('--min_seq_length', type=int, default=1, help='Min Sequence Length') + parser.add_argument('--tokens_in_batch', type=int, default=16000, help='# Tokens per batch per GPU') + parser.add_argument( + '--lines_per_dataset_fragment', + type=int, + default=1000000, + help='Number of lines to consider for bucketing and padding', + ) + parser.add_argument( + '--num_batches_per_tarfile', + type=int, + default=1000, + help='Number of batches (pickle files) within each tarfile', + ) + + args = parser.parse_args() + if not os.path.exists(args.out_dir): + os.mkdir(args.out_dir) + if not os.path.exists(args.tokenizer_model): + assert FileNotFoundError("Could not find tokenizer model %s" % (args.tokenizer)) + + tokenizer_model = MTDataPreproc.get_monolingual_tokenizer( + tokenizer_name=args.tokenizer_name, tokenizer_model=args.tokenizer_model, bpe_dropout=args.bpe_droput + ) + + MTDataPreproc.preprocess_monolingual_dataset( + clean=args.clean, + fname=args.fname, + out_dir=args.out_dir, + tokenizer=tokenizer_model, + max_seq_length=args.max_seq_length, + min_seq_length=args.min_seq_length, + tokens_in_batch=args.tokens_in_batch, + lines_per_dataset_fragment=args.lines_per_dataset_fragment, + num_batches_per_tarfile=args.num_batches_per_tarfile, + pkl_file_prefix=args.pkl_file_prefix, + global_rank=0, + world_size=1, + ) diff --git a/tts/NeMo/examples/nlp/machine_translation/create_tarred_parallel_dataset.py b/tts/NeMo/examples/nlp/machine_translation/create_tarred_parallel_dataset.py new file mode 100644 index 0000000..d2cd59b --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/create_tarred_parallel_dataset.py @@ -0,0 +1,143 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os + +from nemo.collections.nlp.data.machine_translation.preproc_mt_data import MTDataPreproc + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='NMT dataset pre-processing') + parser.add_argument('--shared_tokenizer', action="store_true", help='Whether to share encoder/decoder tokenizers') + parser.add_argument('--clean', action="store_true", help='Whether to clean dataset based on length diff') + parser.add_argument('--tar_file_prefix', type=str, default='parallel', help='Prefix for tar files') + parser.add_argument('--bpe_dropout', type=float, default=0.1, help='Whether to share encoder/decoder tokenizers') + parser.add_argument('--src_fname', type=str, required=True, help='Path to the source file') + parser.add_argument('--tgt_fname', type=str, required=True, help='Path to the target file') + parser.add_argument('--out_dir', type=str, required=True, help='Path to store dataloader and tokenizer models') + parser.add_argument('--encoder_model_name', type=str, default=None, help='For use with pretrained encoders') + parser.add_argument( + '--decoder_model_name', type=str, default=None, help='For use with pretrained decoders (not yet supported)' + ) + parser.add_argument( + '--encoder_tokenizer_model', type=str, default='None', help='Path to pre-trained encoder tokenizer model' + ) + parser.add_argument( + '--encoder_tokenizer_name', type=str, default='yttm', help='Encoder BPE Tokenizer Name, Options: [yttm]' + ) + parser.add_argument('--encoder_tokenizer_vocab_size', type=int, default=32000, help='Encoder Vocab size after BPE') + parser.add_argument( + '--encoder_tokenizer_coverage', type=float, default=0.999, help='Encoder Character coverage for BPE' + ) + parser.add_argument('--encoder_tokenizer_bpe_dropout', type=float, default=0.1, help='Encoder BPE dropout prob') + parser.add_argument( + '--decoder_tokenizer_model', type=str, default='None', help='Path to pre-trained decoder tokenizer model' + ) + parser.add_argument( + '--decoder_tokenizer_name', type=str, default='yttm', help='Encoder BPE Tokenizer Name, Options: [yttm]' + ) + parser.add_argument('--decoder_tokenizer_vocab_size', type=int, default=32000, help='Encoder Vocab size after BPE') + parser.add_argument( + '--decoder_tokenizer_coverage', type=float, default=0.999, help='Encoder Character coverage for BPE' + ) + parser.add_argument('--decoder_tokenizer_bpe_dropout', type=float, default=0.1, help='Encoder BPE dropout prob') + parser.add_argument('--max_seq_length', type=int, default=512, help='Max Sequence Length') + parser.add_argument('--min_seq_length', type=int, default=1, help='Min Sequence Length') + parser.add_argument('--tokens_in_batch', type=int, default=16000, help='# Tokens per batch per GPU') + parser.add_argument('--coverage', type=float, default=0.999, help='BPE character coverage [0-1]') + parser.add_argument( + '--lines_per_dataset_fragment', + type=int, + default=1000000, + help='Number of lines to consider for bucketing and padding', + ) + parser.add_argument( + '--num_batches_per_tarfile', + type=int, + default=1000, + help='Number of batches (pickle files) within each tarfile', + ) + parser.add_argument( + '--n_preproc_jobs', type=int, default=-2, help='Number of processes to use for creating the tarred dataset.', + ) + + args = parser.parse_args() + if not os.path.exists(args.out_dir): + os.mkdir(args.out_dir) + + if ( + args.encoder_tokenizer_model != 'None' + and args.decoder_tokenizer_model == 'None' + or args.decoder_tokenizer_model != 'None' + and args.encoder_tokenizer_model == 'None' + ): + if args.shared_tokenizer: + raise ValueError( + ''' + If using a pre-trained shared tokenizer, + both encoder and decoder tokenizers must be the same + ''' + ) + else: + raise ValueError('Both encoder and decoder pre-trained tokenizer models must be specified') + + if args.encoder_tokenizer_model == 'None' and args.decoder_tokenizer_model == 'None': + encoder_tokenizer_model, decoder_tokenizer_model = MTDataPreproc.train_tokenizers( + out_dir=args.out_dir, + src_fname=args.src_fname, + tgt_fname=args.tgt_fname, + shared_tokenizer=args.shared_tokenizer, + encoder_tokenizer_name=args.encoder_tokenizer_name, + encoder_tokenizer_vocab_size=args.encoder_tokenizer_vocab_size, + encoder_tokenizer_coverage=args.encoder_tokenizer_coverage, + decoder_tokenizer_name=args.decoder_tokenizer_name, + decoder_tokenizer_vocab_size=args.decoder_tokenizer_vocab_size, + decoder_tokenizer_coverage=args.decoder_tokenizer_coverage, + global_rank=0, + ) + else: + encoder_tokenizer_model, decoder_tokenizer_model = args.encoder_tokenizer_model, args.decoder_tokenizer_model + + encoder_tokenizer, decoder_tokenizer = MTDataPreproc.get_enc_dec_tokenizers( + encoder_tokenizer_name=args.encoder_tokenizer_name, + encoder_tokenizer_model=encoder_tokenizer_model, + encoder_bpe_dropout=args.encoder_tokenizer_bpe_dropout, + decoder_tokenizer_name=args.decoder_tokenizer_name, + decoder_tokenizer_model=decoder_tokenizer_model, + decoder_bpe_dropout=args.decoder_tokenizer_bpe_dropout, + ) + + _, _ = MTDataPreproc.preprocess_parallel_dataset( + clean=args.clean, + src_fname=args.src_fname, + tgt_fname=args.tgt_fname, + out_dir=args.out_dir, + encoder_tokenizer_name=args.encoder_tokenizer_name, + encoder_model_name=args.encoder_model_name, + encoder_tokenizer_model=encoder_tokenizer_model, + encoder_bpe_dropout=args.encoder_tokenizer_bpe_dropout, + decoder_tokenizer_name=args.decoder_tokenizer_name, + decoder_model_name=args.decoder_model_name, + decoder_tokenizer_model=decoder_tokenizer_model, + decoder_bpe_dropout=args.decoder_tokenizer_bpe_dropout, + max_seq_length=args.max_seq_length, + min_seq_length=args.min_seq_length, + tokens_in_batch=args.tokens_in_batch, + lines_per_dataset_fragment=args.lines_per_dataset_fragment, + num_batches_per_tarfile=args.num_batches_per_tarfile, + tar_file_prefix=args.tar_file_prefix, + global_rank=0, + world_size=1, + n_jobs=args.n_preproc_jobs, + ) diff --git a/tts/NeMo/examples/nlp/machine_translation/enc_dec_nmt.py b/tts/NeMo/examples/nlp/machine_translation/enc_dec_nmt.py new file mode 100644 index 0000000..1cfb8bc --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/enc_dec_nmt.py @@ -0,0 +1,137 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from dataclasses import dataclass +from typing import Optional + +from omegaconf import OmegaConf +from pytorch_lightning import Trainer + +from nemo.collections.nlp.data.machine_translation.preproc_mt_data import MTDataPreproc +from nemo.collections.nlp.models.machine_translation.mt_enc_dec_config import MTEncDecModelConfig +from nemo.collections.nlp.models.machine_translation.mt_enc_dec_model import MTEncDecModel +from nemo.core.config import hydra_runner +from nemo.core.config.modelPT import NemoConfig +from nemo.core.config.pytorch_lightning import TrainerConfig +from nemo.utils import logging +from nemo.utils.config_utils import update_model_config +from nemo.utils.exp_manager import ExpManagerConfig, exp_manager + + +""" +Usage: + 1. If you need to start docker and install NeMo, otherwise skip this step: + + a. ```docker run --gpus all -it --rm -v /home/okuchaiev/repos/NeMo/:/NeMo -p 6006:6006 -v /mnt:/mnt --shm-size=16g --ulimit memlock=-1 --ulimit stack=67108864 --device=/dev/snd nvcr.io/nvidia/pytorch:20.11-py3``` + b. ```cd /NeMo``` + c. ```./reinstall.sh``` + + 2. Train a new tokenizer (or use pre-trained one): + ```yttm bpe --data /mnt/D1/Data/NMT/wmt16_de_en/train.clean.en-de.shuffled.common --model tokenizer.BPE.8192.model --vocab_size 8192``` + +(To use WANDB, optionally, do login first) +``wandb login [YOUR WANDB login]`` + + 3. Start training: + + + (This example for "base" model on 2 GPUs for 150000 steps with batch size of 12500 tokens per GPU) + + python enc_dec_nmt.py \ + --config-path=conf \ + --config-name=aayn_base \ + trainer.gpus=[0,1] \ + ~trainer.max_epochs \ + +trainer.max_steps=150000 \ + model.beam_size=4 \ + model.max_generation_delta=5 \ + model.label_smoothing=0.1 \ + model.encoder_tokenizer.tokenizer_model=tokenizer.BPE.8192.model \ + model.decoder_tokenizer.tokenizer_model=tokenizer.BPE.8192.model \ + model.encoder.num_layers=6 \ + model.encoder.hidden_size=512 \ + model.encoder.inner_size=2048 \ + model.encoder.num_attention_heads=8 \ + model.encoder.ffn_dropout=0.1 \ + model.decoder.num_layers=6 \ + model.decoder.hidden_size=512 \ + model.decoder.inner_size=2048 \ + model.decoder.num_attention_heads=8 \ + model.decoder.ffn_dropout=0.1 \ + model.train_ds.src_file_name=/mnt/D1/Data/NMT/wmt16_de_en/train.clean.de.shuffled \ + model.train_ds.tgt_file_name=/mnt/D1/Data/NMT/wmt16_de_en/train.clean.en.shuffled \ + model.train_ds.tokens_in_batch=12500 \ + model.validation_ds.src_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.ref \ + model.validation_ds.tgt_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.src \ + model.validation_ds.tokens_in_batch=8192 \ + model.test_ds.src_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.ref \ + model.test_ds.tgt_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.src \ + model.optim.lr=0.001 \ + model.optim.sched.warmup_ratio=0.05 \ + +exp_manager.create_wandb_logger=True \ + +exp_manager.wandb_logger_kwargs.name=TEST-nmt-base \ + +exp_manager.wandb_logger_kwargs.project=nmt-de-en \ + +exp_manager.create_checkpoint_callback=True \ + +exp_manager.checkpoint_callback_params.monitor=val_sacreBLEU \ + +exp_manager.exp_dir=nmt_base \ + +exp_manager.checkpoint_callback_params.mode=max +""" + + +@dataclass +class MTEncDecConfig(NemoConfig): + name: Optional[str] = 'MTEncDec' + do_training: bool = True + do_testing: bool = False + model: MTEncDecModelConfig = MTEncDecModelConfig() + trainer: Optional[TrainerConfig] = TrainerConfig() + exp_manager: Optional[ExpManagerConfig] = ExpManagerConfig(name='MTEncDec', files_to_copy=[]) + + +@hydra_runner(config_path="conf", config_name="aayn_base") +def main(cfg: MTEncDecConfig) -> None: + # merge default config with user specified config + default_cfg = MTEncDecConfig() + cfg = update_model_config(default_cfg, cfg) + logging.info("\n\n************** Experiment configuration ***********") + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + + # training is managed by PyTorch Lightning + trainer = Trainer(**cfg.trainer) + + # tokenizers will be trained and and tarred training data will be created if needed + # model config is then updated + if cfg.model.preproc_out_dir is not None: + MTDataPreproc(cfg=cfg.model, trainer=trainer) + + # experiment logs, checkpoints, and auto-resume are managed by exp_manager and PyTorch Lightning + exp_manager(trainer, cfg.exp_manager) + + # everything needed to train translation models is encapsulated in the NeMo MTEncdDecModel + mt_model = MTEncDecModel(cfg.model, trainer=trainer) + + logging.info("\n\n************** Model parameters and their sizes ***********") + for name, param in mt_model.named_parameters(): + print(name, param.size()) + logging.info("***********************************************************\n\n") + + if cfg.do_training: + trainer.fit(mt_model) + + if cfg.do_testing: + trainer.test(mt_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_transformer_infer.py b/tts/NeMo/examples/nlp/machine_translation/nmt_transformer_infer.py new file mode 100644 index 0000000..91f2fe9 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_transformer_infer.py @@ -0,0 +1,122 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Given NMT model's .nemo file, this script can be used to translate text. +USAGE Example: +1. Obtain text file in src language. You can use sacrebleu to obtain standard test sets like so: + sacrebleu -t wmt14 -l de-en --echo src > wmt14-de-en.src +2. Translate: + python nmt_transformer_infer.py --model=[Path to .nemo file] --srctext=wmt14-de-en.src --tgtout=wmt14-de-en.pre +""" + + +from argparse import ArgumentParser + +import torch + +import nemo.collections.nlp as nemo_nlp +from nemo.collections.nlp.modules.common.transformer import ( + BeamSearchSequenceGenerator, + BeamSearchSequenceGeneratorWithLanguageModel, +) +from nemo.utils import logging + + +def main(): + parser = ArgumentParser() + parser.add_argument("--model", type=str, required=True, help="") + parser.add_argument("--srctext", type=str, required=True, help="") + parser.add_argument("--tgtout", type=str, required=True, help="") + parser.add_argument("--batch_size", type=int, default=256, help="") + parser.add_argument("--beam_size", type=int, default=4, help="") + parser.add_argument("--len_pen", type=float, default=0.6, help="") + parser.add_argument("--max_delta_length", type=int, default=5, help="") + parser.add_argument("--target_lang", type=str, default=None, help="") + parser.add_argument("--source_lang", type=str, default=None, help="") + # shallow fusion specific parameters + parser.add_argument("--lm_model", type=str, default=None, help="") + parser.add_argument("--fusion_coef", type=float, default=0.0, help="") + + args = parser.parse_args() + torch.set_grad_enabled(False) + if args.model.endswith(".nemo"): + logging.info("Attempting to initialize from .nemo file") + model = nemo_nlp.models.machine_translation.MTEncDecModel.restore_from(restore_path=args.model) + src_text = [] + tgt_text = [] + else: + raise NotImplemented(f"Only support .nemo files, but got: {args.model}") + + if torch.cuda.is_available(): + model = model.cuda() + + if args.lm_model is not None: + lm_model = nemo_nlp.models.language_modeling.TransformerLMModel.restore_from(restore_path=args.lm_model).eval() + model.beam_search = BeamSearchSequenceGeneratorWithLanguageModel( + embedding=model.decoder.embedding, + decoder=model.decoder.decoder, + log_softmax=model.log_softmax, + bos=model.decoder_tokenizer.bos_id, + pad=model.decoder_tokenizer.pad_id, + eos=model.decoder_tokenizer.eos_id, + language_model=lm_model, + fusion_coef=args.fusion_coef, + max_sequence_length=model.decoder.max_sequence_length, + beam_size=args.beam_size, + len_pen=args.len_pen, + max_delta_length=args.max_delta_length, + ) + else: + model.beam_search = BeamSearchSequenceGenerator( + embedding=model.decoder.embedding, + decoder=model.decoder.decoder, + log_softmax=model.log_softmax, + bos=model.decoder_tokenizer.bos_id, + pad=model.decoder_tokenizer.pad_id, + eos=model.decoder_tokenizer.eos_id, + max_sequence_length=model.decoder.max_sequence_length, + beam_size=args.beam_size, + len_pen=args.len_pen, + max_delta_length=args.max_delta_length, + ) + + logging.info(f"Translating: {args.srctext}") + + count = 0 + with open(args.srctext, 'r') as src_f: + for line in src_f: + src_text.append(line.strip()) + if len(src_text) == args.batch_size: + res = model.translate(text=src_text, source_lang=args.source_lang, target_lang=args.target_lang) + if len(res) != len(src_text): + print(len(res)) + print(len(src_text)) + print(res) + print(src_text) + tgt_text += res + src_text = [] + count += 1 + # if count % 300 == 0: + # print(f"Translated {count} sentences") + if len(src_text) > 0: + tgt_text += model.translate(text=src_text, source_lang=args.source_lang, target_lang=args.target_lang) + + with open(args.tgtout, 'w') as tgt_f: + for line in tgt_text: + tgt_f.write(line + "\n") + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/README.rst b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/README.rst new file mode 100644 index 0000000..dd453d1 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/README.rst @@ -0,0 +1,7 @@ +**STEPS 2 RUN** +=============== +0. (Make sure you have Flask installed - ``pip install -r requirements.txt``) +1. Edit "config.json" file to only contain models you need. If model's location starts with "NGC/" - it will load this model from NVIDIA's NGC. Otherwise, specify full path to .nemo file. +4. To run: ``python nmt_service.py`` +5. To translate: ``http://127.0.0.1:5000/translate?text=Frohe%20Weihnachten`` (here %20 means space) +6. Run web UI: ``python -m http.server`` \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/config.json b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/config.json new file mode 100644 index 0000000..938d91a --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/config.json @@ -0,0 +1,12 @@ +{ + "en-de": "NGC/nmt_en_de_transformer12x2", + "de-en": "NGC/nmt_de_en_transformer12x2", + "en-es": "NGC/nmt_en_es_transformer12x2", + "es-en": "NGC/nmt_es_en_transformer12x2", + "en-ru": "NGC/nmt_en_ru_transformer6x6", + "ru-en": "NGC/nmt_ru_en_transformer6x6", + "en-fr": "NGC/nmt_en_fr_transformer12x2", + "fr-en": "NGC/nmt_fr_en_transformer12x2", + "en-zh": "NGC/nmt_en_zh_transformer6x6", + "zh-en": "NGC/nmt_zh_en_transformer6x6" +} diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/index.html b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/index.html new file mode 100644 index 0000000..2f639d5 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/index.html @@ -0,0 +1,140 @@ + + + + + + Neural Machine Translation Demo App + + + + + + + + + +
+

Neural Machine Translation Demo

+

+
+

Running NeMo commit id: v1.0.2

+
+

+

+

+ Select translation direction: + + + + + + + + + + + + + + + + + + + + + + + +
+ + +             + + +             + + +             + + +
+ + +             + + +             + + +             + + +             + + +             + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+ +
+
+

+
+ + + + diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/nmt_service.py b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/nmt_service.py new file mode 100644 index 0000000..3661fcd --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/nmt_service.py @@ -0,0 +1,100 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import json +import time + +import flask +import torch +from flask import Flask, json, request +from flask_cors import CORS + +import nemo.collections.nlp as nemo_nlp +from nemo.utils import logging + +MODELS_DICT = {} + +model = None +api = Flask(__name__) +CORS(api) + + +def initialize(config_file_path: str): + """ + Loads 'language-pair to NMT model mapping' + """ + __MODELS_DICT = None + + logging.info("Starting NMT service") + logging.info(f"I will attempt to load all the models listed in {config_file_path}.") + logging.info(f"Edit {config_file_path} to disable models you don't need.") + if torch.cuda.is_available(): + logging.info("CUDA is available. Running on GPU") + else: + logging.info("CUDA is not available. Defaulting to CPUs") + + # read config + with open(config_file_path) as f: + __MODELS_DICT = json.load(f) + + if __MODELS_DICT is not None: + for key, value in __MODELS_DICT.items(): + logging.info(f"Loading model for {key} from file: {value}") + if value.startswith("NGC/"): + model = nemo_nlp.models.machine_translation.MTEncDecModel.from_pretrained(model_name=value[4:]) + else: + model = nemo_nlp.models.machine_translation.MTEncDecModel.restore_from(restore_path=value) + if torch.cuda.is_available(): + model = model.cuda() + MODELS_DICT[key] = model + else: + raise ValueError("Did not find the config.json or it was empty") + logging.info("NMT service started") + + +@api.route('/translate', methods=['GET', 'POST', 'OPTIONS']) +def get_translation(): + try: + time_s = time.time() + langpair = request.args["langpair"] + src = request.args["text"] + do_moses = request.args.get('do_moses', False) + if langpair in MODELS_DICT: + if do_moses: + result = MODELS_DICT[langpair].translate( + [src], source_lang=langpair.split('-')[0], target_lang=langpair.split('-')[1] + ) + else: + result = MODELS_DICT[langpair].translate([src]) + + duration = time.time() - time_s + logging.info( + f"Translated in {duration}. Input was: {request.args['text']} <############> Translation was: {result[0]}" + ) + res = {'translation': result[0]} + response = flask.jsonify(res) + response.headers.add('Access-Control-Allow-Origin', '*') + return response + + else: + logging.error(f"Got the following langpair: {langpair} which was not found") + except Exception as ex: + res = {'translation': str(ex)} + response = flask.jsonify(res) + response.headers.add('Access-Control-Allow-Origin', '*') + return res + + +if __name__ == '__main__': + initialize('config.json') + api.run(host='0.0.0.0') diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/requirements.txt b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/requirements.txt new file mode 100644 index 0000000..cd6e0e7 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/requirements.txt @@ -0,0 +1,3 @@ +nemo_toolkit[all]>=1.0.0rc1 +flask +flask_cors \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/style.css b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/style.css new file mode 100644 index 0000000..58f2334 --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/nmt_webapp/style.css @@ -0,0 +1,111 @@ +@import url("https://fonts.googleapis.com/css?family=Spartan&display=swap"); +* { + margin: 0; + padding: 0; +} + +body { + /*background: url("https://img.wallpapersafari.com/desktop/1680/1050/65/18/8AYkSt.jpg") center center;*/ + background: url("https://images5.alphacoders.com/550/550948.jpg") center center; + background-size: cover; + width: 100vw; + height: 100vh; + display: grid; + align-items: center; + justify-items: center; + font-size: 12pt; + font-family: "Spartan"; + color: #ffffff; +} + +.contact-us { + /*background: #1f1d1d;*/ + padding: 50px 100px; + border-top: 10px solid #229955; +} + +label, input, textarea { + display: block; + width: 100%; + font-size: 12pt; + line-height: 24pt; + font-family: "Spartan"; +} + +input { + margin-bottom: 24pt; +} + +h1 { + color: #ffffff; + font-weight: bold; + font-size: 22pt; + line-height: 24pt; + font-style: italic; + margin: 0 0 0.5em 0; +} + +span { + font-size: 8pt; +} + +em { + color: #229955; + font-weight: bold; +} + +input, textarea { + border: none; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 2px; + background: #f8f4e5; + padding-left: 5px; + outline: none; +} + +input:focus, textarea:focus { + border: 1px solid #6bd4b1; +} + +textarea { + resize: none; +} + +fieldset { + overflow: hidden + } + +button { + display: block; + float: left; + line-height: 24pt; + padding: 0 20px; + border: none; + background: #f45702; + color: white; + letter-spacing: 2px; + transition: 0.2s all ease-in-out; + border-bottom: 2px solid transparent; + outline: none; +} +button:hover { + background: inherit; + color: #ea6153; + border-bottom: 2px solid #f45702; +} + +::selection { + background: #ffc7b8; +} + +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +textarea:-webkit-autofill, +textarea:-webkit-autofill:hover, +textarea:-webkit-autofill:focus { + border: 1px solid #6bd4b1; + -webkit-text-fill-color: #2A293E; + -webkit-box-shadow: 0 0 0px 1000px #f8f4e5 inset; + transition: background-color 5000s ease-in-out 0s; +} \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/machine_translation/translate_ddp.py b/tts/NeMo/examples/nlp/machine_translation/translate_ddp.py new file mode 100644 index 0000000..bf057df --- /dev/null +++ b/tts/NeMo/examples/nlp/machine_translation/translate_ddp.py @@ -0,0 +1,122 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +from argparse import ArgumentParser + +import torch +import torch.multiprocessing as mp +from torch.utils.data import DataLoader + +from nemo.collections.nlp.data.language_modeling import TarredSentenceDataset +from nemo.collections.nlp.data.machine_translation import TarredTranslationDataset +from nemo.collections.nlp.models.machine_translation.mt_enc_dec_model import MTEncDecModel +from nemo.utils import logging + + +def get_args(): + parser = ArgumentParser(description='Batch translation of sentences from a pre-trained model on multiple GPUs') + parser.add_argument("--model", type=str, required=True, help="Path to the .nemo translation model file") + parser.add_argument( + "--text2translate", type=str, required=True, help="Path to the pre-processed tarfiles for translation" + ) + parser.add_argument("--result_dir", type=str, required=True, help="Folder to write translation results") + parser.add_argument( + "--twoside", action="store_true", help="Set flag when translating the source side of a parallel dataset" + ) + parser.add_argument( + '--metadata_path', type=str, required=True, help="Path to the JSON file that contains dataset info" + ) + parser.add_argument('--topk', type=int, default=500, help="Value of k for topk sampling") + parser.add_argument('--src_language', type=str, required=True, help="Source lang ID for detokenization") + parser.add_argument('--tgt_language', type=str, required=True, help="Target lang ID for detokenization") + parser.add_argument( + '--reverse_lang_direction', + action="store_true", + help="Reverse source and target language direction for parallel dataset", + ) + parser.add_argument('--n_gpus', type=int, default=-1, help="Number of GPUs to use") + args = parser.parse_args() + return args + + +def translate(rank, world_size, args): + if args.model.endswith(".nemo"): + logging.info("Attempting to initialize from .nemo file") + model = MTEncDecModel.restore_from(restore_path=args.model, map_location=f"cuda:{rank}") + elif args.model.endswith(".ckpt"): + logging.info("Attempting to initialize from .ckpt file") + model = MTEncDecModel.load_from_checkpoint(checkpoint_path=args.model, map_location=f"cuda:{rank}") + model.replace_beam_with_sampling(topk=args.topk) + model.eval() + if args.twoside: + dataset = TarredTranslationDataset( + text_tar_filepaths=args.text2translate, + metadata_path=args.metadata_path, + encoder_tokenizer=model.encoder_tokenizer, + decoder_tokenizer=model.decoder_tokenizer, + shuffle_n=100, + shard_strategy="scatter", + world_size=world_size, + global_rank=rank, + reverse_lang_direction=args.reverse_lang_direction, + ) + else: + dataset = TarredSentenceDataset( + text_tar_filepaths=args.text2translate, + metadata_path=args.metadata_path, + tokenizer=model.encoder_tokenizer, + shuffle_n=100, + shard_strategy="scatter", + world_size=world_size, + global_rank=rank, + ) + loader = DataLoader(dataset, batch_size=1) + result_dir = os.path.join(args.result_dir, f'rank{rank}') + os.makedirs(result_dir, exist_ok=True) + originals_file_name = os.path.join(result_dir, 'originals.txt') + translations_file_name = os.path.join(result_dir, 'translations.txt') + num_translated_sentences = 0 + + with open(originals_file_name, 'w') as of, open(translations_file_name, 'w') as tf: + for batch_idx, batch in enumerate(loader): + for i in range(len(batch)): + if batch[i].ndim == 3: + batch[i] = batch[i].squeeze(dim=0) + batch[i] = batch[i].to(rank) + if args.twoside: + src_ids, src_mask, _, _, _ = batch + else: + src_ids, src_mask = batch + if batch_idx % 100 == 0: + logging.info( + f"{batch_idx} batches ({num_translated_sentences} sentences) were translated by process with " + f"rank {rank}" + ) + num_translated_sentences += len(src_ids) + inputs, translations = model.batch_translate(src=src_ids, src_mask=src_mask) + for src, translation in zip(inputs, translations): + of.write(src + '\n') + tf.write(translation + '\n') + + +def main() -> None: + args = get_args() + world_size = torch.cuda.device_count() if args.n_gpus == -1 else args.n_gpus + mp.spawn(translate, args=(world_size, args), nprocs=world_size, join=True) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/question_answering/conf/question_answering_squad_config.yaml b/tts/NeMo/examples/nlp/question_answering/conf/question_answering_squad_config.yaml new file mode 100644 index 0000000..929409d --- /dev/null +++ b/tts/NeMo/examples/nlp/question_answering/conf/question_answering_squad_config.yaml @@ -0,0 +1,135 @@ +# Question Answering with SQUAD +name: &name QA + +pretrained_model: null # pretrained QAModel model from list_available_models() +do_training: true # training mode, for testing change to false +trainer: + gpus: 1 # the number of gpus, 0 for CPU, or list with gpu indices + num_nodes: 1 + max_epochs: 2 # the number of training epochs + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + precision: 16 # 16 to use AMP + amp_level: O1 # O1 or O2 if using AMP + accelerator: ddp + gradient_clip_val: 0.0 + val_check_interval: 1.0 # check once per epoch .25 for 4 times per epoch + checkpoint_callback: false # provided by exp_manager + logger: false # provided by exp_manager + num_sanity_val_steps: 0 + log_every_n_steps: 1 # Interval of logging. + +model: + nemo_path: null # exported .nemo path + dataset: + version_2_with_negative: false + # If true, the examples contain some that do not have an answer. + doc_stride: 128 + # When splitting up a long document into chunks, + # how much stride to take between chunks. + max_query_length: 64 + # The maximum number of tokens for the question. + # Questions longer than this will be truncated to + # this length. + max_seq_length: 384 + # The maximum total input sequence length after + # WordPiece tokenization. Sequences longer than this + # will be truncated, and sequences shorter than this + # will be padded. + max_answer_length: 30 + # The maximum length of an answer that can be + # generated. This is needed because the start + # and end predictions are not conditioned + # on one another. + null_score_diff_threshold: 0.0 + # If null_score - best_non_null is greater than the threshold predict null. + n_best_size: 20 + # The total number of n-best predictions to generate at testing. + use_cache: true + do_lower_case: true + # if true does lower case + + num_workers: 2 + pin_memory: false + drop_last: false + + train_ds: + file: null # .json file + batch_size: 24 # per GPU + shuffle: true + num_samples: -1 + # Default values for the following params are retrieved from dataset config section, but you may override them + num_workers: ${model.dataset.num_workers} + drop_last: ${model.dataset.drop_last} + pin_memory: ${model.dataset.pin_memory} + + validation_ds: + file: null # .json file + batch_size: 24 # per GPU + shuffle: false + num_samples: -1 + # Default values for the following params are retrieved from dataset config section, but you may override them + num_workers: ${model.dataset.num_workers} + drop_last: ${model.dataset.drop_last} + pin_memory: ${model.dataset.pin_memory} + + test_ds: + file: null # .json file + batch_size: 24 # per GPU + shuffle: false + num_samples: -1 + # Default values for the following params are retrieved from dataset config section, but you may override them + num_workers: ${model.dataset.num_workers} + drop_last: ${model.dataset.drop_last} + pin_memory: ${model.dataset.pin_memory} + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # tokenizer that inherits from TokenizerSpec + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null # expand the following to a dictionary if special tokens need to be added. + # only necessary for adding transformer/bert-specific special tokens to tokenizer if the tokenizer does not already have these inherently. + + language_model: + pretrained_model_name: bert-base-uncased # BERT-like model name + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null # if specified initializes model from scratch + + token_classifier: + num_layers: 1 + dropout: 0.0 + num_classes: 2 + activation: relu + log_softmax: false + use_transformer_init: true + + + optim: + name: adamw + lr: 3e-5 + weight_decay: 0.0 + sched: + name: SquareRootAnnealing + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + + # scheduler config override + warmup_steps: null + warmup_ratio: 0.0 + last_epoch: -1 + +exp_manager: + exp_dir: null # where to store logs and checkpoints + name: *name # name of experiment + create_tensorboard_logger: True + create_checkpoint_callback: True + +hydra: + run: + dir: . + job_logging: + root: + handlers: null \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/question_answering/get_squad.py b/tts/NeMo/examples/nlp/question_answering/get_squad.py new file mode 100755 index 0000000..255b040 --- /dev/null +++ b/tts/NeMo/examples/nlp/question_answering/get_squad.py @@ -0,0 +1,68 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os +import urllib.request + +from nemo.utils import logging + + +class SquadDownloader: + def __init__(self, save_path): + self.save_path = save_path + '/squad' + + if not os.path.exists(self.save_path): + os.makedirs(self.save_path) + + if not os.path.exists(self.save_path + '/v1.1'): + os.makedirs(self.save_path + '/v1.1') + + if not os.path.exists(self.save_path + '/v2.0'): + os.makedirs(self.save_path + '/v2.0') + + self.download_urls = { + 'https://rajpurkar.github.io/SQuAD-explorer' '/dataset/train-v1.1.json': 'v1.1/train-v1.1.json', + 'https://rajpurkar.github.io/SQuAD-explorer' '/dataset/dev-v1.1.json': 'v1.1/dev-v1.1.json', + 'https://rajpurkar.github.io/SQuAD-explorer' '/dataset/train-v2.0.json': 'v2.0/train-v2.0.json', + 'https://rajpurkar.github.io/SQuAD-explorer' '/dataset/dev-v2.0.json': 'v2.0/dev-v2.0.json', + } + + def download(self): + for item in self.download_urls: + url = item + file = self.download_urls[item] + + logging.info('Downloading: %s', url) + if os.path.isfile(self.save_path + '/' + file): + logging.info('** Download file already exists, skipping download') + else: + response = urllib.request.urlopen(url) + with open(self.save_path + '/' + file, "wb") as handle: + handle.write(response.read()) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Download Squad') + parser.add_argument( + '--destDir', + type=str, + required=False, + help='directory to store data', + default=os.path.split(os.path.abspath(__file__))[0], + ) + args = parser.parse_args() + logging.info(args.destDir) + squad_dl = SquadDownloader(args.destDir) + squad_dl.download() diff --git a/tts/NeMo/examples/nlp/question_answering/question_answering_squad.py b/tts/NeMo/examples/nlp/question_answering/question_answering_squad.py new file mode 100644 index 0000000..269b4bf --- /dev/null +++ b/tts/NeMo/examples/nlp/question_answering/question_answering_squad.py @@ -0,0 +1,134 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + + +""" +This script contains an example on how to train, evaluate and perform inference with the question answering model. +The QAModel in NeMo supports extractive question answering problems for data in the SQuAD (https://rajpurkar.github.io/SQuAD-explorer/) format. + +***Data format*** +The QAModel requires a JSON file for each dataset split. +In the following we will show example for a training file. Each title has one or multiple paragraph entries, each consisting of the text - "context", and question-answer entries. Each question-answer entry has: +* a question +* a globally unique id +* a boolean flag "is_impossible" which shows if the question is answerable or not +* in case the question is answerable one answer entry, which contains the text span and its starting character index in the context. If not answerable, the "answers" list is empty + +The evaluation file follows the above format except for it can provide more than one answers to the same question. +The inference file follows the above format except for it does not require the "answers" and "is_impossible" keywords. + + +***Downloading the dataset*** +Run ./NeMo/examples/nlp/question_answering/get_squad.py to download the SQuAD dataset: + +# python get_squad.py --destDir= + +***Setting the configs*** +The model and the PT trainer are defined in a config file which declares multiple important sections. +The most important ones are: + model: All arguments that are related to the Model - language model, tokenizer, token classifier, optimizer, + schedulers, and datasets/data loaders. + trainer: Any argument to be passed to PyTorch Lightning including number of epochs, number of GPUs, + precision level, etc. + +This script uses the `/examples/nlp/question_answering/conf/question_answering_squad_config.yaml` config file +by default. You may update the config file from the file directly. The other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + + +***Model Training*** +# python question_answering_squad.py + model.train_ds.file= + model.validation_ds= + trainer.max_epochs= + trainer.gpus=[] + + +***Model Evaluation*** +Set `do_training=False` in the script and run: + +# python question_answering_squad.py + model.test_file= + +To load a pretrained checkpoint from cloud prior to training (e.g. for fine-tuning) or evaluation you can set cfg.from_pretrained=, +e.g. MODEL_NAME='BERTBaseUncasedSQuADv1.1'. You can find all pretrained model names by using +QAModel.list_available_models(). To load a local checkpoint use qa_model.restore_from() + + +***Model Inference*** +For inference use + qa_model.inference( + file=, + batch_size=, + output_nbest_file=, + output_prediction_file= + ) + +More details on how to use this script can be found in +./NeMo/tutorials/nlp/Question_Answering_Squad.ipynb +""" + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.question_answering.qa_model import QAModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="question_answering_squad_config") +def main(cfg: DictConfig) -> None: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + exp_dir = exp_manager(trainer, cfg.get("exp_manager", None)) + + if not cfg.pretrained_model: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + model = QAModel(cfg.model, trainer=trainer) + else: + logging.info(f'Loading pretrained model {cfg.pretrained_model}') + model = QAModel.from_pretrained(cfg.pretrained_model) + if cfg.do_training: + model.setup_training_data(train_data_config=cfg.model.train_ds) + model.setup_validation_data(val_data_config=cfg.model.validation_ds) + + if cfg.do_training: + trainer.fit(model) + if cfg.model.nemo_path: + model.save_to(cfg.model.nemo_path) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.file is not None: + trainer.test(model) + + # change to path if you want results to be written to file e.g. os.path.join(exp_dir, "output_nbest_file.txt") + output_nbest_file = None + # change to path if you want results to be written to file e.g. os.path.join(exp_dir, "output_prediction_file.txt") + output_prediction_file = None + inference_samples = 5 # for test purposes. To use entire inference dataset set to -1 + all_preds, all_nbests = model.inference( + file=cfg.model.validation_ds.file, + batch_size=1, + num_samples=inference_samples, + output_nbest_file=output_nbest_file, + output_prediction_file=output_prediction_file, + ) + + for _, item in all_preds.items(): + print(f"question: {item[0]} answer: {item[1]}") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/text2sparql/conf/text2sparql_config.yaml b/tts/NeMo/examples/nlp/text2sparql/conf/text2sparql_config.yaml new file mode 100644 index 0000000..1603279 --- /dev/null +++ b/tts/NeMo/examples/nlp/text2sparql/conf/text2sparql_config.yaml @@ -0,0 +1,105 @@ +# Text2Sparql with BART + +name: &name Text2Sparql + +trainer: + gpus: 1 # the number of gpus, 0 for CPU, or list with gpu indices + num_nodes: 1 + max_epochs: 2 # the number of training epochs + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + accelerator: ddp + gradient_clip_val: 0.0 + log_every_n_steps: 1 + val_check_interval: 1.0 # check once per epoch .25 for 4 times per epoch + checkpoint_callback: false # provided by exp_manager + logger: false # provided by exp_manager + +model: + nemo_path: null # exported .nemo path + max_seq_length: 150 + batch_size: 16 + convert_labels: true # true if Bart, false otherwise (converts pad_id to -100 for masked loss) + data_dir: null + + language_model: + pretrained_model_name: facebook/bart-base # huggingface end-to-end model name + pretrained_encoder_model_name: null # huggingface encoder model name + pretrained_decoder_model_name: null # huggingface decoder model name + lm_checkpoint: null + config: null + config_file: null # json file, precedence over config + + encoder_tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # tokenizer that inherits from TokenizerSpec + vocab_file: null # path to vocab file + tokenizer_model: null # tokenizer model for sentencepiece + special_tokens: null + add_special_tokens: true + + decoder_tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # tokenizer that inherits from TokenizerSpec + vocab_file: null # path to vocab file + tokenizer_model: null # tokenizer model for sentencepiece + special_tokens: null + add_special_tokens: true + + train_ds: + filepath: ${model.data_dir}/train.tsv # path to data file + shuffle: true + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + validation_ds: + filepath: ${model.data_dir}/test_easy.tsv # path to data file + shuffle: false + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + test_ds: + filepath: ${model.data_dir}/test_hard.tsv # path to data file + shuffle: false + num_samples: -1 + num_workers: 2 + drop_last: false + pin_memory: false + + optim: + name: adamw + lr: 4e-5 + weight_decay: 0.0 + + sched: + name: CosineAnnealing + warmup_steps: null + warmup_ratio: 0.06 + min_lr: 0.0 + last_epoch: -1 + + generate: + max_length: ${model.max_seq_length} + num_beams: 1 + length_penalty: 2.0 + early_stopping: true + repetition_penalty: 1.0 + do_sample: false + top_k: null + top_p: null + num_return_sequences: 1 + +exp_manager: + exp_dir: null # where to store logs and checkpoints + name: *name # name of experiment + create_tensorboard_logger: True + create_checkpoint_callback: True + +hydra: + run: + dir: . + job_logging: + root: + handlers: null \ No newline at end of file diff --git a/tts/NeMo/examples/nlp/text2sparql/data/import_datasets.py b/tts/NeMo/examples/nlp/text2sparql/data/import_datasets.py new file mode 100644 index 0000000..ce5f863 --- /dev/null +++ b/tts/NeMo/examples/nlp/text2sparql/data/import_datasets.py @@ -0,0 +1,134 @@ +# Copyright (c) 2020, MeetKai Inc. All rights reserved. +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script downloads Text2Sparql data and processes it into NeMo's neural machine translation dataset format. + +Text2Sparql data consists of 3 files which are saved to source_data_dir: + - train_queries_v3.tsv + - test_easy_queries_v3.tsv + - test_hard_queries_v3.tsv + +After processing, the script saves them to the target_data_dir as: + - train.tsv + - test_easy.tsv + - test_hard.tsv + + +You may run it with: + +python import_datasets \ + --source_data_dir ./text2sparql_src \ + --target_data_dir ./text2sparql_tgt +""" + +import argparse +import csv +import os +from urllib.request import Request, urlopen + +from nemo.collections.nlp.data.data_utils.data_preprocessing import MODE_EXISTS_TMP, if_exist +from nemo.utils import logging + +base_url = "https://m.meetkai.com/public_datasets/knowledge/" +prefix_map = { + "train_queries_v3.tsv": "train.tsv", + "test_easy_queries_v3.tsv": "test_easy.tsv", + "test_hard_queries_v3.tsv": "test_hard.tsv", +} + + +def download_text2sparql(infold: str): + """Downloads text2sparql train, test_easy, and test_hard data + + Args: + infold: save directory path + """ + os.makedirs(infold, exist_ok=True) + + for prefix in prefix_map: + url = base_url + prefix + + logging.info(f"Downloading: {url}") + if if_exist(infold, [prefix]): + logging.info("** Download file already exists, skipping download") + else: + req = Request(url, headers={"User-Agent": "Mozilla/5.0"}) + with open(os.path.join(infold, prefix), "wb") as handle: + handle.write(urlopen(req, timeout=20).read()) + + +def process_text2sparql(infold: str, outfold: str, do_lower_case: bool): + """ Process and convert MeetKai's text2sparql datasets to NeMo's neural machine translation format. + + Args: + infold: directory path to raw text2sparql data containing + train.tsv, test_easy.tsv, test_hard.tsv + outfold: output directory path to save formatted data for NeuralMachineTranslationDataset + the first line is header (sentence [tab] label) + each line should be [sentence][tab][label] + do_lower_case: if true, convert all sentences and labels to lower + """ + logging.info(f"Processing Text2Sparql dataset and storing at: {outfold}") + + os.makedirs(outfold, exist_ok=True) + + dataset_name = "Text2Sparql" + for prefix in prefix_map: + input_file = os.path.join(infold, prefix) + output_file = os.path.join(outfold, prefix_map[prefix]) + + if if_exist(outfold, [prefix_map[prefix]]): + logging.info(f"** {MODE_EXISTS_TMP.format(prefix_map[prefix], dataset_name, output_file)}") + continue + + if not if_exist(infold, [prefix]): + logging.info(f"** {prefix} of {dataset_name}" f" is skipped as it was not found") + continue + + assert input_file != output_file, "input file cannot equal output file" + with open(input_file, "r") as in_file: + with open(output_file, "w") as out_file: + reader = csv.reader(in_file, delimiter="\t") + + # replace headers + out_file.write("sentence\tlabel\n") + next(reader) + + for line in reader: + sentence = line[0] + label = line[1] + if do_lower_case: + sentence = sentence.lower() + label = label.lower() + out_file.write(f"{sentence}\t{label}\n") + + +if __name__ == "__main__": + # Parse the command-line arguments. + parser = argparse.ArgumentParser(description="Process and convert datasets into NeMo's format") + parser.add_argument( + "--source_data_dir", required=True, type=str, help="Path to the folder containing the dataset files" + ) + parser.add_argument("--target_data_dir", required=True, type=str, help="Path to save the processed dataset") + parser.add_argument("--do_lower_case", action="store_true") + args = parser.parse_args() + + source_dir = args.source_data_dir + target_dir = args.target_data_dir + do_lower_case = args.do_lower_case + + download_text2sparql(infold=source_dir) + process_text2sparql(infold=source_dir, outfold=target_dir, do_lower_case=do_lower_case) diff --git a/tts/NeMo/examples/nlp/text2sparql/evaluate_text2sparql.py b/tts/NeMo/examples/nlp/text2sparql/evaluate_text2sparql.py new file mode 100644 index 0000000..050d142 --- /dev/null +++ b/tts/NeMo/examples/nlp/text2sparql/evaluate_text2sparql.py @@ -0,0 +1,72 @@ +# Copyright (c) 2020, MeetKai Inc. All rights reserved. +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script contains an example on how to evaluate a NeuralMachineTranslationModel. +To load the example Text2Sparql dataset, please refer to ./data/import_datasets.py. +To train a model, please refer to text2sparql.py. + + +***Setting the configs*** +This script uses the `/examples/nlp/text2sparql/conf/text2sparql_config.yaml` config file by default. +You may update the config file from the file directly or by using the command line arguments. +Another other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +Please refer to text2sparql.py for detailed instructions on setting the configuration. + + +***How to run the script?*** +- To reload and evaluate the model, run: + +python evaluate_text2sparql.py \ + model.test_ds.filepath="$TGT_DATA_DIR"/test_easy.tsv \ + model.batch_size=16 \ + model.nemo_path=./NeMo_logs/bart.nemo \ + exp_manager.exp_dir=./NeMo_logs +""" + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.neural_machine_translation import NeuralMachineTranslationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging + + +@hydra_runner(config_path="conf", config_name="text2sparql_config") +def main(cfg: DictConfig) -> None: + logging.info(f"Config:\n {OmegaConf.to_yaml(cfg)}") + trainer = pl.Trainer(gpus=cfg.trainer.gpus) + nmt_model = NeuralMachineTranslationModel.restore_from(restore_path=cfg.model.nemo_path) + nmt_model.setup_test_data(cfg.model.test_ds) + results = trainer.test(nmt_model) + + with open(cfg.model.test_ds.filepath, "r") as f: + lines = f.readlines() + + lines[0] = lines[0].strip() + f"\tpredictions\n" + for i, res in enumerate(results[0]["texts"]): + lines[i + 1] = lines[i + 1].strip() + f"\t{res}\n" + + savepath = os.path.join(cfg.exp_manager.exp_dir, os.path.basename(cfg.model.test_ds.filepath)) + with open(savepath, "w") as f: + f.writelines(lines) + logging.info(f"Predictions saved to {savepath}") + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/examples/nlp/text2sparql/text2sparql.py b/tts/NeMo/examples/nlp/text2sparql/text2sparql.py new file mode 100644 index 0000000..062094c --- /dev/null +++ b/tts/NeMo/examples/nlp/text2sparql/text2sparql.py @@ -0,0 +1,112 @@ +# Copyright (c) 2020, MeetKai Inc. All rights reserved. +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script contains an example on how to train and save a NeuralMachineTranslationModel. +NeuralMachineTranslationModel in NeMo supports sequence to sequence problems such as language translation +and text summarization, provided the data follows the format specified below. + + +***Data format*** +NeuralMachineTranslationModel requires the data to be stored in TAB separated files (.tsv) with two columns of +sentence and label, where the first line is a header of format: + sentence[TAB]label +And each line is of the format: + [SENTENCE][TAB][LABEL] + +If your dataset is stored in another format, you need to convert it to this format to use a +NeuralMachineTranslationModel. + + +***Setting the configs*** +This script uses the `/examples/nlp/text2sparql/conf/text2sparql_config.yaml` config file by default. +You may update the config file from the file directly or by using the command line arguments. +Another other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +A NeuralMachineTranslationModel's config file declares multiple import sections. They are: + - trainer: Arguments to be passed to PyTorch Lightning. + - model: All arguments that relate to the Model - language_model, tokenizers, datasets, optimizer, generate. + - exp_manager: Arguments to be passed to NeMo's experiment manager. + - hydra: Arguments to be passed to Hydra. + +If using text2sparql_config.yaml, you must first update the following fields in the config: + - model.nemo_path: Model save path. Eg. [PATH]/bart.nemo + - model.data_dir: Path to data directory. Alternatively, you can adjust the file paths directly: + - model.train_ds.filepath + - model.validation_ds.filepath + - model.test_ds.filepath + - exp_manager.exp_dir: Directory to log results from the experiment. + +It is highly recommended to also adjust these parameters as necessary: + - trainer.gpus: Set to 0 to use CPU. Otherwise the number denotes the number of GPUs. + - trainer.max_epochs: Maximum number of epochs to train for. + - model.batch_size: 8 is sufficient to train a decent Bart model for Text2Sparql. + - model.max_seq_length: Maximum (tokenized) sequence length. 150 is sufficient for Text2Sparql. + - model.language_model.pretrained_model_name: End2end pretrained model name from huggingface. + - model.encoder_tokenizer.tokenizer_name: Pretrained tokenizer name from huggingface. + - model.decoder_tokenizer.tokenizer_name: The same as above, as the tokenizer will handle encoding and decoding. + - model.optim.lr: Learning rate. + +You can also specify an encoder and decoder rather than using an end2end model like Bart by defining these parameters: + - model.language_model.pretrained_encoder_model_name: Pretrained huggingface encoder model name. + - model.encoder_tokenizer.tokenizer_name: Pretrained huggingface encoder tokenizer name. + - model.language_model.pretrained_decoder_model_name: Pretrained huggingface decoder model name. + - model.decoder_tokenizer.tokenizer_name: Pretrained huggingface decoder tokenizer name. + - model.language_model.pretrained_model_name: Set this to null. + + +***How to run the script?*** +- First, download the data to TGT_DATA_DIR (see ./data/import_datasets.py): + +SRC_DATA_DIR=./data/text2sparql_src +TGT_DATA_DIR=./data/text2sparql_tgt + +python ./data/import_datasets.py \ + --source_data_dir $SRC_DATA_DIR \ + --target_data_dir $TGT_DATA_DIR + +- And run the following to train and save the model: + +python text2sparql.py \ + model.train_ds.filepath="$TGT_DATA_DIR"/train.tsv \ + model.validation_ds.filepath="$TGT_DATA_DIR"/test_easy.tsv \ + model.test_ds.filepath="$TGT_DATA_DIR"/test_hard.tsv \ + model.batch_size=16 \ + model.nemo_path=./NeMo_logs/bart.nemo \ + exp_manager.exp_dir=./NeMo_logs +""" + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.neural_machine_translation import NeuralMachineTranslationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="text2sparql_config") +def main(cfg: DictConfig) -> None: + logging.info(f"Config:\n {OmegaConf.to_yaml(cfg)}") + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + nmt_model = NeuralMachineTranslationModel(cfg.model, trainer=trainer) + trainer.fit(nmt_model) + if cfg.model.nemo_path: + nmt_model.save_to(cfg.model.nemo_path) + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/examples/nlp/text_classification/conf/text_classification_config.yaml b/tts/NeMo/examples/nlp/text_classification/conf/text_classification_config.yaml new file mode 100644 index 0000000..8470991 --- /dev/null +++ b/tts/NeMo/examples/nlp/text_classification/conf/text_classification_config.yaml @@ -0,0 +1,119 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# Config file for text classification with pre-trained BERT models + +trainer: + gpus: 1 # number of GPUs (0 for CPU), or list of the GPUs to use e.g. [0, 1] + num_nodes: 1 + max_epochs: 100 + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP. + accelerator: ddp + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it + + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + +model: + nemo_path: text_classification_model.nemo # filename to save the model and associated artifacts to .nemo file + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null + + language_model: + pretrained_model_name: bert-base-uncased + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null + + classifier_head: + num_output_layers: 2 + fc_dropout: 0.1 + + class_labels: + class_labels_file : null # optional to specify a file containing the list of the labels + + dataset: + num_classes: ??? # The number of classes. 0 < Label ", "") + outfiles[mode].write(f'{review}\t{label}\n') + + for mode in modes: + outfiles[mode].close() + + class_labels_file = open(os.path.join(outfold, 'label_ids.tsv'), 'w') + class_labels_file.write('negative\npositive\n') + class_labels_file.close() + + +def process_sst2(infold, outfold, uncased, splits=['train', 'dev']): + """Process sst2 dataset.""" + # "test" split doesn't have labels, so it is skipped + if not os.path.exists(infold): + link = 'https://dl.fbaipublicfiles.com/glue/data/SST-2.zip' + raise ValueError( + f'Data not found at {infold}. Please download SST-2 dataset from `{link}` and ' + f'extract it into the folder specified by `source_data_dir` argument.' + ) + + logging.info(f'Processing SST-2 dataset') + os.makedirs(outfold, exist_ok=True) + + def _read_tsv(input_file, quotechar=None): + """Read a tab separated value file.""" + with open(input_file, "r") as f: + reader = csv.reader(f, delimiter="\t", quotechar=quotechar) + lines = [] + for line in reader: + lines.append(line) + return lines + + for split in splits: + # Load input file. + input_file = os.path.join(infold, split + '.tsv') + lines = _read_tsv(input_file) + # Create output. + outfile = open(os.path.join(outfold, split + '.tsv'), 'w') + + # Copy lines, skip the header (line 0). + for line in lines[1:]: + text = line[0] + label = line[1] + # Lowercase when required. + if uncased: + text = text.lower() + # Write output. + outfile.write(f'{text}\t{label}\n') + # Close file. + outfile.close() + + class_labels_file = open(os.path.join(outfold, 'label_ids.tsv'), 'w') + class_labels_file.write('negative\npositive\n') + class_labels_file.close() + + logging.info(f'Result stored at {outfold}') + + +def process_chemprot(source_dir, target_dir, uncased, modes=['train', 'test', 'dev']): + if not os.path.exists(source_dir): + link = 'https://github.com/arwhirang/recursive_chemprot/tree/master/Demo/tree_LSTM/data' + raise ValueError(f'Data not found at {source_dir}. ' f'Please download ChemProt from {link}.') + + logging.info(f'Processing Chemprot dataset and store at {target_dir}') + os.makedirs(target_dir, exist_ok=True) + + naming_map = {'train': 'trainingPosit_chem', 'test': 'testPosit_chem', 'dev': 'developPosit_chem'} + + def _read_tsv(input_file, quotechar=None): + """Reads a tab separated value file.""" + with open(input_file, "r") as f: + reader = csv.reader(f, delimiter="\t", quotechar=quotechar) + lines = [] + for line in reader: + lines.append(line) + return lines + + outfiles = {} + label_mapping = {} + out_label_mapping = open(os.path.join(target_dir, 'label_mapping.tsv'), 'w') + for mode in modes: + outfiles[mode] = open(os.path.join(target_dir, mode + '.tsv'), 'w') + input_file = os.path.join(source_dir, naming_map[mode]) + lines = _read_tsv(input_file) + for line in lines: + text = line[1] + label = line[2] + if label == "True": + label = line[3] + if uncased: + text = text.lower() + if label not in label_mapping: + out_label_mapping.write(f'{label}\t{len(label_mapping)}\n') + label_mapping[label] = len(label_mapping) + label = label_mapping[label] + outfiles[mode].write(f'{text}\t{label}\n') + for mode in modes: + outfiles[mode].close() + out_label_mapping.close() + + +def process_thucnews(infold, outfold): + modes = ['train', 'test'] + train_size = 0.8 + if not os.path.exists(infold): + link = 'thuctc.thunlp.org/' + raise ValueError(f'Data not found at {infold}. ' f'Please download THUCNews from {link}.') + + logging.info(f'Processing THUCNews dataset and store at {outfold}') + os.makedirs(outfold, exist_ok=True) + + outfiles = {} + for mode in modes: + outfiles[mode] = open(os.path.join(outfold, mode + '.tsv'), 'a+', encoding='utf-8') + categories = ['体育', '娱乐', '家居', '彩票', '房产', '教育', '时尚', '时政', '星座', '游戏', '社会', '科技', '股票', '财经'] + for category in categories: + label = categories.index(category) + category_files = glob.glob(f'{infold}/{category}/*.txt') + test_num = int(len(category_files) * (1 - train_size)) + test_files = category_files[:test_num] + train_files = category_files[test_num:] + + for mode in modes: + logging.info(f'Processing {mode} data of the category {category}') + if mode == 'test': + files = test_files + else: + files = train_files + + if len(files) == 0: + logging.info(f'Skipping category {category} for {mode} mode') + continue + + for file in tqdm.tqdm(files): + with open(file, 'r', encoding='utf-8') as f: + news = f.read().strip().replace('\r', '') + news = news.replace('\n', '').replace('\t', ' ') + outfiles[mode].write(f'{news}\t{label}\n') + for mode in modes: + outfiles[mode].close() + + +if __name__ == "__main__": + # Parse the command-line arguments. + parser = argparse.ArgumentParser(description="Process and convert datasets into NeMo\'s format.") + parser.add_argument("--dataset_name", required=True, type=str, choices=['imdb', 'thucnews', 'chemprot']) + parser.add_argument( + "--source_data_dir", required=True, type=str, help='The path to the folder containing the dataset files.' + ) + parser.add_argument("--target_data_dir", required=True, type=str) + parser.add_argument("--do_lower_case", action='store_true') + args = parser.parse_args() + + dataset_name = args.dataset_name + do_lower_case = args.do_lower_case + source_dir = args.source_data_dir + target_dir = args.target_data_dir + + if not exists(source_dir): + raise FileNotFoundError(f"{source_dir} does not exist.") + + if dataset_name == 'imdb': + process_imdb(source_dir, target_dir, do_lower_case) + elif dataset_name == 'thucnews': + process_thucnews(source_dir, target_dir) + elif dataset_name == "chemprot": + process_chemprot(source_dir, target_dir, do_lower_case) + elif dataset_name == "sst-2": + process_sst2(source_dir, target_dir, do_lower_case) + else: + raise ValueError( + f'Dataset {dataset_name} is not supported.' + + "Please make sure that you build the preprocessing process for it. " + + "NeMo's format assumes that a data file has a header and each line of the file follows " + + "the format: text [TAB] label. Label is assumed to be an integer." + ) diff --git a/tts/NeMo/examples/nlp/text_classification/model_parallel_text_classification_evaluation.py b/tts/NeMo/examples/nlp/text_classification/model_parallel_text_classification_evaluation.py new file mode 100644 index 0000000..255a27e --- /dev/null +++ b/tts/NeMo/examples/nlp/text_classification/model_parallel_text_classification_evaluation.py @@ -0,0 +1,41 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +""" +This script runs model parallel text classification evaluation. +""" +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.text_classification import TextClassificationModel +from nemo.collections.nlp.parts.nlp_overrides import NLPDDPPlugin +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="text_classification_config") +def main(cfg: DictConfig) -> None: + logging.info(f'\nConfig Params:\n{OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(plugins=[NLPDDPPlugin()], **cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + # TODO: can we drop strict=False + model = TextClassificationModel.restore_from(cfg.model.nemo_path, trainer=trainer, strict=False) + model.setup_test_data(test_data_config=cfg.model.test_ds) + + trainer.test(model=model, ckpt_path=None) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/text_classification/text_classification_with_bert.py b/tts/NeMo/examples/nlp/text_classification/text_classification_with_bert.py new file mode 100644 index 0000000..1cad923 --- /dev/null +++ b/tts/NeMo/examples/nlp/text_classification/text_classification_with_bert.py @@ -0,0 +1,154 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script contains an example on how to train, evaluate and perform inference with the TextClassificationModel. +TextClassificationModel in NeMo supports text classification problems such as sentiment analysis or +domain/intent detection for dialogue systems, as long as the data follows the format specified below. + +***Data format*** +TextClassificationModel requires the data to be stored in TAB separated files (.tsv) with two columns of sentence and +label. Each line of the data file contains text sequences, where words are separated with spaces and label separated +with [TAB], i.e.: + +[WORD][SPACE][WORD][SPACE][WORD][TAB][LABEL] + +For example: + +hide new secretions from the parental units[TAB]0 +that loves its characters and communicates something rather beautiful about human nature[TAB]1 +... + +If your dataset is stored in another format, you need to convert it to this format to use the TextClassificationModel. + + +***Setting the configs*** +The model and the PT trainer are defined in a config file which declares multiple important sections. +The most important ones are: + model: All arguments that are related to the Model - language model, tokenizer, head classifier, optimizer, + schedulers, and datasets/data loaders. + trainer: Any argument to be passed to PyTorch Lightning including number of epochs, number of GPUs, + precision level, etc. + +This script uses the `/examples/nlp/text_classification/conf/text_classification_config.yaml` default config file +by default. You may update the config file from the file directly or by using the command line arguments. +Other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +You first need to set the num_classes in the config file which specifies the number of classes in the dataset. +Notice that some config lines, including `model.dataset.classes_num`, have `???` as their value, this means that values +for these fields are required to be specified by the user. We need to specify and set the `model.train_ds.file_name`, +`model.validation_ds.file_name`, and `model.test_ds.file_name` in the config file to the paths of the train, validation, + and test files if they exist. We may do it by updating the config file or by setting them from the command line. + + +***How to run the script?*** +For example the following would train a model for 50 epochs in 2 GPUs on a classification task with 2 classes: + +# python text_classification_with_bert.py + model.dataset.num_classes=2 + model.train_ds=PATH_TO_TRAIN_FILE + model.validation_ds=PATH_TO_VAL_FILE + trainer.max_epochs=50 + trainer.gpus=2 + +This script would also reload the last checkpoint after the training is done and does evaluation on the dev set, +then performs inference on some sample queries. + +By default, this script uses examples/nlp/text_classification/conf/text_classifciation_config.py config file, and +you may update all the params in the config file from the command line. You may also use another config file like this: + +# python text_classification_with_bert.py --config-name==PATH_TO_CONFIG_FILE + model.dataset.num_classes=2 + model.train_ds=PATH_TO_TRAIN_FILE + model.validation_ds=PATH_TO_VAL_FILE + trainer.max_epochs=50 + trainer.gpus=2 + +***Load a saved model*** +This script would save the model after training into '.nemo' checkpoint file specified by nemo_path of the model config. +You may restore the saved model like this: + model = TextClassificationModel.restore_from(restore_path=NEMO_FILE_PATH) + +***Evaluation a saved model on another dataset*** +# If you wanted to evaluate the saved model on another dataset, you may restore the model and create a new data loader: + eval_model = TextClassificationModel.restore_from(restore_path=checkpoint_path) + +# Then, you may create a dataloader config for evaluation: + eval_config = OmegaConf.create( + {'file_path': cfg.model.test_ds.file_path, 'batch_size': 64, 'shuffle': False, 'num_workers': 3} + ) + eval_model.setup_test_data(test_data_config=eval_config) + +# You need to create a new trainer: + eval_trainer = pl.Trainer(gpus=1) + eval_model.set_trainer(eval_trainer) + eval_trainer.test(model=eval_model, verbose=False) +""" +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models.text_classification import TextClassificationModel +from nemo.collections.nlp.parts.nlp_overrides import NLPDDPPlugin +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="text_classification_config") +def main(cfg: DictConfig) -> None: + logging.info(f'\nConfig Params:\n{OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(plugins=[NLPDDPPlugin()], **cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + if not cfg.model.train_ds.file_path: + raise ValueError("'train_ds.file_path' need to be set for the training!") + + model = TextClassificationModel(cfg.model, trainer=trainer) + logging.info("===========================================================================================") + logging.info('Starting training...') + trainer.fit(model) + logging.info('Training finished!') + logging.info("===========================================================================================") + + if cfg.model.nemo_path: + # '.nemo' file contains the last checkpoint and the params to initialize the model + model.save_to(cfg.model.nemo_path) + logging.info(f'Model is saved into `.nemo` file: {cfg.model.nemo_path}') + + # We evaluate the trained model on the test set if test_ds is set in the config file + if cfg.model.test_ds.file_path: + logging.info("===========================================================================================") + logging.info("Starting the testing of the trained model on test set...") + trainer.test(model=model, ckpt_path=None, verbose=False) + logging.info("Testing finished!") + logging.info("===========================================================================================") + + # perform inference on a list of queries. + if "infer_samples" in cfg.model and cfg.model.infer_samples: + logging.info("===========================================================================================") + logging.info("Starting the inference on some sample queries...") + + # max_seq_length=512 is the maximum length BERT supports. + results = model.classifytext(queries=cfg.model.infer_samples, batch_size=16, max_seq_length=512) + logging.info('The prediction results of some sample queries with the trained model:') + for query, result in zip(cfg.model.infer_samples, results): + logging.info(f'Query : {query}') + logging.info(f'Predicted label: {result}') + + logging.info("Inference finished!") + logging.info("===========================================================================================") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml b/tts/NeMo/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml new file mode 100644 index 0000000..0d27907 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml @@ -0,0 +1,133 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# Punctuation and capitalization model with pretrained BERT-like models + +pretrained_model: null # pretrained Punctuation and Capitalization model from list_available_models(), for example: +# punctuation_en_bert or punctuation_en_distilbert +# or your_model.nemo +trainer: + gpus: 1 # the number of gpus, 0 for CPU + num_nodes: 1 + max_epochs: 3 + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0 + accelerator: ddp + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + +exp_manager: + exp_dir: null # exp_dir for your experiment, if None, defaults to "./nemo_experiments" + name: Punctuation_and_Capitalization # The name of your model + create_tensorboard_logger: true # Whether you want exp_manger to create a tb logger + create_checkpoint_callback: true # Whether you want exp_manager to create a model checkpoint callback + +model: + punct_label_ids: null # will be filled during training + capit_label_ids: null # will be filled during training + class_labels: + punct_labels_file: punct_label_ids.csv + capit_labels_file: capit_label_ids.csv + dataset: + data_dir: ??? # /path/to/training/data + # parameters for dataset preprocessing + max_seq_length: 128 + pad_label: 'O' + ignore_extra_tokens: false + ignore_start_end: false + use_cache: true + # shared among dataloaders + num_workers: 2 + pin_memory: false + drop_last: false + + train_ds: + text_file: text_train.txt + labels_file: labels_train.txt + shuffle: true + num_samples: -1 + batch_size: 64 + + validation_ds: + # if evaluation data is not in the model.dataset.data_dir as the training data or multiple datasets are used for + # evaluation is needed, specify ds_item, otherwise by default data_dir is used + ds_item: null # expected format: [PATH_TO_DEV1,PATH_TO_DEV2] (Note no space between the paths and square brackets) + text_file: text_dev.txt + labels_file: labels_dev.txt + shuffle: false + num_samples: -1 + batch_size: 64 + + test_ds: + # if evaluation data is not in the model.dataset.data_dir as the training data or multiple datasets are used for + # evaluation is needed, specify ds_item, otherwise by default data_dir is used + ds_item: null # expected format: [PATH_TO_DEV1,PATH_TO_DEV2] (Note no space between the paths and square brackets) + text_file: text_dev.txt + labels_file: labels_dev.txt + shuffle: false + num_samples: -1 + batch_size: 64 + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null + + language_model: + pretrained_model_name: bert-base-uncased + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null + + punct_head: + punct_num_fc_layers: 1 + fc_dropout: 0.1 + activation: 'relu' + use_transformer_init: True + + capit_head: + capit_num_fc_layers: 1 + fc_dropout: 0.1 + activation: 'relu' + use_transformer_init: true + + optim: + name: adam + lr: 1e-4 + weight_decay: 0.00 + + sched: + name: WarmupAnnealing + # Scheduler params + warmup_steps: null + warmup_ratio: 0.1 + last_epoch: -1 + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/nlp/token_classification/conf/token_classification_config.yaml b/tts/NeMo/examples/nlp/token_classification/conf/token_classification_config.yaml new file mode 100644 index 0000000..8cb162a --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/conf/token_classification_config.yaml @@ -0,0 +1,119 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# Token Classification tasks (for example, Named Entity Recognition) with pretrained BERT-like models + +pretrained_model: null # pretrained TokenClassification model from list_available_models() or path to a .nemo file, +# for example: ner_en_bert or your_model.nemo +trainer: + gpus: 1 # the number of gpus, 0 for CPU + num_nodes: 1 + max_epochs: 5 + max_steps: null # precedence over max_epochs + accumulate_grad_batches: 1 # accumulates grads every k batches + gradient_clip_val: 0.0 + amp_level: O0 # O1/O2 for mixed precision + precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0 + accelerator: ddp + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc. + +exp_manager: + exp_dir: null # exp_dir for your experiment, if None, defaults to "./nemo_experiments" + name: token_classification_model # The name of your model + create_tensorboard_logger: true # Whether you want exp_manager to create a tb logger + create_checkpoint_callback: true # Whether you want exp_manager to create a model checkpoint callback + +model: + label_ids: null # will be filled during training + class_labels: + class_labels_file: label_ids.csv # will be generated during training and saved in .nemo file + dataset: + data_dir: ??? # /path/to/data + class_balancing: null # choose from [null, weighted_loss]. Weighted_loss enables the weighted class balancing of the loss, may be used for handling unbalanced classes + max_seq_length: 128 + pad_label: 'O' + ignore_extra_tokens: false + ignore_start_end: false + use_cache: true + # shared among dataloaders + num_workers: 2 + pin_memory: false + drop_last: false + + train_ds: + text_file: text_train.txt + labels_file: labels_train.txt + shuffle: true + num_samples: -1 + batch_size: 64 + + validation_ds: + text_file: text_dev.txt + labels_file: labels_dev.txt + shuffle: false + num_samples: -1 + batch_size: 64 + + test_ds: + text_file: text_dev.txt + labels_file: labels_dev.txt + shuffle: false + num_samples: -1 + batch_size: 64 + + tokenizer: + tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece + vocab_file: null # path to vocab file + tokenizer_model: null # only used if tokenizer is sentencepiece + special_tokens: null + + language_model: + pretrained_model_name: bert-base-uncased + lm_checkpoint: null + config_file: null # json file, precedence over config + config: null + + + head: + num_fc_layers: 2 + fc_dropout: 0.5 + activation: 'relu' + use_transformer_init: True + + optim: + name: adam + lr: 5e-5 + weight_decay: 0.00 + + sched: + name: WarmupAnnealing + # Scheduler params + warmup_steps: null + warmup_ratio: 0.1 + last_epoch: -1 + + # pytorch lightning args + monitor: val_loss + reduce_on_plateau: false + +hydra: + run: + dir: . + job_logging: + root: + handlers: null diff --git a/tts/NeMo/examples/nlp/token_classification/data/get_tatoeba_data.py b/tts/NeMo/examples/nlp/token_classification/data/get_tatoeba_data.py new file mode 100644 index 0000000..d895e81 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/data/get_tatoeba_data.py @@ -0,0 +1,242 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import logging +import os +import random +import re +import string +import subprocess + +from nemo.utils import logging + +URL = {'tatoeba': 'https://downloads.tatoeba.org/exports/sentences.csv'} + + +def __maybe_download_file(destination: str, source: str): + """ + Downloads source to destination if not exists. + If exists, skips download + Args: + destination: local filepath + source: url of resource + """ + source = URL[source] + if not os.path.exists(destination): + logging.info(f'Downloading {source} to {destination}') + subprocess.run(['wget', '-O', destination, source]) + else: + logging.info(f'{destination} found. Skipping download') + + +def __process_english_sentences( + in_file: str, out_file: str, percent_to_cut: float = 0, num_to_combine: int = 1, num_samples: int = -1 +): + """ + Extract English sentences from the Tatoeba dataset. + + Expected in_file format + that + contrain letters and punctuation marks (,.?). + Chop and combine sentences. + Args: + in_file: local filepath to the tatoeba dataset. + Format: id [TAB] region_name [TAB] sentence, + for example: "1276\teng\tLet's try something.\n" + out_file: local filepath to the clean dataset + percent_to_cut: Percent of sentences to cut in the middle + to get examples of incomplete sentences. + This could be useful since ASR output not always + represents a complete sentence + num_to_combine: Number of sentences to combine into + a single example + num_samples: Number of samples in the final dataset + """ + if not os.path.exists(in_file): + raise FileNotFoundError(f'{in_file} not found.') + + in_file = open(in_file, 'r') + out_file = open(out_file, 'w') + lines_to_combine = [] + samples_count = 0 + + for line in in_file: + line = line.split('\t') + # use only English sentences + if line[1] == 'eng': + line = line[2].strip() + if re.match("^[A-Z][A-Za-z.,'?\s]+$", line): # nopep8 + # chop some sentences in the middle + if percent_to_cut > 0: + line = line.split() + if random.random() < percent_to_cut: + line = line[: len(line) // 2] + line = ' '.join(line) + + # combine multiple sentences into a single example + # to make it harder for the model to learn eos punctuation + if len(lines_to_combine) >= num_to_combine: + if samples_count == num_samples: + return + out_file.write(' '.join(lines_to_combine) + '\n') + lines_to_combine = [] + samples_count += 1 + lines_to_combine.append(line) + + if len(lines_to_combine) > 0 and (samples_count < num_samples or num_samples < 0): + out_file.write(' '.join(lines_to_combine) + '\n') + + +def __split_into_train_dev(in_file: str, train_file: str, dev_file: str, percent_dev: float): + """ + Create train and dev split of the dataset. + Args: + in_file: local filepath to the dataset + train_file: local filepath to the train dataset + dev_file: local filepath to the dev dataset + percent_dev: Percent of the sentences in the dev set + """ + if not os.path.exists(in_file): + raise FileNotFoundError(f'{in_file} not found.') + + lines = open(in_file, 'r').readlines() + train_file = open(train_file, 'w') + dev_file = open(dev_file, 'w') + + dev_size = int(len(lines) * percent_dev) + train_file.write(' '.join(lines[:-dev_size])) + dev_file.write(' '.join(lines[-dev_size:])) + + +def remove_punctuation(word: str): + """ + Removes all punctuation marks from a word except for ' + that is often a part of word: don't, it's, and so on + """ + all_punct_marks = string.punctuation.replace("'", '') + return re.sub('[' + all_punct_marks + ']', '', word) + + +def create_text_and_labels(output_dir: str, file_path: str, punct_marks: str = ',.?'): + """ + Create datasets for training and evaluation. + + Args: + output_dir: path to the output data directory + file_path: path to file name + punct_marks: supported punctuation marks + + The data will be split into 2 files: text.txt and labels.txt. \ + Each line of the text.txt file contains text sequences, where words\ + are separated with spaces. The labels.txt file contains \ + corresponding labels for each word in text.txt, the labels are \ + separated with spaces. Each line of the files should follow the \ + format: \ + [WORD] [SPACE] [WORD] [SPACE] [WORD] (for text.txt) and \ + [LABEL] [SPACE] [LABEL] [SPACE] [LABEL] (for labels.txt).' + """ + if not os.path.exists(file_path): + raise ValueError(f'{file_path} not found') + + os.makedirs(output_dir, exist_ok=True) + + base_name = os.path.basename(file_path) + labels_file = os.path.join(output_dir, 'labels_' + base_name) + text_file = os.path.join(output_dir, 'text_' + base_name) + + with open(file_path, 'r') as f: + with open(text_file, 'w') as text_f: + with open(labels_file, 'w') as labels_f: + for line in f: + line = line.split() + text = '' + labels = '' + for word in line: + label = word[-1] if word[-1] in punct_marks else 'O' + word = remove_punctuation(word) + if len(word) > 0: + if word[0].isupper(): + label += 'U' + else: + label += 'O' + + word = word.lower() + text += word + ' ' + labels += label + ' ' + + text_f.write(text.strip() + '\n') + labels_f.write(labels.strip() + '\n') + + print(f'{text_file} and {labels_file} created from {file_path}.') + + +def __delete_file(file_to_del: str): + """ + Deletes the file + Args: + file_to_del: local filepath to the file to delete + """ + if os.path.exists(file_to_del): + os.remove(file_to_del) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Prepare tatoeba dataset') + parser.add_argument("--data_dir", required=True, type=str) + parser.add_argument("--dataset", default='tatoeba', type=str) + parser.add_argument("--num_samples", default=-1, type=int, help='-1 to use the whole dataset') + parser.add_argument("--percent_to_cut", default=0, type=float, help='Percent of sentences to cut in the middle') + parser.add_argument( + "--num_lines_to_combine", default=1, type=int, help='Number of lines to combine into single example' + ) + parser.add_argument("--percent_dev", default=0.2, type=float, help='Size of the dev set, float') + parser.add_argument("--clean_dir", action='store_true') + args = parser.parse_args() + + if not os.path.exists(args.data_dir): + os.makedirs(args.data_dir) + + if args.dataset != 'tatoeba': + raise ValueError("Unsupported dataset.") + + logging.info(f'Downloading tatoeba dataset') + tatoeba_dataset = os.path.join(args.data_dir, 'sentences.csv') + __maybe_download_file(tatoeba_dataset, args.dataset) + + logging.info(f'Processing English sentences...') + clean_eng_sentences = os.path.join(args.data_dir, 'clean_eng_sentences.txt') + __process_english_sentences( + tatoeba_dataset, clean_eng_sentences, args.percent_to_cut, args.num_lines_to_combine, args.num_samples + ) + + train_file = os.path.join(args.data_dir, 'train.txt') + dev_file = os.path.join(args.data_dir, 'dev.txt') + + logging.info( + f'Splitting the {args.dataset} dataset into train and dev sets' + ' and creating labels and text files' + ) + __split_into_train_dev(clean_eng_sentences, train_file, dev_file, args.percent_dev) + + logging.info(f'Creating text and label files for training') + create_text_and_labels(args.data_dir, os.path.join(args.data_dir, 'train.txt')) + create_text_and_labels(args.data_dir, os.path.join(args.data_dir, 'dev.txt')) + + if args.clean_dir: + logging.info(f'Cleaning up {args.data_dir}') + __delete_file(clean_eng_sentences) + __delete_file(tatoeba_dataset) + __delete_file(train_file) + __delete_file(dev_file) + logging.info(f'Processing of the {args.dataset} is complete') diff --git a/tts/NeMo/examples/nlp/token_classification/data/import_from_iob_format.py b/tts/NeMo/examples/nlp/token_classification/data/import_from_iob_format.py new file mode 100644 index 0000000..4a6f154 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/data/import_from_iob_format.py @@ -0,0 +1,124 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os + +from nemo.utils import logging + + +def __convert_data(in_file: str, out_text_f: str, out_labels_f: str, max_length: int): + """ + Convert data from the IOB format to NeMo accepted format described below. + in_file should be in the IOB format, see example here: + https://www.clips.uantwerpen.be/conll2003/ner/. + + Args: + in_file: input file name + out_text_f: output file with text + out_labels_f: output file with labels + max_length: use -1 to leave the examples' length as is, otherwise long examples will be split into multiple + examples + After the conversion, the dataset is split into 2 files: text.txt + and labels.txt. + Each line of the text.txt file contains text sequences, where words + are separated with spaces. The labels.txt file contains corresponding + labels for each word in text.txt, the labels are separated with spaces. + Each line of the files should follow the format: + [WORD] [SPACE] [WORD] [SPACE] [WORD] (for text.txt) and + [LABEL] [SPACE] [LABEL] [SPACE] [LABEL] (for labels.txt). + + """ + in_file = open(in_file, 'r') + + if max_length == -1: + with open(out_text_f, 'w') as out_text, open(out_labels_f, 'w') as out_labels: + for line in in_file: + if line == '\n': + out_text.write(line) + out_labels.write(line) + else: + line = line.split() + out_text.write(line[0] + ' ') + out_labels.write(line[-1] + ' ') + + else: + words = [] + labels = [] + with open(out_text_f, 'w') as out_text, open(out_labels_f, 'w') as out_labels: + lines = in_file.readlines() + for line_id, line in enumerate(lines): + logging.info(f"{line_id} {len(lines)}") + contends = line.strip() + if len(contends) == 0: + assert len(words) == len(labels) + if len(words) > max_length: + # split if the sentence is longer than max_length + while len(words) > max_length: + tmplabel = labels[:max_length] + for iidx in range(len(tmplabel)): + if tmplabel.pop() == 'O': + break + l = ' '.join([label for label in labels[: len(tmplabel) + 1] if len(label) > 0]) + w = ' '.join([word for word in words[: len(tmplabel) + 1] if len(word) > 0]) + + out_text.write(w + "\n") + out_labels.write(l + "\n") + words = words[len(tmplabel) + 1 :] + labels = labels[len(tmplabel) + 1 :] + + if len(words) == 0: + continue + l = ' '.join([label for label in labels if len(label) > 0]) + w = ' '.join([word for word in words if len(word) > 0]) + + out_text.write(w + "\n") + out_labels.write(l + "\n") + words = [] + labels = [] + continue + + word = line.strip().split()[0] + label = line.strip().split()[-1] + words.append(word) + labels.append(label) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Convert data from IOB format to the format compatible with \ + nlp/examples/token_classification/scripts/token_classification_train.py and \ + token_classification_evaluate.py' + ) + parser.add_argument("--data_file", required=True, type=str, help='path to a file in IOB format') + parser.add_argument( + "--max_length", + default=-1, + type=int, + help='use -1 to leave the examples\'s length as is, ' + 'otherwise long examples will be split into multiple examples', + ) + args = parser.parse_args() + + data_dir, basename = os.path.split(args.data_file) + prefix = os.path.splitext(basename)[0] + if not os.path.exists(args.data_file): + raise FileNotFoundError(f"{args.data_file} not found") + + logging.info(f'Processing {args.data_file}') + out_text = os.path.join(data_dir, 'text_' + prefix + '.txt') + out_labels = os.path.join(data_dir, 'labels_' + prefix + '.txt') + + __convert_data(args.data_file, out_text, out_labels, args.max_length) + logging.info(f'Processing of the {args.data_file} is complete') diff --git a/tts/NeMo/examples/nlp/token_classification/data/prepare_data_for_punctuation_capitalization.py b/tts/NeMo/examples/nlp/token_classification/data/prepare_data_for_punctuation_capitalization.py new file mode 100644 index 0000000..f31e6fc --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/data/prepare_data_for_punctuation_capitalization.py @@ -0,0 +1,99 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +""" +The script converts raw text to the NeMo format for punctuation and capitalization task. + +Raw Data Format +--------------- + +The Punctuation and Capitalization model can work with any text dataset, although it is recommended to balance the data, especially for the punctuation task. +Before pre-processing the data to the format expected by the model, the data should be split into train.txt and dev.txt (and optionally test.txt). +Each line in the **train.txt/dev.txt/test.txt** should represent one or more full and/or truncated sentences. + +Example of the train.txt/dev.txt file: + When is the next flight to New York? + The next flight is ... + .... + + +The `source_data_dir` structure should look like this: + . + |--sourced_data_dir + |-- dev.txt + |-- train.txt + + + +NeMo Data Format for training the model +--------------------------------------- + +The punctuation and capitalization model expects the data in the following format: + +The training and evaluation data is divided into 2 files: text.txt and labels.txt. \ +Each line of the **text.txt** file contains text sequences, where words are separated with spaces, i.e. + +[WORD] [SPACE] [WORD] [SPACE] [WORD], for example: + when is the next flight to new york + the next flight is ... + ... + +The **labels.txt** file contains corresponding labels for each word in text.txt, the labels are separated with spaces. \ +Each label in labels.txt file consists of 2 symbols: + +* the first symbol of the label indicates what punctuation mark should follow the word (where O means no punctuation needed); +* the second symbol determines if a word needs to be capitalized or not (where U indicates that the word should be upper cased, and O - no capitalization needed.) + +By default the following punctuation marks are considered: commas, periods, and question marks; the rest punctuation marks were removed from the data. +This can be changed by introducing new labels in the labels.txt files + +Each line of the labels.txt should follow the format: [LABEL] [SPACE] [LABEL] [SPACE] [LABEL] (for labels.txt). \ +For example, labels for the above text.txt file should be: + + OU OO OO OO OO OO OU ?U + OU OO OO OO ... + ... + +The complete list of all possible labels for this task used in this tutorial is: OO, ,O, .O, ?O, OU, ,U, .U, ?U. + +Converting Raw data to NeMo format +---------------------------------- + +To pre-process the raw text data, stored under :code:`sourced_data_dir` (see the :ref:`raw_data_format_punct` +section), run the following command: + + python examples/nlp/token_classification/data/prepare_data_for_punctuation_capitalization.py \ + -s + -o + +""" + +import argparse +import os + +from get_tatoeba_data import create_text_and_labels + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Prepare data for punctuation and capitalization tasks') + parser.add_argument("-s", "--source_file", required=True, type=str, help="Path to the source file") + parser.add_argument("-o", "--output_dir", required=True, type=str, help="Path to the output directory") + args = parser.parse_args() + + if not os.path.exists(args.source_file): + raise ValueError(f'{args.source_file} was not found') + + os.makedirs(args.output_dir, exist_ok=True) + create_text_and_labels(args.output_dir, args.source_file) + + print(f'Processing of the {args.source_file} is complete') diff --git a/tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_evaluate.py b/tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_evaluate.py new file mode 100644 index 0000000..b91b332 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_evaluate.py @@ -0,0 +1,127 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig + +from nemo.collections.nlp.models import PunctuationCapitalizationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +""" +This script shows how to perform evaluation and runs inference of a few examples. + +More details on the task and data format could be found in tutorials/nlp/Punctuation_and_Capitalization.ipynb + +*** Setting the configs *** + +This script uses the `/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml` config file +by default. You may update the config file from the file directly. +The other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +For more details about the config files and different ways of model restoration, see tutorials/00_NeMo_Primer.ipynb + + +*** Model Evaluation *** + + python punctuation_capitalization_evaluate.py \ + model.dataset.data_dir= \ + pretrained_model=punctuation_en_distilbert + + - a directory that contains test_ds.text_file and test_ds.labels_file (see the config) +pretrained_model - pretrained PunctuationCapitalizationModel model from list_available_models() or + path to a .nemo file, for example: punctuation_en_bert or your_model.nemo + +""" + + +@hydra_runner(config_path="conf", config_name="punctuation_capitalization_config") +def main(cfg: DictConfig) -> None: + logging.info( + 'During evaluation/testing, it is currently advisable to construct a new Trainer with single GPU and \ + no DDP to obtain accurate results' + ) + + if not hasattr(cfg.model, 'test_ds'): + raise ValueError(f'model.test_ds was not found in the config, skipping evaluation') + else: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + + trainer = pl.Trainer( + gpus=gpu, + precision=cfg.trainer.precision, + amp_level=cfg.trainer.amp_level, + logger=False, + checkpoint_callback=False, + ) + exp_dir = exp_manager(trainer, cfg.exp_manager) + + if not cfg.pretrained_model: + raise ValueError( + 'To run evaluation and inference script a pre-trained model or .nemo file must be provided.' + f'Choose from {PunctuationCapitalizationModel.list_available_models()} or "pretrained_model"="your_model.nemo"' + ) + + if os.path.exists(cfg.pretrained_model): + model = PunctuationCapitalizationModel.restore_from(cfg.pretrained_model) + elif cfg.pretrained_model in PunctuationCapitalizationModel.get_available_model_names(): + model = PunctuationCapitalizationModel.from_pretrained(cfg.pretrained_model) + else: + raise ValueError( + f'Provide path to the pre-trained .nemo file or choose from {PunctuationCapitalizationModel.list_available_models()}' + ) + + data_dir = cfg.model.dataset.get('data_dir', None) + + if data_dir is None: + logging.error( + 'No dataset directory provided. Skipping evaluation. ' + 'To run evaluation on a file, specify path to the directory that contains test_ds.text_file and test_ds.labels_file with "model.dataset.data_dir" argument.' + ) + elif not os.path.exists(data_dir): + logging.error(f'{data_dir} is not found, skipping evaluation on the test set.') + else: + model.update_data_dir(data_dir=data_dir) + model._cfg.dataset = cfg.model.dataset + + if not hasattr(cfg.model, 'test_ds'): + logging.error(f'model.test_ds was not found in the config, skipping evaluation') + elif model.prepare_test(trainer): + model.setup_test_data(cfg.model.test_ds) + trainer.test(model) + else: + logging.error('Skipping the evaluation. The trainer is not setup properly.') + + # run an inference on a few examples + queries = [ + 'we bought four shirts one pen and a mug from the nvidia gear store in santa clara', + 'what can i do for you today', + 'how are you', + ] + + inference_results = model.add_punctuation_capitalization(queries, batch_size=len(queries), max_seq_length=512) + + for query, result in zip(queries, inference_results): + logging.info(f'Query : {query}') + logging.info(f'Result: {result.strip()}\n') + + logging.info(f'Results are saved at {exp_dir}') + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_train.py b/tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_train.py new file mode 100644 index 0000000..ae55448 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/punctuation_capitalization_train.py @@ -0,0 +1,101 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import PunctuationCapitalizationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +""" +This script show how to train a Punctuation and Capitalization Model. +More details on the task and data format could be found in tutorials/nlp/Punctuation_and_Capitalization.ipynb + +*** Setting the configs *** + +The model and the PT trainer are defined in a config file which declares multiple important sections. +The most important ones are: + model: All arguments that are related to the Model - language model, tokenizer, token classifier, optimizer, + schedulers, and datasets/data loaders. + trainer: Any argument to be passed to PyTorch Lightning including number of epochs, number of GPUs, + precision level, etc. +This script uses the `/examples/nlp/token_classification/conf/punctuation_capitalization_config.yaml` config file +by default. You may update the config file from the file directly. +The other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +For more details about the config files and different ways of model restoration, see tutorials/00_NeMo_Primer.ipynb + +*** Model training *** + +To run this script and train the model from scratch, use: + python punctuation_and_capitalization_train.py \ + model.dataset.data_dir= + +To use one of the pretrained versions of the model and finetune it, run: + python punctuation_and_capitalization.py \ + pretrained_model=punctuation_en_bert \ + model.dataset.data_dir= + + - a directory that contains test_ds.text_file and test_ds.labels_file (see the config) + pretrained_model - pretrained PunctuationCapitalization model from list_available_models() or + path to a .nemo file, for example: punctuation_en_bert or model.nemo + +""" + + +@hydra_runner(config_path="conf", config_name="punctuation_capitalization_config") +def main(cfg: DictConfig) -> None: + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + if not cfg.pretrained_model: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + model = PunctuationCapitalizationModel(cfg.model, trainer=trainer) + else: + if os.path.exists(cfg.pretrained_model): + model = PunctuationCapitalizationModel.restore_from(cfg.pretrained_model) + elif cfg.pretrained_model in PunctuationCapitalizationModel.get_available_model_names(): + model = PunctuationCapitalizationModel.from_pretrained(cfg.pretrained_model) + else: + raise ValueError( + f'Provide path to the pre-trained .nemo file or choose from {PunctuationCapitalizationModel.list_available_models()}' + ) + + data_dir = cfg.model.dataset.get('data_dir', None) + if data_dir: + if not os.path.exists(data_dir): + raise ValueError(f'{data_dir} is not found at') + + # we can also do finetuning of the pretrained model but we would need to update the data dir + model.update_data_dir(data_dir) + # setup train and validation Pytorch DataLoaders + model.setup_training_data() + model.setup_validation_data() + logging.info(f'Using config file of the pretrained model') + else: + raise ValueError( + 'Specify a valid dataset directory that contains test_ds.text_file and test_ds.labels_file \ + with "model.dataset.data_dir" argument' + ) + + trainer.fit(model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/token_classification/token_classification_evaluate.py b/tts/NeMo/examples/nlp/token_classification/token_classification_evaluate.py new file mode 100644 index 0000000..4a888f5 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/token_classification_evaluate.py @@ -0,0 +1,137 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig + +from nemo.collections.nlp.models import TokenClassificationModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +""" +This script shows how to perform evaluation and runs inference of a few examples. + +More details on Token Classification model could be found in tutorials/nlp/Token_Classification_Named_Entity_Recognition.ipynb + +*** Setting the configs *** + +This script uses the `/examples/nlp/token_classification/conf/token_classification_config.yaml` config file +by default. You may update the config file from the file directly. +The other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +For more details about the config files and different ways of model restoration, see tutorials/00_NeMo_Primer.ipynb + +*** Model Evaluation *** + +The script runs two types of evaluation: + * model.test() - this eval will use the config setting for evaluation such as model.dataset.max_seq_length + * model.evaluate_from_file(): + * disregards model.dataset.max_seq_length and evaluates all the tokens, BERT max seq length - 512 tokens after tokenization + * creates confusion matrix + * saves predictions and labels (if provided) + +To run the script: + + python token_classification_evaluate.py \ + model.dataset.data_dir= \ + pretrained_model=ner_en_bert + + - a directory that contains test_ds.text_file and test_ds.labels_file (see the config) +pretrained_model - pretrained TokenClassification model from list_available_models() or + path to a .nemo file, for example: ner_en_bert or your_model.nemo + +""" + + +@hydra_runner(config_path="conf", config_name="token_classification_config") +def main(cfg: DictConfig) -> None: + logging.info( + 'During evaluation/testing, it is currently advisable to construct a new Trainer with single GPU and \ + no DDP to obtain accurate results' + ) + + if not hasattr(cfg.model, 'test_ds'): + raise ValueError(f'model.test_ds was not found in the config, skipping evaluation') + else: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + + trainer = pl.Trainer( + gpus=gpu, + precision=cfg.trainer.precision, + amp_level=cfg.trainer.amp_level, + logger=False, + checkpoint_callback=False, + ) + exp_dir = exp_manager(trainer, cfg.exp_manager) + + if not cfg.pretrained_model: + raise ValueError( + 'To run evaluation and inference script a pre-trained model or .nemo file must be provided.' + f'Choose from {TokenClassificationModel.list_available_models()} or "pretrained_model"="your_model.nemo"' + ) + + if os.path.exists(cfg.pretrained_model): + model = TokenClassificationModel.restore_from(cfg.pretrained_model) + elif cfg.pretrained_model in TokenClassificationModel.get_available_model_names(): + model = TokenClassificationModel.from_pretrained(cfg.pretrained_model) + else: + raise ValueError( + f'Provide path to the pre-trained .nemo checkpoint or choose from {TokenClassificationModel.list_available_models()}' + ) + + data_dir = cfg.model.dataset.get('data_dir', None) + if data_dir is None: + logging.error( + 'No dataset directory provided. Skipping evaluation. ' + 'To run evaluation on a file, specify path to the directory that contains test_ds.text_file and test_ds.labels_file with "model.dataset.data_dir" argument.' + ) + elif not os.path.exists(data_dir): + logging.error(f'{data_dir} is not found, skipping evaluation on the test set.') + else: + model.update_data_dir(data_dir=data_dir) + model._cfg.dataset = cfg.model.dataset + + if not hasattr(cfg.model, 'test_ds'): + logging.error(f'model.test_ds was not found in the config, skipping evaluation') + elif model.prepare_test(trainer): + model.setup_test_data(cfg.model.test_ds) + trainer.test(model) + + model.evaluate_from_file( + text_file=os.path.join(data_dir, cfg.model.test_ds.text_file), + labels_file=os.path.join(data_dir, cfg.model.test_ds.labels_file), + output_dir=exp_dir, + add_confusion_matrix=True, + normalize_confusion_matrix=True, + ) + else: + logging.error('Skipping the evaluation. The trainer is not setup properly.') + + # run an inference on a few examples + queries = ['we bought four shirts from the nvidia gear store in santa clara.', 'Nvidia is a company.'] + results = model.add_predictions(queries, output_file='predictions.txt') + + for query, result in zip(queries, results): + logging.info(f'Query : {query}') + logging.info(f'Result: {result.strip()}\n') + + logging.info(f'Results are saved at {exp_dir}') + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/nlp/token_classification/token_classification_train.py b/tts/NeMo/examples/nlp/token_classification/token_classification_train.py new file mode 100644 index 0000000..f4ffb61 --- /dev/null +++ b/tts/NeMo/examples/nlp/token_classification/token_classification_train.py @@ -0,0 +1,147 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytorch_lightning as pl +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import TokenClassificationModel +from nemo.collections.nlp.parts.nlp_overrides import NLPDDPPlugin +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +""" +This scripts shows how to train a Token Classification model. + +The Token Classification model supports Named Entity Recognition task and other token level classification tasks, +as long as the data follows the format specified below. + +More details on how to use this script could be found in +tutorials/nlp/Token_Classification_Named_Entity_Recognition.ipynb + +*** Data Format *** +Token Classification Model requires the data to be split into 2 files: text.txt and labels.txt. +Each line of the text.txt file contains text sequences, where words are separated with spaces, i.e.: +[WORD] [SPACE] [WORD] [SPACE] [WORD]. +The labels.txt file contains corresponding labels for each word in text.txt, the labels are separated with spaces, i.e.: +[LABEL] [SPACE] [LABEL] [SPACE] [LABEL]. + +Example of a text.txt file: +Jennifer is from New York City . +She likes ... +... + +Corresponding labels.txt file: +B-PER O O B-LOC I-LOC I-LOC O +O O ... +... + +*** Preparing the dataset *** + +To convert an IOB format data to the format required for training, run +examples/nlp/token_classification/data/import_from_iob_format.py on your train and dev files, as follows: + +python examples/nlp/token_classification/data/import_from_iob_format.py --data_file PATH_TO_IOB_FORMAT_DATAFILE + +*** Setting the configs *** + +The model and the PT trainer are defined in a config file which declares multiple important sections. +The most important ones are: + model: All arguments that are related to the Model - language model, tokenizer, token classifier, optimizer, + schedulers, and datasets/data loaders. + trainer: Any argument to be passed to PyTorch Lightning including number of epochs, number of GPUs, + precision level, etc. +This script uses the `/examples/nlp/token_classification/conf/token_classification_config.yaml` config file +by default. You may update the config file from the file directly. +The other option is to set another config file via command line arguments by `--config-name=CONFIG_FILE_PATH'. + +For more details about the config files and different ways of model restoration, see tutorials/00_NeMo_Primer.ipynb + +*** Model Training *** + +To train TokenClassification model from scratch with the default config file, run: + + python token_classification_train.py \ + model.dataset.data_dir= \ + trainer.max_epochs= \ + trainer.gpus=[] + +To use one of the pretrained versions of the model specify a `pretrained_model` arg with either +TokenClassification model from list_available_models() or path to a .nemo file, for example: +ner_en_bert or model.nemo, run: + + python token_classification_train.py pretrained_model=ner_en_bert + +To use one of the pretrained versions of the model and fine-tune it, run: + + python token_classification_train.py \ + model.dataset.data_dir= \ + pretrained_model=ner_en_bert + + - a directory that contains test_ds.text_file and test_ds.labels_file (see the config) +pretrained_model - pretrained TokenClassification model from list_available_models() or + path to a .nemo file, for example: ner_en_bert or model.nemo + +For more ways of restoring a pre-trained model, see tutorials/00_NeMo_Primer.ipynb +""" + + +@hydra_runner(config_path="conf", config_name="token_classification_config") +def main(cfg: DictConfig) -> None: + trainer = pl.Trainer(plugins=[NLPDDPPlugin()], **cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + + if not cfg.pretrained_model: + logging.info(f'Config: {OmegaConf.to_yaml(cfg)}') + model = TokenClassificationModel(cfg.model, trainer=trainer) + else: + if os.path.exists(cfg.pretrained_model): + # TODO: can we drop strict=False? + model = TokenClassificationModel.restore_from(cfg.pretrained_model, trainer=trainer, strict=False) + elif cfg.pretrained_model in TokenClassificationModel.get_available_model_names(): + model = TokenClassificationModel.from_pretrained(cfg.pretrained_model) + else: + raise ValueError( + f'Provide path to the pre-trained .nemo file or choose from {TokenClassificationModel.list_available_models()}' + ) + + data_dir = cfg.model.dataset.get('data_dir', None) + if data_dir: + if not os.path.exists(data_dir): + raise ValueError(f'{data_dir} is not found at') + + # we can also do finetuning of the pretrained model but it will require + # setup the data dir to get class weights statistics + model.update_data_dir(data_dir=data_dir) + # finally, setup train and validation Pytorch DataLoaders + model.setup_training_data() + model.setup_validation_data() + # then we're setting up loss, use model.dataset.class_balancing, + # if you want to add class weights to the CrossEntropyLoss + model.setup_loss(class_balancing=cfg.model.dataset.class_balancing) + logging.info(f'Using config file of the pretrained model') + else: + raise ValueError( + 'Specify a valid dataset directory that contains test_ds.text_file and test_ds.labels_file \ + with "model.dataset.data_dir" argument' + ) + + trainer.fit(model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/speaker_recognition/README.md b/tts/NeMo/examples/speaker_recognition/README.md new file mode 100644 index 0000000..4e321b3 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/README.md @@ -0,0 +1,21 @@ +# Speaker Recognition + +Documentation section for speaker related tasks can be found at: + - [Speaker Recognition and Verification](https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/speaker_recognition/intro.html) + - [Speaker Diarization](https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/speaker_diarization/intro.html) + +This folder contains scripts for performing various speaker related tasks as breiefly explained below: + - **speaker_reco.py** +: Training script for speaker verification and recognition + - **speaker_reco_infer.py** +: Inference for speaker recognition. Can be used to map labels using trained model on test set with known speaker labels from train set. (speaker id) + - **extract_speaker_embeddings.py** +: Extract speaker embeddings using trained model for speaker verification purposes. + - **speaker_reco_finetune.py** +: Sample script to demonstrate on how to finetune a already trained model for specific sub tasks. + - **voxceleb_eval.py** +: Helper script to evaluate speaker embeddings on voxceleb trail files. + - **speaker_diarize.py** +: Inference script for speaker diarization - knowing who spoke when. + - **conf/** +: Folder containing configuration files for training speaker tasks. We currently only support inference for speaker diarization. diff --git a/tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_recognition_3x2x512.yaml b/tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_recognition_3x2x512.yaml new file mode 100644 index 0000000..4bba3a7 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_recognition_3x2x512.yaml @@ -0,0 +1,157 @@ +name: &name "SpeakerNet" +sample_rate: &sample_rate 16000 +repeat: &rep 2 +dropout: &drop 0.5 +separable: &separable True +n_filters: &n_filters 512 + +model: + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: null + batch_size: 64 + shuffle: True + time_length: 8 + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: null + batch_size: 128 + shuffle: False + time_length: 8 + + test_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: null + batch_size: 1 + shuffle: False + time_length: 8 + embedding_dir: '.' + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: *n_filters + repeat: 1 + kernel: [3] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: *n_filters + repeat: *rep + kernel: [7] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: *n_filters + repeat: *rep + kernel: [11] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: *n_filters + repeat: *rep + kernel: [15] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: &enc_feat_out 1500 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: *separable + + decoder: + _target_: nemo.collections.asr.modules.SpeakerDecoder + feat_in: *enc_feat_out + num_classes: 7205 + pool_mode: 'xvector' + emb_sizes: 512,512 + angular: False + + loss: + scale: 30 + margin: 0.2 + + optim: + name: novograd + # _target_: nemo.core.optim.optimizers.Novograd + lr: .008 + # optimizer arguments + args: + name: auto + # _target_: nemo.core.config.optimizers.NovogradParams + betas: [0.95, 0.5] + weight_decay: 0.001 + + # scheduler setup + sched: + name: CosineAnnealing + iters_per_batch: 1 # computed at runtime + max_steps: null # computed at runtime or explicitly set here + + # scheduler config override + args: + name: auto + # _target_: nemo.core.config.schedulers.CosineAnnealingParams + warmup_steps: null + warmup_ratio: 0.1 + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 1 # number of gpus + max_epochs: 200 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + amp_level: O0 + deterministic: True + checkpoint_callback: False + logger: False + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_verification_3x2x512.yaml b/tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_verification_3x2x512.yaml new file mode 100644 index 0000000..9ce23f1 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/conf/SpeakerNet_verification_3x2x512.yaml @@ -0,0 +1,145 @@ +name: &name "SpeakerNet" +sample_rate: &sample_rate 16000 +repeat: &rep 2 +dropout: &drop 0.5 +separable: &separable True +n_filters: &n_filters 512 + +model: + train_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: null + batch_size: 64 + shuffle: True + time_length: 8 + is_tarred: False + tarred_audio_filepaths: null + tarred_shard_strategy: "scatter" + + validation_ds: + manifest_filepath: ??? + sample_rate: 16000 + labels: null + batch_size: 128 + shuffle: False + time_length: 8 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + normalize: "per_feature" + window_size: 0.02 + sample_rate: *sample_rate + window_stride: 0.01 + window: "hann" + features: &n_mels 64 + n_fft: 512 + frame_splicing: 1 + dither: 0.00001 + + encoder: + _target_: nemo.collections.asr.modules.ConvASREncoder + feat_in: *n_mels + activation: relu + conv_mask: true + + jasper: + - filters: *n_filters + repeat: 1 + kernel: [3] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: *n_filters + repeat: *rep + kernel: [7] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: *n_filters + repeat: *rep + kernel: [11] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: *n_filters + repeat: *rep + kernel: [15] + stride: [1] + dilation: [1] + dropout: *drop + residual: true + separable: *separable + + - filters: &enc_feat_out 1500 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: 0.0 + residual: false + separable: *separable + + decoder: + _target_: nemo.collections.asr.modules.SpeakerDecoder + feat_in: *enc_feat_out + num_classes: 7205 + pool_mode: 'xvector' + emb_sizes: 256 + angular: True + + loss: + scale: 30 + margin: 0.2 + + optim: + name: sgd + lr: .006 + # optimizer arguments + args: + name: auto + weight_decay: 0.001 + momentum: 0.9 + + # scheduler setup + sched: + name: CosineAnnealing + iters_per_batch: 1 # computed at runtime + max_steps: null # computed at runtime or explicitly set here + + # scheduler config override + args: + name: auto + warmup_steps: null + warmup_ratio: 0.1 + min_lr: 0.0 + last_epoch: -1 + +trainer: + gpus: 1 # number of gpus + max_epochs: 200 + max_steps: null # computed at runtime if not set + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + amp_level: O0 + deterministic: True + checkpoint_callback: False + logger: False + log_every_n_steps: 1 # Interval of logging. + val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations + +exp_manager: + exp_dir: null + name: *name + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/speaker_recognition/conf/speaker_diarization.yaml b/tts/NeMo/examples/speaker_recognition/conf/speaker_diarization.yaml new file mode 100644 index 0000000..482bf46 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/conf/speaker_diarization.yaml @@ -0,0 +1,27 @@ +name: &name "ClusterDiarizer" + +num_workers: 4 +sample_rate: &sample_rate 16000 + +diarizer: + oracle_num_speakers: ??? # oracle number of speakers or pass null if not known. [int or path to file containing uniq-id with num of speakers of that session] + max_num_speakers: 20 # max number of speakers for each recording. If oracle num speakers is passed this value is ignored. + out_dir: ??? + paths2audio_files: ??? #file containing paths to audio files for inference + path2groundtruth_rttm_files: null #file containing paths to ground truth rttm files for score computation or null if no reference rttms are present + + vad: + model_path: null #.nemo local model path or pretrained model name or none + window_length_in_sec: 0.15 + shift_length_in_sec: 0.01 + threshold: 0.7 # tune threshold on dev set. Check /scripts/voice_activity_detection/vad_tune_threshold.py + vad_decision_smoothing: True + smoothing_params: + method: "median" + overlap: 0.875 + + speaker_embeddings: + oracle_vad_manifest: null + model_path: ??? #.nemo local model path or pretrained model name (speakerverification_speakernet or speakerdiarization_speakernet) + window_length_in_sec: 1.5 # window length in sec for speaker embedding extraction + shift_length_in_sec: 0.75 # shift length in sec for speaker embedding extraction diff --git a/tts/NeMo/examples/speaker_recognition/extract_speaker_embeddings.py b/tts/NeMo/examples/speaker_recognition/extract_speaker_embeddings.py new file mode 100644 index 0000000..ce7ce0a --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/extract_speaker_embeddings.py @@ -0,0 +1,101 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This is a helper script to extract speaker embeddings based on manifest file +Usage: +python extract_speaker_embeddings.py --manifest=/path/to/manifest/file' +--model_path='/path/to/.nemo/file'(optional) +--embedding_dir='/path/to/embedding/directory' + +Args: +--manifest: path to manifest file containing audio_file paths for which embeddings need to be extracted +--model_path(optional): path to .nemo speaker verification model file to extract embeddings, if not passed SpeakerNet-M model would + be downloaded from NGC and used to extract embeddings +--embeddings_dir(optional): path to directory where embeddings need to stored default:'./' + + +""" + +from argparse import ArgumentParser + +import pytorch_lightning as pl +import torch +from omegaconf import OmegaConf + +from nemo.collections.asr.models.label_models import ExtractSpeakerEmbeddingsModel +from nemo.utils import logging + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--manifest", type=str, required=True, help="Path to manifest file", + ) + parser.add_argument( + "--model_path", + type=str, + default='speakerverification_speakernet', + required=False, + help="path to .nemo speaker verification model file to extract embeddings, if not passed SpeakerNet-M model would be downloaded from NGC and used to extract embeddings", + ) + parser.add_argument( + "--embedding_dir", + type=str, + default='./', + required=False, + help="path to directory where embeddings need to stored default:'./'", + ) + args = parser.parse_args() + torch.set_grad_enabled(False) + + if args.model_path.endswith('.nemo'): + logging.info(f"Using local speaker model from {args.model_path}") + speaker_model = ExtractSpeakerEmbeddingsModel.restore_from(restore_path=args.model_path) + else: + speaker_model = ExtractSpeakerEmbeddingsModel.from_pretrained(model_name="speakerverification_speakernet") + logging.info(f"using pretrained speaker verification model from NGC") + + num_gpus = 1 if torch.cuda.is_available() else 0 + if not num_gpus: + logging.warning("Running model on CPU, for faster performance it is adviced to use atleast one NVIDIA GPUs") + + trainer = pl.Trainer(gpus=num_gpus, accelerator=None) + + test_config = OmegaConf.create( + dict( + manifest_filepath=args.manifest, + sample_rate=16000, + labels=None, + batch_size=1, + shuffle=False, + time_length=8, + embedding_dir=args.embedding_dir, + ) + ) + speaker_model.setup_test_data(test_config) + trainer.test(speaker_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/speaker_recognition/speaker_diarize.py b/tts/NeMo/examples/speaker_recognition/speaker_diarize.py new file mode 100644 index 0000000..a901313 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/speaker_diarize.py @@ -0,0 +1,49 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from omegaconf import OmegaConf +from pytorch_lightning import seed_everything + +from nemo.collections.asr.models import ClusteringDiarizer +from nemo.core.config import hydra_runner +from nemo.utils import logging + +""" +This script demonstrates how to use run speaker diarization. +Usage: + python speaker_diarize.py \ + diarizer.paths2audio_files= \ + diarizer.path2groundtruth_rttm_files=<(Optional) either list of rttm file paths or file containing paths to rttm files> \ + diarizer.vad.model_path="vad_telephony_marblenet" \ + diarizer.vad.threshold=0.7 \ + diarizer.speaker_embeddings.model_path="speakerverification_speakernet" \ + diarizer.out_dir="demo" + +Check out whole parameters in ./conf/speaker_diarization.yaml and their meanings. +For details, have a look at /tutorials/speaker_recognition/Speaker_Diarization_Inference.ipynb +""" + +seed_everything(42) + + +@hydra_runner(config_path="conf", config_name="speaker_diarization.yaml") +def main(cfg): + + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + sd_model = ClusteringDiarizer(cfg=cfg) + sd_model.diarize() + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/speaker_recognition/speaker_reco.py b/tts/NeMo/examples/speaker_recognition/speaker_reco.py new file mode 100644 index 0000000..90bb753 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/speaker_reco.py @@ -0,0 +1,73 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytorch_lightning as pl +from omegaconf import ListConfig, OmegaConf +from pytorch_lightning import seed_everything + +from nemo.collections.asr.models import EncDecSpeakerLabelModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + +""" +Basic run (on GPU for 10 epochs for 2 class training): +EXP_NAME=sample_run +python ./speaker_reco.py --config-path='conf' --config-name='SpeakerNet_recognition_3x2x512.yaml' \ + trainer.max_epochs=10 \ + model.train_ds.batch_size=64 model.validation_ds.batch_size=64 \ + model.train_ds.manifest_filepath="" model.validation_ds.manifest_filepath="" \ + model.test_ds.manifest_filepath="" \ + trainer.gpus=1 \ + model.decoder.params.num_classes=2 \ + exp_manager.name=$EXP_NAME +exp_manager.use_datetime_version=False \ + exp_manager.exp_dir='./speaker_exps' + +See https://github.com/NVIDIA/NeMo/blob/main/tutorials/speaker_recognition/Speaker_Recognition_Verification.ipynb for notebook tutorial + +Optional: Use tarred dataset to speech up data loading. + Prepare ONE manifest that contains all training data you would like to include. Validation should use non-tarred dataset. + Note that it's possible that tarred datasets impacts validation scores because it drop values in order to have same amount of files per tarfile; + Scores might be off since some data is missing. + + Use the `convert_to_tarred_audio_dataset.py` script under /speech_recognition/scripts in order to prepare tarred audio dataset. + For details, please see TarredAudioToClassificationLabelDataset in /nemo/collections/asr/data/audio_to_label.py +""" + +seed_everything(42) + + +@hydra_runner(config_path="conf", config_name="SpeakerNet_recognition_3x2x512.yaml") +def main(cfg): + + logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}') + trainer = pl.Trainer(**cfg.trainer) + log_dir = exp_manager(trainer, cfg.get("exp_manager", None)) + speaker_model = EncDecSpeakerLabelModel(cfg=cfg.model, trainer=trainer) + trainer.fit(speaker_model) + if not trainer.fast_dev_run: + model_path = os.path.join(log_dir, '..', 'spkr.nemo') + speaker_model.save_to(model_path) + + if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None: + gpu = 1 if cfg.trainer.gpus != 0 else 0 + trainer = pl.Trainer(gpus=gpu) + if speaker_model.prepare_test(trainer): + trainer.test(speaker_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/speaker_recognition/speaker_reco_finetune.py b/tts/NeMo/examples/speaker_recognition/speaker_reco_finetune.py new file mode 100644 index 0000000..c8ed4d1 --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/speaker_reco_finetune.py @@ -0,0 +1,98 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script demonstrates how to use pretrained .nemo speaker recognition model to finetune on your domain set +Usage: +python speaker_reco_finetune.py --pretrained_model='/path/to/.nemo_or_.ckpt/file' --finetune_config_file=/path/to/finetune/config/yaml/file' + +in finetune config file make sure to change +- train manifest +- validation manifest +- decoder num classes +- learning rate +- num of epochs + +for finetuning tips see: https://github.com/NVIDIA/NeMo/blob/main/tutorials/speaker_recognition/Speaker_Recognition_Verification.ipynb +""" + + +from argparse import ArgumentParser + +import pytorch_lightning as pl +from omegaconf import OmegaConf + +from nemo.collections.asr.models import EncDecSpeakerLabelModel +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--pretrained_model", + type=str, + default="speakerverification_speakernet", + required=False, + help="Pass your trained .nemo model", + ) + parser.add_argument( + "--finetune_config_file", + type=str, + required=True, + help="path to speakernet config yaml file to load train, validation dataset and also for trainer parameters", + ) + + parser.add_argument( + "--freeze_encoder", + type=bool, + required=False, + default=True, + help="True if speakernet encoder paramteres needs to be frozen while finetuning", + ) + + args = parser.parse_args() + + if args.pretrained_model.endswith('.nemo'): + logging.info(f"Using local speaker model from {args.pretrained_model}") + speaker_model = EncDecSpeakerLabelModel.restore_from(restore_path=args.pretrained_model) + elif args.pretrained_model.endswith('.ckpt'): + logging.info(f"Using local speaker model from checkpoint {args.pretrained_model}") + speaker_model = EncDecSpeakerLabelModel.load_from_checkpoint(checkpoint_path=args.pretrained_model) + else: + logging.info("Using pretrained speaker recognition model from NGC") + speaker_model = EncDecSpeakerLabelModel.from_pretrained(model_name=args.pretrained_model) + + finetune_config = OmegaConf.load(args.finetune_config_file) + + if 'test_ds' in finetune_config.model and finetune_config.model.test_ds is not None: + finetune_config.model.test_ds = None + logging.warning("Removing test ds") + + speaker_model.setup_finetune_model(finetune_config.model) + finetune_trainer = pl.Trainer(**finetune_config.trainer) + speaker_model.set_trainer(finetune_trainer) + + _ = exp_manager(finetune_trainer, finetune_config.get('exp_manager', None)) + speaker_model.setup_optimization(finetune_config.optim) + + if args.freeze_encoder: + for param in speaker_model.encoder.parameters(): + param.requires_grad = False + + finetune_trainer.fit(speaker_model) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/speaker_recognition/speaker_reco_infer.py b/tts/NeMo/examples/speaker_recognition/speaker_reco_infer.py new file mode 100644 index 0000000..bc3ceaf --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/speaker_reco_infer.py @@ -0,0 +1,139 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script serves two goals: + (1) Demonstrate how to use NeMo Models outside of PytorchLightning + (2) Shows example of batch speaker recognition inference +Usage: +python speaker_reco_infer.py --spkr_model='/path/to/.nemo/file' --train_manifest=/path/to/train/manifest/file' +--test_manifest=/path/to/train/manifest/file' --batch_size=32 +train_manifest file is used to map the labels from which model was trained so it is mandatory to +pass the train manifest file + +for finetuning tips see: https://colab.research.google.com/github/NVIDIA/NeMo/blob/main/tutorials/speaker_recognition/Speaker_Recognition_Verification.ipynb +""" + + +import json +import os +import sys +from argparse import ArgumentParser + +import numpy as np +import torch +from tqdm import tqdm + +from nemo.collections.asr.models import EncDecSpeakerLabelModel +from nemo.utils import logging + +try: + from torch.cuda.amp import autocast +except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + +can_gpu = torch.cuda.is_available() + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--spkr_model", + type=str, + default="speakerrecognition_speakernet", + required=True, + help="Pass your trained .nemo model", + ) + parser.add_argument( + "--train_manifest", type=str, required=True, help="path to train manifest file to match labels" + ) + parser.add_argument( + "--test_manifest", type=str, required=True, help="path to test manifest file to perform inference" + ) + parser.add_argument("--batch_size", type=int, default=32) + args = parser.parse_args() + torch.set_grad_enabled(False) + + if args.spkr_model.endswith('.nemo'): + logging.info(f"Using local speaker model from {args.spkr_model}") + speaker_model = EncDecSpeakerLabelModel.restore_from(restore_path=args.spkr_model) + else: + logging.error(f"Please pass a trained .nemo file") + sys.exit() + + labels = [] + with open(args.train_manifest, 'rb') as f: + lines = f.readlines() + for line in lines: + line = line.strip() + item = json.loads(line) + labels.append(item['label']) + + labels_map = sorted(set(labels)) + label2id, id2label = {}, {} + for label_id, label in enumerate(labels_map): + label2id[label] = label_id + id2label[label_id] = label + + speaker_model.setup_test_data( + test_data_layer_params={ + 'sample_rate': 16000, + 'manifest_filepath': args.test_manifest, + 'labels': labels_map, + 'batch_size': args.batch_size, + 'trim_silence': False, + 'shuffle': False, + } + ) + if can_gpu: + speaker_model = speaker_model.cuda() + speaker_model.eval() + + speaker_model.test_dataloader() + all_labels = [] + all_logits = [] + for test_batch in tqdm(speaker_model.test_dataloader()): + if can_gpu: + test_batch = [x.cuda() for x in test_batch] + with autocast(): + audio_signal, audio_signal_len, labels, _ = test_batch + logits, _ = speaker_model.forward(input_signal=audio_signal, input_signal_length=audio_signal_len) + + all_logits.extend(logits.cpu().numpy()) + all_labels.extend(labels.cpu().numpy()) + + all_logits, true_labels = np.asarray(all_logits), np.asarray(all_labels) + infer_labels = all_logits.argmax(axis=1) + + out_manifest = os.path.basename(args.test_manifest).split('.')[0] + '_infer.json' + out_manifest = os.path.join(os.path.dirname(args.test_manifest), out_manifest) + with open(args.test_manifest, 'rb') as f1, open(out_manifest, 'w') as f2: + lines = f1.readlines() + for idx, line in enumerate(lines): + line = line.strip() + item = json.loads(line) + item['infer'] = id2label[infer_labels[idx]] + json.dump(item, f2) + f2.write('\n') + + logging.info("Inference labels have been written to {} manifest file".format(out_manifest)) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/examples/speaker_recognition/voxceleb_eval.py b/tts/NeMo/examples/speaker_recognition/voxceleb_eval.py new file mode 100644 index 0000000..cdfd1db --- /dev/null +++ b/tts/NeMo/examples/speaker_recognition/voxceleb_eval.py @@ -0,0 +1,110 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os +import pickle as pkl +import sys + +import numpy as np +from scipy.interpolate import interp1d +from scipy.optimize import brentq +from sklearn.metrics import roc_curve +from tqdm import tqdm + + +""" +This script faciliates to get EER % based on cosine-smilarity +for Voxceleb dataset. + +Args: + trial_file str: path to voxceleb trial file + emb : path to pickle file of embeddings dictionary (generated from spkr_get_emb.py) + save_kaldi_emb: if required pass this argument to save kaldi embeddings for KALDI PLDA training later + Note: order of audio files in manifest file should match the embeddings +""" + + +def get_acc(trial_file='', emb='', save_kaldi_emb=False): + + trial_score = open('trial_score.txt', 'w') + dirname = os.path.dirname(trial_file) + emb = pkl.load(open(emb, 'rb')) + trial_embs = [] + keys = [] + all_scores = [] + all_keys = [] + + # for each trials in trial file + with open(trial_file, 'r') as f: + tmp_file = f.readlines() + for line in tqdm(tmp_file): + line = line.strip() + truth, x_speaker, y_speaker = line.split() + + x_speaker = x_speaker.split('/') + x_speaker = '@'.join(x_speaker) + + y_speaker = y_speaker.split('/') + y_speaker = '@'.join(y_speaker) + + X = emb[x_speaker] + Y = emb[y_speaker] + + if save_kaldi_emb and x_speaker not in keys: + keys.append(x_speaker) + trial_embs.extend([X]) + + if save_kaldi_emb and y_speaker not in keys: + keys.append(y_speaker) + trial_embs.extend([Y]) + + score = (X @ Y.T) / (((X @ X.T) * (Y @ Y.T)) ** 0.5) + score = (score + 1) / 2 + + all_scores.append(score) + trial_score.write(str(score) + "\t" + truth) + truth = int(truth) + all_keys.append(truth) + + trial_score.write('\n') + trial_score.close() + + if save_kaldi_emb: + np.save(dirname + '/all_embs_voxceleb.npy', np.asarray(trial_embs)) + np.save(dirname + '/all_ids_voxceleb.npy', np.asarray(keys)) + print("Saved KALDI PLDA related embeddings to {}".format(dirname)) + + return np.asarray(all_scores), np.asarray(all_keys) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--trial_file", help="path to voxceleb trial file", type=str, required=True) + parser.add_argument("--emb", help="path to numpy file of embeddings", type=str, required=True) + parser.add_argument( + "--save_kaldi_emb", + help=":save kaldi embeddings for KALDI PLDA training later", + required=False, + action='store_true', + ) + + args = parser.parse_args() + trial_file, emb, save_kaldi_emb = args.trial_file, args.emb, args.save_kaldi_emb + + y_score, y = get_acc(trial_file=trial_file, emb=emb, save_kaldi_emb=save_kaldi_emb) + fpr, tpr, thresholds = roc_curve(y, y_score, pos_label=1) + + eer = brentq(lambda x: 1.0 - x - interp1d(fpr, tpr)(x), 0.0, 1.0) + sys.stdout.write("{0:.2f}\n".format(eer * 100)) diff --git a/tts/NeMo/examples/tts/aligner.py b/tts/NeMo/examples/tts/aligner.py new file mode 100644 index 0000000..e32c044 --- /dev/null +++ b/tts/NeMo/examples/tts/aligner.py @@ -0,0 +1,33 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import AlignerModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path='conf', config_name='aligner') +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get('exp_manager', None)) + model = AlignerModel(cfg=cfg.model, trainer=trainer) + trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/conf/aligner.yaml b/tts/NeMo/examples/tts/conf/aligner.yaml new file mode 100644 index 0000000..801b577 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/aligner.yaml @@ -0,0 +1,123 @@ +name: Aligner +sample_rate: 22050 + +train_dataset: ??? +validation_datasets: ??? +attn_prior_folder: ??? + +model: + d_char: 512 + n_mels: 80 + bin_start_ratio: 0.3 + + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithPriorDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + int_values: false + normalize: false + sample_rate: ${sample_rate} + trim: false + attn_prior_folder: ${attn_prior_folder} + n_window_stride: 256 + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: None + pad_with_space: True + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithPriorDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + int_values: false + normalize: false + sample_rate: ${sample_rate} + trim: false + attn_prior_folder: ${attn_prior_folder} + n_window_stride: 256 + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: None + pad_with_space: True + dataloader_params: + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 1 + + preprocessor: + _target_: "nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor" + dither: 0.0 + features: ${model.n_mels} + frame_splicing: 1 + highfreq: 8000 + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + window_size: False + n_window_stride: 256 + window_stride: False + normalize: null + pad_to: 1 + pad_value: -11.52 + preemph: null + sample_rate: ${sample_rate} + stft_conv: false + window: hann + + alignment_encoder: + _target_: "nemo.collections.tts.modules.aligner.AlignmentEncoder" + n_mel_channels: ${model.n_mels} + n_text_channels: ${model.d_char} + n_att_channels: ${model.n_mels} + + optim: + name: adam + lr: 1e-3 + weight_decay: 1e-6 + + sched: + name: CosineAnnealing + min_lr: 5e-5 + warmup_ratio: 0.35 + +trainer: + gpus: 1 + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False + logger: False + gradient_clip_val: 1.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: False + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_forward_sum_loss" + mode: "min" \ No newline at end of file diff --git a/tts/NeMo/examples/tts/conf/degli.yaml b/tts/NeMo/examples/tts/conf/degli.yaml new file mode 100644 index 0000000..5327694 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/degli.yaml @@ -0,0 +1,107 @@ +name: "DeepGriffinLim" +sample_rate: 22050 +n_fft: 1024 +hop_length: 256 +destination: "/tmp" + +model: + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.NoisySpecsDataset" + destination: ${destination} + subdir: "/train" + n_fft: ${n_fft} + hop_length: ${hop_length} + num_snr: 1 + dataloader_params: + drop_last: false + shuffle: true + batch_size: 16 + num_workers: 1 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.NoisySpecsDataset" + destination: ${destination} + subdir: "/valid" + n_fft: ${n_fft} + hop_length: ${hop_length} + num_snr: 1 + + dataloader_params: + drop_last: false + shuffle: false + batch_size: 16 + num_workers: 1 + + preprocessor: + valid_filelist: none + train_filelist: none + n_fft: ${n_fft} + hop_length: ${hop_length} + num_snr: 1 + destination: ${destination} + + degli: + _target_: nemo.collections.tts.modules.degli.DegliModule + n_fft: ${n_fft} + hop_length: ${hop_length} + depth: 1 + out_all_block: True + tiny: False # overrides all below configurations if true. + layers: 6 + k_x: 3 + k_y: 3 + s_x: 1 + s_y: 2 + widening: 16 + use_bn: False + linear_finalizer: True + convGlu: False + act: relu + act2: selu + glu_bn: True + use_weight_norm: True + + + optim: + name: novograd + lr: 0.01 + weight_decay: 0.001 + + sched: + name: ReduceLROnPlateau + mode: min + factor: 0.6 + patience: 5 + verbose: True + threshold: 0.01 + threshold_mode: 'rel' + cooldown: 0 + min_lr: 0.00001 + eps: 1.e-08 + + train_params: + repeat_training: 2 + repeat_validation: 32 + sampling_rate: ${sample_rate} + +trainer: + gpus: 1 # number of gpus + max_epochs: 200 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + flush_logs_every_n_steps: 2000 + log_every_n_steps: 200 + check_val_every_n_epoch: 5 + precision: 32 + gradient_clip_val: 4.0 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/ed_mel2spec.yaml b/tts/NeMo/examples/tts/conf/ed_mel2spec.yaml new file mode 100755 index 0000000..d98464e --- /dev/null +++ b/tts/NeMo/examples/tts/conf/ed_mel2spec.yaml @@ -0,0 +1,103 @@ +name: "EncoderDecoderMelToSpec" +sample_rate: 22050 +n_fft: 1024 +hop_length: 256 +destination: "/tmp" + +model: + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.NoisySpecsDataset" + destination: ${destination} + subdir: "/train" + n_fft: ${n_fft} + hop_length: ${hop_length} + num_snr: 1 + dataloader_params: + drop_last: false + shuffle: true + batch_size: 16 + num_workers: 1 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.NoisySpecsDataset" + destination: ${destination} + subdir: "/valid" + n_fft: ${n_fft} + hop_length: ${hop_length} + num_snr: 1 + + dataloader_params: + drop_last: false + shuffle: false + batch_size: 16 + num_workers: 1 + + preprocessor: + valid_filelist: none + train_filelist: none + n_fft: ${n_fft} + hop_length: ${hop_length} + num_snr: 1 + destination: ${destination} + + mel2spec: + _target_: nemo.collections.tts.modules.ed_mel2spec.EDMel2SpecModule + n_fft: ${n_fft} + hop_length: ${hop_length} + mel_fmin: 0 + mel_fmax: null + mel_freq: 80 + layers: 8 + sampling_rate: ${sample_rate} + widening: 16 + use_batchnorm: True + droprate: 0.2 + num_dropout: 3 + pre_final_lin: True + act1: lrelu + act2: relu + use_weight_norm: False + + optim: + name: adam + lr: 5.e-4 + weight_decay: 1.e-3 + + sched: + name: ReduceLROnPlateau + mode: min + factor: 0.8 + patience: 5 + verbose: True + threshold: 0.01 + threshold_mode: 'rel' + cooldown: 0 + min_lr: 5.e-5 + eps: 1.e-08 + + train_params: + lreg_factor: 1.0 + loss_mode: 3 + validate_scores: True # Slow! + +trainer: + gpus: 1 # number of gpus + max_epochs: 200 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + flush_logs_every_n_steps: 2000 + log_every_n_steps: 200 + check_val_every_n_epoch: 10 + precision: 32 + gradient_clip_val: 4.0 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/fastpitch.yaml b/tts/NeMo/examples/tts/conf/fastpitch.yaml new file mode 100644 index 0000000..8336d7e --- /dev/null +++ b/tts/NeMo/examples/tts/conf/fastpitch.yaml @@ -0,0 +1,144 @@ +name: "FastPitch" +sample_rate: 22050 + +labels: [' ', '!', "'", '(', ')', ',', '-', '.', ':', ';', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] +train_dataset: ??? +validation_datasets: ??? +test_datasets: null + +model: + labels: ${labels} + n_speakers: 1 + symbols_embedding_dim: 384 + max_token_duration: 75 + n_mel_channels: 80 + pitch_embedding_kernel_size: 3 + + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.FastPitchDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + trim: false + int_values: false + sample_rate: ${sample_rate} + dataloader_params: + drop_last: false + shuffle: true + batch_size: 48 + num_workers: 12 + + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.FastPitchDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: null + int_values: false + sample_rate: ${sample_rate} + trim: false + dataloader_params: + drop_last: false + shuffle: false + batch_size: 48 + num_workers: 8 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + dither: 0.0 + features: ${model.n_mel_channels} + frame_splicing: 1 + highfreq: 8000 + log: true + log_zero_guard_type: add + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + n_window_stride: 256 + normalize: null + pad_to: 1 + pad_value: 0 + preemph: null + sample_rate: ${sample_rate} + window: hann + window_size: null + window_stride: null + + input_fft: + _target_: nemo.collections.tts.modules.transformer.FFTransformerEncoder + n_layer: 6 + n_head: 1 + d_model: ${model.symbols_embedding_dim} + d_head: 64 + d_inner: 1536 + kernel_size: 3 + dropout: 0.1 + dropatt: 0.1 + dropemb: 0.0 + n_embed: 148 # NOTE Should match # of tokens in `symbol_set` + d_embed: ${model.symbols_embedding_dim} + padding_idx: 0 + + output_fft: + _target_: nemo.collections.tts.modules.transformer.FFTransformerDecoder + n_layer: 6 + n_head: 1 + d_model: ${model.symbols_embedding_dim} + d_head: 64 + d_inner: 1536 + kernel_size: 3 + dropout: 0.1 + dropatt: 0.1 + dropemb: 0.0 + + duration_predictor: + _target_: nemo.collections.tts.modules.fastpitch.TemporalPredictor + input_size: ${model.symbols_embedding_dim} + kernel_size: 3 + filter_size: 256 + dropout: 0.1 + n_layers: 2 + + pitch_predictor: + _target_: nemo.collections.tts.modules.fastpitch.TemporalPredictor + input_size: ${model.symbols_embedding_dim} + kernel_size: 3 + filter_size: 256 + dropout: 0.1 + n_layers: 2 + + optim: + name: lamb + lr: 1e-1 + betas: [0.9, 0.98] + weight_decay: 1e-6 + + sched: + name: NoamAnnealing + warmup_steps: 1000 + last_epoch: -1 + d_model: 1 # Disable scaling based on model dim + +trainer: + gpus: -1 # number of gpus + max_epochs: 1500 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + gradient_clip_val: 1000.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 100 + check_val_every_n_epoch: 5 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/fastpitch_align.yaml b/tts/NeMo/examples/tts/conf/fastpitch_align.yaml new file mode 100644 index 0000000..4b26618 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/fastpitch_align.yaml @@ -0,0 +1,185 @@ +name: "FastPitch" +sample_rate: 22050 +train_dataset: ??? +validation_datasets: ??? +prior_folder: ??? + +model: + learn_alignment: true + n_speakers: 1 + symbols_embedding_dim: 384 + max_token_duration: 75 + n_mel_channels: 80 + pitch_embedding_kernel_size: 3 + n_window_size: 1024 + n_window_stride: 256 + pitch_fmin: 80 + pitch_fmax: 640 + pitch_avg: 211.27540199742586 + pitch_std: 52.1851002822779 + + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithPriorAndPitchDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + int_values: false + normalize: true + sample_rate: ${sample_rate} + trim: false + sup_data_path: ${prior_folder} + n_window_stride: ${model.n_window_stride} + n_window_size: ${model.n_window_size} + pitch_fmin: ${model.pitch_fmin} + pitch_fmax: ${model.pitch_fmax} + pitch_avg: ${model.pitch_avg} + pitch_std: ${model.pitch_std} + vocab: + notation: phonemes + punct: true + spaces: true + stresses: true + add_blank_at: None + pad_with_space: True + chars: true + improved_version_g2p: true + dataloader_params: + drop_last: false + shuffle: true + batch_size: 32 + num_workers: 12 + + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithPriorAndPitchDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: null + int_values: false + normalize: true + sample_rate: ${sample_rate} + trim: false + sup_data_path: ${prior_folder} + n_window_stride: ${model.n_window_stride} + n_window_size: ${model.n_window_size} + pitch_fmin: ${model.pitch_fmin} + pitch_fmax: ${model.pitch_fmax} + pitch_avg: ${model.pitch_avg} + pitch_std: ${model.pitch_std} + vocab: + notation: phonemes + punct: true + spaces: true + stresses: true + add_blank_at: None + pad_with_space: True + chars: true + improved_version_g2p: true + dataloader_params: + drop_last: false + shuffle: false + batch_size: 32 + num_workers: 8 + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + dither: 0.0 + features: ${model.n_mel_channels} + frame_splicing: 1 + highfreq: null + log: true + log_zero_guard_type: add + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${model.n_window_size} + n_window_size: ${model.n_window_size} + n_window_stride: ${model.n_window_stride} + normalize: null + pad_to: 1 + pad_value: 0 + preemph: null + sample_rate: ${sample_rate} + window: hann + window_size: null + window_stride: null + + input_fft: #n_embed and padding_idx are added by the model + _target_: nemo.collections.tts.modules.transformer.FFTransformerEncoder + n_layer: 6 + n_head: 1 + d_model: ${model.symbols_embedding_dim} + d_head: 64 + d_inner: 1536 + kernel_size: 3 + dropout: 0.1 + dropatt: 0.1 + dropemb: 0.0 + d_embed: ${model.symbols_embedding_dim} + + output_fft: + _target_: nemo.collections.tts.modules.transformer.FFTransformerDecoder + n_layer: 6 + n_head: 1 + d_model: ${model.symbols_embedding_dim} + d_head: 64 + d_inner: 1536 + kernel_size: 3 + dropout: 0.1 + dropatt: 0.1 + dropemb: 0.0 + + alignment_module: + _target_: nemo.collections.tts.modules.aligner.AlignmentEncoder + n_text_channels: ${model.symbols_embedding_dim} + + duration_predictor: + _target_: nemo.collections.tts.modules.fastpitch.TemporalPredictor + input_size: ${model.symbols_embedding_dim} + kernel_size: 3 + filter_size: 256 + dropout: 0.1 + n_layers: 2 + + pitch_predictor: + _target_: nemo.collections.tts.modules.fastpitch.TemporalPredictor + input_size: ${model.symbols_embedding_dim} + kernel_size: 3 + filter_size: 256 + dropout: 0.1 + n_layers: 2 + + optim: + name: lamb + lr: 1e-1 + betas: [0.9, 0.98] + weight_decay: 1e-6 + + sched: + name: NoamAnnealing + warmup_steps: 1000 + last_epoch: -1 + d_model: 1 # Disable scaling based on model dim + +trainer: + gpus: -1 # number of gpus + max_epochs: 1500 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + gradient_clip_val: 1000.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 100 + check_val_every_n_epoch: 5 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: v_loss diff --git a/tts/NeMo/examples/tts/conf/fastpitch_hifigan_e2e.yaml b/tts/NeMo/examples/tts/conf/fastpitch_hifigan_e2e.yaml new file mode 100644 index 0000000..c0570ee --- /dev/null +++ b/tts/NeMo/examples/tts/conf/fastpitch_hifigan_e2e.yaml @@ -0,0 +1,138 @@ +name: "FastPitch_HiFiGAN_E2E" + +labels: [' ', '!', "'", '(', ')', ',', '-', '.', ':', ';', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] +train_dataset: ??? +validation_datasets: ??? +test_datasets: null + +model: + sample_rate: 22050 + splice_length: 64 + lr: 3e-2 + labels: ${labels} + n_speakers: 1 + symbols_embedding_dim: 384 + max_token_duration: 75 + n_mel_channels: 80 + pitch_embedding_kernel_size: 3 + mel_loss_coeff: 40 + hop_size: 256 + + train_ds: + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + sample_rate: ${model.sample_rate} + trim: false + parser: null + drop_last: true + shuffle: true + batch_size: 64 + num_workers: 12 + + validation_ds: + manifest_filepath: ${validation_datasets} + sample_rate: ${model.sample_rate} + trim: false + parser: null + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 8 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${model.n_mel_channels} + frame_splicing: 1 + highfreq: 8000 + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + n_window_stride: ${model.hop_size} + normalize: null + pad_to: 1 + pad_value: 0 + preemph: null + sample_rate: ${model.sample_rate} + window: hann + exact_pad: true + use_grads: false + + input_fft: + _target_: nemo.collections.tts.modules.transformer.FFTransformerEncoder + n_layer: 6 + n_head: 1 + d_model: ${model.symbols_embedding_dim} + d_head: 64 + d_inner: 1536 + kernel_size: 3 + dropout: 0.1 + dropatt: 0.1 + dropemb: 0.0 + n_embed: 148 # NOTE Should match # of tokens in `symbol_set` + d_embed: ${model.symbols_embedding_dim} + padding_idx: 0 + + output_fft: + _target_: nemo.collections.tts.modules.transformer.FFTransformerDecoder + n_layer: 6 + n_head: 1 + d_model: ${model.symbols_embedding_dim} + d_head: 64 + d_inner: 1536 + kernel_size: 3 + dropout: 0.1 + dropatt: 0.1 + dropemb: 0.0 + + duration_predictor: + _target_: nemo.collections.tts.modules.fastpitch.TemporalPredictor + input_size: ${model.symbols_embedding_dim} + kernel_size: 3 + filter_size: 256 + dropout: 0.1 + n_layers: 2 + + pitch_predictor: + _target_: nemo.collections.tts.modules.fastpitch.TemporalPredictor + input_size: ${model.symbols_embedding_dim} + kernel_size: 3 + filter_size: 256 + dropout: 0.1 + n_layers: 2 + + generator: + _target_: nemo.collections.tts.modules.hifigan_modules.Generator + upsample_kernel_sizes: [16,16,4,4] + upsample_rates: [8,8,2,2] + upsample_initial_channel: 512 + resblock_kernel_sizes: [3,7,11] + resblock_dilation_sizes: [[1,3,5], [1,3,5], [1,3,5]] + resblock: 1 + initial_input_size: 384 + +trainer: + gpus: -1 # number of gpus + max_epochs: 1500 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + gradient_clip_val: 1000.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 100 + check_val_every_n_epoch: 5 + precision: 16 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/fastspeech2.yaml b/tts/NeMo/examples/tts/conf/fastspeech2.yaml new file mode 100644 index 0000000..ed1dea2 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/fastspeech2.yaml @@ -0,0 +1,144 @@ +name: FastSpeech2 +sample_rate: 22050 +n_mels: 80 + +# Dataset info +train_dataset: ??? +validation_datasets: ??? +mappings_file: ??? # JSON file with word->phone and phone->idx mappings +ignore_file: ??? + +model: + add_pitch_predictor: True + add_energy_predictor: True + d_model: 256 + duration_coeff: 0.25 + mappings_filepath: ${mappings_file} + + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.FastSpeech2Dataset" + manifest_filepath: ${train_dataset} + mappings_filepath: ${mappings_file} + sample_rate: ${sample_rate} + max_duration: null + min_duration: 0.1 + ignore_file: ${ignore_file} + trim: false + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.FastSpeech2Dataset" + manifest_filepath: ${validation_datasets} + mappings_filepath: ${mappings_file} + sample_rate: ${sample_rate} + ignore_file: ${ignore_file} + trim: false + load_supplementary_values: false + dataloader_params: + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 4 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${n_mels} + frame_splicing: 1 + highfreq: 8000 + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + n_window_stride: 256 + normalize: null + pad_to: 16 + pad_value: -11.52 + preemph: null + sample_rate: ${sample_rate} + window: hann + + # FFTransformer encoder + encoder: + _target_: nemo.collections.tts.modules.fastspeech2.FastSpeech2Encoder + d_model: ${model.d_model} + n_layers: 4 + n_attn_heads: 2 + d_attn_head: 256 + d_inner: 1024 + kernel_size: 9 + dropout: 0.1 + attn_dropout: 0.1 + n_embed: 74 # Should match number of tokens in symbol set +1 (pad_idx) + padding_idx: 73 + + # FFTransformer mel spec decoder + decoder: + _target_: nemo.collections.tts.modules.fastspeech2.MelSpecDecoder + d_model: ${model.d_model} + d_out: ${n_mels} + n_layers: 4 + n_attn_heads: 2 + d_attn_head: 256 + d_inner: 1024 + kernel_size: 9 + dropout: 0.1 + attn_dropout: 0.1 + + # VarianceAdaptor + variance_adaptor: + _target_: nemo.collections.tts.modules.fastspeech2.VarianceAdaptor + d_model: ${model.d_model} + dropout: 0.2 + dur_d_hidden: 256 + dur_kernel_size: 3 + pitch: ${model.add_pitch_predictor} + log_pitch: True + n_f0_bins: 256 + pitch_kernel_size: 3 + pitch_min: 80.0 + pitch_max: 800.0 + energy: ${model.add_energy_predictor} + n_energy_bins: 256 + energy_kernel_size: 3 + energy_min: 0.0 + energy_max: 600.0 + + optim: + name: adam + betas: [0.9,0.98] + lr: 1e-3 + weight_decay: 1e-6 + # scheduler setup + sched: + name: NoamAnnealing + warmup_steps: 4000 + min_lr: 1e-5 + d_model: ${model.d_model} + +trainer: + gpus: 1 # number of gpus + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/fastspeech2_hifigan_e2e.yaml b/tts/NeMo/examples/tts/conf/fastspeech2_hifigan_e2e.yaml new file mode 100644 index 0000000..95acf3d --- /dev/null +++ b/tts/NeMo/examples/tts/conf/fastspeech2_hifigan_e2e.yaml @@ -0,0 +1,136 @@ +name: FastSpeech2_HiFiGAN_E2E + +# Dataset info +train_dataset: ??? +validation_datasets: ??? +mappings_file: ??? # JSON file with word->phone and phone->idx mappings +ignore_file: ??? + + +model: + lr: 0.5 + splice_length: 64 # Length in frames + mel_loss_coeff: 45. + pitch_loss_coeff: 0.003 + energy_loss_coeff: 0.03 + add_energy_predictor: True + add_pitch_predictor: True + mappings_filepath: ${mappings_file} + sample_rate: 22050 + n_mels: 80 + hop_size: 256 + + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.FastSpeech2Dataset" + manifest_filepath: ${train_dataset} + mappings_filepath: ${mappings_file} + sample_rate: ${model.sample_rate} + max_duration: null + min_duration: 0.75 + ignore_file: ${ignore_file} + trim: false + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.FastSpeech2Dataset" + manifest_filepath: ${validation_datasets} + mappings_filepath: ${mappings_file} + sample_rate: ${model.sample_rate} + ignore_file: ${ignore_file} + trim: false + load_supplementary_values: false + dataloader_params: + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 4 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${n_mels} + frame_splicing: 1 + highfreq: 8000 + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + n_window_stride: ${model.hop_size} + normalize: null + pad_to: 0 + preemph: null + sample_rate: ${model.sample_rate} + window: hann + + # FFTransformer encoder + encoder: + _target_: nemo.collections.tts.modules.fastspeech2.FastSpeech2Encoder + d_model: 256 + n_layers: 4 + n_attn_heads: 2 + d_attn_head: 256 + d_inner: 1024 + kernel_size: 9 + dropout: 0.1 + attn_dropout: 0.1 + n_embed: 74 # Should match number of tokens in symbol set +1 (pad_idx) + padding_idx: 73 + + # VarianceAdaptor + variance_adaptor: + _target_: nemo.collections.tts.modules.fastspeech2.VarianceAdaptor + d_model: 256 + dropout: 0.2 + dur_d_hidden: 256 + dur_kernel_size: 3 + + pitch: ${model.add_pitch_predictor} + log_pitch: True + n_f0_bins: 256 + pitch_kernel_size: 3 + pitch_min: 80.0 + pitch_max: 800.0 + energy: ${model.add_energy_predictor} + n_energy_bins: 256 + energy_kernel_size: 3 + energy_min: 0.0 + energy_max: 600.0 + + generator: + _target_: nemo.collections.tts.modules.hifigan_modules.Generator + upsample_kernel_sizes: [16,16,4,4] + upsample_rates: [8,8,2,2] + upsample_initial_channel: 512 + resblock_kernel_sizes: [3,7,11] + resblock_dilation_sizes: [[1,3,5], [1,3,5], [1,3,5]] + resblock: 1 + initial_input_size: 256 + apply_weight_init_conv_pre: true + +trainer: + gpus: 1 # number of gpus + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + move_metrics_to_cpu: False + precision: 16 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True \ No newline at end of file diff --git a/tts/NeMo/examples/tts/conf/glow_tts.yaml b/tts/NeMo/examples/tts/conf/glow_tts.yaml new file mode 100644 index 0000000..f082d9f --- /dev/null +++ b/tts/NeMo/examples/tts/conf/glow_tts.yaml @@ -0,0 +1,143 @@ +name: "GlowTTS" +sample_rate: 22050 +n_fft: 1024 +n_mels: 80 +fmax: 8000 +pad_value: -11.52 +gin_channels: 0 + +train_dataset: ??? +validation_datasets: ??? +test_datasets: null +cmu_dict_path: null + +model: + + n_speakers: 1 + gin_channels: ${gin_channels} + + train_ds: + manifest_filepath: ${train_dataset} + sample_rate: ${sample_rate} + batch_size: 32 + max_duration: null + min_duration: 0.1 + trim: false + shuffle: True + num_workers: 8 + cmu_dict_path: ${cmu_dict_path} + + + validation_ds: + manifest_filepath: ${validation_datasets} + sample_rate: ${sample_rate} + batch_size: 8 + max_duration: null + min_duration: 0.1 + trim: false + shuffle: False + num_workers: 8 + cmu_dict_path: ${cmu_dict_path} + + test_ds: + manifest_filepath: ${test_datasets} + sample_rate: ${sample_rate} + batch_size: 1 + max_duration: null + min_duration: 0.1 + trim: false + shuffle: False + num_workers: 8 + cmu_dict_path: ${cmu_dict_path} + + parser: + _target_: nemo.collections.tts.modules.glow_tts_parser.GlowTTSParser + cmu_dict_path: ${cmu_dict_path} + + preprocessor: + _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor + dither: 0.0 + features: ${n_mels} + frame_splicing: 1 + highfreq: ${fmax} + log: true + log_zero_guard_type: add + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${n_fft} + n_window_size: 1024 + n_window_stride: 256 + normalize: null + pad_to: 16 + pad_value: ${pad_value} + preemph: null + sample_rate: ${sample_rate} + window: hann + window_size: null + window_stride: null + + encoder: + _target_: nemo.collections.tts.modules.glow_tts.TextEncoder + n_vocab: 148 + out_channels: ${n_mels} + hidden_channels: 192 + filter_channels: 768 + filter_channels_dp: 256 + kernel_size: 3 + p_dropout: 0.1 + n_layers: 6 + n_heads: 2 + window_size: 4 + prenet: true + mean_only: true + gin_channels: ${gin_channels} + + decoder: + _target_: nemo.collections.tts.modules.glow_tts.FlowSpecDecoder + in_channels: ${n_mels} + hidden_channels: 192 + kernel_size: 5 + n_blocks: 12 + n_layers: 4 + n_sqz: 2 + n_split: 4 + sigmoid_scale: false + p_dropout: 0.05 + dilation_rate: 1 + gin_channels: ${gin_channels} + + optim: + name: adam + lr: 1e-3 + # optimizer arguments + betas: [0.9, 0.98] + weight_decay: 0 + + # scheduler setup + sched: + name: CosineAnnealing + + # Scheduler params + warmup_steps: 3000 + min_lr: 1e-4 + last_epoch: -1 + +trainer: + gpus: -1 # number of gpus + max_epochs: 350 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + gradient_clip_val: 1.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 50 + check_val_every_n_epoch: 5 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/hifigan/hifigan.yaml b/tts/NeMo/examples/tts/conf/hifigan/hifigan.yaml new file mode 100644 index 0000000..9412ced --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/hifigan.yaml @@ -0,0 +1,67 @@ +name: "HifiGan" +train_dataset: ??? +validation_datasets: ??? + +defaults: + - model/generator: v1 + - model/train_ds: train_ds + - model/validation_ds: val_ds + +model: + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + frame_splicing: 1 + nfilt: 80 + highfreq: 8000 + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + n_window_stride: 256 + normalize: null + pad_to: 0 + pad_value: -11.52 + preemph: null + sample_rate: 22050 + window: hann + use_grads: false + exact_pad: true + + optim: + _target_: torch.optim.AdamW + lr: 0.0002 + betas: [0.8, 0.99] + + sched: + name: CosineAnnealing + min_lr: 1e-5 + warmup_ratio: 0.02 + + max_steps: 25000000 + l1_loss_factor: 45 + denoise_strength: 0.0025 + +trainer: + gpus: -1 # number of gpus + max_steps: ${model.max_steps} + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + flush_logs_every_n_steps: 200 + log_every_n_steps: 100 + check_val_every_n_epoch: 10 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_loss" + mode: "min" diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/generator/v1.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/generator/v1.yaml new file mode 100644 index 0000000..30b819e --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/generator/v1.yaml @@ -0,0 +1,8 @@ +# @package _group_ +_target_: nemo.collections.tts.modules.hifigan_modules.Generator +resblock: 1 +upsample_rates: [8,8,2,2] +upsample_kernel_sizes: [16,16,4,4] +upsample_initial_channel: 512 +resblock_kernel_sizes: [3,7,11] +resblock_dilation_sizes: [[1,3,5], [1,3,5], [1,3,5]] diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/generator/v2.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/generator/v2.yaml new file mode 100644 index 0000000..ef33801 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/generator/v2.yaml @@ -0,0 +1,8 @@ +# @package _group_ +_target_: nemo.collections.tts.modules.hifigan_modules.Generator +resblock: 1 +upsample_rates: [8,8,2,2] +upsample_kernel_sizes: [16,16,4,4] +upsample_initial_channel: 128 +resblock_kernel_sizes: [3,7,11] +resblock_dilation_sizes: [[1,3,5], [1,3,5], [1,3,5]] diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/generator/v3.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/generator/v3.yaml new file mode 100644 index 0000000..734f0a3 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/generator/v3.yaml @@ -0,0 +1,8 @@ +# @package _group_ +_target_: nemo.collections.tts.modules.hifigan_modules.Generator +resblock: 2 +upsample_rates: [8,8,4] +upsample_kernel_sizes: [16,16,8] +upsample_initial_channel: 256 +resblock_kernel_sizes: [3,5,7] +resblock_dilation_sizes: [[1,2], [2,6], [3,12]] diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds.yaml new file mode 100644 index 0000000..d7bfce8 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds.yaml @@ -0,0 +1,13 @@ +# @package _group_ +dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.75 + n_segments: 8192 + trim: false +dataloader_params: + drop_last: false + shuffle: true + batch_size: 16 + num_workers: 4 diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds_finetune.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds_finetune.yaml new file mode 100644 index 0000000..195f3b2 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/train_ds/train_ds_finetune.yaml @@ -0,0 +1,11 @@ +# @package _group_ +dataset: + _target_: "nemo.collections.tts.data.datalayers.MelAudioDataset" + manifest_filepath: ${train_dataset} + min_duration: 0.75 + n_segments: 8192 +dataloader_params: + drop_last: false + shuffle: true + batch_size: 16 + num_workers: 4 diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds.yaml new file mode 100644 index 0000000..cfe6003 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds.yaml @@ -0,0 +1,13 @@ +# @package _group_ +dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: null + n_segments: -1 + trim: false +dataloader_params: + drop_last: false + shuffle: false + batch_size: 16 + num_workers: 1 diff --git a/tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds_finetune.yaml b/tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds_finetune.yaml new file mode 100644 index 0000000..ad9e2b9 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/hifigan/model/validation_ds/val_ds_finetune.yaml @@ -0,0 +1,11 @@ +# @package _group_ +dataset: + _target_: "nemo.collections.tts.data.datalayers.MelAudioDataset" + manifest_filepath: ${validation_datasets} + min_duration: 3 + n_segments: 66048 +dataloader_params: + drop_last: false + shuffle: false + batch_size: 16 + num_workers: 4 diff --git a/tts/NeMo/examples/tts/conf/melgan.yaml b/tts/NeMo/examples/tts/conf/melgan.yaml new file mode 100644 index 0000000..9259988 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/melgan.yaml @@ -0,0 +1,108 @@ +name: "MelGan" +sample_rate: 22050 +n_fft: 1024 +fmax: 8000 +pad_value: -11.52 +train_dataset: ??? +validation_datasets: ??? +n_mels: 80 + +model: + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.75 + n_segments: 16384 + trim: false + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: null + n_segments: -1 + trim: false + dataloader_params: + drop_last: false + shuffle: false + batch_size: 13 + num_workers: 4 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + frame_splicing: 1 + nfilt: ${n_mels} + highfreq: ${fmax} + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${n_fft} + + n_window_size: 1024 + n_window_stride: 256 + + normalize: null + pad_to: 0 + pad_value: ${pad_value} + preemph: null + sample_rate: ${sample_rate} + window: hann + exact_pad: true + + generator: + _target_: nemo.collections.tts.modules.melgan_modules.MelGANGenerator + in_channels: ${n_mels} # Number of input channels. + out_channels: 1 # Number of output channels. + kernel_size: 7 # Kernel size of initial and final conv layers. + channels: 512 # Initial number of channels for conv layers. + upsample_scales: [8, 4, 4, 2] # List of Upsampling scales. + stack_kernel_size: 3 # Kernel size of dilated conv layers in residual stack. + stacks: 4 # Number of stacks in a single residual stack module. + use_weight_norm: True # Whether to use weight normalization. + + discriminator: + _target_: nemo.collections.tts.modules.melgan_modules.MelGANMultiScaleDiscriminator + scales: 3 + out_channels: 1 # Number of output channels. + kernel_sizes: [5, 3] # List of kernel size. + channels: 16 # Number of channels of the initial conv layer. + max_downsample_channels: 512 # Maximum number of channels of downsampling layers. + downsample_scales: [4, 4, 4] # List of downsampling scales. + use_weight_norm: True # Whether to use weight norm. + use_spectral_norm: False # Whether to use spectral norm. + + loss: + _target_: nemo.collections.tts.losses.stftlosses.MultiResolutionSTFTLoss + fft_sizes: [1024, 2048, 512] + hop_sizes: [120, 240, 50] + win_lengths: [600, 1200, 240] + window: "hann_window" + +trainer: + gpus: 1 # number of gpus + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + log_every_n_steps: 1000 + check_val_every_n_epoch: 150 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/squeezewave.yaml b/tts/NeMo/examples/tts/conf/squeezewave.yaml new file mode 100644 index 0000000..9fc620f --- /dev/null +++ b/tts/NeMo/examples/tts/conf/squeezewave.yaml @@ -0,0 +1,104 @@ +name: "SqueezeWave" +sample_rate: 22050 +n_fft: 1024 +n_mels: 80 +fmax: 8000 +pad_value: -11.52 +train_dataset: ??? +validation_datasets: ??? + +model: + sigma: 1.0 + train_ds: + dataset: + # Use SplicedAudioDataset to use all of training data + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + n_segments: 16384 + trim: false + dataloader_params: + drop_last: true + pin_memory: true + shuffle: true + batch_size: 96 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + n_segments: -1 + trim: false + # This value is hard-coded to reflect n_window_stride * lcm(2, pad_to) + truncate_to: 512 + dataloader_params: + drop_last: false + shuffle: false + batch_size: 1 + num_workers: 4 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${n_mels} + frame_splicing: 1 + highfreq: ${fmax} + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${n_fft} + + # SqueezeWave is currently hardcoded to these values for window size and stride + # Changing these parameters are not recommended + n_window_size: 1024 + n_window_stride: 256 + + normalize: null + pad_to: 1 + pad_value: ${pad_value} + preemph: null + sample_rate: ${sample_rate} + window: hann + exact_pad: true + + squeezewave: + _target_: nemo.collections.tts.modules.squeezewave.SqueezeWaveModule + n_early_every: 2 + n_early_size: 16 + n_flows: 12 + n_group: 128 + n_mel_channels: ${n_mels} + n_wn_channels: 256 + n_wn_layers: 8 + wn_kernel_size: 3 + + optim: + name: adam + lr: 4e-4 + +trainer: + gpus: 1 # number of gpus + max_epochs: 10000 + max_steps: 600000 + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: false # Provided by exp_manager + logger: false # Provided by exp_manager + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + precision: 16 + amp_level: O1 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: true + create_checkpoint_callback: true diff --git a/tts/NeMo/examples/tts/conf/tacotron2.yaml b/tts/NeMo/examples/tts/conf/tacotron2.yaml new file mode 100644 index 0000000..11b37cf --- /dev/null +++ b/tts/NeMo/examples/tts/conf/tacotron2.yaml @@ -0,0 +1,140 @@ +name: Tacotron2 +sample_rate: 22050 +# , , will be added by the tacotron2.py script +labels: [' ', '!', '"', "'", '(', ')', ',', '-', '.', ':', ';', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', ']', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z'] +n_fft: 1024 +n_mels: 80 +fmax: 8000 +n_stride: 256 +pad_value: -11.52 +train_dataset: ??? +validation_datasets: ??? + +model: + labels: ${labels} + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + trim: false + int_values: false + normalize: true + sample_rate: ${sample_rate} + # bos_id: 66 + # eos_id: 67 + # pad_id: 68 These parameters are added automatically in Tacotron2 + dataloader_params: + drop_last: false + shuffle: true + batch_size: 48 + num_workers: 4 + + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + int_values: false + normalize: true + sample_rate: ${sample_rate} + trim: false + # bos_id: 66 + # eos_id: 67 + # pad_id: 68 These parameters are added automatically in Tacotron2 + dataloader_params: + drop_last: false + shuffle: false + batch_size: 48 + num_workers: 8 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${n_mels} + frame_splicing: 1 + highfreq: ${fmax} + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${n_fft} + n_window_size: 1024 + n_window_stride: ${n_stride} + normalize: null + pad_to: 16 + pad_value: ${pad_value} + preemph: null + sample_rate: ${sample_rate} + window: hann + + encoder: + _target_: nemo.collections.tts.modules.tacotron2.Encoder + encoder_kernel_size: 5 + encoder_n_convolutions: 3 + encoder_embedding_dim: 512 + + decoder: + _target_: nemo.collections.tts.modules.tacotron2.Decoder + decoder_rnn_dim: 1024 + encoder_embedding_dim: ${model.encoder.encoder_embedding_dim} + gate_threshold: 0.5 + max_decoder_steps: 1000 + n_frames_per_step: 1 # currently only 1 is supported + n_mel_channels: ${n_mels} + p_attention_dropout: 0.1 + p_decoder_dropout: 0.1 + prenet_dim: 256 + prenet_p_dropout: 0.5 + # Attention parameters + attention_dim: 128 + attention_rnn_dim: 1024 + # AttentionLocation Layer parameters + attention_location_kernel_size: 31 + attention_location_n_filters: 32 + early_stopping: true + + postnet: + _target_: nemo.collections.tts.modules.tacotron2.Postnet + n_mel_channels: ${n_mels} + p_dropout: 0.5 + postnet_embedding_dim: 512 + postnet_kernel_size: 5 + postnet_n_convolutions: 5 + + optim: + name: adam + lr: 1e-3 + weight_decay: 1e-6 + + # scheduler setup + sched: + name: CosineAnnealing + min_lr: 1e-5 + + +trainer: + gpus: 1 # number of gpus + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + gradient_clip_val: 1.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/talknet-durs.yaml b/tts/NeMo/examples/tts/conf/talknet-durs.yaml new file mode 100644 index 0000000..aaa977d --- /dev/null +++ b/tts/NeMo/examples/tts/conf/talknet-durs.yaml @@ -0,0 +1,175 @@ +name: TalkNetDurs +sample_rate: 22050 + +train_dataset: ??? +validation_datasets: ??? +durs_file: ??? +f0_file: ??? + +model: + d_char: 128 + dropout: 0.1 + separable: true + + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + int_values: false + load_audio: false + normalize: false + sample_rate: ${sample_rate} + trim: false + durs_file: ${durs_file} + f0_file: ${f0_file} + blanking: true + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: last + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + int_values: false + load_audio: false + normalize: false + sample_rate: ${sample_rate} + trim: false + durs_file: ${durs_file} + f0_file: ${f0_file} + blanking: true + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: last + dataloader_params: + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 1 + + model: + _target_: "nemo.collections.asr.modules.ConvASREncoder" + feat_in: ${model.d_char} + activation: relu + conv_mask: true + + jasper: + - filters: 256 + repeat: 1 + kernel: [3] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + + - filters: 256 + repeat: 5 + kernel: [5] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [7] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [9] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 512 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + + optim: + name: adam + lr: 1e-3 + weight_decay: 1e-6 + + sched: + name: CosineAnnealing + min_lr: 1e-5 + warmup_ratio: 0.02 + +trainer: + gpus: 1 + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False + logger: False + gradient_clip_val: 1.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_acc" + mode: "max" \ No newline at end of file diff --git a/tts/NeMo/examples/tts/conf/talknet-pitch.yaml b/tts/NeMo/examples/tts/conf/talknet-pitch.yaml new file mode 100644 index 0000000..722c429 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/talknet-pitch.yaml @@ -0,0 +1,179 @@ +name: TalkNetPitch +sample_rate: 22050 + +train_dataset: ??? +validation_datasets: ??? +durs_file: ??? +f0_file: ??? + +model: + d_char: 128 + dropout: 0.1 + separable: true + + # F0 stats (depends on dataset, current for LJSpeech) + f0_mean: 178.7767791748047 + f0_std: 33.51659393310547 + + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + int_values: false + load_audio: false + normalize: false + sample_rate: ${sample_rate} + trim: false + durs_file: ${durs_file} + f0_file: ${f0_file} + blanking: true + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: last + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + int_values: false + load_audio: false + normalize: false + sample_rate: ${sample_rate} + trim: false + durs_file: ${durs_file} + f0_file: ${f0_file} + blanking: true + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: last + dataloader_params: + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 1 + + model: + _target_: "nemo.collections.asr.modules.ConvASREncoder" + feat_in: ${model.d_char} + activation: relu + conv_mask: true + + jasper: + - filters: 256 + repeat: 1 + kernel: [3] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + + - filters: 256 + repeat: 5 + kernel: [5] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [7] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [9] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [11] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: True + se_reduction_ratio: 8 + + - filters: 512 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + + optim: + name: adam + lr: 1e-3 + weight_decay: 1e-6 + + sched: + name: CosineAnnealing + min_lr: 1e-5 + warmup_ratio: 0.02 + +trainer: + gpus: 1 + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False + logger: False + gradient_clip_val: 1.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_body_mae" + mode: "min" \ No newline at end of file diff --git a/tts/NeMo/examples/tts/conf/talknet-spect.yaml b/tts/NeMo/examples/tts/conf/talknet-spect.yaml new file mode 100644 index 0000000..e476b4d --- /dev/null +++ b/tts/NeMo/examples/tts/conf/talknet-spect.yaml @@ -0,0 +1,244 @@ +name: TalkNetSpect +sample_rate: 22050 + +train_dataset: ??? +validation_datasets: ??? +durs_file: ??? +f0_file: ??? + +model: + d_char: 128 + n_mels: 80 + dropout: 0.1 + separable: true + + train_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + int_values: false + load_audio: true + normalize: false + sample_rate: ${sample_rate} + trim: false + durs_file: ${durs_file} + f0_file: ${f0_file} + blanking: true + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: last + dataloader_params: + drop_last: false + shuffle: true + batch_size: 64 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.asr.data.audio_to_text.AudioToCharWithDursF0Dataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + int_values: false + load_audio: true + normalize: false + sample_rate: ${sample_rate} + trim: false + durs_file: ${durs_file} + f0_file: ${f0_file} + blanking: true + vocab: + notation: phonemes + punct: true + spaces: true + stresses: false + add_blank_at: last + dataloader_params: + drop_last: false + shuffle: false + batch_size: 64 + num_workers: 1 + + preprocessor: + _target_: "nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor" + dither: 0.0 + features: ${model.n_mels} + frame_splicing: 1 + highfreq: 8000 + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: 1024 + n_window_size: 1024 + window_size: False + n_window_stride: 256 + window_stride: False + normalize: null + pad_to: 1 + pad_value: -11.52 + preemph: null + sample_rate: ${sample_rate} + stft_conv: false + window: hann + + model: + _target_: "nemo.collections.asr.modules.ConvASREncoder" + feat_in: ${model.d_char} + activation: relu + conv_mask: true + + jasper: + - filters: 256 + repeat: 3 + kernel: [3] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + + - filters: 256 + repeat: 5 + kernel: [5] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [7] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [9] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [13] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [15] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 256 + repeat: 5 + kernel: [17] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 512 + repeat: 5 + kernel: [21] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 512 + repeat: 5 + kernel: [23] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 512 + repeat: 5 + kernel: [25] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + separable: ${model.separable} + se: true + se_reduction_ratio: 8 + + - filters: 1024 + repeat: 1 + kernel: [1] + stride: [1] + dilation: [1] + dropout: ${model.dropout} + residual: true + + optim: + name: adam + lr: 1e-3 + weight_decay: 1e-6 + + sched: + name: CosineAnnealing + min_lr: 1e-5 + warmup_ratio: 0.02 + +trainer: + gpus: 1 + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False + logger: False + gradient_clip_val: 1.0 + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True + checkpoint_callback_params: + monitor: "val_loss" + mode: "min" diff --git a/tts/NeMo/examples/tts/conf/uniglow.yaml b/tts/NeMo/examples/tts/conf/uniglow.yaml new file mode 100644 index 0000000..b74584d --- /dev/null +++ b/tts/NeMo/examples/tts/conf/uniglow.yaml @@ -0,0 +1,96 @@ +name: "UniGlow" +sample_rate: 22050 +n_fft: 1024 +n_mels: 80 +fmax: 8000 +pad_value: -11.52 +train_dataset: ??? +validation_datasets: ??? +resume_from_ckpt: null + +model: + sigma: 1.0 + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + n_segments: 16384 + trim: false + dataloader_params: + drop_last: false + shuffle: true + batch_size: 12 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + n_segments: 49152 # 3 secs + trim: false + dataloader_params: + drop_last: false + shuffle: false + batch_size: 12 + num_workers: 4 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${n_mels} + frame_splicing: 1 + highfreq: ${fmax} + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${n_fft} + + # UniGlow is currently hardcoded to these values for window size and stride + # Changing these parameters are not recommended + n_window_size: 1024 + n_window_stride: 256 + + normalize: null + pad_to: 0 #16 + pad_value: ${pad_value} + preemph: null + sample_rate: ${sample_rate} + window: hann + + uniglow: + n_flows: 16 + n_group: 8 + n_mel_channels: ${n_mels} + n_wn_channels: 256 + n_wn_layers: 8 + wn_kernel_size: 3 + stft_loss_coef: 0.1 + + optim: + name: adam + lr: 1e-4 + +trainer: + gpus: 1 # number of gpus + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + precision: 16 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/conf/waveglow.yaml b/tts/NeMo/examples/tts/conf/waveglow.yaml new file mode 100644 index 0000000..83f97a0 --- /dev/null +++ b/tts/NeMo/examples/tts/conf/waveglow.yaml @@ -0,0 +1,97 @@ +name: "WaveGlow" +sample_rate: 22050 +n_fft: 1024 +n_mels: 80 +fmax: 8000 +pad_value: -11.52 +train_dataset: ??? +validation_datasets: ??? + +model: + sigma: 1.0 + train_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${train_dataset} + max_duration: null + min_duration: 0.1 + n_segments: 16000 + trim: false + dataloader_params: + drop_last: false + shuffle: true + batch_size: 12 + num_workers: 4 + + validation_ds: + dataset: + _target_: "nemo.collections.tts.data.datalayers.AudioDataset" + manifest_filepath: ${validation_datasets} + max_duration: null + min_duration: 0.1 + n_segments: -1 + trim: false + dataloader_params: + drop_last: false + shuffle: false + batch_size: 8 + num_workers: 4 + + preprocessor: + _target_: nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures + dither: 0.0 + nfilt: ${n_mels} + frame_splicing: 1 + highfreq: ${fmax} + log: true + log_zero_guard_type: clamp + log_zero_guard_value: 1e-05 + lowfreq: 0 + mag_power: 1.0 + n_fft: ${n_fft} + + # Waveglow is currently hardcoded to these values for window size and stride + # Changing these parameters are not recommended + n_window_size: 1024 + n_window_stride: 256 + + normalize: null + pad_to: 16 + pad_value: ${pad_value} + preemph: null + sample_rate: ${sample_rate} + window: hann + + waveglow: + _target_: nemo.collections.tts.modules.waveglow.WaveGlowModule + n_early_every: 4 + n_early_size: 2 + n_flows: 12 + n_group: 8 + n_mel_channels: ${n_mels} + n_wn_channels: 256 + n_wn_layers: 8 + wn_kernel_size: 3 + + optim: + name: adam + lr: 1e-4 + +trainer: + gpus: 1 # number of gpus + max_epochs: ??? + num_nodes: 1 + accelerator: ddp + accumulate_grad_batches: 1 + checkpoint_callback: False # Provided by exp_manager + logger: False # Provided by exp_manager + flush_logs_every_n_steps: 1000 + log_every_n_steps: 200 + check_val_every_n_epoch: 25 + precision: 16 + +exp_manager: + exp_dir: null + name: ${name} + create_tensorboard_logger: True + create_checkpoint_callback: True diff --git a/tts/NeMo/examples/tts/degli.py b/tts/NeMo/examples/tts/degli.py new file mode 100755 index 0000000..b38b4eb --- /dev/null +++ b/tts/NeMo/examples/tts/degli.py @@ -0,0 +1,36 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.data.datalayers import preprocess_linear_specs_dataset +from nemo.collections.tts.models import DegliModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="degli") +def main(cfg): + preprocess_linear_specs_dataset(**cfg.model.preprocessor) + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = DegliModel(cfg=cfg.model, trainer=trainer) + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/ed_mel2spec.py b/tts/NeMo/examples/tts/ed_mel2spec.py new file mode 100755 index 0000000..8815018 --- /dev/null +++ b/tts/NeMo/examples/tts/ed_mel2spec.py @@ -0,0 +1,36 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.data.datalayers import preprocess_linear_specs_dataset +from nemo.collections.tts.models import EDMel2SpecModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="ed_mel2spec") +def main(cfg): + preprocess_linear_specs_dataset(**cfg.model.preprocessor) + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = EDMel2SpecModel(cfg=cfg.model, trainer=trainer) + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/fastpitch.py b/tts/NeMo/examples/tts/fastpitch.py new file mode 100644 index 0000000..3afb305 --- /dev/null +++ b/tts/NeMo/examples/tts/fastpitch.py @@ -0,0 +1,35 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import FastPitchModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="fastpitch") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = FastPitchModel(cfg=cfg.model, trainer=trainer) + lr_logger = pl.callbacks.LearningRateMonitor() + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([lr_logger, epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/fastpitch_hifigan_e2e.py b/tts/NeMo/examples/tts/fastpitch_hifigan_e2e.py new file mode 100644 index 0000000..f8b5253 --- /dev/null +++ b/tts/NeMo/examples/tts/fastpitch_hifigan_e2e.py @@ -0,0 +1,36 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl +from pytorch_lightning.plugins import DDPPlugin + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models.fastpitch_hifigan_e2e import FastPitchHifiGanE2EModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="fastpitch_hifigan_e2e") +def main(cfg): + trainer = pl.Trainer(plugins=[DDPPlugin(find_unused_parameters=True)], **cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = FastPitchHifiGanE2EModel(cfg=cfg.model, trainer=trainer) + lr_logger = pl.callbacks.LearningRateMonitor() + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([lr_logger, epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/fastspeech2.py b/tts/NeMo/examples/tts/fastspeech2.py new file mode 100644 index 0000000..0b95dff --- /dev/null +++ b/tts/NeMo/examples/tts/fastspeech2.py @@ -0,0 +1,35 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import FastSpeech2Model +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="fastspeech2") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = FastSpeech2Model(cfg=cfg.model, trainer=trainer) + lr_logger = pl.callbacks.LearningRateMonitor() + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([lr_logger, epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/fastspeech2_hifigan_e2e.py b/tts/NeMo/examples/tts/fastspeech2_hifigan_e2e.py new file mode 100644 index 0000000..4122eef --- /dev/null +++ b/tts/NeMo/examples/tts/fastspeech2_hifigan_e2e.py @@ -0,0 +1,35 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models.fastspeech2_hifigan_e2e import FastSpeech2HifiGanE2EModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="fastspeech2_hifigan_e2e") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = FastSpeech2HifiGanE2EModel(cfg=cfg.model, trainer=trainer) + lr_logger = pl.callbacks.LearningRateMonitor() + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([lr_logger, epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/glow_tts.py b/tts/NeMo/examples/tts/glow_tts.py new file mode 100644 index 0000000..7d797ff --- /dev/null +++ b/tts/NeMo/examples/tts/glow_tts.py @@ -0,0 +1,35 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import GlowTTSModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="glow_tts") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = GlowTTSModel(cfg=cfg.model, trainer=trainer) + lr_logger = pl.callbacks.LearningRateMonitor() + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([lr_logger, epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/hifigan.py b/tts/NeMo/examples/tts/hifigan.py new file mode 100644 index 0000000..5c3406a --- /dev/null +++ b/tts/NeMo/examples/tts/hifigan.py @@ -0,0 +1,31 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.tts.models import HifiGanModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf/hifigan", config_name="hifigan") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = HifiGanModel(cfg=cfg.model, trainer=trainer) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/melgan.py b/tts/NeMo/examples/tts/melgan.py new file mode 100644 index 0000000..946f2b7 --- /dev/null +++ b/tts/NeMo/examples/tts/melgan.py @@ -0,0 +1,35 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl +from pytorch_lightning.plugins import DDPPlugin + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import MelGanModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="melgan") +def main(cfg): + trainer = pl.Trainer(plugins=[DDPPlugin(find_unused_parameters=True)], **cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = MelGanModel(cfg=cfg.model, trainer=trainer) + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/squeezewave.py b/tts/NeMo/examples/tts/squeezewave.py new file mode 100755 index 0000000..d7a5ad8 --- /dev/null +++ b/tts/NeMo/examples/tts/squeezewave.py @@ -0,0 +1,34 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import SqueezeWaveModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="squeezewave") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = SqueezeWaveModel(cfg=cfg.model, trainer=trainer) + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/tacotron2.py b/tts/NeMo/examples/tts/tacotron2.py new file mode 100755 index 0000000..a5446c3 --- /dev/null +++ b/tts/NeMo/examples/tts/tacotron2.py @@ -0,0 +1,44 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import Tacotron2Model +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +# hydra_runner is a thin NeMo wrapper around Hydra +# It looks for a config named tacotron2.yaml inside the conf folder +# Hydra parses the yaml and returns it as a Omegaconf DictConfig +@hydra_runner(config_path="conf", config_name="tacotron2") +def main(cfg): + # Define the Lightning trainer + trainer = pl.Trainer(**cfg.trainer) + # exp_manager is a NeMo construct that helps with logging and checkpointing + exp_manager(trainer, cfg.get("exp_manager", None)) + # Define the Tacotron 2 model, this will construct the model as well as + # define the training and validation dataloaders + model = Tacotron2Model(cfg=cfg.model, trainer=trainer) + # Let's add a few more callbacks + lr_logger = pl.callbacks.LearningRateMonitor() + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([lr_logger, epoch_time_logger]) + # Call lightning trainer's fit() to train the model + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/talknet_durs.py b/tts/NeMo/examples/tts/talknet_durs.py new file mode 100644 index 0000000..f3543f6 --- /dev/null +++ b/tts/NeMo/examples/tts/talknet_durs.py @@ -0,0 +1,33 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import TalkNetDursModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path='conf', config_name='talknet-durs') +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get('exp_manager', None)) + model = TalkNetDursModel(cfg=cfg.model, trainer=trainer) + trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/talknet_pitch.py b/tts/NeMo/examples/tts/talknet_pitch.py new file mode 100644 index 0000000..6836d63 --- /dev/null +++ b/tts/NeMo/examples/tts/talknet_pitch.py @@ -0,0 +1,33 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import TalkNetPitchModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path='conf', config_name='talknet-pitch') +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get('exp_manager', None)) + model = TalkNetPitchModel(cfg=cfg.model, trainer=trainer) + trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/talknet_spect.py b/tts/NeMo/examples/tts/talknet_spect.py new file mode 100644 index 0000000..619403c --- /dev/null +++ b/tts/NeMo/examples/tts/talknet_spect.py @@ -0,0 +1,33 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import TalkNetSpectModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path='conf', config_name='talknet-spect') +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get('exp_manager', None)) + model = TalkNetSpectModel(cfg=cfg.model, trainer=trainer) + trainer.callbacks.extend([pl.callbacks.LearningRateMonitor(), LogEpochTimeCallback()]) # noqa + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/test_tts_infer.py b/tts/NeMo/examples/tts/test_tts_infer.py new file mode 100644 index 0000000..ce98fef --- /dev/null +++ b/tts/NeMo/examples/tts/test_tts_infer.py @@ -0,0 +1,153 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +This script is used as a CI test and shows how to chain TTS and ASR models +""" + +from argparse import ArgumentParser +from math import ceil +from pathlib import Path + +import librosa +import soundfile +import torch + +from nemo.collections.asr.metrics.wer import word_error_rate +from nemo.collections.asr.models import EncDecCTCModel +from nemo.collections.common.parts.preprocessing import parsers +from nemo.collections.tts.models.base import SpectrogramGenerator, Vocoder +from nemo.utils import logging + +LIST_OF_TEST_STRINGS = [ + "Hey, this is a test of the speech synthesis system.", + "roupell received the announcement with a cheerful countenance.", + "with thirteen dollars, eighty-seven cents when considerably greater resources were available to him.", + "Two other witnesses were able to offer partial descriptions of a man they saw in the southeast corner window.", + "'just to steady their legs a little' in other words, to add his weight to that of the hanging bodies.", + "The discussion above has already set forth examples of his expression of hatred for the United States.", + "At two:thirty-eight p.m., Eastern Standard Time, Lyndon Baines Johnson took the oath of office as the thirty-sixth President of the United States.", + "or, quote, other high government officials in the nature of a complaint coupled with an expressed or implied determination to use a means.", + "As for my return entrance visa please consider it separately. End quote.", + "it appears that Marina Oswald also complained that her husband was not able to provide more material things for her.", + "appeared in The Dallas Times Herald on November fifteen, nineteen sixty-three.", + "The only exit from the office in the direction Oswald was moving was through the door to the front stairway.", +] + + +def main(): + parser = ArgumentParser() + parser.add_argument( + "--asr_model", + type=str, + default="QuartzNet15x5Base-En", + choices=[x.pretrained_model_name for x in EncDecCTCModel.list_available_models()], + ) + parser.add_argument( + "--tts_model_spec", + type=str, + default="tts_en_tacotron2", + choices=[x.pretrained_model_name for x in SpectrogramGenerator.list_available_models()], + ) + parser.add_argument( + "--tts_model_vocoder", + type=str, + default="tts_waveglow_88m", + choices=[x.pretrained_model_name for x in Vocoder.list_available_models()], + ) + parser.add_argument("--wer_tolerance", type=float, default=1.0, help="used by test") + parser.add_argument("--trim", action="store_true") + parser.add_argument("--debug", action="store_true") + args = parser.parse_args() + torch.set_grad_enabled(False) + + if args.debug: + logging.set_verbosity(logging.DEBUG) + + logging.info(f"Using NGC cloud ASR model {args.asr_model}") + asr_model = EncDecCTCModel.from_pretrained(model_name=args.asr_model) + logging.info(f"Using NGC cloud TTS Spectrogram Generator model {args.tts_model_spec}") + tts_model_spec = SpectrogramGenerator.from_pretrained(model_name=args.tts_model_spec) + logging.info(f"Using NGC cloud TTS Vocoder model {args.tts_model_vocoder}") + tts_model_vocoder = Vocoder.from_pretrained(model_name=args.tts_model_vocoder) + models = [asr_model, tts_model_spec, tts_model_vocoder] + + if torch.cuda.is_available(): + for i, m in enumerate(models): + models[i] = m.cuda() + for m in models: + m.eval() + + asr_model, tts_model_spec, tts_model_vocoder = models + + parser = parsers.make_parser( + labels=asr_model.decoder.vocabulary, name="en", unk_id=-1, blank_id=-1, do_normalize=True, + ) + labels_map = dict([(i, asr_model.decoder.vocabulary[i]) for i in range(len(asr_model.decoder.vocabulary))]) + + tts_input = [] + asr_references = [] + longest_tts_input = 0 + for test_str in LIST_OF_TEST_STRINGS: + tts_parsed_input = tts_model_spec.parse(test_str) + if len(tts_parsed_input[0]) > longest_tts_input: + longest_tts_input = len(tts_parsed_input[0]) + tts_input.append(tts_parsed_input.squeeze()) + + asr_parsed = parser(test_str) + asr_parsed = ''.join([labels_map[c] for c in asr_parsed]) + asr_references.append(asr_parsed) + + # Pad TTS Inputs + for i, text in enumerate(tts_input): + pad = (0, longest_tts_input - len(text)) + tts_input[i] = torch.nn.functional.pad(text, pad, value=68) + + logging.debug(tts_input) + + # Do TTS + tts_input = torch.stack(tts_input) + if torch.cuda.is_available(): + tts_input = tts_input.cuda() + specs = tts_model_spec.generate_spectrogram(tokens=tts_input) + audio = [] + step = ceil(len(specs) / 4) + for i in range(4): + audio.append(tts_model_vocoder.convert_spectrogram_to_audio(spec=specs[i * step : i * step + step])) + + audio = [item for sublist in audio for item in sublist] + audio_file_paths = [] + # Save audio + logging.debug(f"args.trim: {args.trim}") + for i, aud in enumerate(audio): + aud = aud.cpu().numpy() + if args.trim: + aud = librosa.effects.trim(aud, top_db=40)[0] + soundfile.write(f"{i}.wav", aud, samplerate=22050) + audio_file_paths.append(str(Path(f"{i}.wav"))) + + # Do ASR + hypotheses = asr_model.transcribe(audio_file_paths) + for i, _ in enumerate(hypotheses): + logging.debug(f"{i}") + logging.debug(f"ref:'{asr_references[i]}'") + logging.debug(f"hyp:'{hypotheses[i]}'") + wer_value = word_error_rate(hypotheses=hypotheses, references=asr_references) + if wer_value > args.wer_tolerance: + raise ValueError(f"Got WER of {wer_value}. It was higher than {args.wer_tolerance}") + logging.info(f'Got WER of {wer_value}. Tolerance was {args.wer_tolerance}') + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/uniglow.py b/tts/NeMo/examples/tts/uniglow.py new file mode 100755 index 0000000..39a4be5 --- /dev/null +++ b/tts/NeMo/examples/tts/uniglow.py @@ -0,0 +1,44 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import UniGlowModel +from nemo.core.config import hydra_runner +from nemo.utils import logging +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="uniglow") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([epoch_time_logger]) + exp_manager(trainer, cfg.get("exp_manager", None)) + + if cfg.resume_from_ckpt is None: + logging.info("Training UniGlow from scratch") + model = UniGlowModel(cfg=cfg.model, trainer=trainer) + else: + logging.info("Fine-tuning UniGlow from {cfg.resume_from_ckpt}") + model = UniGlowModel.restore_from(cfg.resume_from_ckpt) + model.setup_training_data(cfg.model.train_ds) + model.setup_validation_data(cfg.model.validation_ds) + + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/examples/tts/waveglow.py b/tts/NeMo/examples/tts/waveglow.py new file mode 100755 index 0000000..66b1349 --- /dev/null +++ b/tts/NeMo/examples/tts/waveglow.py @@ -0,0 +1,34 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytorch_lightning as pl + +from nemo.collections.common.callbacks import LogEpochTimeCallback +from nemo.collections.tts.models import WaveGlowModel +from nemo.core.config import hydra_runner +from nemo.utils.exp_manager import exp_manager + + +@hydra_runner(config_path="conf", config_name="waveglow") +def main(cfg): + trainer = pl.Trainer(**cfg.trainer) + exp_manager(trainer, cfg.get("exp_manager", None)) + model = WaveGlowModel(cfg=cfg.model, trainer=trainer) + epoch_time_logger = LogEpochTimeCallback() + trainer.callbacks.extend([epoch_time_logger]) + trainer.fit(model) + + +if __name__ == '__main__': + main() # noqa pylint: disable=no-value-for-parameter diff --git a/tts/NeMo/external/get_collections.py b/tts/NeMo/external/get_collections.py new file mode 100644 index 0000000..803db2a --- /dev/null +++ b/tts/NeMo/external/get_collections.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" Script responsible for generation of a JSON file with list of NeMo collections. """ + +import argparse +import importlib +import json +import os + +import nemo +from nemo.utils import logging + + +def process_collection(id, col): + """ Helper function processing the collection. + + Args: + id: (short) name of the collection. + col: a collection (python module). + """ + return { + "id": id, + "name": col.__name__, + "description": col.__description__, + "version": col.__version__, + "author": col.__author__, + } + + +def main(): + """ Main function generating a JSON file with list of NeMo collections. """ + # Parse filename. + parser = argparse.ArgumentParser() + parser.add_argument('--filename', help='Name of the output JSON file', type=str, default="collections.json") + args = parser.parse_args() + + # Get collections directory. + colletions_dir = os.path.dirname(nemo.collections.__file__) + logging.info('Analysing collections in `{}`'.format(colletions_dir)) + + # Generate list of NeMo collections - from the list of collection subfolders. + collections = {} + for sub_dir in os.listdir(colletions_dir): + # Skip cache. + if sub_dir == "__pycache__": + continue + # Check if it is a directory. + if os.path.isdir(os.path.join(colletions_dir, sub_dir)): + collections[sub_dir] = "nemo.collections." + sub_dir + + output_list = [] + # Iterate over all collections. + for key, val in collections.items(): + # Try to get module specification. + module_spec = importlib.util.find_spec(val) + if module_spec is None: + logging.warning(" * Failed to process `{}`".format(val)) + else: + try: + # Import the module from the module specification. + module = importlib.util.module_from_spec(module_spec) + module_spec.loader.exec_module(module) + # Add to list. + output_list.append(process_collection(key, module)) + logging.info(" * Processed `{}`".format(val)) + except AttributeError: + logging.warning(" * Failed to process `{}`".format(val)) + + # Export to JSON. + with open(args.filename, 'w') as outfile: + json.dump(output_list, outfile) + + logging.info('Finshed the analysis, results exported to `{}`.'.format(args.filename)) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/external/get_modules.py b/tts/NeMo/external/get_modules.py new file mode 100644 index 0000000..ba8f2f6 --- /dev/null +++ b/tts/NeMo/external/get_modules.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" Script responsible for generation of a JSON file containing list of modules of a given collection. """ + +import argparse +import importlib +import inspect +import json +import os + +import nemo +from nemo.utils import logging + + +def process_member(name, obj, module_list): + """ Helper function processing the passed object and, if ok, adding a record to the module list. + + Args: + name: name of the member + obj: member (class/function etc.) + module_list: list of modules that (probably) will be expanded. + """ + # It is not a class - skip it. + if not inspect.isclass(obj): + return + + # Check inheritance - we know that all our datasets/modules/losses inherit from Serialization, + # Btw. Serialization is also required by this script. + if not issubclass(obj, nemo.core.Serialization): + return + + logging.info(" * Processing `{}`".format(str(obj))) + + module_list.append( + { + "name": name, + "cls": str(obj), + # Temporary solution: mockup arguments. + "arguments": [ + "jasper", + "activation", + "feat_in", + "normalization_mode", + "residual_mode", + "norm_groups", + "conv_mask", + "frame_splicing", + "init_mode", + ], + # Temporary solution: mockup input types. + "input_types": { + "audio_signal": "axes: (batch, dimension, time); elements_type: MelSpectrogramType", + "length": "axes: (batch,); elements_type: LengthType", + }, + # Temporary solution: mockup output types. + "output_types": { + "encoder_output": "axes: (batch, dimension, time); elements_type: AcousticEncodedRepresentation" + }, + } + ) + + +def main(): + """ Main function analysing the indicated NeMo collection and generating a JSON file with module descriptions. """ + # Parse filename. + parser = argparse.ArgumentParser() + parser.add_argument('--collection', help='ID of the collection', type=str) + parser.add_argument('--filename', help='Name of the output JSON file', type=str, default="modules.json") + args = parser.parse_args() + + # Get collections directory. + colletions_dir = os.path.dirname(nemo.collections.__file__) + logging.info('Analysing collections in `{}`'.format(colletions_dir)) + + # Generate list of NeMo collections - from the list of collection subfolders. + collections = {} + for sub_dir in os.listdir(colletions_dir): + # Skip cache. + if sub_dir == "__pycache__": + continue + # Check if it is a directory. + if os.path.isdir(os.path.join(colletions_dir, sub_dir)): + collections[sub_dir] = "nemo.collections." + sub_dir + + # Check the collection. + if args.collection not in collections.keys(): + logging.error("Coudn't process the incidated `{}` collection".format(args.collection)) + logging.info( + "Please select one of the existing collections using `--collection [{}]`".format("|".join(collections)) + ) + exit(-1) + + # Load the collection specification. + collection_spec = importlib.util.find_spec(collections[args.collection]) + if collection_spec is None: + logging.error("Failed to load the `{}` collection".format(val)) + + # Import the module from the module specification. + collection = importlib.util.module_from_spec(collection_spec) + collection_spec.loader.exec_module(collection) + + module_list = [] + # Iterate over the packages in the indicated collection. + logging.info("Analysing the `{}` collection".format(args.collection)) + + try: # Datasets in dataset folder + logging.info("Analysing the 'data' package") + for name, obj in inspect.getmembers(collection.data): + process_member(name, obj, module_list) + except AttributeError as e: + logging.info(" * No datasets found") + + try: # Datasets in dataset folder + logging.info("Analysing the 'datasets' package") + for name, obj in inspect.getmembers(collection.datasets): + process_member(name, obj, module_list) + except AttributeError as e: + logging.info(" * No datasets found") + + try: # Modules + logging.info("Analysing the 'modules' package") + for name, obj in inspect.getmembers(collection.modules): + process_member(name, obj, module_list) + except AttributeError as e: + logging.info(" * No modules found") + + try: # Losses + logging.info("Analysing the 'losses' package") + for name, obj in inspect.getmembers(collection.losses): + process_member(name, obj, module_list) + except AttributeError as e: + logging.info(" * No losses found") + + # Add prefix - only for default name. + filename = args.filename if args.filename != "modules.json" else args.collection + "_" + args.filename + # Export to JSON. + with open(filename, 'w') as outfile: + json.dump(module_list, outfile) + + logging.info( + 'Finished analysis of the `{}` collection, results exported to `{}`.'.format(args.collection, filename) + ) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/nemo_text_processing/README.md b/tts/NeMo/nemo_text_processing/README.md new file mode 100644 index 0000000..fd0f019 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/README.md @@ -0,0 +1,8 @@ +**nemo_text_processing** +========================== + +Introduction +------------ + +NeMo's `nemo_text_processing` is a Python package that is installed with the `nemo_toolkit`. +See [documentation](https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/) for details. \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/__init__.py b/tts/NeMo/nemo_text_processing/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/README.md b/tts/NeMo/nemo_text_processing/inverse_text_normalization/README.md new file mode 100644 index 0000000..30d2f22 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/README.md @@ -0,0 +1,12 @@ +Inverse Text Normalization system for english, e.g. `one hundred twenty three kilograms` -> `123 kg` +Offers prediction and evaluation on text normalization data, e.g. [Google text normalization dataset](https://www.kaggle.com/richardwilliamsproat/text-normalization-for-english-russian-and-polish). + + +Install dependencies: +bash setup.sh + +Example prediction run: +python run_predict.py --input=`INPUT_FILE` --output=`OUTPUT_FILE` [--verbose] + +Example evaluation run: +python run_evaluate.py --input=./en_with_types/output-00001-of-00100 [--cat CATEGORY] [--filter] diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/__init__.py new file mode 100644 index 0000000..51e4804 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/__init__.py @@ -0,0 +1,32 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from nemo_text_processing.inverse_text_normalization.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.inverse_text_normalization.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.inverse_text_normalization.verbalizers.verbalize_final import VerbalizeFinalFst + +from nemo.utils import logging + +try: + import pynini + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + logging.warning( + "`pynini` is not installed ! \n" + "Please run the `nemo_text_processing/setup.sh` script" + "prior to usage of this toolkit." + ) + + PYNINI_AVAILABLE = False diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/clean_eval_data.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/clean_eval_data.py new file mode 100644 index 0000000..d9bc2fc --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/clean_eval_data.py @@ -0,0 +1,342 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser +from typing import List + +import regex as re +from nemo_text_processing.text_normalization.data_loader_utils import ( + EOS_TYPE, + Instance, + load_files, + training_data_to_sentences, +) + + +""" +This file is for evaluation purposes. +filter_loaded_data() cleans data (list of instances) for inverse text normalization. Filters and cleaners can be specified for each semiotic class individually. +For example, normalized text should only include characters and whitespace characters but no punctuation. + Cardinal unnormalized instances should contain at least one integer and all other characters are removed. +""" + + +class Filter: + """ + Filter class + + Args: + class_type: semiotic class used in dataset + process_func: function to transform text + filter_func: function to filter text + + """ + + def __init__(self, class_type: str, process_func: object, filter_func: object): + self.class_type = class_type + self.process_func = process_func + self.filter_func = filter_func + + def filter(self, instance: Instance) -> bool: + """ + filter function + + Args: + filters given instance with filter function + + Returns: True if given instance fulfills criteria or does not belong to class type + """ + if instance.token_type != self.class_type: + return True + return self.filter_func(instance) + + def process(self, instance: Instance) -> Instance: + """ + process function + + Args: + processes given instance with process function + + Returns: processed instance if instance belongs to expected class type or original instance + """ + if instance.token_type != self.class_type: + return instance + return self.process_func(instance) + + +def filter_cardinal_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_cardinal_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r"[^0-9]", "", un_normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_ordinal_1(instance: Instance) -> bool: + ok = re.search(r"(st|nd|rd|th)\s*$", instance.un_normalized) + return ok + + +def process_ordinal_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r"[,\s]", "", un_normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_decimal_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_decimal_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + un_normalized = re.sub(r",", "", un_normalized) + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_measure_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_measure_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r",", "", un_normalized) + un_normalized = re.sub(r"m2", "m²", un_normalized) + un_normalized = re.sub(r"(\d)([^\d.\s])", r"\1 \2", un_normalized) + normalized = re.sub(r"[^a-z\s]", "", normalized) + normalized = re.sub(r"per ([a-z\s]*)s$", r"per \1", normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_money_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_money_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r",", "", un_normalized) + un_normalized = re.sub(r"a\$", r"$", un_normalized) + un_normalized = re.sub(r"us\$", r"$", un_normalized) + un_normalized = re.sub(r"(\d)m\s*$", r"\1 million", un_normalized) + un_normalized = re.sub(r"(\d)bn?\s*$", r"\1 billion", un_normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_time_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_time_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + un_normalized = re.sub(r": ", ":", un_normalized) + un_normalized = re.sub(r"(\d)\s?a\s?m\s?", r"\1 a.m.", un_normalized) + un_normalized = re.sub(r"(\d)\s?p\s?m\s?", r"\1 p.m.", un_normalized) + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_plain_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_plain_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_punct_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_punct_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_date_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_date_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + un_normalized = re.sub(r",", "", un_normalized) + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_letters_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_letters_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_verbatim_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_verbatim_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_digit_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_digit_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_telephone_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_telephone_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_electronic_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_electronic_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_fraction_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_fraction_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_address_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_address_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +filters = [] +filters.append(Filter(class_type="CARDINAL", process_func=process_cardinal_1, filter_func=filter_cardinal_1)) +filters.append(Filter(class_type="ORDINAL", process_func=process_ordinal_1, filter_func=filter_ordinal_1)) +filters.append(Filter(class_type="DECIMAL", process_func=process_decimal_1, filter_func=filter_decimal_1)) +filters.append(Filter(class_type="MEASURE", process_func=process_measure_1, filter_func=filter_measure_1)) +filters.append(Filter(class_type="MONEY", process_func=process_money_1, filter_func=filter_money_1)) +filters.append(Filter(class_type="TIME", process_func=process_time_1, filter_func=filter_time_1)) + +filters.append(Filter(class_type="DATE", process_func=process_date_1, filter_func=filter_date_1)) +filters.append(Filter(class_type="PLAIN", process_func=process_plain_1, filter_func=filter_plain_1)) +filters.append(Filter(class_type="PUNCT", process_func=process_punct_1, filter_func=filter_punct_1)) +filters.append(Filter(class_type="LETTERS", process_func=process_letters_1, filter_func=filter_letters_1)) +filters.append(Filter(class_type="VERBATIM", process_func=process_verbatim_1, filter_func=filter_verbatim_1)) +filters.append(Filter(class_type="DIGIT", process_func=process_digit_1, filter_func=filter_digit_1)) +filters.append(Filter(class_type="TELEPHONE", process_func=process_telephone_1, filter_func=filter_telephone_1)) +filters.append(Filter(class_type="ELECTRONIC", process_func=process_electronic_1, filter_func=filter_electronic_1)) +filters.append(Filter(class_type="FRACTION", process_func=process_fraction_1, filter_func=filter_fraction_1)) +filters.append(Filter(class_type="ADDRESS", process_func=process_address_1, filter_func=filter_address_1)) +filters.append(Filter(class_type=EOS_TYPE, process_func=lambda x: x, filter_func=lambda x: True)) + + +def filter_loaded_data(data: List[Instance], verbose: bool = False) -> List[Instance]: + """ + Filters list of instances + + Args: + data: list of instances + + Returns: filtered and transformed list of instances + """ + updates_instances = [] + for instance in data: + updated_instance = False + for fil in filters: + if fil.class_type == instance.token_type and fil.filter(instance): + instance = fil.process(instance) + updated_instance = True + if updated_instance: + if verbose: + print(instance) + updates_instances.append(instance) + return updates_instances + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--input", help="input file path", type=str, default='./en_with_types/output-00001-of-00100') + parser.add_argument("--verbose", help="print filtered instances", action='store_true') + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + file_path = args.input + + print("Loading training data: " + file_path) + instance_list = load_files([file_path]) # List of instances + filtered_instance_list = filter_loaded_data(instance_list, args.verbose) + training_data_to_sentences(filtered_instance_list) diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/currency.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/currency.tsv new file mode 100644 index 0000000..1c300bf --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/currency.tsv @@ -0,0 +1,35 @@ +$ dollar +$ us dollar +$ united states dollar +£ pound +€ euro +₩ won +nzd new zealand dollar +rs rupee +chf swiss franc +dkk danish kroner +fim finnish markka +aed arab emirates dirham +¥ yen +czk czech koruna +mro mauritanian ouguiya +pkr pakistani rupee +crc costa rican colon +hk$ hong kong dollar +npr nepalese rupee +awg aruban florin +nok norwegian kroner +tzs tanzanian shilling +sek swedish kronor +cyp cypriot pound +r real +sar saudi riyal +cve cape verde escudo +rsd serbian dinar +dm german mark +shp saint helena pounds +php philippine peso +cad canadian dollar +ssp south sudanese pound +scr seychelles rupee +mvr maldivian rufiyaa \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/domain.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/domain.tsv new file mode 100644 index 0000000..cb4bc3f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/domain.tsv @@ -0,0 +1 @@ +com com \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/server_name.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/server_name.tsv new file mode 100644 index 0000000..c447cf4 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/electronic/server_name.tsv @@ -0,0 +1,2 @@ +gmail g mail +nvidia n vidia \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/magnitudes.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/magnitudes.tsv new file mode 100644 index 0000000..3bfa484 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/magnitudes.tsv @@ -0,0 +1,4 @@ +k thousand +m million +b billion +t trillion \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/measurements.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/measurements.tsv new file mode 100644 index 0000000..db22e2a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/measurements.tsv @@ -0,0 +1,110 @@ +f fahrenheit +c celsius +km kilometer +m meter +cm centimeter +mm millimeter +ha hectare +mi mile +m² square meter +km² square kilometer +ft foot +% percent +hz hertz +kw kilowatt +hp horsepower +mg milligram +kg kilogram +ghz gigahertz +khz kilohertz +mhz megahertz +lb pound +v volt +h hour +mc mega coulomb +s second +nm nanometer +rpm revolution per minute +min minute +mA milli ampere +% per cent +kwh kilo watt hour +m³ cubic meter +mph mile per hour +tw tera watt +mv milli volt +mw megawatt +μm micrometer +" inch +tb terabyte +cc c c +g gram +da dalton +atm atmosphere +ω ohm +db decibel +ps peta second +oz ounce +hl hecto liter +μg microgram +pg petagram +gb gigabyte +kb kilobit +ev electron volt +mb megabyte +kb kilobyte +kbps kilobit per second +mbps megabit per second +st stone +kl kilo liter +tj tera joule +kv kilo volt +mv mega volt +kn kilonewton +mm megameter +au astronomical unit +yd yard +rad radian +lm lumen +hs hecto second +mol mole +gpa giga pascal +ml milliliter +gw gigawatt +ma mega ampere +kt knot +kgf kilogram force +ng nano gram +ns nanosecond +ms mega siemens +bar bar +gl giga liter +μs microsecond +da deci ampere +pa pascal +ds deci second +ms milli second +dm deci meter +dm³ cubic deci meter +amu atomic mass unit +mb megabit +mf mega farad +bq becquerel +pb petabit +mm² square millimeter +cm² square centimeter +sq mi square mile +sq ft square foot +kpa kilopascal +cd candela +tl tera liter +ms mega second +mpa megapascal +pm peta meter +pb peta byte +gwh giga watt hour +kcal kilo calory +gy gray +sv sievert +cwt hundredweight +cc c c diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/months.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/months.tsv new file mode 100644 index 0000000..6e7903c --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/months.tsv @@ -0,0 +1,12 @@ +january +february +march +april +may +june +july +august +september +october +november +december \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/digit.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/digit.tsv new file mode 100644 index 0000000..fa32979 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/digit.tsv @@ -0,0 +1,9 @@ +one 1 +two 2 +three 3 +four 4 +five 5 +six 6 +seven 7 +eight 8 +nine 9 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/hundred.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/hundred.tsv new file mode 100644 index 0000000..10e2b96 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/hundred.tsv @@ -0,0 +1 @@ +hundred \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/teen.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/teen.tsv new file mode 100644 index 0000000..8e60fa1 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/teen.tsv @@ -0,0 +1,10 @@ +ten 10 +eleven 11 +twelve 12 +thirteen 13 +fourteen 14 +fifteen 15 +sixteen 16 +seventeen 17 +eighteen 18 +nineteen 19 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/thousands.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/thousands.tsv new file mode 100644 index 0000000..bf30542 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/thousands.tsv @@ -0,0 +1,22 @@ +thousand +million +billion +trillion +quadrillion +quintillion +sextillion +septillion +octillion +nonillion +decillion +undecillion +duodecillion +tredecillion +quattuordecillion +quindecillion +sexdecillion +septendecillion +octodecillion +novemdecillion +vigintillion +centillion \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/ties.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/ties.tsv new file mode 100644 index 0000000..d7ec82e --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/ties.tsv @@ -0,0 +1,9 @@ +twenty 2 +thirty 3 +forty 4 +fourty 4 +fifty 5 +sixty 6 +seventy 7 +eighty 8 +ninety 9 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/zero.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/zero.tsv new file mode 100644 index 0000000..c479272 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/numbers/zero.tsv @@ -0,0 +1 @@ +zero 0 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/digit.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/digit.tsv new file mode 100644 index 0000000..4b7fc24 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/digit.tsv @@ -0,0 +1,9 @@ +first one +second two +third three +fourth four +fifth five +sixth sixth +seventh seven +eighth eight +ninth nine \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/teen.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/teen.tsv new file mode 100644 index 0000000..496fefc --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/ordinals/teen.tsv @@ -0,0 +1 @@ +twelfth twelve \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_suffix.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_suffix.tsv new file mode 100644 index 0000000..b39a9ef --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_suffix.tsv @@ -0,0 +1,8 @@ +p m p.m. +pm p.m. +p.m. +p.m p.m. +am a.m. +a.m. +a.m a.m. +a m a.m. \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_to.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_to.tsv new file mode 100644 index 0000000..1b006ea --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_to.tsv @@ -0,0 +1,12 @@ +one 12 +two 1 +three 2 +four 3 +five 4 +six 5 +seven 6 +eigh 7 +nine 8 +ten 9 +eleven 10 +twelve 11 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_zone.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_zone.tsv new file mode 100644 index 0000000..3e0ade4 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/time/time_zone.tsv @@ -0,0 +1,7 @@ +cst c s t +cet c e t +pst p s t +est e s t +pt p t +et e t +gmt g m t diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/whitelist.tsv b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/whitelist.tsv new file mode 100644 index 0000000..92f3877 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/data/whitelist.tsv @@ -0,0 +1,10 @@ +e.g. for example +i.e. that is +dr. doctor +mr. mister +mrs. misses +ms. miss +st. saint +7-eleven seven eleven +es3 e s three +s&p s and p diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/inverse_normalize.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/inverse_normalize.py new file mode 100644 index 0000000..44f4d5e --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/inverse_normalize.py @@ -0,0 +1,71 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser +from typing import List + +from nemo_text_processing.inverse_text_normalization.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.inverse_text_normalization.verbalizers.verbalize_final import VerbalizeFinalFst +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.token_parser import TokenParser + + +class InverseNormalizer(Normalizer): + """ + Inverse normalizer that converts text from spoken to written form. Useful for ASR postprocessing. + Input is expected to have no punctuation and be lower cased. + """ + + def __init__(self): + self.tagger = ClassifyFst() + self.verbalizer = VerbalizeFinalFst() + self.parser = TokenParser() + + def inverse_normalize_list(self, texts: List[str], verbose=False) -> List[str]: + """ + NeMo inverse text normalizer + + Args: + texts: list of input strings + verbose: whether to print intermediate meta information + + Returns converted list of input strings + """ + return self.normalize_list(texts=texts, verbose=verbose) + + def inverse_normalize(self, text: str, verbose: bool) -> str: + """ + Main function. Inverse normalizes tokens from spoken to written form + e.g. twelve kilograms -> 12 kg + + Args: + text: string that may include semiotic classes + verbose: whether to print intermediate meta information + + Returns: written form + """ + return self.normalize(text=text, verbose=verbose) + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("input_string", help="input string", type=str) + parser.add_argument("--verbose", help="print info for debugging", action='store_true') + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + inverse_normalizer = InverseNormalizer() + print(inverse_normalizer.inverse_normalize(args.input_string, verbose=args.verbose)) diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/run_evaluate.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/run_evaluate.py new file mode 100644 index 0000000..845486f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/run_evaluate.py @@ -0,0 +1,109 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser + +from nemo_text_processing.inverse_text_normalization.clean_eval_data import filter_loaded_data +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.data_loader_utils import ( + evaluate, + known_types, + load_files, + training_data_to_sentences, + training_data_to_tokens, +) + + +''' +Runs Evaluation on data in the format of : \t\t<`self` if trivial class or normalized text> +like the Google text normalization data https://www.kaggle.com/richardwilliamsproat/text-normalization-for-english-russian-and-polish +''' + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--input", help="input file path", type=str) + parser.add_argument( + "--cat", + dest="category", + help="focus on class only (" + ", ".join(known_types) + ")", + type=str, + default=None, + choices=known_types, + ) + parser.add_argument("--filter", action='store_true', help="clean data for inverse normalization purposes") + return parser.parse_args() + + +if __name__ == "__main__": + # Example usage: + # python run_evaluate.py --input= --cat= --filter + args = parse_args() + file_path = args.input + inverse_normalizer = InverseNormalizer() + + print("Loading training data: " + file_path) + training_data = load_files([file_path]) + + if args.filter: + training_data = filter_loaded_data(training_data) + + if args.category is None: + print("Sentence level evaluation...") + sentences_un_normalized, sentences_normalized, _ = training_data_to_sentences(training_data) + print("- Data: " + str(len(sentences_normalized)) + " sentences") + sentences_prediction = inverse_normalizer.inverse_normalize_list(sentences_normalized) + print("- Denormalized. Evaluating...") + sentences_accuracy = evaluate( + preds=sentences_prediction, labels=sentences_un_normalized, input=sentences_normalized + ) + print("- Accuracy: " + str(sentences_accuracy)) + + print("Token level evaluation...") + tokens_per_type = training_data_to_tokens(training_data, category=args.category) + token_accuracy = {} + for token_type in tokens_per_type: + print("- Token type: " + token_type) + tokens_un_normalized, tokens_normalized = tokens_per_type[token_type] + print(" - Data: " + str(len(tokens_normalized)) + " tokens") + tokens_prediction = inverse_normalizer.inverse_normalize_list(tokens_normalized) + print(" - Denormalized. Evaluating...") + token_accuracy[token_type] = evaluate(tokens_prediction, tokens_un_normalized, input=tokens_normalized) + print(" - Accuracy: " + str(token_accuracy[token_type])) + token_count_per_type = {token_type: len(tokens_per_type[token_type][0]) for token_type in tokens_per_type} + token_weighted_accuracy = [ + token_count_per_type[token_type] * accuracy for token_type, accuracy in token_accuracy.items() + ] + print("- Accuracy: " + str(sum(token_weighted_accuracy) / sum(token_count_per_type.values()))) + + print(" - Total: " + str(sum(token_count_per_type.values())), '\n') + + for token_type in token_accuracy: + if token_type not in known_types: + raise ValueError("Unexpected token type: " + token_type) + + if args.category is None: + c1 = ['Class', 'sent level'] + known_types + c2 = ['Num Tokens', len(sentences_normalized)] + [ + token_count_per_type[known_type] if known_type in tokens_per_type else '0' for known_type in known_types + ] + c3 = ["Denormalization", sentences_accuracy] + [ + token_accuracy[known_type] if known_type in token_accuracy else '0' for known_type in known_types + ] + + for i in range(len(c1)): + print(f'{str(c1[i]):10s} | {str(c2[i]):10s} | {str(c3[i]):5s}') + else: + print(f'numbers\t{token_count_per_type[args.category]}') + print(f'Denormalization\t{token_accuracy[args.category]}') diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/run_predict.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/run_predict.py new file mode 100644 index 0000000..39ce2ca --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/run_predict.py @@ -0,0 +1,75 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser +from typing import List + +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer + + +''' +Runs inverse text normalization on text data +''' + + +def load_file(file_path: str) -> List[str]: + """ + Load given text file into list of string. + + Args: + file_path: file path + + Returns: flat list of string + """ + res = [] + with open(file_path, 'r') as fp: + for line in fp: + res.append(line) + return res + + +def write_file(file_path: str, data: List[str]): + """ + Writes out list of string to file. + + Args: + file_path: file path + data: list of string + + """ + with open(file_path, 'w') as fp: + for line in data: + fp.write(line + '\n') + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--input", help="input file path", required=True, type=str) + parser.add_argument("--output", help="output file path", required=True, type=str) + parser.add_argument("--verbose", help="print denormalization info. For debugging", action='store_true') + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + file_path = args.input + inverse_normalizer = InverseNormalizer() + + print("Loading data: " + file_path) + data = load_file(file_path) + + print("- Data: " + str(len(data)) + " sentences") + inverse_normalizer_prediction = inverse_normalizer.inverse_normalize_list(data, verbose=args.verbose) + write_file(args.output, inverse_normalizer_prediction) + print(f"- Denormalized. Writing out to {args.output}") diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/cardinal.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/cardinal.py new file mode 100644 index 0000000..20c78af --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/cardinal.py @@ -0,0 +1,134 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path, num_to_word +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_DIGIT, + NEMO_SIGMA, + NEMO_SPACE, + GraphFst, + delete_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class CardinalFst(GraphFst): + """ + Finite state transducer for classifying cardinals + e.g. minus twenty three -> cardinal { integer: "23" negative: "-" } } + Numbers below thirteen are not converted. + """ + + def __init__(self): + super().__init__(name="cardinal", kind="classify") + graph_zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + graph_ties = pynini.string_file(get_abs_path("data/numbers/ties.tsv")) + graph_teen = pynini.string_file(get_abs_path("data/numbers/teen.tsv")) + + graph_hundred = pynini.cross("hundred", "") + + graph_hundred_component = pynini.union(graph_digit + delete_space + graph_hundred, pynutil.insert("0")) + graph_hundred_component += delete_space + graph_hundred_component += pynini.union( + graph_teen | pynutil.insert("00"), + (graph_ties | pynutil.insert("0")) + delete_space + (graph_digit | pynutil.insert("0")), + ) + + graph_hundred_component_at_least_one_none_zero_digit = graph_hundred_component @ ( + pynini.closure(NEMO_DIGIT) + (NEMO_DIGIT - "0") + pynini.closure(NEMO_DIGIT) + ) + self.graph_hundred_component_at_least_one_none_zero_digit = ( + graph_hundred_component_at_least_one_none_zero_digit + ) + + graph_thousands = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("thousand"), + pynutil.insert("000", weight=0.1), + ) + + graph_million = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("million"), + pynutil.insert("000", weight=0.1), + ) + graph_billion = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("billion"), + pynutil.insert("000", weight=0.1), + ) + graph_trillion = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("trillion"), + pynutil.insert("000", weight=0.1), + ) + graph_quadrillion = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("quadrillion"), + pynutil.insert("000", weight=0.1), + ) + graph_quintillion = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("quintillion"), + pynutil.insert("000", weight=0.1), + ) + graph_sextillion = pynini.union( + graph_hundred_component_at_least_one_none_zero_digit + delete_space + pynutil.delete("sextillion"), + pynutil.insert("000", weight=0.1), + ) + + graph = pynini.union( + graph_sextillion + + delete_space + + graph_quintillion + + delete_space + + graph_quadrillion + + delete_space + + graph_trillion + + delete_space + + graph_billion + + delete_space + + graph_million + + delete_space + + graph_thousands + + delete_space + + graph_hundred_component, + graph_zero, + ) + + graph = graph @ pynini.union( + pynutil.delete(pynini.closure("0")) + pynini.difference(NEMO_DIGIT, "0") + pynini.closure(NEMO_DIGIT), "0" + ) + + labels_exception = [num_to_word(x) for x in range(0, 13)] + graph_exception = pynini.union(*labels_exception) + + graph = pynini.cdrewrite(pynutil.delete("and"), NEMO_SPACE, NEMO_SPACE, NEMO_SIGMA) @ graph + + self.graph_no_exception = graph + + self.graph = (pynini.project(graph, "input") - graph_exception.arcsort()) @ graph + + optional_minus_graph = pynini.closure( + pynutil.insert("negative: ") + pynini.cross("minus", "\"-\"") + NEMO_SPACE, 0, 1 + ) + + final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.graph + pynutil.insert("\"") + + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/date.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/date.py new file mode 100644 index 0000000..60088db --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/date.py @@ -0,0 +1,163 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_ALPHA, + NEMO_DIGIT, + GraphFst, + delete_extra_space, + delete_space, +) + +try: + import pynini + from pynini.lib import pynutil + + graph_teen = pynini.string_file(get_abs_path("data/numbers/teen.tsv")).optimize() + graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")).optimize() + ties_graph = pynini.string_file(get_abs_path("data/numbers/ties.tsv")).optimize() + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + graph_teen = None + graph_digit = None + ties_graph = None + + PYNINI_AVAILABLE = True + + +def _get_month_graph(): + """ + Transducer for month, e.g. march -> march + """ + month_graph = pynini.string_file(get_abs_path("data/months.tsv")) + return month_graph + + +def _get_ties_graph(): + """ + Transducer for 20-99 e.g + twenty three -> 23 + """ + graph = ties_graph + (delete_space + graph_digit | pynutil.insert("0")) + return graph + + +def _get_range_graph(): + """ + Transducer for decades (1**0s, 2**0s), centuries (2*00s, 1*00s), millennia (2000s) + """ + graph_ties = _get_ties_graph() + graph = (graph_ties | graph_teen) + delete_space + pynini.cross("hundreds", "00s") + graph |= pynini.cross("two", "2") + delete_space + pynini.cross("thousands", "000s") + graph |= ( + (graph_ties | graph_teen) + + delete_space + + (pynini.closure(NEMO_ALPHA, 1) + (pynini.cross("ies", "y") | pynutil.delete("s"))) + @ (graph_ties | pynini.cross("ten", "10")) + + pynutil.insert("s") + ) + graph @= pynini.union("1", "2") + NEMO_DIGIT + NEMO_DIGIT + NEMO_DIGIT + "s" + return graph + + +def _get_year_graph(): + """ + Transducer for year, e.g. twenty twenty -> 2020 + """ + + def _get_digits_graph(): + zero = pynini.cross((pynini.accep("oh") | pynini.accep("o")), "0") + graph = zero + delete_space + graph_digit + graph.optimize() + return graph + + def _get_thousands_graph(): + graph_ties = _get_ties_graph() + graph_hundred_component = (graph_digit + delete_space + pynutil.delete("hundred")) | pynutil.insert("0") + graph = ( + graph_digit + + delete_space + + pynutil.delete("thousand") + + delete_space + + graph_hundred_component + + delete_space + + (graph_teen | graph_ties) + ) + return graph + + graph_ties = _get_ties_graph() + graph_digits = _get_digits_graph() + graph_thousands = _get_thousands_graph() + year_graph = ( + # 20 19, 40 12, 2012 - assuming no limit on the year + (graph_teen + delete_space + (graph_ties | graph_digits | graph_teen)) + | (graph_ties + delete_space + (graph_ties | graph_digits | graph_teen)) + | graph_thousands + ) + year_graph.optimize() + return year_graph + + +class DateFst(GraphFst): + """ + Finite state transducer for classifying date, + e.g. january fifth twenty twelve -> date { month: "january" day: "5" year: "2012" preserve_order: true } + e.g. the fifth of january twenty twelve -> date { day: "5" month: "january" year: "2012" preserve_order: true } + e.g. twenty twenty -> date { year: "2012" preserve_order: true } + + Args: + ordinal: OrdinalFst + """ + + def __init__(self, ordinal: GraphFst): + super().__init__(name="date", kind="classify") + + ordinal_graph = ordinal.graph + year_graph = _get_year_graph() + YEAR_WEIGHT = 0.001 + year_graph = pynutil.add_weight(year_graph, YEAR_WEIGHT) + month_graph = _get_month_graph() + + month_graph = pynutil.insert("month: \"") + month_graph + pynutil.insert("\"") + + day_graph = pynutil.insert("day: \"") + pynutil.add_weight(ordinal_graph, -0.7) + pynutil.insert("\"") + optional_day_graph = pynini.closure(delete_extra_space + day_graph, 0, 1) + optional_graph_year = pynini.closure( + delete_extra_space + + pynutil.insert("year: \"") + + pynutil.add_weight(year_graph, -YEAR_WEIGHT) + + pynutil.insert("\""), + 0, + 1, + ) + graph_mdy = month_graph + optional_day_graph + optional_graph_year + graph_dmy = ( + pynutil.delete("the") + + delete_space + + day_graph + + delete_space + + pynutil.delete("of") + + delete_extra_space + + month_graph + + optional_graph_year + ) + graph_year = pynutil.insert("year: \"") + (year_graph | _get_range_graph()) + pynutil.insert("\"") + + final_graph = graph_mdy | graph_dmy | graph_year + final_graph += pynutil.insert(" preserve_order: true") + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/decimal.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/decimal.py new file mode 100644 index 0000000..47017f4 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/decimal.py @@ -0,0 +1,95 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import NEMO_DIGIT, GraphFst, delete_extra_space, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +def get_quantity(decimal: 'pynini.FstLike', cardinal_up_to_hundred: 'pynini.FstLike') -> 'pynini.FstLike': + """ + Returns FST that transforms either a cardinal or decimal followed by a quantity into a numeral, + e.g. one million -> integer_part: "1" quantity: "million" + e.g. one point five million -> integer_part: "1" fractional_part: "5" quantity: "million" + + Args: + decimal: decimal FST + cardinal_up_to_hundred: cardinal FST + """ + numbers = cardinal_up_to_hundred @ ( + pynutil.delete(pynini.closure("0")) + pynini.difference(NEMO_DIGIT, "0") + pynini.closure(NEMO_DIGIT) + ) + suffix = pynini.union("million", "billion", "trillion", "quadrillion", "quintillion", "sextillion") + res = ( + pynutil.insert("integer_part: \"") + + numbers + + pynutil.insert("\"") + + delete_extra_space + + pynutil.insert("quantity: \"") + + suffix + + pynutil.insert("\"") + ) + res |= decimal + delete_extra_space + pynutil.insert("quantity: \"") + (suffix | "thousand") + pynutil.insert("\"") + return res + + +class DecimalFst(GraphFst): + """ + Finite state transducer for classifying decimal + e.g. minus twelve point five o o six billion -> decimal { negative: "true" integer_part: "12" fractional_part: "5006" quantity: "billion" } + e.g. one billion -> decimal { integer_part: "1" quantity: "billion" } + Args: + cardinal: CardinalFst + """ + + def __init__(self, cardinal: GraphFst): + super().__init__(name="decimal", kind="classify") + + cardinal_graph = cardinal.graph_no_exception + + graph_decimal = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + graph_decimal |= pynini.string_file(get_abs_path("data/numbers/zero.tsv")) | pynini.cross("o", "0") + + graph_decimal = pynini.closure(graph_decimal + delete_space) + graph_decimal + self.graph = graph_decimal + + point = pynutil.delete("point") + + optional_graph_negative = pynini.closure( + pynutil.insert("negative: ") + pynini.cross("minus", "\"true\"") + delete_extra_space, 0, 1 + ) + + graph_fractional = pynutil.insert("fractional_part: \"") + graph_decimal + pynutil.insert("\"") + graph_integer = pynutil.insert("integer_part: \"") + cardinal_graph + pynutil.insert("\"") + final_graph_wo_sign = ( + pynini.closure(graph_integer + delete_extra_space, 0, 1) + point + delete_extra_space + graph_fractional + ) + final_graph = optional_graph_negative + final_graph_wo_sign + + self.final_graph_wo_negative = final_graph_wo_sign | get_quantity( + final_graph_wo_sign, cardinal.graph_hundred_component_at_least_one_none_zero_digit + ) + final_graph |= optional_graph_negative + get_quantity( + final_graph_wo_sign, cardinal.graph_hundred_component_at_least_one_none_zero_digit + ) + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/electronic.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/electronic.py new file mode 100644 index 0000000..018efd6 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/electronic.py @@ -0,0 +1,66 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import NEMO_ALPHA, GraphFst, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class ElectronicFst(GraphFst): + """ + Finite state transducer for classifying electronic: as URLs, email addresses, etc. + e.g. c d f one at a b c dot e d u -> tokens { electronic { username: "cdf1" domain: "abc.edu" } } + """ + + def __init__(self): + super().__init__(name="electronic", kind="classify") + + delete_extra_space = pynutil.delete(" ") + alpha_num = ( + NEMO_ALPHA + | pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + | pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + ) + username = ( + pynutil.insert("username: \"") + + pynini.closure( + alpha_num + delete_extra_space + pynini.closure(pynini.cross("dot", '.') + delete_extra_space, 0, 1) + ) + + alpha_num + + pynutil.insert("\"") + ) + single_alphanum = pynini.closure(alpha_num + delete_extra_space) + alpha_num + server = single_alphanum | pynini.string_file(get_abs_path("data/electronic/server_name.tsv")).invert() + domain = single_alphanum | pynini.string_file(get_abs_path("data/electronic/domain.tsv")).invert() + domain_graph = ( + pynutil.insert("domain: \"") + + server + + delete_extra_space + + pynini.cross("dot", ".") + + delete_extra_space + + domain + + pynutil.insert("\"") + ) + graph = username + delete_extra_space + pynutil.delete("at") + insert_space + delete_extra_space + domain_graph + + final_graph = self.add_tokens(graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/fraction.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/fraction.py new file mode 100644 index 0000000..6b2cd74 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/fraction.py @@ -0,0 +1,26 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst + + +class FractionFst(GraphFst): + """ + Finite state transducer for classifying fraction + """ + + def __init__(self): + super().__init__(name="fraction", kind="classify") + # integer_part # numerator # denominator diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/measure.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/measure.py new file mode 100644 index 0000000..9cb6755 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/measure.py @@ -0,0 +1,103 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_SIGMA, + GraphFst, + convert_space, + delete_extra_space, + delete_space, + get_singulars, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class MeasureFst(GraphFst): + """ + Finite state transducer for classifying measure + e.g. minus twelve kilograms -> measure { negative: "true" cardinal { integer: "12" } units: "kg" } + + Args: + cardinal: CardinalFst + decimal: DecimalFst + """ + + def __init__(self, cardinal: GraphFst, decimal: GraphFst): + super().__init__(name="measure", kind="classify") + + cardinal_graph = cardinal.graph_no_exception + + graph_unit = pynini.string_file(get_abs_path("data/measurements.tsv")) + graph_unit_singular = pynini.invert(graph_unit) # singular -> abbr + graph_unit_plural = get_singulars(graph_unit_singular) # plural -> abbr + + optional_graph_negative = pynini.closure( + pynutil.insert("negative: ") + pynini.cross("minus", "\"true\"") + delete_extra_space, 0, 1 + ) + + unit_singular = convert_space(graph_unit_singular) + unit_plural = convert_space(graph_unit_plural) + unit_misc = pynutil.insert("/") + pynutil.delete("per") + delete_space + convert_space(graph_unit_singular) + + unit_singular = ( + pynutil.insert("units: \"") + + (unit_singular | unit_misc | pynutil.add_weight(unit_singular + delete_space + unit_misc, 0.01)) + + pynutil.insert("\"") + ) + unit_plural = ( + pynutil.insert("units: \"") + + (unit_plural | unit_misc | pynutil.add_weight(unit_plural + delete_space + unit_misc, 0.01)) + + pynutil.insert("\"") + ) + + subgraph_decimal = ( + pynutil.insert("decimal { ") + + optional_graph_negative + + decimal.final_graph_wo_negative + + pynutil.insert(" }") + + delete_extra_space + + unit_plural + ) + subgraph_cardinal = ( + pynutil.insert("cardinal { ") + + optional_graph_negative + + pynutil.insert("integer: \"") + + ((NEMO_SIGMA - "one") @ cardinal_graph) + + pynutil.insert("\"") + + pynutil.insert(" }") + + delete_extra_space + + unit_plural + ) + subgraph_cardinal |= ( + pynutil.insert("cardinal { ") + + optional_graph_negative + + pynutil.insert("integer: \"") + + pynini.cross("one", "1") + + pynutil.insert("\"") + + pynutil.insert(" }") + + delete_extra_space + + unit_singular + ) + final_graph = subgraph_decimal | subgraph_cardinal + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/money.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/money.py new file mode 100644 index 0000000..8787419 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/money.py @@ -0,0 +1,112 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_DIGIT, + NEMO_SIGMA, + GraphFst, + convert_space, + delete_extra_space, + delete_space, + get_singulars, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class MoneyFst(GraphFst): + """ + Finite state transducer for classifying money + e.g. twelve dollars and five cents -> money { integer_part: "12" fractional_part: 05 currency: "$" } + + Args: + cardinal: CardinalFst + decimal: DecimalFst + """ + + def __init__(self, cardinal: GraphFst, decimal: GraphFst): + super().__init__(name="money", kind="classify") + # quantity, integer_part, fractional_part, currency + + cardinal_graph = cardinal.graph_no_exception + graph_decimal_final = decimal.final_graph_wo_negative + + unit = pynini.string_file(get_abs_path("data/currency.tsv")) + unit_singular = pynini.invert(unit) + unit_plural = get_singulars(unit_singular) + + graph_unit_singular = pynutil.insert("currency: \"") + convert_space(unit_singular) + pynutil.insert("\"") + graph_unit_plural = pynutil.insert("currency: \"") + convert_space(unit_plural) + pynutil.insert("\"") + + add_leading_zero_to_double_digit = (NEMO_DIGIT + NEMO_DIGIT) | (pynutil.insert("0") + NEMO_DIGIT) + # twelve dollars (and) fifty cents, zero cents + cents_standalone = ( + pynutil.insert("fractional_part: \"") + + pynini.union( + pynutil.add_weight(((NEMO_SIGMA - "one") @ cardinal_graph), -0.7) @ add_leading_zero_to_double_digit + + delete_space + + pynutil.delete("cents"), + pynini.cross("one", "01") + delete_space + pynutil.delete("cent"), + ) + + pynutil.insert("\"") + ) + + optional_cents_standalone = pynini.closure( + delete_space + + pynini.closure(pynutil.delete("and") + delete_space, 0, 1) + + insert_space + + cents_standalone, + 0, + 1, + ) + # twelve dollars fifty, only after integer + optional_cents_suffix = pynini.closure( + delete_extra_space + + pynutil.insert("fractional_part: \"") + + pynutil.add_weight(cardinal_graph @ add_leading_zero_to_double_digit, -0.7) + + pynutil.insert("\""), + 0, + 1, + ) + + graph_integer = ( + pynutil.insert("integer_part: \"") + + ((NEMO_SIGMA - "one") @ cardinal_graph) + + pynutil.insert("\"") + + delete_extra_space + + graph_unit_plural + + (optional_cents_standalone | optional_cents_suffix) + ) + graph_integer |= ( + pynutil.insert("integer_part: \"") + + pynini.cross("one", "1") + + pynutil.insert("\"") + + delete_extra_space + + graph_unit_singular + + (optional_cents_standalone | optional_cents_suffix) + ) + graph_decimal = graph_decimal_final + delete_extra_space + graph_unit_plural + graph_decimal |= pynutil.insert("currency: \"$\" integer_part: \"0\" ") + cents_standalone + final_graph = graph_integer | graph_decimal + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/ordinal.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/ordinal.py new file mode 100644 index 0000000..54b48ae --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/ordinal.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ImportError, ModuleNotFoundError): + PYNINI_AVAILABLE = False + + +class OrdinalFst(GraphFst): + """ + Finite state transducer for classifying ordinal + e.g. thirteenth -> ordinal { integer: "13" } + + Args: + cardinal: CardinalFst + """ + + def __init__(self, cardinal: GraphFst): + super().__init__(name="ordinal", kind="classify") + + cardinal_graph = cardinal.graph_no_exception + graph_digit = pynini.string_file(get_abs_path("data/ordinals/digit.tsv")) + graph_teens = pynini.string_file(get_abs_path("data/ordinals/teen.tsv")) + graph = pynini.closure(NEMO_CHAR) + pynini.union( + graph_digit, graph_teens, pynini.cross("tieth", "ty"), pynini.cross("th", "") + ) + + self.graph = graph @ cardinal_graph + final_graph = pynutil.insert("integer: \"") + self.graph + pynutil.insert("\"") + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/punctuation.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/punctuation.py new file mode 100644 index 0000000..bd5a426 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/punctuation.py @@ -0,0 +1,41 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = False +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class PunctuationFst(GraphFst): + """ + Finite state transducer for classifying punctuation + e.g. a, -> tokens { name: "a" } tokens { name: "," } + """ + + def __init__(self): + super().__init__(name="punctuation", kind="classify") + + s = "!#$%&\'()*+,-./:;<=>?@^_`{|}~" + punct = pynini.union(*s) + + graph = pynutil.insert("name: \"") + punct + pynutil.insert("\"") + + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/telephone.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/telephone.py new file mode 100644 index 0000000..8705f0e --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/telephone.py @@ -0,0 +1,67 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_space, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TelephoneFst(GraphFst): + """ + Finite state transducer for classifying telephone numbers, e.g. + one two three one two three five six seven eight -> { number_part: "123-123-5678" } + """ + + def __init__(self): + super().__init__(name="telephone", kind="classify") + delete_space = pynutil.delete(' ') + # country code, number_part, extension + add_separator = pynutil.insert(" ") # between components + digit = pynini.invert(pynini.string_file(get_abs_path("data/numbers/digit.tsv"))).optimize() | pynini.cross( + "0", pynini.union("o", "oh", "zero") + ) + + number_part = ( + ( + (pynini.closure(digit + insert_space, 2, 2) + digit + pynutil.delete("-")) + | ( + pynutil.delete("(") + + pynini.closure(digit + insert_space, 2, 2) + + digit + + pynutil.delete(")") + + pynini.closure(pynutil.delete("-"), 0, 1) + + delete_space + ) + ) + + add_separator + + pynini.closure(digit + insert_space, 2, 2) + + digit + + pynutil.delete("-") + + add_separator + + pynini.closure(digit + insert_space, 3, 3) + + digit + ) + number_part = pynutil.insert("number_part: \"") + pynini.invert(number_part) + pynutil.insert("\"") + + graph = number_part + final_graph = self.add_tokens(graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/time.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/time.py new file mode 100644 index 0000000..1132ee9 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/time.py @@ -0,0 +1,124 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.inverse_text_normalization.taggers.cardinal import CardinalFst +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path, num_to_word +from nemo_text_processing.text_normalization.graph_utils import ( + GraphFst, + convert_space, + delete_extra_space, + delete_space, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TimeFst(GraphFst): + """ + Finite state transducer for classifying time + e.g. twelve thirty -> time { hours: "12" minutes: "30" } + e.g. twelve past one -> time { minutes: "12" hours: "1" } + e.g. two o clock a m -> time { hours: "2" suffix: "a.m." } + e.g. quarter to two -> time { hours: "1" minutes: "45" } + e.g. quarter past two -> time { hours: "2" minutes: "15" } + e.g. half past two -> time { hours: "2" minutes: "30" } + """ + + def __init__(self): + super().__init__(name="time", kind="classify") + # hours, minutes, seconds, suffix, zone, style, speak_period + + suffix_graph = pynini.string_file(get_abs_path("data/time/time_suffix.tsv")) + time_zone_graph = pynini.invert(pynini.string_file(get_abs_path("data/time/time_zone.tsv"))) + time_to_graph = pynini.string_file(get_abs_path("data/time/time_to.tsv")) + + # only used for < 1000 thousand -> 0 weight + cardinal = pynutil.add_weight(CardinalFst().graph_no_exception, weight=-0.7) + + labels_hour = [num_to_word(x) for x in range(0, 24)] + labels_minute_single = [num_to_word(x) for x in range(1, 10)] + labels_minute_double = [num_to_word(x) for x in range(10, 60)] + + graph_hour = pynini.union(*labels_hour) @ cardinal + + graph_minute_single = pynini.union(*labels_minute_single) @ cardinal + graph_minute_double = pynini.union(*labels_minute_double) @ cardinal + graph_minute_verbose = pynini.cross("half", "30") | pynini.cross("quarter", "15") + oclock = pynini.cross(pynini.union("o' clock", "o clock", "o'clock", "oclock"), "") + + final_graph_hour = pynutil.insert("hours: \"") + graph_hour + pynutil.insert("\"") + final_graph_minute = ( + pynutil.insert("minutes: \"") + + ( + pynutil.insert("00") + | oclock + pynutil.insert("00") + | pynutil.delete("o") + delete_space + graph_minute_single + | graph_minute_double + ) + + pynutil.insert("\"") + ) + final_suffix = pynutil.insert("suffix: \"") + convert_space(suffix_graph) + pynutil.insert("\"") + final_suffix_optional = pynini.closure(delete_space + insert_space + final_suffix, 0, 1) + final_time_zone_optional = pynini.closure( + delete_space + + insert_space + + pynutil.insert("zone: \"") + + convert_space(time_zone_graph) + + pynutil.insert("\""), + 0, + 1, + ) + + # five o' clock + # two o eight, two thiry five (am/pm) + # two pm/am + graph_hm = final_graph_hour + delete_extra_space + final_graph_minute + # 10 past four, quarter past four, half past four + graph_mh = ( + pynutil.insert("minutes: \"") + + pynini.union(graph_minute_single, graph_minute_double, graph_minute_verbose) + + pynutil.insert("\"") + + delete_space + + pynutil.delete("past") + + delete_extra_space + + final_graph_hour + ) + + graph_quarter_time = ( + pynutil.insert("minutes: \"") + + pynini.cross("quarter", "45") + + pynutil.insert("\"") + + delete_space + + pynutil.delete(pynini.union("to", "till")) + + delete_extra_space + + pynutil.insert("hours: \"") + + time_to_graph + + pynutil.insert("\"") + ) + final_graph = ( + (graph_hm | graph_mh | graph_quarter_time) + final_suffix_optional + final_time_zone_optional + ).optimize() + + final_graph = self.add_tokens(final_graph) + + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/tokenize_and_classify.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/tokenize_and_classify.py new file mode 100644 index 0000000..0c7718c --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/tokenize_and_classify.py @@ -0,0 +1,91 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.taggers.cardinal import CardinalFst +from nemo_text_processing.inverse_text_normalization.taggers.date import DateFst +from nemo_text_processing.inverse_text_normalization.taggers.decimal import DecimalFst +from nemo_text_processing.inverse_text_normalization.taggers.electronic import ElectronicFst +from nemo_text_processing.inverse_text_normalization.taggers.measure import MeasureFst +from nemo_text_processing.inverse_text_normalization.taggers.money import MoneyFst +from nemo_text_processing.inverse_text_normalization.taggers.ordinal import OrdinalFst +from nemo_text_processing.inverse_text_normalization.taggers.punctuation import PunctuationFst +from nemo_text_processing.inverse_text_normalization.taggers.telephone import TelephoneFst +from nemo_text_processing.inverse_text_normalization.taggers.time import TimeFst +from nemo_text_processing.inverse_text_normalization.taggers.whitelist import WhiteListFst +from nemo_text_processing.inverse_text_normalization.taggers.word import WordFst +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_extra_space, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class ClassifyFst(GraphFst): + """ + Final class that composes all other classification grammars. This class can process an entire sentence, that is lower cased. + For deployment, this grammar will be compiled and exported to OpenFst Finate State Archiv (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + """ + + def __init__(self): + super().__init__(name="tokenize_and_classify", kind="classify") + + cardinal = CardinalFst() + cardinal_graph = cardinal.fst + + ordinal = OrdinalFst(cardinal) + ordinal_graph = ordinal.fst + + decimal = DecimalFst(cardinal) + decimal_graph = decimal.fst + + measure_graph = MeasureFst(cardinal=cardinal, decimal=decimal).fst + date_graph = DateFst(ordinal=ordinal).fst + word_graph = WordFst().fst + time_graph = TimeFst().fst + money_graph = MoneyFst(cardinal=cardinal, decimal=decimal).fst + whitelist_graph = WhiteListFst().fst + punct_graph = PunctuationFst().fst + electronic_graph = ElectronicFst().fst + telephone_graph = TelephoneFst().fst + + classify = ( + pynutil.add_weight(whitelist_graph, 1.01) + | pynutil.add_weight(time_graph, 1.1) + | pynutil.add_weight(date_graph, 1.09) + | pynutil.add_weight(decimal_graph, 1.1) + | pynutil.add_weight(measure_graph, 1.1) + | pynutil.add_weight(cardinal_graph, 1.1) + | pynutil.add_weight(ordinal_graph, 1.1) + | pynutil.add_weight(money_graph, 1.1) + | pynutil.add_weight(telephone_graph, 1.1) + | pynutil.add_weight(electronic_graph, 1.1) + | pynutil.add_weight(word_graph, 100) + ) + + punct = pynutil.insert("tokens { ") + pynutil.add_weight(punct_graph, weight=1.1) + pynutil.insert(" }") + token = pynutil.insert("tokens { ") + classify + pynutil.insert(" }") + token_plus_punct = ( + pynini.closure(punct + pynutil.insert(" ")) + token + pynini.closure(pynutil.insert(" ") + punct) + ) + + graph = token_plus_punct + pynini.closure(delete_extra_space + token_plus_punct) + graph = delete_space + graph + delete_space + + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/whitelist.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/whitelist.py new file mode 100644 index 0000000..3ac3b9e --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/whitelist.py @@ -0,0 +1,40 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import GraphFst, convert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WhiteListFst(GraphFst): + """ + Finite state transducer for classifying whitelisted tokens + e.g. misses -> tokens { name: "mrs." } + This class has highest priority among all classifier grammars. Whitelisted tokens are defined and loaded from "data/whitelist.tsv". + """ + + def __init__(self): + super().__init__(name="whitelist", kind="classify") + + whitelist = pynini.string_file(get_abs_path("data/whitelist.tsv")).invert() + graph = pynutil.insert("name: \"") + convert_space(whitelist) + pynutil.insert("\"") + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/word.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/word.py new file mode 100644 index 0000000..6be7360 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/taggers/word.py @@ -0,0 +1,36 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_SPACE, GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WordFst(GraphFst): + """ + Finite state transducer for classifying plain tokens, that do not belong to any special class. This can be considered as the default class. + e.g. sleep -> tokens { name: "sleep" } + """ + + def __init__(self): + super().__init__(name="word", kind="classify") + word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") + self.fst = word.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/utils.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/utils.py new file mode 100644 index 0000000..6a8bd48 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/utils.py @@ -0,0 +1,47 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from typing import Union + +import inflect + +_inflect = inflect.engine() + + +def num_to_word(x: Union[str, int]): + """ + converts integer to spoken representation + + Args + x: integer + + Returns: spoken representation + """ + if isinstance(x, int): + x = str(x) + x = _inflect.number_to_words(str(x)).replace("-", " ").replace(",", "") + return x + + +def get_abs_path(rel_path): + """ + Get absolute path + + Args: + rel_path: relative path to this file + + Returns absolute path + """ + return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/__init__.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/cardinal.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/cardinal.py new file mode 100644 index 0000000..905da49 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/cardinal.py @@ -0,0 +1,55 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class CardinalFst(GraphFst): + """ + Finite state transducer for verbalizing cardinal + e.g. cardinal { integer: "23" negative: "-" } -> -23 + """ + + def __init__(self): + super().__init__(name="cardinal", kind="verbalize") + optional_sign = pynini.closure( + pynutil.delete("negative:") + + delete_space + + pynutil.delete("\"") + + NEMO_NOT_QUOTE + + pynutil.delete("\"") + + delete_space, + 0, + 1, + ) + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + self.numbers = graph + graph = optional_sign + graph + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/date.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/date.py new file mode 100644 index 0000000..00ee9c5 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/date.py @@ -0,0 +1,87 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_NOT_QUOTE, + GraphFst, + delete_extra_space, + delete_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class DateFst(GraphFst): + """ + Finite state transducer for verbalizing date, e.g. + date { month: "january" day: "5" year: "2012" preserve_order: true } -> february 5 2012 + date { day: "5" month: "january" year: "2012" preserve_order: true } -> 5 february 2012 + """ + + def __init__(self): + super().__init__(name="date", kind="verbalize") + month = ( + pynutil.delete("month:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + day = ( + pynutil.delete("day:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + year = ( + pynutil.delete("year:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + delete_space + + pynutil.delete("\"") + ) + + # month (day) year + graph_mdy = ( + month + pynini.closure(delete_extra_space + day, 0, 1) + pynini.closure(delete_extra_space + year, 0, 1) + ) + + # (day) month year + graph_dmy = ( + pynini.closure(day + delete_extra_space, 0, 1) + month + pynini.closure(delete_extra_space + year, 0, 1) + ) + + optional_preserve_order = pynini.closure( + pynutil.delete("preserve_order:") + delete_space + pynutil.delete("true") + delete_space + | pynutil.delete("field_order:") + + delete_space + + pynutil.delete("\"") + + NEMO_NOT_QUOTE + + pynutil.delete("\"") + + delete_space + ) + + final_graph = (graph_mdy | year | graph_dmy) + delete_space + optional_preserve_order + + delete_tokens = self.delete_tokens(final_graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/decimal.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/decimal.py new file mode 100644 index 0000000..82645af --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/decimal.py @@ -0,0 +1,65 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class DecimalFst(GraphFst): + """ + Finite state transducer for verbalizing decimal, e.g. + decimal { negative: "true" integer_part: "12" fractional_part: "5006" quantity: "billion" } -> -12.5006 billion + """ + + def __init__(self): + super().__init__(name="decimal", kind="verbalize") + optionl_sign = pynini.closure(pynini.cross("negative: \"true\"", "-") + delete_space, 0, 1) + integer = ( + pynutil.delete("integer_part:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + optional_integer = pynini.closure(integer + delete_space, 0, 1) + fractional = ( + pynutil.insert(".") + + pynutil.delete("fractional_part:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + optional_fractional = pynini.closure(fractional + delete_space, 0, 1) + quantity = ( + pynutil.delete("quantity:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + optional_quantity = pynini.closure(pynutil.insert(" ") + quantity + delete_space, 0, 1) + graph = optional_integer + optional_fractional + optional_quantity + self.numbers = graph + graph = optionl_sign + graph + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/electronic.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/electronic.py new file mode 100644 index 0000000..8a8cdf8 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/electronic.py @@ -0,0 +1,52 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class ElectronicFst(GraphFst): + """ + Finite state transducer for verbalizing electronic + e.g. tokens { electronic { username: "cdf1" domain: "abc.edu" } } -> cdf1@abc.edu + """ + + def __init__(self): + super().__init__(name="electronic", kind="verbalize") + user_name = ( + pynutil.delete("username:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + domain = ( + pynutil.delete("domain:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + + graph = user_name + delete_space + pynutil.insert("@") + domain + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/fraction.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/fraction.py new file mode 100644 index 0000000..45a6bd0 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/fraction.py @@ -0,0 +1,25 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst + + +class FractionFst(GraphFst): + """ + Finite state transducer for verbalizing fraction, + """ + + def __init__(self): + super().__init__(name="fraction", kind="verbalize") diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/measure.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/measure.py new file mode 100644 index 0000000..734beff --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/measure.py @@ -0,0 +1,69 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + + PYNINI_AVAILABLE = False + + +class MeasureFst(GraphFst): + """ + Finite state transducer for verbalizing measure, e.g. + measure { negative: "true" cardinal { integer: "12" } units: "kg" } -> -12 kg + + Args: + decimal: DecimalFst + cardinal: CardinalFst + """ + + def __init__(self, decimal: GraphFst, cardinal: GraphFst): + super().__init__(name="measure", kind="verbalize") + optional_sign = pynini.closure(pynini.cross("negative: \"true\"", "-"), 0, 1) + unit = ( + pynutil.delete("units:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_CHAR - " ", 1) + + pynutil.delete("\"") + + delete_space + ) + graph_decimal = ( + pynutil.delete("decimal {") + + delete_space + + optional_sign + + delete_space + + decimal.numbers + + delete_space + + pynutil.delete("}") + ) + graph_cardinal = ( + pynutil.delete("cardinal {") + + delete_space + + optional_sign + + delete_space + + cardinal.numbers + + delete_space + + pynutil.delete("}") + ) + graph = (graph_cardinal | graph_decimal) + delete_space + pynutil.insert(" ") + unit + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/money.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/money.py new file mode 100644 index 0000000..30dec90 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/money.py @@ -0,0 +1,48 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + + PYNINI_AVAILABLE = False + + +class MoneyFst(GraphFst): + """ + Finite state transducer for verbalizing money, e.g. + money { integer_part: "12" fractional_part: "05" currency: "$" } -> $12.05 + + Args: + decimal: DecimalFst + """ + + def __init__(self, decimal: GraphFst): + super().__init__(name="money", kind="verbalize") + unit = ( + pynutil.delete("currency:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_CHAR - " ", 1) + + pynutil.delete("\"") + ) + graph = unit + delete_space + decimal.numbers + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/ordinal.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/ordinal.py new file mode 100644 index 0000000..8896067 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/ordinal.py @@ -0,0 +1,64 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, NEMO_SIGMA, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class OrdinalFst(GraphFst): + """ + Finite state transducer for verbalizing ordinal, e.g. + ordinal { integer: "13" } -> 13th + """ + + def __init__(self): + super().__init__(name="ordinal", kind="verbalize") + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + convert_eleven = pynini.cross("11", "11th") + convert_twelve = pynini.cross("12", "12th") + convert_thirteen = pynini.cross("13", "13th") + convert_one = pynini.cross("1", "1st") + convert_two = pynini.cross("2", "2nd") + convert_three = pynini.cross("3", "3rd") + convert_rest = pynutil.insert("th", weight=0.01) + + suffix = pynini.cdrewrite( + convert_eleven + | convert_twelve + | convert_thirteen + | convert_one + | convert_two + | convert_three + | convert_rest, + "", + "[EOS]", + NEMO_SIGMA, + ) + graph = graph @ suffix + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/telephone.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/telephone.py new file mode 100644 index 0000000..5e6329e --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/telephone.py @@ -0,0 +1,39 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TelephoneFst(GraphFst): + """ + Finite state transducer for verbalizing telephone, e.g. + telephone { number_part: "123-123-5678" } + -> 123-123-5678 + """ + + def __init__(self): + super().__init__(name="telephone", kind="verbalize") + + number_part = pynutil.delete("number_part: \"") + pynini.closure(NEMO_NOT_QUOTE, 1) + pynutil.delete("\"") + delete_tokens = self.delete_tokens(number_part) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/time.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/time.py new file mode 100644 index 0000000..0319738 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/time.py @@ -0,0 +1,87 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_CHAR, + NEMO_DIGIT, + GraphFst, + delete_space, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TimeFst(GraphFst): + """ + Finite state transducer for verbalizing time, e.g. + time { hours: "12" minutes: "30" } -> 12:30 + time { hours: "1" minutes: "12" } -> 01:12 + time { hours: "2" suffix: "a.m." } -> 02:00 a.m. + """ + + def __init__(self): + super().__init__(name="time", kind="verbalize") + add_leading_zero_to_double_digit = (NEMO_DIGIT + NEMO_DIGIT) | (pynutil.insert("0") + NEMO_DIGIT) + hour = ( + pynutil.delete("hours:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_DIGIT, 1) + + pynutil.delete("\"") + ) + minute = ( + pynutil.delete("minutes:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_DIGIT, 1) + + pynutil.delete("\"") + ) + suffix = ( + delete_space + + insert_space + + pynutil.delete("suffix:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_CHAR - " ", 1) + + pynutil.delete("\"") + ) + optional_suffix = pynini.closure(suffix, 0, 1) + zone = ( + delete_space + + insert_space + + pynutil.delete("zone:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_CHAR - " ", 1) + + pynutil.delete("\"") + ) + optional_zone = pynini.closure(zone, 0, 1) + graph = ( + hour @ add_leading_zero_to_double_digit + + delete_space + + pynutil.insert(":") + + (minute @ add_leading_zero_to_double_digit) + + optional_suffix + + optional_zone + ) + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize.py new file mode 100644 index 0000000..684a239 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize.py @@ -0,0 +1,62 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.verbalizers.cardinal import CardinalFst +from nemo_text_processing.inverse_text_normalization.verbalizers.date import DateFst +from nemo_text_processing.inverse_text_normalization.verbalizers.decimal import DecimalFst +from nemo_text_processing.inverse_text_normalization.verbalizers.electronic import ElectronicFst +from nemo_text_processing.inverse_text_normalization.verbalizers.measure import MeasureFst +from nemo_text_processing.inverse_text_normalization.verbalizers.money import MoneyFst +from nemo_text_processing.inverse_text_normalization.verbalizers.ordinal import OrdinalFst +from nemo_text_processing.inverse_text_normalization.verbalizers.telephone import TelephoneFst +from nemo_text_processing.inverse_text_normalization.verbalizers.time import TimeFst +from nemo_text_processing.inverse_text_normalization.verbalizers.whitelist import WhiteListFst +from nemo_text_processing.text_normalization.graph_utils import GraphFst + + +class VerbalizeFst(GraphFst): + """ + Composes other verbalizer grammars. + For deployment, this grammar will be compiled and exported to OpenFst Finate State Archiv (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + """ + + def __init__(self): + super().__init__(name="verbalize", kind="verbalize") + cardinal = CardinalFst() + cardinal_graph = cardinal.fst + ordinal_graph = OrdinalFst().fst + decimal = DecimalFst() + decimal_graph = decimal.fst + measure_graph = MeasureFst(decimal=decimal, cardinal=cardinal).fst + money_graph = MoneyFst(decimal=decimal).fst + time_graph = TimeFst().fst + date_graph = DateFst().fst + whitelist_graph = WhiteListFst().fst + telephone_graph = TelephoneFst().fst + electronic_graph = ElectronicFst().fst + graph = ( + time_graph + | date_graph + | money_graph + | measure_graph + | ordinal_graph + | decimal_graph + | cardinal_graph + | whitelist_graph + | telephone_graph + | electronic_graph + ) + self.fst = graph diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize_final.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize_final.py new file mode 100644 index 0000000..e6f6610 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/verbalize_final.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.inverse_text_normalization.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.inverse_text_normalization.verbalizers.word import WordFst +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_extra_space, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class VerbalizeFinalFst(GraphFst): + """ + Finite state transducer that verbalizes an entire sentence, e.g. + tokens { name: "its" } tokens { time { hours: "12" minutes: "30" } } tokens { name: "now" } -> its 12:30 now + """ + + def __init__(self): + super().__init__(name="verbalize_final", kind="verbalize") + verbalize = VerbalizeFst().fst + word = WordFst().fst + types = verbalize | word + graph = ( + pynutil.delete("tokens") + + delete_space + + pynutil.delete("{") + + delete_space + + types + + delete_space + + pynutil.delete("}") + ) + graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space + self.fst = graph diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/whitelist.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/whitelist.py new file mode 100644 index 0000000..4bea2e5 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/whitelist.py @@ -0,0 +1,44 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WhiteListFst(GraphFst): + """ + Finite state transducer for verbalizing whitelist + e.g. tokens { name: "mrs." } -> mrs. + """ + + def __init__(self): + super().__init__(name="whitelist", kind="verbalize") + graph = ( + pynutil.delete("name:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_CHAR - " ", 1) + + pynutil.delete("\"") + ) + graph = graph @ pynini.cdrewrite(pynini.cross(u"\u00A0", " "), "", "", NEMO_SIGMA) + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/word.py b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/word.py new file mode 100644 index 0000000..2456580 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/inverse_text_normalization/verbalizers/word.py @@ -0,0 +1,39 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WordFst(GraphFst): + """ + Finite state transducer for verbalizing plain tokens + e.g. tokens { name: "sleep" } -> sleep + """ + + def __init__(self): + super().__init__(name="word", kind="verbalize") + chars = pynini.closure(NEMO_CHAR - " ", 1) + char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") + graph = char @ pynini.cdrewrite(pynini.cross(u"\u00A0", " "), "", "", NEMO_SIGMA) + + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/setup.sh b/tts/NeMo/nemo_text_processing/setup.sh new file mode 100644 index 0000000..e410b40 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/setup.sh @@ -0,0 +1,2 @@ +#!/bin/bash +conda install -c conda-forge -y pynini=2.1.3 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/README.md b/tts/NeMo/nemo_text_processing/text_normalization/README.md new file mode 100644 index 0000000..f4405dd --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/README.md @@ -0,0 +1,11 @@ +Text Normalization system for english, e.g. `123 kg` -> `one hundred twenty three kilograms` +Offers prediction and evaluation on text normalization data, e.g. [Google text normalization dataset](https://www.kaggle.com/richardwilliamsproat/text-normalization-for-english-russian-and-polish). + + +Install dependencies: +bash ../setup.sh + +Example prediction run: +python run_predict.py --input=`INPUT_FILE` --output=`OUTPUT_FILE` [--verbose] +Example evaluation run: +python run_evaluate.py --input=./en_with_types/output-00001-of-00100 [--cat CATEGORY] diff --git a/tts/NeMo/nemo_text_processing/text_normalization/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/__init__.py new file mode 100644 index 0000000..97aabf7 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/__init__.py @@ -0,0 +1,33 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst +from nemo_text_processing.text_normalization.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.text_normalization.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.text_normalization.verbalizers.verbalize_final import VerbalizeFinalFst + +from nemo.utils import logging + +try: + import pynini + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + logging.warning( + "`pynini` is not installed ! \n" + "Please run the `nemo_text_processing/setup.sh` script" + "prior to usage of this toolkit." + ) + + PYNINI_AVAILABLE = False diff --git a/tts/NeMo/nemo_text_processing/text_normalization/clean_eval_data.py b/tts/NeMo/nemo_text_processing/text_normalization/clean_eval_data.py new file mode 100644 index 0000000..8c33c4f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/clean_eval_data.py @@ -0,0 +1,342 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser +from typing import List + +import regex as re +from nemo_text_processing.text_normalization.data_loader_utils import ( + EOS_TYPE, + Instance, + load_files, + training_data_to_sentences, +) + + +""" +This file is for evaluation purposes. +filter_loaded_data() cleans data (list of instances) for text normalization. Filters and cleaners can be specified for each semiotic class individually. +For example, normalized text should only include characters and whitespace characters but no punctuation. + Cardinal unnormalized instances should contain at least one integer and all other characters are removed. +""" + + +class Filter: + """ + Filter class + + Args: + class_type: semiotic class used in dataset + process_func: function to transform text + filter_func: function to filter text + + """ + + def __init__(self, class_type: str, process_func: object, filter_func: object): + self.class_type = class_type + self.process_func = process_func + self.filter_func = filter_func + + def filter(self, instance: Instance) -> bool: + """ + filter function + + Args: + filters given instance with filter function + + Returns: True if given instance fulfills criteria or does not belong to class type + """ + if instance.token_type != self.class_type: + return True + return self.filter_func(instance) + + def process(self, instance: Instance) -> Instance: + """ + process function + + Args: + processes given instance with process function + + Returns: processed instance if instance belongs to expected class type or original instance + """ + if instance.token_type != self.class_type: + return instance + return self.process_func(instance) + + +def filter_cardinal_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_cardinal_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r"[^0-9]", "", un_normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_ordinal_1(instance: Instance) -> bool: + ok = re.search(r"(st|nd|rd|th)\s*$", instance.un_normalized) + return ok + + +def process_ordinal_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r"[,\s]", "", un_normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_decimal_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_decimal_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + un_normalized = re.sub(r",", "", un_normalized) + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_measure_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_measure_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r",", "", un_normalized) + un_normalized = re.sub(r"m2", "m²", un_normalized) + un_normalized = re.sub(r"(\d)([^\d.\s])", r"\1 \2", un_normalized) + normalized = re.sub(r"[^a-z\s]", "", normalized) + normalized = re.sub(r"per ([a-z\s]*)s$", r"per \1", normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_money_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_money_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + un_normalized = re.sub(r",", "", un_normalized) + un_normalized = re.sub(r"a\$", r"$", un_normalized) + un_normalized = re.sub(r"us\$", r"$", un_normalized) + un_normalized = re.sub(r"(\d)m\s*$", r"\1 million", un_normalized) + un_normalized = re.sub(r"(\d)bn?\s*$", r"\1 billion", un_normalized) + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_time_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_time_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + un_normalized = re.sub(r": ", ":", un_normalized) + un_normalized = re.sub(r"(\d)\s?a\s?m\s?", r"\1 a.m.", un_normalized) + un_normalized = re.sub(r"(\d)\s?p\s?m\s?", r"\1 p.m.", un_normalized) + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_plain_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_plain_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_punct_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_punct_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_date_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_date_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + un_normalized = re.sub(r",", "", un_normalized) + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_letters_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_letters_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_verbatim_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_verbatim_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_digit_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_digit_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_telephone_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_telephone_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_electronic_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_electronic_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_fraction_1(instance: Instance) -> bool: + ok = re.search(r"[0-9]", instance.un_normalized) + return ok + + +def process_fraction_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +def filter_address_1(instance: Instance) -> bool: + ok = True + return ok + + +def process_address_1(instance: Instance) -> Instance: + un_normalized = instance.un_normalized + normalized = instance.normalized + normalized = re.sub(r"[^a-z ]", "", normalized) + return Instance(token_type=instance.token_type, un_normalized=un_normalized, normalized=normalized) + + +filters = [] +filters.append(Filter(class_type="CARDINAL", process_func=process_cardinal_1, filter_func=filter_cardinal_1)) +filters.append(Filter(class_type="ORDINAL", process_func=process_ordinal_1, filter_func=filter_ordinal_1)) +filters.append(Filter(class_type="DECIMAL", process_func=process_decimal_1, filter_func=filter_decimal_1)) +filters.append(Filter(class_type="MEASURE", process_func=process_measure_1, filter_func=filter_measure_1)) +filters.append(Filter(class_type="MONEY", process_func=process_money_1, filter_func=filter_money_1)) +filters.append(Filter(class_type="TIME", process_func=process_time_1, filter_func=filter_time_1)) + +filters.append(Filter(class_type="DATE", process_func=process_date_1, filter_func=filter_date_1)) +filters.append(Filter(class_type="PLAIN", process_func=process_plain_1, filter_func=filter_plain_1)) +filters.append(Filter(class_type="PUNCT", process_func=process_punct_1, filter_func=filter_punct_1)) +filters.append(Filter(class_type="LETTERS", process_func=process_letters_1, filter_func=filter_letters_1)) +filters.append(Filter(class_type="VERBATIM", process_func=process_verbatim_1, filter_func=filter_verbatim_1)) +filters.append(Filter(class_type="DIGIT", process_func=process_digit_1, filter_func=filter_digit_1)) +filters.append(Filter(class_type="TELEPHONE", process_func=process_telephone_1, filter_func=filter_telephone_1)) +filters.append(Filter(class_type="ELECTRONIC", process_func=process_electronic_1, filter_func=filter_electronic_1)) +filters.append(Filter(class_type="FRACTION", process_func=process_fraction_1, filter_func=filter_fraction_1)) +filters.append(Filter(class_type="ADDRESS", process_func=process_address_1, filter_func=filter_address_1)) +filters.append(Filter(class_type=EOS_TYPE, process_func=lambda x: x, filter_func=lambda x: True)) + + +def filter_loaded_data(data: List[Instance], verbose: bool = False) -> List[Instance]: + """ + Filters list of instances + + Args: + data: list of instances + + Returns: filtered and transformed list of instances + """ + updates_instances = [] + for instance in data: + updated_instance = False + for fil in filters: + if fil.class_type == instance.token_type and fil.filter(instance): + instance = fil.process(instance) + updated_instance = True + if updated_instance: + if verbose: + print(instance) + updates_instances.append(instance) + return updates_instances + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--input", help="input file path", type=str, default='./en_with_types/output-00001-of-00100') + parser.add_argument("--verbose", help="print filtered instances", action='store_true') + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + file_path = args.input + + print("Loading training data: " + file_path) + instance_list = load_files([file_path]) # List of instances + filtered_instance_list = filter_loaded_data(instance_list, args.verbose) + training_data_to_sentences(filtered_instance_list) diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/currency/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency.tsv new file mode 100644 index 0000000..1c300bf --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency.tsv @@ -0,0 +1,35 @@ +$ dollar +$ us dollar +$ united states dollar +£ pound +€ euro +₩ won +nzd new zealand dollar +rs rupee +chf swiss franc +dkk danish kroner +fim finnish markka +aed arab emirates dirham +¥ yen +czk czech koruna +mro mauritanian ouguiya +pkr pakistani rupee +crc costa rican colon +hk$ hong kong dollar +npr nepalese rupee +awg aruban florin +nok norwegian kroner +tzs tanzanian shilling +sek swedish kronor +cyp cypriot pound +r real +sar saudi riyal +cve cape verde escudo +rsd serbian dinar +dm german mark +shp saint helena pounds +php philippine peso +cad canadian dollar +ssp south sudanese pound +scr seychelles rupee +mvr maldivian rufiyaa \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor.tsv new file mode 100644 index 0000000..61597b9 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor.tsv @@ -0,0 +1,2 @@ +cents +pence \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor_one.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor_one.tsv new file mode 100644 index 0000000..d6ab85f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/currency/currency_minor_one.tsv @@ -0,0 +1,2 @@ +cent +penny \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/domain.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/domain.tsv new file mode 100644 index 0000000..cb4bc3f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/domain.tsv @@ -0,0 +1 @@ +com com \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/server_name.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/server_name.tsv new file mode 100644 index 0000000..c447cf4 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/server_name.tsv @@ -0,0 +1,2 @@ +gmail g mail +nvidia n vidia \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/symbols.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/symbols.tsv new file mode 100644 index 0000000..c14f465 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/electronic/symbols.tsv @@ -0,0 +1,20 @@ +. dot +- dash +_ underscore +! exclamation mark +# number sign +$ dollar sign +% percent sign +& ampersand +' quote +* asterisk ++ plus +/ slash += equal sign +? question mark +^ circumflex +` right single quote +{ left brace +| vertical bar +} right brace +~ tilde \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/letter_pronunciation.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/letter_pronunciation.tsv new file mode 100644 index 0000000..3ec49ac --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/letter_pronunciation.tsv @@ -0,0 +1,2 @@ +k kay +j jay \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/magnitudes.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/magnitudes.tsv new file mode 100644 index 0000000..3bfa484 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/magnitudes.tsv @@ -0,0 +1,4 @@ +k thousand +m million +b billion +t trillion \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/measurements.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/measurements.tsv new file mode 100644 index 0000000..b86459a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/measurements.tsv @@ -0,0 +1,115 @@ +f fahrenheit +c celsius +km kilometer +m meter +cm centimeter +mm millimeter +ha hectare +mi mile +m² square meter +m2 square meter +km² square kilometer +km2 square kilometer +ft foot +% percent +hz hertz +kw kilowatt +hp horsepower +mg milligram +kg kilogram +ghz gigahertz +khz kilohertz +mhz megahertz +lb pound +lbs pound +lbs. pound +v volt +h hour +mc mega coulomb +s second +nm nanometer +rpm revolution per minute +min minute +mA milli ampere +kwh kilo watt hour +m³ cubic meter +m3 cubic meter +mph mile per hour +tw tera watt +mv milli volt +mw megawatt +μm micrometer +" inch +tb terabyte +cc c c +g gram +da dalton +atm atmosphere +ω ohm +db decibel +ps peta second +oz ounce +hl hecto liter +μg microgram +pg petagram +gb gigabyte +kb kilobit +ev electron volt +mb megabyte +kb kilobyte +kbps kilobit per second +mbps megabit per second +kl kilo liter +tj tera joule +kv kilo volt +mv mega volt +kn kilonewton +mm megameter +au astronomical unit +yd yard +rad radian +lm lumen +hs hecto second +mol mole +gpa giga pascal +ml milliliter +gw gigawatt +ma mega ampere +kt knot +kgf kilogram force +ng nano gram +ns nanosecond +ms mega siemens +bar bar +gl giga liter +μs microsecond +da deci ampere +pa pascal +ds deci second +ms milli second +dm deci meter +dm³ cubic deci meter +dm3 cubic deci meter +amu atomic mass unit +mb megabit +mf mega farad +bq becquerel +pb petabit +mm² square millimeter +mm2 square millimeter +cm² square centimeter +cm2 square centimeter +sq mi square mile +sq ft square foot +kpa kilopascal +cd candela +tl tera liter +ms mega second +mpa megapascal +pb peta byte +gwh giga watt hour +kcal kilo calory +gy gray +sv sievert +cwt hundredweight +cc c c diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/months/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/months/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/months/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/months/abbr.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/months/abbr.tsv new file mode 100644 index 0000000..5609e21 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/months/abbr.tsv @@ -0,0 +1,12 @@ +jan january +feb february +mar march +apr april +jun june +jul july +aug august +sep september +sept september +oct october +nov november +dec december \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/months/names.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/months/names.tsv new file mode 100644 index 0000000..1c05ac0 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/months/names.tsv @@ -0,0 +1,12 @@ +january +february +march +april +may +june +july +august +september +october +november +december diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/months/numbers.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/months/numbers.tsv new file mode 100644 index 0000000..f0cacd5 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/months/numbers.tsv @@ -0,0 +1,24 @@ +1 january +2 february +3 march +4 april +5 may +6 june +7 july +8 august +9 september +10 october +11 november +12 december +01 january +02 february +03 march +04 april +05 may +06 june +07 july +08 august +09 september +10 october +11 november +12 december \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/cardinal_number_name.far b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/cardinal_number_name.far new file mode 100755 index 0000000000000000000000000000000000000000..2ec682541ca72e575663537b1555059536f6876f GIT binary patch literal 325078 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νgPV%4i|l}uMM5kC0o}Q`d80$5z|OvlU(t4JYtSn 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 E2SNrX6aWAK literal 0 HcmV?d00001 diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/digit.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/digit.tsv new file mode 100644 index 0000000..fa32979 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/digit.tsv @@ -0,0 +1,9 @@ +one 1 +two 2 +three 3 +four 4 +five 5 +six 6 +seven 7 +eight 8 +nine 9 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/hundred.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/hundred.tsv new file mode 100644 index 0000000..10e2b96 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/hundred.tsv @@ -0,0 +1 @@ +hundred \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/teen.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/teen.tsv new file mode 100644 index 0000000..8e60fa1 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/teen.tsv @@ -0,0 +1,10 @@ +ten 10 +eleven 11 +twelve 12 +thirteen 13 +fourteen 14 +fifteen 15 +sixteen 16 +seventeen 17 +eighteen 18 +nineteen 19 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/thousands.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/thousands.tsv new file mode 100644 index 0000000..bf30542 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/thousands.tsv @@ -0,0 +1,22 @@ +thousand +million +billion +trillion +quadrillion +quintillion +sextillion +septillion +octillion +nonillion +decillion +undecillion +duodecillion +tredecillion +quattuordecillion +quindecillion +sexdecillion +septendecillion +octodecillion +novemdecillion +vigintillion +centillion \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/ties.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/ties.tsv new file mode 100644 index 0000000..65f9839 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/ties.tsv @@ -0,0 +1,8 @@ +twenty 2 +thirty 3 +forty 4 +fifty 5 +sixty 6 +seventy 7 +eighty 8 +ninety 9 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/zero.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/zero.tsv new file mode 100644 index 0000000..c479272 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/numbers/zero.tsv @@ -0,0 +1 @@ +zero 0 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/digit.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/digit.tsv new file mode 100644 index 0000000..4b7fc24 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/digit.tsv @@ -0,0 +1,9 @@ +first one +second two +third three +fourth four +fifth five +sixth sixth +seventh seven +eighth eight +ninth nine \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/teen.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/teen.tsv new file mode 100644 index 0000000..496fefc --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/ordinals/teen.tsv @@ -0,0 +1 @@ +twelfth twelve \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/roman/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/roman/digit_teen.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/digit_teen.tsv new file mode 100644 index 0000000..cd09913 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/digit_teen.tsv @@ -0,0 +1,49 @@ +i 1 +ii 2 +iii 3 +iv 4 +v 5 +vi 6 +vii 7 +viii 8 +ix 9 +x 10 +xi 11 +xii 12 +xiii 13 +xiv 14 +xv 15 +xvi 16 +xvii 17 +xviii 18 +xix 19 +xx 20 +xxi 21 +xxii 22 +xxiii 23 +xxiv 24 +xxv 25 +xxvi 26 +xxvii 27 +xxviii 28 +xxix 29 +xxx 30 +xxxi 31 +xxxii 32 +xxxiii 33 +xxxiv 34 +xxxv 35 +xxxvi 36 +xxxvii 37 +xxxviii 38 +xxxix 39 +xl 40 +xli 41 +xlii 42 +xliii 43 +xliv 44 +xlv 45 +xlvi 46 +xlvii 47 +xlviii 48 +xlix 49 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/roman/hundreds.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/hundreds.tsv new file mode 100644 index 0000000..0aafad3 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/hundreds.tsv @@ -0,0 +1,9 @@ +c 100 +cc 200 +ccc 300 +cd 400 +d 500 +dc 600 +dcc 700 +dccc 800 +cm 900 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/roman/ties.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/ties.tsv new file mode 100644 index 0000000..5516676 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/roman/ties.tsv @@ -0,0 +1,5 @@ +l 50 +lx 60 +lxx 70 +lxxx 80 +xc 90 \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/suppletive.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/suppletive.tsv new file mode 100644 index 0000000..dea620f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/suppletive.tsv @@ -0,0 +1,37 @@ +deer +fish +sheep +foot feet +goose geese +man men +mouse mice +tooth teeth +woman women +won +child children +ox oxen +wife wives +wolf wolves +analysis analyses +criterion criteria +focus foci +percent +hertz +kroner krone +inch inches +calory calories +yen +megahertz +gigahertz +kilohertz +hertz +c c +horsepower +hundredweight +kilogram force kilograms force +mega siemens +revolution per minute revolutions per minute +mile per hour miles per hour +megabit per second megabits per second +square foot square feet +kilobit per second kilobits per second \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/time_suffix.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/time_suffix.tsv new file mode 100644 index 0000000..98664c5 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/time_suffix.tsv @@ -0,0 +1,6 @@ +p.m. p m +p.m. p m +pm p m +a.m. a m +a.m a m +am a m \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/time_zone.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/time_zone.tsv new file mode 100644 index 0000000..1d39472 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/time_zone.tsv @@ -0,0 +1,14 @@ +cst c s t +c.s.t c s t +cet c e t +c.e.t c e t +pst p s t +p.s.t p s t +est e s t +e.s.t e s t +pt p t +p.t p t +et e t +e.t e t +gmt g m t +g.m.t g m t diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/whitelist.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/whitelist.tsv new file mode 100644 index 0000000..8539931 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/whitelist.tsv @@ -0,0 +1,15924 @@ +Ph.D. p h d +Hon. honorable +& and +Mt. Mount +Maj. Major +Rev. Reverend +# hash +Gov. governor +7-eleven seven eleven +A. A. a a +A.A. a a +A.A.A. a a a +A&A a and a +AAAI a a a i +AAAM a a a m +AAAs a a a's +AAAS a a a s +AAAW a a a w +AABA a a b a +AaB a a b +A. A. B. a a b +AAB- a a b +AAB a a b +AABC a a b c +Aabo a a b o +AABP a a b p +AABW a a b w +aac a a c +AAC a a c +AACAR a a c a r +AACC a a c c +AACCUP a a c c u p +AACMI a a c m i +AACNo a a c n o +AACR a a c r +AACS a a c s +AACSB a a c s b +AACTA a a c t a +AACUPR a a c u p r +A.A.D. a a d +AADT a a d t +AADTs a a d t's +Aadu a a d u +AAEA a a e a +AAE a a e +AAERT a a e r t +AAF a a f +AAFCA a a f c a +AAFC a a f c +AAFC's a a f c's +AAFld a a f l d +AAFPOA a a f p o a +AAGPBL a a g p b l +AAHHE a a h h e +AAI a a i +AAIB a a i b +AAIP a a i p +AAK a a k +Aap a a p +AAP a a p +AAPB a a p b +AAPC a a p c +AAPEP a a p e p +AAPG a a p g +AAPM a a p m +AAPT a a p t +A.A.R.M. a a r m +A.B.A. a b a +A. B. a b +A.B. a b +A.B.A. J. a b a j +A.B.C. a b c +A. B. G. a b g +ABG a b g +ABH a b h +ABHD a b h d +Abhi a b h i +ABK a b k +abl a b l +Abl a b l +ABL a b l +ABLV a b l v +ABM a b m +ABMC a b m c +ABN a b n +ABN's a b n's +Abp a b p +ABP- a b p +ABP a b p +ABPD a b p d +ABPI a b p i +ABPN a b p n +ABPP a b p p +ABPRS a b p r s +ABPW a b p w +Abr a b r +ABR a b r +abv a b v +ABV- a b v +ABV a b v +ABW a b w +ABX a b x +Abz a b z +A.C.A. a c a +ACA a c a +A&C a and c +A. C. a c +A.C. a c +acac a c a c +Acad a c a d +ACAD a c a d +A.C.A.P. a c a p +ACAP a c a p +ACAS a c a s +ACAZ a c a z +ACBA a c b a +ACB a c b +ACBL a c b l +ACBS a c b s +ACBSP a c b s p +ACCA a c c a +ACC- a c c +ACC a c c +ACCC a c c c +ACCJ a c c j +ACC&S a c c and s +ACC's a c c's +ACCS a c c s +ACD a c d +ACDC a c d c +A.C. D.F.C. A.F.C. a c d f c a f c +A.C.E. a c e +ACF a c f +ACFE a c f e +A.C.G. a c g +ACG a c g +ACGIH's a c g i h's +A.C.H. a c h +ACH a c h +ACHP a c h p +ACHR a c h r +ACHRE a c h r e +Achs a c h's +ACHS a c h s +ACIA a c i a +ACI a c i +ACICS a c i c s +ACIGA a c i g a +ACIP a c i p +Acis a c i's +ACIS a c i s +ACLA a c l a +A.C.L. a c l +ACL a c l +A.C.L.N. a c l n +acls a c l s +ACL's a c l's +ACLS a c l s +ACLU a c l u +ACM- a c m +ACM a c m +ACMI a c m i +ACMs a c m's +ACN a c n +ACO's a c o's +AcpA a c p a +ACP- a c p +ACP a c p +AcpB a c p b +ACPI a c p i +ACPO a c p o +ACPP a c p p +ACPSEM a c p s e m +acq a c q +A&CR a and c r +ACR a c r +ACRPS a c r p s +ACSA a c s a +ACSAC a c s a c +ACSBR a c s b r +ACSCN a c s c n +ACSEL a c s e l +ACSIA a c s i a +ACSI a c s i +AcSOC a c s o c +ACSR a c s r +ACSS a c s s +ACSS's a c s s's +A.C.T. a c t +A.C.T.A.F.L. a c t a f l +acu a c u +ACU a c u +ACU's a c u's +ACUS a c u s +ACUV a c u v +ACV a c v +ACWA a c w a +AC&W a c and w +ACW a c w +ACWM a c w m +ACWS a c w s +Acy a c y +ADAA a d a a +A&D a and d +Adab a d a b +ADAC- a d a c +ADAC a d a c +A. D. a d +A.D. a d +A.D.A.M. a d a m +AdaSL a d a s l +ADATA a d a t a +ADBAC a d b a c +ADB- a d b +ADB a d b +ADBGR a d b g r +ADBICA a d b i c a +ADCA a d c a +AdC a d c +A.D.C. a d c +ADC a d c +ADCAF a d c a f +ADCC a d c c +ADC's a d c's +ADCs a d c's +ADCY a d c y +ADDA a d d a +AD&D a d and d +ADF a d f +ADF's a d f's +ADFS a d f s +ADG a d g +ADGB a d g b +ADH a d h +ADHD a d h d +ADHM a d h m +ADHS a d h s +ADIAC a d i a c +AdK a d k +ADK a d k +Adl a d l +ADL a d l +ADLL a d l l +ADLs a d l's +A.D.M.A.C. a d m a c +adm a d m +Adm a d m +ADM- a d m +ADM a d m +ADMK a d m k +admn a d m n +ADMN a d m n +ADNAC a d n a c +ADNEC a d n e c +ADNs a d n's +AdP a d p +A.D.P. a d p +ADP- a d p +ADP a d p +ADPCM a d p c m +ADPF a d p f +ADQ a d q +ADQ's a d q's +ADR a d r +ADRC a d r c +ADRP a d r p +ADRs a d r's +ADSB a d s b +ADSL a d s l +ADSP- a d s p +ADSR a d s r +ADSRs a d s r's +ADSs a d s's +ADT a d t +ADTG a d t g +Adwa a d w a +ADWC a d w c +ADX a d x +AEA a e a +A&E a and e +A. E. a e +A.E. a e +AEBN a e b n +A.E.C. a e c +AEC a e c +AECL a e c l +AECR a e c r +AEC's a e c's +Aed a e d +AED a e d +AEE a e e +AEF a e f +AEG a e g +A.E.G.I.S. a e g i s +aegte a e g t e +AEHL a e h l +AEIA a e i a +AEI a e i +AEIO- a e i o +AEIOU a e i o u +Aeka a e k a +AEK a e k +ael a e l +AEL a e l +Aema a e m a +AEM a e m +aen a e n +AEO a e o +AEPA a e p a +AEP a e p +aere a e r e +AEre a e r e +AErn a e r n +AERN a e r n +Aert a e r t +AESA a e s a +Aes a e's +AES- a e s +AES a e s +aet a e t +AET a e t +AETC a e t c +AEU a e u +AEV a e v +AEW a e w +AEX a e x +Afa a f a +AFA a f a +af a f +Af a f +A. F. a f +A.F. a f +AF- a f +AF a f +Afaf a f a f +AFAP a f a p +AFB a f b +AFCA- a f c a +AFCA a f c a +afc a f c +A.F.C. a f c +AFC a f c +AFCEC a f c e c +AFCO a f c o +AFC's a f c's +AFCS a f c s +AFCSThe a f c s t h e +Afd a f d +AfD a f d +AfDB a f d b +AFDD a f d d +Afe a f e +AFE a f e +Aff a f f +AFF a f f +AFFDL- a f f d l +AFG a f g +AFGM a f g m +AFH a f h +AFIA a f i a +Afi a f i +AFI a f i +AFIP a f i p +Afiq a f i q +AFI's a f i's +AFJ a f j +A.F.L. a f l +AFL- a f l +AFL a f l +AFLEG a f l e g +AFLPA a f l p a +AFLP a f l p +AFL's a f l's +AFLUA a f l u a +A. F.M.A. a f m a +AFM- a f m +AFM a f m +AFMC a f m c +AFMs a f m's +AFN a f n +AFNET a f n e t +AFNOR a f n o r +AfNS a f n s +Afo a f o +AFO a f o +AFOP a f o p +AFP a f p +AFRA a f r a +Afr a f r +AFR a f r +AFRC a f r c +AFRL a f r l +AFROTC a f r o t c +AFRTS a f r t s +AFS a f s +AFSC a f s c +AFSPC a f s p c +A. F. T. a f t +AFTRA a f t r a +AFTRA's a f t r a's +AFTRS a f t r s +AFV a f v +AFW a f w +AFWS a f w s +AFX a f x +A. G. a g +A.G. a g +AGB a g b +AGC a g c +Agco a g c o +AGCO a g c o +Agda a g d a +AGD a g d +A.G.E. a g e +AGF- a g f +AGF a g f +AG&G a g and g +agg a g g +Agi a g i +AGI a g i +AGID a g i d +AGIR a g i r +Agis a g i's +A.G.J. a g j +A. G. K. a g k +AGL a g l +agli a g l i +AGM- a g m +AGM a g m +AGMR- a g m r +Agn a g n +AgN a g n +AGN a g n +AGNs a g n's +A.G.P. a g p +AGP a g p +AGPL a g p l +AGPS a g p s +AGPW a g p w +AGRs a g r's +AGS a g s +AGSM a g s m +AGSS- a g s s +Agsu a g s u +agt a g t +AGT a g t +Agte a g t e +Agu a g u +AGU a g u +AGV a g v +A.H.A. a h a +A. H. a h +A.H. a h +A. H. C. a h c +AHC a h c +AHD a h d +Ahdhra a h d h r a +AHDR a h d r +ahe a h e +Ahe a h e +AHEC a h e c +AHF a h f +Ahirs a h i r's +AHJD- a h j d +Ahk a h k +AHL's a h l's +AHP a h p +AHRC a h r c +AHRS a h r s +AHSAA a h s a a +Ahsa'i a h s a i +Ahta a h t a +aht a h t +AHT a h t +AHTD a h t d +Ahu a h u +Ahva a h v a +AHV a h v +AIAA a i a a +A.I.A. a i a +A&I a and i +A. I. a i +A.I. a i +AI- a i +AI a i +AIAP a i a p +Aias a i a's +AIAS a i a s +AIATSIS a i a t s i s +AIAW a i a w +AIAWU a i a w u +A.I.B.A. a i b a +AIB a i b +AIBO's a i b o's +AIBS a i b s +AIC a i c +AICAR a i c a r +AICC a i c c +AICCCR a i c c c r +aici a i c i +AICL- a i c l +Aicme a i c m e +AICN a i c n +AICPA a i c p a +AICP a i c p +AICPS a i c p s +AICs a i c's +AICTE a i c t e +AICUF a i c u f +AIDA a i d a +AIDN a i d n +AIEC a i e c +AIEE- a i e e +AIEE a i e e +Aiel a i e l +AIEP a i e p +AIFA a i f a +AIF- a i f +AIF a i f +AIFB a i f b +Aife a i f e +AIFF a i f f +AIFM a i f m +AIFMD a i f m d +AiG a i g +AIG a i g +Aigis a i g i's +AIHA a i h a +AIH a i h +AIHL a i h l +AIIMS a i i m s +Aija a i j a +Aik a i k +AIK- a i k +AIK a i k +AIKR a i k r +A.I.M. a i m +AIP a i p +A.I.R. a i r +AIs a i's +AISC a i s c +AISD a i s d +AISRI a i s r i +Aist a i s t +AIST a i s t +AIT's a i t's +Aitu a i t u +Aiud a i u d +aius a i u s +AIVC a i v c +AIW a i w +AIX a i x +A. J. a j +A.J. a j +Ajba a j b a +A.J.B. a j b +AJC a j c +A.J.E. a j e +A.J.G.C. a j g c +A. J. J. a j j +A.J.K. a j k +AJK a j k +AJKF a j k f +AJL a j l +A. J. M. a j m +Ajmi a j m i +AJN a j n +AJO a j o +Ajok a j o k +A. J. P. a j p +A.J.P. a j p +AJPW a j p w +A.J.R. a j r +AJR- a j r +AJR a j r +Ajsa a j s a +A.J.S. a j s +AJS- a j s +AJS a j s +A. J. T. a j t +A.J.T. a j t +AJT a j t +Aju a j u +AJUFE a j u f e +AJUSCO a j u s c o +AJV a j v +AJW a j w +AJWRC a j w r c +Akaa a k a a +a.k.a. a k a +aka. a k a +aka a k a +Aka. a k a +Aka a k a +AKA- a k a +AKA a k a +A&K a and k +ak- a k +A. K. a k +A.K. a k +AK- a k +AK a k +AKAP a k a p +AKAPs a k a p's +akas a k a's +AKAs a k a's +AKB a k b +AKC a k c +AKCR a k c r +AKD a k d +AKG a k g +AKG's a k g's +akh a k h +AKH a k h +AKHS a k h s +AKK- a k k +AKM a k m +AKN a k n +Akpa a k p a +AKP a k p +AKPD a k p d +AKQA a k q a +AKR- a k r +AKR a k r +A.K.S. a k s +AKS a k s +Aku a k u +AKU a k u +AKW a k w +A&L a and l +A. L. a l +A.L. a l +ALDF a l d f +ALDH a l d h +ALDS a l d s +ALDT a l d t +ALFASID a l f a s i d +ALFIDI a l f i d i +ALFTP a l f t p +Alh a l h +ALH a l h +A. L. M. a l m +A.L.P. a l p +ALP- a l p +ALPG a l p g +ALQ- a l q +ALR a l r +ALSC a l s c +ALSF a l s f +ALSP a l s p +ALUs a l u's +A.L.V. a l v +ALVF a l v f +ALW a l w +ALWS a l w s +AMAA a m a a +A'ma a m a +A&M a and m +A. M. a m +A.M. a m +AMAP a m a p +AMARC a m a r c +AMAs a m a's +amb a m b +Amb a m b +AMB a m b +AmBX a m b x +AMc- a m c +A.M.C. a m c +AMC- a m c +AMC a m c +AMC's a m c's +AMCs a m c's +Amda a m d a +Amd a m d +AMD a m d +AMDH a m d h +AMDISA a m d i s a +AMD's a m d's +A.M.E. a m e +AMF a m f +AM&FM a m and f m +A. M. G. a m g +AMG- a m g +AMG a m g +AMGTV a m g t v +Amha a m h a +AMH a m h +A.M.H.S. a m h s +A. M. J. a m j +AMJ a m j +A. M. K. a m k +A.M.K. a m k +AMK a m k +aml a m l +AML- a m l +AML a m l +Amli a m l i +AMLS a m l s +Amlwch a m l w c h +Amm a m m +A. M. M. a m m +AMM a m m +AMMAYI a m m a y i +AMMB a m m b +AMMK a m m k +AMN a m n +AMNH a m n h +AMNRL a m n r l +AM&O a m and o +AMPK- a m p k +AMPK a m p k +AMPL a m p l +AMP's a m p's +Ampt a m p t +AMPTP a m p t p +amr a m r +A. M. R. a m r +AMREF a m r e f +AMSA a m s a +A&M's a and m's +Ams' a m's +AMS- a m s +amsl a m s l +AMSO's a m s o's +AMSRS a m s r s +AMS's a m s's +AMSS a m s s +AMSU- a m s u +AMSU a m s u +Amta a m t a +amt a m t +Amt a m t +A.M.T. a m t +AMT- a m t +AMT a m t +AMTB a m t b +AMTPAT a m t p a t +Amts a m t's +AMTV a m t v +Amu a m u +AMU a m u +AMU's a m u's +A.M.V.M. a m v m +AMW a m w +AMX- a m x +AMX a m x +AMYF a m y f +A. N. a n +A.N. a n +ANB a n b +ANBO a n b o +ANC a n c +ANCC a n c c +ANC's a n c's +andFHL a n d f h l +ANDOC a n d o c +ANDP a n d p +ANDPOP a n d p o p +andPPP a n d p p p +Anej a n e j +ANELFA a n e l f a +ANF a n f +ANFIS a n f i s +ANFP's a n f p's +ANGB a n g b +ANGPTL a n g p t l +ANGRAU a n g r a u +Angti a n g t i +Angu a n g u +Angul- a n g u l +Anhe a n h e +ANI a n i +ANL a n l +ANM a n m +ANP a n p +ANPP a n p p +ANPR a n p r +Anra a n r a +Anr a n r +ANR a n r +ANRC a n r c +ANREF's a n r e f's +Anrep a n r e p +ANRS a n r s +ANRW a n r w +Ans a n's +A.N.S. a n s +ANS a n s +ANSF a n s f +ANTB a n t b +ANTM a n t m +ANTV a n t v +ANUGA a n u g a +ANWB a n w b +ANX a n x +ANZ a n z +A&O a and o +AOA a o a +AOAC a o a c +A. O. a o +A.O. a o +AOB a o b +AOC a o c +AOCB a o c b +AOCCs a o c c's +AOCE a o c e +AOD a o d +Aodh a o d h +Aodla a o d l a +AODV a o d v +AOE a o e +AOGCC a o g c c +Aogo a o g o +AOH a o h +Aoke a o k e +Aoko a o k o +AOKP a o k p +Aola a o l a +Aol a o l +AOL- a o l +AOL a o l +AOL's a o l's +AOLTV a o l t v +AOM a o m +AOMC a o m c +AONB a o n b +Aone a o n e +Aoni a o n i +Aoos a o o's +AOPA a o p a +AOP a o p +aor a o r +AOR a o r +AORs a o r's +AORS a o r s +aos a o s +AoS a o s +AOS a o s +Aotus a o t u's +AOTW a o t w +aov a o v +aovf a o v f +AOWC a o w c +A&P a and p +A. P. a p +A.P. a p +APBA a p b a +APB a p b +APBL a p b l +APCA a p c a +Apc a p c +APC- a p c +APC a p c +APCCR a p c c r +APCh a p c h +APCR a p c r +APCRDA a p c r d a +APC's a p c's +APCs a p c's +APDA a p d a +APD- a p d +APD a p d +APDM a p d m +APEGBC a p e g b c +APFA a p f a +APF a p f +APFCT a p f c t +APFOL a p f o l +APFSDS a p f s d s +APFUTU a p f u t u +apg a p g +APG a p g +APGAW a p g a w +Aph a p h +A.P.H. a p h +APH a p h +APHEDA a p h e d a +APHL a p h l +Apiao a p i a o +Api a p i +APi a p i +API- a p i +API a p i +Apic a p i c +APICv a p i c v +API's a p i's +A.P.J. a p j +APJ a p j +Apl a p l +APL a p l +APLP a p l p +APLS a p l s +Aplu a p l u +APM a p m +APML a p m l +APMR a p m r +APMSO a p m s o +APN- a p n +APN a p n +A.P.N.C. a p n c +Apphttp a p p h t t p +Appl a p p l +APPO's a p p o's +appr a p p r +Appts a p p t's +appu a p p u +Appu a p p u +APRA's a p r a's +APRC a p r c +APR's a p r's +APRS a p r s +APRST a p r s t +A&P's a and p's +Aps a p's +APs a p's +APS- a p s +APS a p s +APSF a p s f +APSL a p s l +APSU- a p s u +APTA- a p t a +APTA a p t a +AP&T a p and t +APW a p w +APX a p x +APXS a p x s +Aqa a q a +AQA a q a +AQC a q c +AQI a q i +Aql a q l +AQP a q p +Aqr a q r +AQS- a q s +A&R a and r +ARA a r a +A. R. a r +A.R. a r +A.R.B. a r b +ARD a r d +ARDF a r d f +A.R.E. a r e +A.R.F. a r f +ARF a r f +A.R.G. a r g +ArgR a r g r +ARGs a r g's +ARGT a r g t +ArH a r h +ARJ a r j +ARL a r l +ARLFC a r l f c +A. R. M. a r m +ARMv a r m v +Arnd a r n d +ARNG a r n g +ARNT a r n t +A.R.P. a r p +ARPP- a r p p +ARQ- a r q +ARQ a r q +ARTL a r t l +A.R.U. a r u +arv a r v +Arv a r v +ARV a r v +ARVD a r v d +ARVN a r v n +ARW a r w +Arwi a r w i +ARWU a r w u +A.S.A. a s a +ASA a s a +As'ad a s a d +Asai a s a i +Asao a s a o +A.s a's +A. S. a s +A.S. a s +ASAS a s a s +Asasp a s a s p +ASAU a s a u +A.S.B. a s b +ASB a s b +ASBDA a s b d a +asbl a s b l +ASBM a s b m +ASBMH a s b m h +ASBO a s b o +A.S.C. a s c +ASC a s c +ASCB a s c b +ASCE a s c e +asci a s c i +Asci a s c i +ASCP a s c p +ASCW a s c w +A.S.D. a s d +ASD a s d +ASDIC a s d i c +Asdis a s d i's +ASE a s e +ASEC a s e c +ASEE a s e e +ASEF a s e f +ASFA a s f a +ASF a s f +Asfi a s f i +ASGA a s g a +ASG a s g +ASGC a s g c +ASGE a s g e +ASGS a s g s +A. S. H. a s h +A.S.I. a s i +ASL a s l +A.S.M. a s m +ASM a s m +ASMD a s m d +ASME a s m e +ASMIK a s m i k +ASML a s m l +ASMPH a s m p h +ASMSU a s m s u +Asn a s n +ASN- a s n +ASN a s n +Aso a s o +ASO a s o +ASP a s p +ASPCA a s p c a +Aspe a s p e +ASPTS a s p t s +ASQ- a s q +Asr a s r +ASR a s r +Assn a s s n +assoc a s s o c +Assoc a s s o c +ASSPs a s s p's +ASSR a s s r +Asst a s s t +ASSU a s s u +A. S. T. a s t +ASTAT a s t a t +ASTCL a s t c l +Aste a s t e +ASTE a s t e +ASTM a s t m +ASTR a s t r +Astt a s t t +A.S.U. a s u +ASU- a s u +ASU a s u +A.S.V. a s v +ASV a s v +Aswa a s w a +ASW- a s w +ASW a s w +ASX a s x +A&T a and t +atac a t a c +Atac a t a c +ATAC- a t a c +Atad a t a d +Ata's a t a's +Atas a t a's +ATA's a t a's +A. T. a t +A.T. a t +ATBF a t b f +ATBs a t b's +atc a t c +A.T.C. a t c +ATC a t c +atcc a t c c +ATCC- a t c c +ATCC a t c c +ATCDE a t c d e +ATCL a t c l +ATDC a t d c +ATF- a t f +ATF a t f +Atg a t g +ATG a t g +ATGM a t g m +ath a t h +Ath a t h +ATH a t h +ATHN a t h n +ATIA a t i a +Atia's a t i a's +Ati a t i +ATi a t i +ATI a t i +Atid a t i d +Atiiq a t i i q +Atil a t i l +ATINC a t i n c +ATIP a t i p +Atiq a t i q +atis a t i s +Ativ a t i v +ATJ a t j +Atka a t k a +ATK a t k +ATKN a t k n +ATK's a t k's +Atl a t l +ATL a t l +Atli a t l i +ATLY a t l y +A.T.M.A. a t m a +atm a t m +Atm a t m +ATM a t m +ATMs a t m's +ATN a t n +ATO- a t o +ATO a t o +Atos a t o's +ATO's a t o's +ATOs a t o's +ATOS a t o s +ATP- a t p +ATP a t p +atpB a t p b +A.T.Q. a t q +ATR- a t r +ATR a t r +atri a t r i +Atri a t r i +ATRP a t r p +A&T's a and t's +A.T.s a t's +A.T.S. a t s +ATS a t s +ATSC a t s c +ATSDR a t s d r +AT&SF a t and s f +ATSF a t s f +ATSIC a t s i c +AT&T- a t and t +AT&T a t and t +attd a t t d +ATTESA a t t e s a +ATTF a t t f +AT&T's a t and t's +ATTS a t t s +ATTWI a t t w i +ATTWX's a t t w x's +ATU's a t u's +atv a t v +ATV- a t v +ATV a t v +ATV's a t v's +ATVs a t v's +ATW a t w +AtxA a t x a +ATX a t x +ATXN a t x n +A. U. a u +A.U. a u +Aub a u b +Aubl a u b l +AUC a u c +AUVs a u v's +Auw a u w +avab a v a b +AVAC a v a c +A. V. a v +A.V. a v +AVCA a v c a +AVC- a v c +AVC a v c +AVCHD a v c h d +AVCs a v c's +AVCS a v c s +AVD a v d +avg a v g +AVG a v g +AVK a v k +AVL a v l +A. V. M. a v m +AVM a v m +Avn a v n +AVN a v n +Avo a v o +AvP a v p +AVP- a v p +AVP a v p +AVR a v r +AVRs a v r's +AVSA a v s a +Avs' a v's +Avs a v's +AVS a v s +AVSM a v s m +AVU a v u +avvo a v v o +AVX a v x +Awa a w a +A. W. A. a w a +AWA a w a +A. W. A. M. a w a m +AWAs a w a's +A. W. a w +A.W. a w +A. W. B. a w b +A.W.B. a w b +AWB a w b +AWB's a w b's +A.W.C. a w c +AWC a w c +AWD a w d +A. W. F. a w f +AWG a w g +AWGIE a w g i e +AWGN a w g n +A. W. H. a w h +AWHL a w h l +AWI a w i +AWM a w m +Awo a w o +AWP a w p +AWP's a w p's +AWR a w r +AWSA a w s a +AWU a w u +Awwa a w w a +AXAF a x a f +A. X. a x +AXS a x s +AXV a x v +A. Y. a y +A.Y. a y +AYF a y f +AYK a y k +AYP a y p +A. Z. a z +A.Z. a z +AZD- a z d +AZE a z e +Azg a z g +Azi a z i +AZI a z i +AZL a z l +azm a z m +AZN a z n +AZS a z s +AZSTA's a z s t a's +AZT a z t +AzTV a z t v +Baad b a a d +BAAG b a a g +Ba'al b a a l +Baal b a a l +BAAL b a a l +Baam b a a m +Baap b a a p +ba'as b a a's +Baat b a a t +Ba'ath b a a t h +B. A. b a +B.A. b a +B&A b and a +Bac b a c +B.A.C. b a c +BAC b a c +bae b a e +Bae b a e +BAe b a e +BAE b a e +BAFA b a f a +BAF b a f +BAMF b a m f +BAPED- b a p e d +BAPH- b a p h +B.A.R. b a r +BARV b a r v +BASCA b a s c a +BASEC b a s e c +BASF b a s f +B.A.S.P. b a s p +BATVG b a t v g +Bauw b a u w +B'Av b a v +BAV b a v +BBA b b a +BBAG b b a g +B&B b and b +bb b b +B. B. b b +B.B. b b +BB- b b +BB b b +BBB b b b +bbc b b c +B.B.C. b b c +BBC- b b c +BBC b b c +BBCBBC b b c b b c +BBCH- b b c h +BB&CI b b and c i +BBC&PJR b b c and p j r +BBC's b b c's +B.B.D. b b d +BBDO b b d o +BBE b b e +BBF b b f +BBFC b b f c +BBFF b b f f +BBG b b g +BBH b b h +BBI b b i +BBK b b k +BBKL b b k l +BBLB b b l b +BBL- b b l +BBL b b l +BBM b b m +BBMP b b m p +BBNG b b n g +BBN's b b n's +BBO b b o +BBP b b p +BBQ'er b b q e r +B&Bs b and b's +BB&S b b and s +BBS b b s +BBSes b b s e's +BBS's b b s's +BB&T b b and t +BBT b b t +BBTV b b t v +BBU b b u +BBVA b b v a +BbvCI b b v c i +BBV's b b v's +BBWAA b b w a a +BBWA b b w a +BBWR's b b w r's +BBYA b b y a +BBYO b b y o +BCA- b c a +BCA b c a +BCAD b c a d +BCAM b c a m +BCATP b c a t p +BCBA b c b a +BCB b c b +bc b c +B. C. b c +B.C. b c +BC- b c +BC, b c +BC b c +BCCA b c c a +BCC b c c +BCCCA b c c c a +Bcci b c c i +BCCI b c c i +BCCP b c c p +BCC's b c c's +BCDA b c d a +BCD b c d +BCEA b c e a +BCE- b c e +BCE, b c e +BCE b c e +BCE's b c e's +BCF b c f +BCG b c g +BCG's b c g's +BCHL b c h l +BCHR's b c h r's +BCHS b c h s +BCI b c i +B. C. J. b c j +bcl- b c l +Bcl- b c l +BCL b c l +BCLR b c l r +BCMA b c m a +BCM b c m +BCMG b c m g +BCMHS b c m h s +BCMS b c m s +BCN b c n +BCN's b c n's +BCP b c p +BCPM b c p m +BCR- b c r +BCR b c r +BCRF's b c r f's +B.C.'s b c's +BC's b c's +BCs b c's +BCS- b c s +BCS b c s +BCSC b c s c +BCSic b c s i c +BCSN b c s n +BCT b c t +BCTC- b c t c +BCTC b c t c +BCU b c u +BCYP b c y p +BdA b d a +BDA b d a +bd b d +B. D. b d +B.D. b d +BD- b d +BD b d +BDBL b d b l +BDC b d c +BDC's b d c's +BDD b d d +Bde b d e +B. D. E. b d e +BDE b d e +BDF b d f +BDI b d i +BDJ b d j +BDK b d k +BDK's b d k's +BDM- b d m +BDMI b d m i +BDN b d n +BDNF b d n f +BDO b d o +BDO's b d o's +BDOS b d o s +BDP b d p +BDR b d r +bds b d s +BDS b d s +BDSM b d s m +BdU b d u +BDU b d u +BDV b d v +B. D. W. b d w +B.E.A. b e a +B. E. b e +B.E. b e +Bedw b e d w +B.E.E. b e e +bef b e f +B.E.F. b e f +BEF b e f +BEF's b e f's +bei b e i +Bei b e i +Beih b e i h +BEIR b e i r +Beis b e i's +bej b e j +B.E.M. b e m +BEMs b e m's +BEP- b e p +BEP b e p +Ber b e r +BER b e r +Bes b e's +B.E.S. b e s +BES b e s +B.F.A. b f a +BFA b f a +bf b f +Bf- b f +B. F. b f +B.F. b f +BF b f +BFCA b f c a +BFC b f c +BFC's b f c's +BFDG b f d g +BFES b f e s +BFF b f f +BFFs b f f's +B. F. G. b f g +BFG b f g +BFG's b f g's +BFI b f i +BFI's b f i's +BFJA b f j a +BFKL b f k l +BFL b f l +BFM b f m +BFO b f o +BFRA b f r a +BFR b f r +BFSA b f s a +BFS b f s +BFT b f t +BFU b f u +bfy b f y +BGAB b g a b +BGA b g a +BGB b g b +B. G. b g +B.G. b g +BGC b g c +BGCI b g c i +BGD b g d +BGEA b g e a +B. G. E. b g e +BGH b g h +B. G. J. S. b g j s +BGL b g l +BglII b g l i i +BGM- b g m +BGM b g m +BGP- b g p +BGP b g p +BGRA b g r a +BGR b g r +BGRC b g r c +BGRSO b g r s o +bgs b g s +B.G.S. b g s +BGS b g s +BGSU b g s u +BGT b g t +Bgy b g y +Bha b h a +B&H b and h +B. H. b h +B.H. b h +BHCC b h c c +BHDP b h d p +BH&E b h and e +Bhe b h e +BHL b h l +BHMA b h m a +BHMO b h m o +BHMs b h m's +BHMT b h m t +BHO b h o +B. H. P. b h p +BHP b h p +BHRT b h r t +BHS b h s +BHSN b h s n +BHSU b h s u +bhttp b h t t p +BHU b h u +BHUSD b h u s d +BHVS b h v s +B. I. b i +B.I. b i +Bie b i e +BIE b i e +biedt b i e d t +Biem b i e m +B.I.G. b i g +B.I.G.'s b i g's +BiH b i h +BIH b i h +B.I.O.L.A. b i o l a +B. J. b j +B.J. b j +BJC- b j c +BJCC b j c c +BJCP b j c p +BJD b j d +B.J.F. b j f +B. J. I. b j i +BJJ b j j +BJP b j p +BJP's b j p's +BJPs b j p's +BJPS b j p s +B.J.'s b j's +B.J.T. b j t +BJT b j t +BJU b j u +BJY b j y +B.K.A. b k a +B&K b and k +BKB- b k b +B. K. b k +B.K. b k +BKCa b k c a +BKC b k c +BKF b k f +BKI b k i +BKN's b k n's +BKO b k o +B.K.R. b k r +BKR b k r +BK's b k's +BKS b k s +BKT b k t +BKTV b k t v +BKV b k v +B. L. b l +B.L. b l +BL- b l +BL b l +BLC b l c +BLCC b l c c +BLCN b l c n +ble b l e +bleg b l e g +blev b l e v +BLG- b l g +BLG b l g +BLH- b l h +bli b l i +BLI b l i +Blla b l l a +BLL- b l l +BLL b l l +BLM- b l m +BLM b l m +BLMC b l m c +BLOU's b l o u's +BLPP b l p p +BLR b l r +BLRC b l r c +BLR&D b l r and d +B.L.S. b l s +BLS b l s +BLT b l t +BLTF b l t f +BLTs b l t's +BLTTA- b l t t a +BLV b l v +BMAA b m a a +B.M.A. b m a +BMA b m a +BMAL b m a l +BMARC b m a r c +BMA's b m a's +B&M b and m +BMB b m b +B. M. b m +B.M. b m +BMCA b m c a +B.M.C. b m c +BMC b m c +bmd b m d +BMD b m d +BME b m e +BMF b m f +BMG b m g +BMHS b m h s +bmi b m i +BMI b m i +BMIC b m i c +BMIR b m i r +BMI's b m i's +BMIT b m i t +BMJ b m j +BMK b m k +BMKG b m k g +BMML- b m m l +BMMO b m m o +BMNA b m n a +BMNH b m n h +BMNP b m n p +BMO b m o +BMP- b m p +BMP b m p +BMPs b m p's +BMR- b m r +BMR b m r +BMRs b m r's +BMSA b m s a +B.M.S. b m s +BMS- b m s +BMS b m s +bmt b m t +B. M. T. b m t +B.M.T. b m t +BMT b m t +BMT's b m t's +BMU b m u +B.M.V. b m v +BMV b m v +B. M. W. b m w +BMW b m w +BMW M b m w +BMW's b m w's +BMX- b m x +BMX b m x +BNA b n a +B&N b and n +bnb b n b +BNB b n b +B. N. b n +B.N. b n +BNC b n c +BNCI b n c i +BNCM b n c m +BNCT b n c t +BND b n d +BNDY b n d y +BNET b n e t +BNF b n f +BNFL b n f l +BNI b n i +BNIC b n i c +BNL b n l +BNO b n o +BNP b n p +BNPH- b n p h +BNR b n r +BNRC b n r c +BNS b n s +BNSF b n s f +BNST b n s t +BNT b n t +BNU b n u +BNY b n y +BNZ b n z +Boac b o a c +BOAC- b o a c +BOAC b o a c +B&O b and o +B. O. b o +B.O. b o +Boc b o c +BoC b o c +BOC- b o c +BOC b o c +BOCs b o c's +BOCS b o c s +boj b o j +Boj b o j +BOJ b o j +B.O.M.B. b o m b +B&O's b and o's +B.O.S. b o s +BOYZZ b o y z z +BPA b p a +BPB b p b +bp b p +B. P. b p +B.P. b p +BP b p +BPC b p c +BPD b p d +BPER b p e r +B.P.H. b p h +BPH- b p h +BPI b p i +BPJ b p j +BPK b p k +bpl b p l +BPL b p l +B. P. M. b p m +BPM b p m +BPMN b p m n +B.P.N. b p n +BPN b p n +B.P.O. b p o +BPO b p o +BPPA b p p a +BPP b p p +BPR b p r +B.P.R.D. b p r d +BPRD b p r d +BPSA b p s a +BP's b p's +BPS b p s +BPSK b p s k +BPUP b p u p +BPV b p v +BPY b p y +B&Q b and q +BQB b q b +B. Q. b q +BQM- b q m +BRAC's b r a c's +BRAM b r a m +BRBDP b r b d p +Brbic b r b i c +B. R. b r +B.R. b r +BRBR b r b r +BRBs b r b's +BRCA b r c a +BRC b r c +BRCC b r c c +BRD b r d +BRF b r f +BRGF b r g f +BRGM b r g m +BRHS b r h s +B.R.I.C.K. b r i c k +BRK b r k +BRL b r l +BRM b r m +BRMS b r m s +Brn- b r n +BRN b r n +BRNC b r n c +Brne b r n e +Brno b r n o +BRNV b r n v +BRP b r p +BRPS b r p s +BRRA b r r a +BRS b r s +BRSCC's b r s c c's +BRT b r t +BRTs b r t's +BRTS b r t s +BRVM b r v m +BRW b r w +BRWK b r w k +Brza b r z a +BRZ b r z +brzu b r z u +brzy b r z y +Brzyk b r z y k +BSAA b s a a +B.S.A. b s a +BSA- b s a +BSA b s a +BSAC b s a c +BsaL b s a l +BSBA b s b a +BSB b s b +BSBI b s b i +B. s b's +B.'s b's +Bs b's +B. S. b s +B.S. b s +BS- b s +BS b s +B.S.C. b s c +BSC b s c +BSCL b s c l +bsd b s d +BSD- b s d +BSD b s d +BSDE b s d e +BSE b s e +BSET b s e t +BSFA b s f a +BSF b s f +BSG b s g +BSh- b s h +BSH b s h +BSIB b s i b +BSI b s i +BSK b s k +BSL- b s l +BSL b s l +BSM b s m +BSME b s m e +BSN b s n +BSNL b s n l +BSOG b s o g +BSPA b s p a +BSP b s p +BSPP b s p p +BSR b s r +BSRN b s r n +BSS b s s +BST- b s t +BSU b s u +BSV b s v +BSX b s x +BTA b t a +BTAF b t a f +BTB- b t b +BTB b t b +BTBD b t b d +bt b t +B. T. b t +B.T. b t +BT- b t +BT b t +BTCA b t c a +BTC- b t c +BTC b t c +BTCC b t c c +BTD b t d +BTF b t f +BTG b t g +BTH b t h +BTK b t k +BTL b t l +BTM b t m +BTN b t n +BTNK b t n k +BTOB b t o b +BTO b t o +BTP b t p +BTR- b t r +BTRC b t r c +BTRDA b t r d a +Btry b t r y +btsan b t s a n +BT's b t's +BTS b t s +BTT b t t +BTU b t u +btus b t u s +BTUs b t u's +BTV b t v +B.U. b u +B.U.M. b u m +BUV b u v +BVA b v a +BVB b v b +BVB's b v b's +B. V. b v +B.V. b v +BVC b v c +BVFB b v f b +BVI b v i +BVM b v m +BVO b v o +BVR b v r +BVRC b v r c +BVT b v t +BVVL b v v l +Bwa b w a +BWAF b w a f +B&W b and w +BWB b w b +BWBR b w b r +B. W. b w +B.W. b w +B.W.C. b w c +BWC b w c +BWF b w f +BWFC b w f c +BWHBC b w h b c +B. W. I. b w i +BWI b w i +BWIR b w i r +BWO b w o +BWR b w r +BWS b w s +BWT b w t +BWTs b w t's +BWV b w v +BWW b w w +bwwtv b w w t v +Bxa b x a +BX b x +Bxe b x e +BXML b x m l +BxPC- b x p c +BYA's b y a's +BYB b y b +B. Y. b y +byc b y c +BYC b y c +BYD b y d +BYFC b y f c +BYG b y g +bygd b y g d +Byk b y k +byn b y n +BYOB b y o b +Byo b y o +BYO b y o +Byou b y o u +BYR b y r +Byrl b y r l +bySLC b y s l c +BYST b y s t +byt b y t +B.Y.U. b y u +BYU b y u +BYU's b y u's +BYX b y x +BYZ b y z +B.Z. b z +BZ b z +BZD b z d +bzhed b z h e d +Bzik b z i k +BZK b z k +BZP b z p +Bzyb b z y b +CAA c a a +CAAC c a a c +CAAC's c a a c's +CAAHEP c a a h e p +CAAM c a a m +CAAS c a a s +CAASE c a a s e +Caat c a a t +CAAT c a a t +C. A. c a +C.A. c a +CA- c a +CA c a +C&A c and a +CAC c a c +CA&CC c a and c c +CACC c a c c +CACM c a c m +Cadw c a d w +CADW c a d w +caeca c a e c a +Cae c a e +CAE c a e +C.A.F.B. c a f b +CAFTT c a f t t +C. A. G. c a g +CAG c a g +CAGM c a g m +C. A. I. c a i +C. A. J. c a j +CALUX c a l u x +CAMC c a m c +CAMLG c a m l g +CAMPCO c a m p c o +C.A.M.'s c a m's +C. A. N. c a n +Capt. captain +C. A. R. c a r +cas c a s +Cas c a's +C.A.S. c a s +CAS c a s +Casc c a s c +CASC c a s c +CASD c a s d +CASF c a s f +CASG c a s g +CASQ c a s q +C. A. T. c a t +C.A.T. c a t +CATV c a t v +C.A.W. c a w +CBA c b a +CBBB c b b b +CBB c b b +CBBC c b b c +CBBS c b b s +CBCA c b c a +cb c b +C. B. c b +C.B. c b +CB- c b +CB c b +cbc c b c +CBC- c b c +CBC c b c +CB&CNS c b and c n s +CBC's c b c's +CBCS c b c s +CBCV- c b c v +CBDA c b d a +CBD c b d +CBDs c b d's +C.B.E. c b e +CBE c b e +CBEF c b e f +CBERS- c b e r s +CBE's c b e's +CBF- c b f +CBF c b f +CBFT- c b f t +CBFX- c b f x +CBGB c b g b +CBGB's c b g b's +CBGBs c b g b's +CBG c b g +CBH c b h +CBHG c b h g +CBI c b i +CBI's c b i's +CbiXS c b i x s +CBKB c b k b +CBK c b k +CBKMT c b k m t +CBKRT c b k r t +CBL c b l +CBL's c b l's +CBM- c b m +CBM c b m +CBME- c b m e +CBMS c b m s +CBMT- c b m t +CBN c b n +CBN's c b n's +CBNT c b n t +CBO- c b o +CBO c b o +CBON- c b o n +CBOT c b o t +CBP- c b p +CBP c b p +CBPE c b p e +CB&Q c b and q +CBR c b r +CBRE c b r e +CBRN c b r n +CBRNE c b r n e +CBSA- c b s a +CBSA c b s a +CBs c b's +CBS- c b s +CBS c b s +C.B.S.E. c b s e +CBSE c b s e +CBS's c b s's +CBT c b t +CBTC c b t c +CBTU c b t u +CBU c b u +CBUT c b u t +CBV- c b v +CBV c b v +CBWT c b w t +CBX c b x +CBY- c b y +CBYT- c b y t +CBYT c b y t +CBZH c b z h +'c c +CcaA c c a a +CCAA c c a a +CCAAT c c a a t +CCAB- c c a b +cca c c a +Cca c c a +CCA c c a +CCAF c c a f +CCAP c c a p +CCAR c c a r +CCAS c c a s +CCB c c b +CCBCC c c b c c +CCBE c c b e +CCCA c c c a +C&C c and c +C. C. c c +C.C. c c +CCCE c c c e +CCCF c c c f +CCCP- c c c p +CCCP c c c p +CCC's c c c's +CCDB c c d b +CCDC c c d c +ccd c c d +CCD c c d +CCDev c c d e v +CCDI c c d i +CCDI's c c d i's +CCDM c c d m +CCDR c c d r +CCD's c c d's +CCDs c c d's +CCEd c c e d +C.C.E.D. c c e d +CCF c c f +CCFO c c f o +CCG c c g +C.C.G.S. c c g s +CCGS c c g s +CCHA c c h a +CCHC c c h c +C.C.H. c c h +CCH c c h +CCHD c c h d +CCHS c c h s +C.C.I.A.A. c c i a a +CCIAA c c i a a +CCi c c i +CCI c c i +CCID c c i d +CCIE c c i e +CCIH c c i h +CCITT c c i t t +CCJ c c j +CCK c c k +CCLC c c l c +CCL c c l +CCMA c c m a +ccm c c m +CCM c c m +CCMM c c m m +CCMP c c m p +CCMS c c m s +CCN c c n +CCNY c c n y +CCO c c o +CCOKC c c o k c +CCOO c c o o +CCOP c c o p +C.C.O.W.E. E.T.F. c c o w e e t f +CCP c c p +CCPD c c p d +CCPL c c p l +CCPN c c p n +CCP's c c p's +CCQ c c q +CCRC c c r c +CCR c c r +CCRCs c c r c's +CCRH c c r h +CCRS c c r s +CCSA c c s a +CCSC c c s c +CC's c c's +CCS c c s +CCSD c c s d +C.C.S.D.N.Y. c c s d n y +C.C.S.M. c c s m +CCSN c c s n +CCSR c c s r +CCS's c c s's +cct c c t +CCT c c t +CCTF c c t f +CCTRN c c t r n +CCTT c c t t +CCTV- c c t v +CCTV c c t v +CCUA c c u a +CCU c c u +ccus c c u s +CCV c c v +CCVG c c v g +C. C. W. c c w +CCWD c c w d +CDAC- c d a c +CDA c d a +CDAT c d a t +CDB c d b +CDBS c d b s +CDCA c d c a +C&D c and d +cdc c d c +CDC- c d c +CDC c d c +cd c d +C. D. c d +C.D. c d +CD- c d +CD c d +CDC's c d c's +CDDB c d d b +CD&DR c d and d r +CDE c d e +CDF c d f +CDFI c d f i +CDFW c d f w +CDG- c d g +CDH c d h +CDi c d i +CDI c d i +CDISC c d i s c +CDI's c d i's +CDK c d k +CDKN c d k n +CDL c d l +CDLI c d l i +CDLS c d l s +CDMA- c d m a +CDMA c d m a +CDM- c d m +CDM c d m +cDNA c d n a +cdnas c d n a s +cDNAs c d n a's +CDN c d n +CDN's c d n's +CDO c d o +CDOs c d o's +CDPC c d p c +CDP c d p +CDP's c d p's +CDPs c d p's +CD&R c d and r +CDR c d r +cds c d s +CD's c d's +CDs, c d's +CDs c d's +CDS- c d s +CDS c d s +CDSG c d s g +CDSP c d s p +CDSPCo c d s p c o +CdtA c d t a +CDT c d t +CdTe c d t e +CDTi c d t i +CDTI c d t i +CDT's c d t's +CDTV c d t v +CDTV's c d t v's +CDU- c d u +CDU c d u +CDU's c d u's +CD&V c d and v +CDV c d v +CDW c d w +CDWP c d w p +Cec c e c +CEC c e c +c'e c e +ce c e +C'e c e +Ce c e +C. E. c e +C.E. c e +CE, c e +CE c e +CECP c e c p +CEDA c e d a +Ced- c e d +CED- c e d +CEDO c e d o +CEDR c e d r +CEDS c e d s +CEEBA c e e b a +CEEB c e e b +CEEH c e e h +Ceel c e e l +CEEOL c e e o l +CEESA c e e s a +CEFC c e f c +CEF c e f +Cefn c e f n +CEFP c e f p +CEFR c e f r +CEGB c e g b +C.E.G. c e g +C. E. H. c e h +CEI c e i +C&EI's c and e i's +C. E. M. c e m +C&EN c and e n +cen c e n +Cen c e n +CEN c e n +ceo c e o +C.E.O. c e o +CEO c e o +Ceol c e o l +CEOP c e o p +Ceorl c e o r l +Ceos c e o's +CEO's c e o's +CEOs' c e o's +CEOs c e o's +C.E.P. c e p +cer c e r +Cer c e r +CER c e r +CERP c e r p +CERPER c e r p e r +CERS c e r s +ces c e s +Ces c e's +C.E.S. c e s +CES c e s +CESL c e s l +CESO c e s o +CETB c e t b +C. E. T. c e t +CEV c e v +CEVCP c e v c p +CEVG c e v g +CEW c e w +Cex c e x +CeX c e x +CEX c e x +CEZ c e z +CEZMS c e z m s +CFAB c f a b +Cfa c f a +CFA c f a +CFAS c f a s +C. F. B. c f b +CFB c f b +CFBG c f b g +CFBISD c f b i s d +CFB's c f b's +C&F c and f +CFC- c f c +CFC c f c +cf c f +C. F. c f +C.F. c f +CF- c f +CF c f +CFCF- c f c f +CFC's c f c's +CFDA c f d a +CFD c f d +C.F.E. c f e +CFE c f e +CFFB- c f f b +CFFC c f f c +C. F. F. c f f +CFF- c f f +CFF c f f +C. F. H. c f h +CFH c f h +CFHS c f h s +CFI c f i +CFIT c f i t +CFJC- c f j c +CFJL c f j l +CFJP- c f j p +CFJR c f j r +CFL c f l +CFL's c f l's +CFM c f m +CFMEU c f m e u +CFMI c f m i +CFMM- c f m m +CFND c f n d +CFNY- c f n y +CFNY c f n y +C.F.O.A. c f o a +CFOA- c f o a +CFO c f o +CFOP c f o p +CFOs c f o's +CFPI c f p i +CFPL c f p l +CFQ c f q +CFRB c f r b +C.F.R. c f r +CFR- c f r +CFR c f r +CFRP c f r p +CFS c f s +CFSCI c f s c i +CFSP c f s p +CFTA c f t a +CFT c f t +CFTK- c f t k +CFTO- c f t o +CFTO c f t o +CFTR c f t r +CFTs c f t's +CFTU- c f t u +CFTXOP c f t x o p +CFU c f u +CFX- c f x +CFYN c f y n +CFZ c f z +CGA c g a +CGAP c g a p +CGB c g b +C&G c and g +CGCFAD c g c f a d +C. G. c g +C.G. c g +CGCRI c g c r i +CGCS c g c s +CGD c g d +CGDK c g d k +CGE c g e +CGF c g f +CGFP c g f p +CGG c g g +CGI- c g i +CGI c g i +CGIL c g i l +CGKD c g k d +cgl c g l +CGL c g l +CGP c g p +CGPM c g p m +CGPME c g p m e +CGPW c g p w +CGR c g r +CGRP c g r p +CGS c g s +CGSS c g s s +CGT c g t +CGTG c g t g +CGTIC c g t i c +CGU c g u +CGW c g w +CGW's c g w's +C.H.B. c h b +CHBM c h b m +CHBX c h b x +C&H c and h +C.H.C. c h c +C. H. c h +C.H. c h +CHCH- c h c h +CHCO c h c o +CHD c h d +CHDK c h d k +CHDS c h d s +CHF c h f +CHFI c h f i +C.H.G. c h g +CHGO c h g o +CHH c h h +CHHOTO c h h o t o +CHHS c h h s +Chhu c h h u +Chirs c h i r's +CHISMS c h i s m s +CHISZ c h i s z +CHJX- c h j x +CHK c h k +CHL c h l +CHLR c h l r +CHL's c h l's +C. H. M. c h m +CHM c h m +CHN c h n +CHP- c h p +CHP c h p +CHP'den c h p d e n +CHPs c h p's +CHPS c h p s +CHR c h r +CHRDI c h r d i +CHRGD c h r g d +C.H.S. c h s +CHS c h s +CHSE c h s e +CHT c h t +CHV c h v +CHX c h x +Chy c h y +CHYR c h y r +CIAC c i a c +Cia c i a +C.I.A. c i a +CIA- c i a +CIA, c i a +CIA c i a +CIC- c i c +CIC c i c +ci c i +Ci c i +C. I. c i +C.I. c i +CI c i +Cicic c i c i c +CICL c i c l +C.I.C.M. c i c m +CICO c i c o +CIC's c i c's +CICT- c i c t +C.I.D. c i d +CIFF c i f f +CIFL c i f l +CIHE c i h e +CIHR c i h r +cii c i i +CII c i i +CIID c i i d +CIJ c i j +CIK- c i k +CIKM c i k m +C.I.L. c i l +CIL c i l +cim c i m +Cim c i m +CIM c i m +Cio c i o +C.I.O. c i o +CIO c i o +CIOs c i o's +CIOS- c i o s +CIOT- c i o t +CIOT c i o t +CIPCA c i p c a +Cip c i p +C.I.P. c i p +CIP c i p +CIPD c i p d +CIPFA c i p f a +CIPM c i p m +CISA c i s a +CISC c i s c +cis- c i s +cis c i s +CIs c i's +CIS- c i s +CIS c i s +CITB c i t b +cit c i t +CIT- c i t +CIT c i t +CiTD c i t d +CITM c i t m +CITN c i t n +CITP c i t p +citS c i t s +CITV c i t v +CITWF c i t w f +CitX c i t x +Ciuc c i u c +Ciu c i u +CiU c i u +CIU c i u +CIUT c i u t +CIVD c i v d +CIW c i w +CIWS c i w s +CIX c i x +Cixi c i x i +CIY c i y +CIZN c i z n +CJA c j a +CJAD- c j a d +CJBHL c j b h l +CJCA c j c a +CJCB c j c b +CJC c j c +C. J. c j +C.J. c j +CJD c j d +C. J. E. c j e +CJFL c j f l +CJFT c j f t +CJFX c j f x +CJGC c j g c +CJGO c j g o +CJHL c j h l +CJIC- c j i c +CJK c j k +CJL c j l +CJLS c j l s +CJM c j m +CJNT c j n t +CJOC c j o c +CJOT- c j o t +CJP c j p +C. J. R. c j r +C.J.R. c j r +CJR c j r +CJSC c j s c +C. J. S. c j s +CJS c j s +CJT c j t +CJTF- c j t f +CJUF c j u f +CJWC c j w c +CKAC c k a c +CKC c k c +C. K. c k +C.K. c k +CK c k +CKD c k d +CKE c k e +CKLM c k l m +CKLN- c k l n +CKLQ c k l q +CKLW c k l w +CKND- c k n d +CKRY- c k r y +CKS c k s +CKSO- c k s o +CKSO c k s o +CKUE- c k u e +CKVL c k v l +C. K. W. c k w +CKWK c k w k +ckx c k x +CKXX c k x x +CKY c k y +CLAC c l a c +CLA c l a +CLAS c l a s +CLB- c l b +CLBs c l b's +clc c l c +CLC- c l c +CLC c l c +cl c l +C. L. c l +C.L. c l +CL- c l +CL c l +CLCN c l c n +CLD c l d +Cle c l e +CLE c l e +CLF c l f +C.L.G. c l g +CLG c l g +CLHIA c l h i a +CLHS c l h s +CLI c l i +clk- c l k +CLK c l k +cllr c l l r +CLM c l m +CLMD c l m d +CLMP c l m p +CL&N c l and n +Clo c l o +CL&P c l and p +CLP c l p +CLRC c l r c +C. L. R. c l r +C.L.R. c l r +CLR c l r +CLRK c l r k +CLSA c l s a +CLSC c l s c +CLs c l's +CLS- c l s +CLS c l s +CLT c l t +CLTD c l t d +CLTPA c l t p a +CLTs c l t's +Clu c l u +CLU c l u +CLUK c l u k +CLV c l v +Clwyd c l w y d +CLX c l x +C&MA c and m a +CMAC c m a c +C.M.A. c m a +CMA c m a +CMAL c m a l +CMAP's c m a p's +CMAS- c m a s +CMAS c m a s +CMAT c m a t +C.M.B. c m b +CMB c m b +CMCC c m c c +CMCCDI c m c c d i +C.M.C. c m c +CMC- c m c +CMC c m c +cm- c m +cm c m +C. M. c m +C.M. c m +CM- c m +CM c m +CMCs c m c's +CMCS c m c s +CMD c m d +Cmde c m d e +CMDISE c m d i s e +cmdr c m d r +CMEC c m e c +CME c m e +CMF c m f +CMFS c m f s +C. M. G. c m g +C.M.G. c m g +CMG c m g +CMHC c m h c +CMH c m h +CMHR c m h r +CMI c m i +CMJ c m j +CMLA c m l a +cml c m l +C.M.L. c m l +CML c m l +CMLDP c m l d p +CMLL c m l l +CMLL's c m l l's +CMM c m m +CMMI c m m i +CMMs c m m's +cmn c m n +CMO c m o +CMO's c m o's +CMPC c m p c +CMP c m p +CMPS c m p s +CMPSO c m p s o +CMPV c m p v +CMQ- c m q +CMQ c m q +CMQT c m q t +C. M. R. c m r +CMR c m r +CMSAF c m s a f +C.M.S. c m s +CMS c m s +C.M.S.L. c m s l +CMT c m t +Cmte c m t e +CMT's c m t's +CMTU c m t u +CMUCL c m u c l +CMU c m u +CMU's c m u's +CMV c m v +cmvIL- c m v i l +CMVM c m v m +CMVSS c m v s s +CMWF c m w f +CMXXII c m x x i i +CMYK c m y k +CNA c n a +CNBC- c n b c +CNBC c n b c +CNB c n b +CNC c n c +cn c n +C. N. c n +C.N. c n +CN c n +CNC's c n c's +CND c n d +CNDL c n d l +CNEB c n e b +CNE c n e +CNF c n f +CNFE c n f e +CNFK c n f k +CNG- c n g +CNG c n g +CNI c n i +CNJ c n j +CNJF c n j f +CNK c n k +C. N. L. c n l +C.N.L. c n l +CNL c n l +CNMs c n m's +CNN- c n n +CNN c n n +CNO c n o +CNPC c n p c +CNP c n p +cnr c n r +CNR c n r +CNRMA c n r m a +CNRS c n r s +CNSA c n s a +CNs c n's +CNS c n s +CNSS c n s s +CNSW c n s w +CNTA c n t a +CNT c n t +CNTE c n t e +CNTI c n t i +CNTK c n t k +CNTN c n t n +CNTs c n t's +CNTS c n t s +CNTV c n t v +CNU c n u +Cnut's c n u t's +CNV c n v +CNVs c n v's +CNW c n w +CNWS c n w s +CNZ c n z +COA c o a +C&O c and o +C. O. c o +C.O. c o +CO- c o +Co. company +C.O.D. c o d +Col. colonel +C.O.M.L. c o m l +Cov c o v +COX c o x +CPAC c p a c +CPA c p a +CPAP- c p a p +CPA's c p a's +CPB c p b +CPBL c p b l +C&P c and p +CPC- c p c +CPC c p c +cp c p +C. P. c p +C.P. c p +CP- c p +CP c p +CPC's c p c's +CPCs c p c's +CPCS c p c s +CPD c p d +CPDM c p d m +CPD's c p d's +CPEB c p e b +CPEC c p e c +C.P.E. c p e +CPE c p e +CPEO c p e o +CPF c p f +CPFO c p f o +CPG c p g +CPHC c p h c +CPH c p h +CPI- c p i +CPI c p i +CPIFL c p i f l +CPIM c p i m +CPI's c p i's +CPJ c p j +CPL c p l +CPLP c p l p +CPM c p m +CPN c p n +CPNI c p n i +cpo c p o +C.P.O. c p o +CPO c p o +CPOE c p o e +CPPA c p p a +CPPCC c p p c c +CPP c p p +CPPE c p p e +CPPIB c p p i b +CPPM c p p m +CPQ c p q +CPR c p r +CPRS c p r s +CPSA c p s a +CPSC c p s c +CPS- c p s +CPS c p s +CPSF c p s f +CPSK c p s k +CPSL c p s l +CPSU c p s u +CPTA c p t a +CPT c p t +CPTM c p t m +CPUC c p u c +CPU- c p u +CPU c p u +CPUID c p u i d +CPUSA c p u s a +CPUs c p u's +CPUT c p u t +CPVA c p v a +CPV c p v +CPW c p w +CQAC c q a c +CQBR c q b r +CQC c q c +cq c q +CQ c q +CQD c q d +CQDs c q d's +CQM c q m +CQO c q o +CQU c q u +CQW- c q w +CRABP- c r a b p +C. R. A. c r a +CRA c r a +C.R.A.Z.Y. c r a z y +CRBC c r b c +CRC c r c +cr- c r +cr c r +Cr- c r +C. R. c r +C.R. c r +CR- c r +CR c r +Cre c r e +CRE c r e +CRF- c r f +CRF c r f +CRG c r g +CRHK c r h k +CRH's c r h's +CRHS c r h s +CRJ c r j +crk c r k +Crkva c r k v a +crkve c r k v e +CRL- c r l +CRL c r l +CRLs c r l's +crm c r m +CRM c r m +CRNA c r n a +CRN- c r n +CRN c r n +Crne c r n e +Crni c r n i +Crno c r n o +CRP c r p +CRPF c r p f +CRRF c r r f +CRs c r's +CRS- c r s +CRS c r s +CRSP c r s p +CRST c r s t +CRTC c r t c +CRT c r t +CRTC's c r t c's +CRUA c r u a +CRWRC c r w r c +CRW's c r w's +CRX c r x +CSAC c s a c +csa c s a +Csa c s a +C.S.A. c s a +CSA c s a +CSAH c s a h +Csak c s a k +Csaky c s a k y +CSAR c s a r +CSAT c s a t +CSAV c s a v +CSB c s b +C&S c and s +C.S.C. c s c +CSC c s c +CSCD c s c d +CSCE c s c e +CSCR c s c r +cs c s +C.s c's +Cs c's +C. S. c s +C.S. c s +CS- c s +CS c s +CSC's c s c's +CSDA c s d a +CSDB c s d b +CSD c s d +CSDL c s d l +CSDN c s d n +CSDP c s d p +CSD's c s d's +CSDS c s d s +CSE c s e +C&SF c and s f +CSF c s f +CSFL c s f l +CSFSO c s f s o +CSGA c s g a +csg c s g +CSG c s g +CSG's c s g's +CSH c s h +CSHL c s h l +CSIC c s i c +CsI c s i +CSI c s i +CSIDC c s i d c +CSILUS c s i l u s +CSIO c s i o +CSIR c s i r +CSIRO c s i r o +CSis c s i's +CSIs c s i's +CSIS- c s i s +CSIS c s i s +CSIU c s i u +CSKA- c s k a +CSKA c s k a +CSKA's c s k a's +CSK c s k +CSK's c s k's +CSL- c s l +CSL c s l +CSLI c s l i +CSM c s m +CSNB c s n b +CSNBX c s n b x +CSN c s n +CSNJ- c s n j +CSN's c s n's +CSOB c s o b +CSO c s o +CSO's c s o's +CSOs c s o's +cspA c s p a +csp c s p +CSP c s p +CSPH c s p h +CSPI c s p i +CSPRA c s p r a +CSPs c s p's +CSRA c s r a +CSR c s r +CSRS c s r s +CSRT c s r t +CSRTT c s r t t +CSSA c s s a +CSS c s s +CSSD c s s d +CSSE c s s e +CSSL c s s l +CSSNCs c s s n c's +CSSR c s s r +CSSS c s s s +CSST c s s t +CSTB c s t b +CST c s t +CSTF c s t f +CSTI c s t i +CSTS c s t s +CSUB c s u b +CSU c s u +CSU's c s u's +Csuz c s u z +CSV c s v +CSW c s w +CSWF c s w f +CSWIP c s w i p +CSWS c s w s +CSX c s x +CSX's c s x's +CSXT c s x t +C.T.A. c t a +CTA c t a +CTAF c t a f +CTARL c t a r l +CTA's c t a's +CTAs c t a's +CTBT c t b t +CTBTO c t b t o +C&T c and t +CTC c t c +ct c t +C. T. c t +C.T. c t +CT- c t +CT c t +CTD c t d +cte c t e +CTE c t e +CTEQ c t e q +CTF c t f +CTGF c t g f +CTI c t i +CTLA- c t l a +CTLA c t l a +CTL c t l +CTLL- c t l l +CTLLS c t l l s +CTLs c t l's +CTM c t m +CTMP- c t m p +CTN c t n +CTO c t o +CTP c t p +ctr c t r +CTRG c t r g +Ctrip c t r i p +CTRL c t r l +CTRP c t r p +CTR's c t r's +CTS- c t s +CTS c t s +CTSD c t s d +CTSF c t s f +CTSG c t s g +CTUC c t u c +CTU c t u +CTUG c t u g +CTU's c t u's +CTVA- c t v a +CTVA c t v a +ctv c t v +CTV c t v +CTV's c t v's +CTX c t x +CTZ c t z +cu c u +C. U. c u +CU- c u +CU c u +C.U.L. c u l +C. U. S. c u s +C. U. T. c u t +CUW c u w +Cuyp c u y p +CVA- c v a +CVA c v a +CVAK c v a k +CVARG c v a r g +CVB c v b +C&V c and v +CVC c v c +cvcp c v c p +'cv c v +cv- c v +cv c v +C. V. c v +C.V. c v +CV- c v +CV c v +CVD c v d +CVEs c v e's +CVG c v g +CVI c v i +CVJM c v j m +CVM c v m +C.V.N. c v n +CVN- c v n +CVN c v n +C.V.O. c v o +CVO c v o +CVODE c v o d e +CVOs c v o's +CVP c v p +CVR c v r +CVs c v's +CVS c v s +CVSNT c v s n t +CVT c v t +CVTs c v t's +CVV c v v +CVVHDF c v v h d f +CVW- c v w +CVW c v w +CVZ c v z +CWA c w a +CWBI c w b i +CWBL c w b l +CWC c w c +C. W. c w +C.W. c w +CWD c w d +CWDS c w d s +C. W. E. c w e +CWE c w e +Cwej c w e j +Cwele c w e l e +CWF c w f +CWGC c w g c +CWG c w g +CWI c w i +C. W. K. c w k +cwm c w m +CWM c w m +CWO c w o +CWPA c w p a +CWR c w r +cwrt c w r t +CWRU c w r u +CWSAC c w s a c +CW's c w's +CWS c w s +CWTS c w t s +CWUR c w u r +C. W. Y. c w y +CWYFL c w y f l +CXAM- c x a m +CXC- c x c +CXC c x c +CXCL c x c l +CXCR c x c r +C.X. c x +C. Y. c y +C.Y. c y +cyl c y l +Cyn c y n +CYOG c y o g +CyP c y p +CYP c y p +Cyrl c y r l +Cys- c y s +Cys c y's +CYS c y s +CYSK c y s k +CYSY c y s y +czci c z c i +cz c z +C.Z. c z +CZ- c z +CZ c z +CZE c z e +CZM c z m +CZW c z w +czy c z y +DAAD d a a d +Daai d a a i +D. A. d a +D.A. d a +D&AD d and a d +D. A. H. d a h +D.A.M. d a m +D.A.N.C.E. d a n c e +D. A. T. d a t +Dav d a v +D.A.V. d a v +DAV d a v +DAV's d a v's +dBa d b a +DBA d b a +DBC d b c +DBCS d b c s +db d b +D. B. d b +D.B. d b +DB- d b +DB, d b +DB d b +DBE d b e +DBI d b i +DBL d b l +DBLE d b l e +DBLP d b l p +DBM d b m +DBMS d b m s +DBR d b r +DB's d b's +D. B. S. d b s +DBS d b s +DBU d b u +DBYC d b y c +DBZ d b z +DCA- d c a +DCA d c a +DCAF d c a f +DCAM d c a m +DCB d c b +DCCC d c c c +DCCCD d c c c d +DCC d c c +DCCG d c c g +DCCs d c c's +D&C d and c +dc d c +D. C. d c +D.C. d c +DC- d c +DC d c +DCE d c e +DCFC d c f c +DCF d c f +DCG- d c g +DCG d c g +DCH d c h +DCI d c i +DCK d c k +D.C.L. d c l +DCL d c l +DCMA d c m a +DCM d c m +DCMF d c m f +DCMI d c m i +DCMS d c m s +DCO- d c o +DCO d c o +DCom d c o m +DCOM d c o m +DCP d c p +DCR- d c r +DCR d c r +D.C.'s d c's +DC's d c's +DCs d c's +DCS d c s +DCSD d c s d +DCSO d c s o +DCSPER d c s p e r +DCSS d c s s +DCTA d c t a +DCT d c t +DCU d c u +DCUO d c u o +DCUs d c u's +DDA d d a +DDB d d b +D.D.C. d d c +DDC- d d c +DDC d d c +D&D d and d +D. D. d d +D.D. d d +DDF d d f +DDG- d d g +DDG d d g +DDHH d d h h +DDi d d i +DDI d d i +DDK d d k +DDLJ d d l j +DDM d d m +DDMS d d m s +DDN d d n +DDNOS d d n o s +Ddoc d d o c +DDO d d o +DDP d d p +DDR- d d r +DDR d d r +DDRMAX d d r m a x +DDSB d d s b +D.D.S. d d s +DDS d d s +DDT d d t +DDTV d d t v +Ddu d d u +DDU- d d u +DDWFTTW d d w f t t w +DDX d d x +DEAE- d e a e +D.E.A.F. d e a f +Deah d e a h +DEA's d e a's +DECC d e c c +DEC d e c +DECS d e c s +DEDD d e d d +D. E. d e +D.E. d e +deg d e g +D. E. G. d e g +DEG d e g +DEH d e h +DEHP d e h p +dei d e i +Dei d e i +DeI d e i +DEI d e i +Deijm d e i j m +Deip d e i p +D. E. J. d e j +D.E.R. d e r +dez d e z +Dez d e z +Dfa d f a +DFA d f a +DFB- d f b +DFB d f b +D.F.C. d f c +DFC d f c +DFCs d f c's +D. F. d f +D.F. d f +DFD's d f d's +DfE d f e +D.F.E. d f e +DFE d f e +DfES d f e s +DFF d f f +DFG d f g +DFJ d f j +DFL d f l +DFM d f m +DFOA d f o a +DFO d f o +DFP d f p +DFPs d f p's +DFRC d f r c +DFR d f r +DFs d f's +DFS d f s +DFT d f t +DFW d f w +dfx d f x +DFX d f x +DGAC d g a c +DGA d g a +DGALS d g a l s +DGAP d g a p +DGB d g b +DGCA d g c a +DGC d g c +DGCR d g c r +D&G d and g +D. G. d g +D.G. d g +D. G. E. d g e +DGE d g e +DGERT d g e r t +DGF d g f +DGFI d g f i +DGH d g h +DGK d g k +D. G. L. R. d g l r +DGM d g m +DGMO d g m o +DGP d g p +DGPS d g p s +DGR d g r +Dha d h a +DHA d h a +DHB d h b +DHBs d h b's +DHCP d h c p +D&H d and h +dh d h +D. H. d h +D.H. d h +DH- d h +DH d h +DHEA d h e a +d'HEC d h e c +dhe d h e +DHE d h e +Dheku d h e k u +DHFS d h f s +DHHC d h h c +DHH d h h +DHL d h l +DHMO d h m o +DHNC d h n c +D.H.N. d h n +DHNS d h n s +Dhod d h o d +dhol d h o l +Dhol d h o l +Dhoo d h o o +Dhor d h o r +Dhou d h o u +DHP d h p +DHPH d h p h +DHQ d h q +dhr d h r +D.H.R. d h r +DHRS d h r s +DHS d h s +DHSs d h s's +DHSS d h s s +DHT d h t +DHV d h v +DHW d h w +DHX d h x +D.I. d i +DIFC d i f c +Dif d i f +DIF d i f +Dir d i r +DIR d i r +Dirs d i r's +DISD d i s d +div d i v +Div d i v +DIV d i v +DIW d i w +DIX d i x +diy d i y +DiY d i y +D.I.Y. d i y +DIY d i y +Diyn d i y n +DIYs d i y's +D. J. A. d j a +Djam d j a m +dj d j +D. J. d j +D.J. d j +DJ- d j +DJ d j +DJ'ed d j e d +Djem d j e m +D.J.H. d j h +Dji d j i +DJI d j i +D.J.N. d j n +Djo d j o +D'Jok d j o k +djr d j r +DJR d j r +D.J.s d j's +DJ's d j's +DJs d j's +D. J. S. d j s +D.J.T. d j t +DjVu d j v u +DJVU d j v u +DjVus d j v u's +D. J. Y. d j y +DKC d k c +D. K. d k +D.K. d k +DKI d k i +DKIM d k i m +DKK d k k +DKNY d k n y +DKPP d k p p +D. K. R. d k r +DKW d k w +dla d l a +DLA d l a +DLC d l c +DLD d l d +dl d l +D. L. d l +D.L. d l +DL- d l +DL d l +DLE d l e +DLEG- d l e g +D.L.F. d l f +DLF- d l f +DLF d l f +DLFN d l f n +DLG d l g +D. L. H. d l h +DLHS- d l h s +dlia d l i a +DLI d l i +DLJ d l j +DLJ's d l j's +DLK d l k +DLL d l l +DL&LR d l and l r +DLL's d l l's +DLLs d l l's +DLM d l m +DLMPST d l m p s t +DLNA- d l n a +dlo d l o +DLP- d l p +DLP d l p +DLPFC d l p f c +DLP's d l p's +DLR d l r +DLS d l s +DLSS d l s s +DLSU d l s u +DLSU's d l s u's +DLT- d l t +DLT d l t +DL&W d l and w +DLZ d l z +DMAA d m a a +DMA d m a +DMBA- d m b a +DMB d m b +DMBT d m b t +DMCA d m c a +DMCC d m c c +DMC- d m c +DMC d m c +DMCM d m c m +D.M.C.'s d m c's +D&M d and m +DMD d m d +DMDK d m d k +D. M. d m +D.M. d m +DM- d m +DM d m +DMDS d m d s +DMed d m e d +DM&E d m and e +DME d m e +DMF d m f +DMG d m g +DMGT d m g t +DMHS d m h s +DMI d m i +DMK d m k +DML d m l +DMN d m n +DMO d m o +DMOFD d m o f d +DMOZ d m o z +DMP d m p +DMRC d m r c +DMR d m r +DMRG d m r g +DMs d m's +DMS- d m s +DMS d m s +DMSII d m s i i +DMT- d m t +DMT d m t +DMTF d m t f +DMU d m u +DMUs d m u's +DMV d m v +DMX d m x +DMZ d m z +Dna d n a +DnA d n a +DNA- d n a +DNA d n a +DNADTC d n a d t c +DNAITV d n a i t v +DNAJA d n a j a +DNAJC d n a j c +DnaJ d n a j +DNAN d n a n +DNB d n b +DNBY d n b y +DNC d n c +DNCG d n c g +DND d n d +D. N. d n +D.N. d n +Dnepr d n e p r +dnes d n e s +Dnes d n e's +DNES d n e s +DNF d n f +DNF's d n f's +DNFs d n f's +DNG d n g +DNJO d n j o +DNKA d n k a +DNK d n k +DNM d n m +DNMT d n m t +DNP d n p +DNQ d n q +DNR d n r +DNSBLs d n s b l's +dns d n s +D.N.S. d n s +DNS d n s +DNSS d n s s +DNT d n t +DNU d n u +DNV- d n v +DNVP d n v p +DNX- d n x +D.O.A. d o a +D.O.A.'s d o a's +DOAS d o a s +D.O.B. d o b +D.O.C. d o c +DOCG d o c g +dod d o d +Dod d o d +DoD d o d +DOD d o d +D. O. d o +D.O. d o +DOD's d o d's +D.O.E. d o e +DOGNY d o g n y +DOHC d o h c +D'oh d o h +DOJ d o j +DOJ's d o j's +dok d o k +Dok- d o k +Dok d o k +domt d o m t +Domt d o m t +Dop d o p +DOP d o p +DOPR d o p r +DOSAAF d o s a a f +DOTC d o t c +dotCMS d o t c m s +DOTD d o t d +DOTP d o t p +DotSVN d o t s v n +Douw d o u w +DOW d o w +DOXO d o x o +dozd d o z d +d'OZ d o z +Dozhd d o z h d +DPAA's d p a a's +DPA d p a +DPB d p b +DPD d p d +dp- d p +dp d p +D. P. d p +D.P. d p +DP- d p +DP d p +DPF- d p f +DPG d p g +DPJ- d p j +DPJ d p j +DPMA d p m a +DPM d p m +DPN d p n +DPNM d p n m +DPO d p o +dpon d p o n +DPP d p p +DPP's d p p's +DPPX d p p x +DPR d p r +DPRK- d p r k +DPRK d p r k +DPRK's d p r k's +DProf d p r o f +DPRP d p r p +DPRT d p r t +DPs d p's +DPS d p s +DPSS d p s s +DPSSL d p s s l +DPT d p t +DPW d p w +DPW's d p w's +DPX d p x +DPYS d p y s +D.Q. d q +DQOY d q o y +DQV d q v +DRB d r b +DRBG d r b g +DRB's d r b's +DRCA d r c a +drc d r c +DRC- d r c +DRC d r c +DRDA d r d a +DRDC d r d c +DRD d r d +Dr. doctor +D. R. d r +D.R. d r +DRG d r g +dri d r i +Dri d r i +DRI d r i +DRIs d r i's +DRITTES d r i t t e s +Driu d r i u +Driv d r i v +DRJTBC d r j t b c +DRK d r k +DRL d r l +DRLR d r l r +DRMC d r m c +D.R.M. d r m +DRM- d r m +DRM d r m +Drnis d r n i's +Dro d r o +DRO d r o +DRP d r p +Drs. doctors +DR's d r's +DRS d r s +Drska d r s k a +DRT d r t +druj d r u j +DSA d s a +DsbA d s b a +DS&BB d s and b b +DSB- d s b +DSB d s b +DSBL d s b l +D.S.C. d s c +DSC- d s c +DSC d s c +D.S.C.H. d s c h +DSCM d s c m +DSCR d s c r +DSCS d s c s +DSDB d s d b +DSD d s d +DSDM d s d m +dsDNA d s d n a +DSDP d s d p +ds d s +Ds d's +D. S. d s +D.S. d s +DS- d s +DS d s +DSDS- d s d s +DSDS d s d s +DSG d s g +DSGi d s g i +DSIC d s i c +dsi d s i +DSi d s i +DSI d s i +DSIF d s i f +DSIR d s i r +DSJ d s j +dsl d s l +D. S. L. d s l +DSL- d s l +DSL d s l +DSLR d s l r +DSMB d s m b +D.S.M. d s m +DSM- d s m +DSM d s m +DSMs d s m's +dsn d s n +D&SNGRR d and s n g r r +DSNP d s n p +D.S.O. d s o +DSO d s o +DSPA d s p a +DSP d s p +DSR- d s r +DSR d s r +DS's d s's +DSS d s s +DST d s t +dsu' d s u +DSU d s u +DSV d s v +DSW d s w +DSX d s x +DSZG d s z g +D.T.A. d t a +DTA- d t a +DTA d t a +DTC d t c +DTC's d t c's +DTCs d t c's +DTDC d t d c +DTD d t d +DTDs d t d's +D. T. d t +D.T. d t +DT&E d t and e +DTE d t e +DTEK d t e k +DTES d t e s +DTG d t g +DTH d t h +DTIC d t i c +DT&I d t and i +DTI d t i +DTLA d t l a +dtl d t l +DTL d t l +DTLLS d t l l s +DTLS d t l s +DTM d t m +DTO d t o +DTPA d t p a +DTPC d t p c +DTRA d t r a +DTR d t r +DTRS d t r s +DTs d t's +DTS- d t s +DTS d t s +DTT d t t +D.T.U. d t u +DTU d t u +DTV d t v +dty d t y +D.U. d u +dva d v a +Dva d v a +DVA d v a +DVB- d v b +DVB d v b +DVBE d v b e +DVBIC d v b i c +DVC d v c +DVCs d v c's +DVCS d v c s +dvd d v d +DVD- d v d +DVD, d v d +DVD d v d +DVD's d v d's +DVDs d v d's +dv d v +D. V. d v +D.V. d v +DV- d v +DV d v +dve d v e +dvfb d v f b +DVFS d v f s +DVGS d v g s +DVHS d v h s +dvi d v i +DVI d v i +dvije d v i j e +Dvin d v i n +Dvir d v i r +DVLA d v l a +DVLA's d v l a's +DVL- d v l +DVL d v l +DVM d v m +DVP d v p +DVR d v r +DVRJRBC d v r j r b c +DVR's d v r's +DVSC d v s c +DVS d v s +DVT d v t +DVV d v v +DVVT d v v t +DVWK d v w k +Dwa d w a +DWA d w a +D&W d and w +DWDM- d w d m +D. W. d w +D.W. d w +Dwedw d w e d w +DWET d w e t +DWF d w f +DWGD- d w g d +DWG d w g +D.W.H. d w h +Dwi d w i +DWI d w i +DWM d w m +DWN d w n +DWNU d w n u +DWP d w p +dwr d w r +DWR d w r +DWRFC d w r f c +DWS d w s +DWT d w t +DWTS d w t s +dwur d w u r +DWWX- d w w x +dxa d x a +DXA d x a +dx d x +D.X. d x +DX- d x +DX d x +DXED- d x e d +DXED d x e d +DXers d x e r's +DXII d x i i +DXK d x k +DXP- d x p +DXR d x r +DXZ d x z +Dydd d y d d +dy d y +Dy d y +D. Y. d y +DY d y +DYFI d y f i +DYIS d y i s +DYNC d y n c +dypl d y p l +dyr d y r +DYSP d y s p +DZBB d z b b +DZB d z b +dz d z +DZEC d z e c +DZEM d z e m +dzis d z i s +DZNE d z n e +Dzog d z o g +Dzor d z o r +DZRH d z r h +DZRH's d z r h's +DZS d z s +Dzus d z u's +DZXL d z x l +DZZ d z z +EAAB e a a b +EAA e a a +EAAP e a a p +E. A. C. e a c +EAC e a c +EACEF e a c e f +EACS e a c s +EAD e a d +E. A. e a +E.A. e a +EAF e a f +EAGE e a g e +E.A.H. e a h +EAH e a h +EAI e a i +EAIE e a i e +E. A. J. e a j +EAMs e a m's +EAP- e a p +EAP e a p +E.A.R.L. e a r l +E.A.R.T.H. e a r t h +EASA e a s a +EASB e a s b +eas e a s +Eas e a's +EA's e a's +EAS e a s +Eav e a v +EAX e a x +E. B. e b +E.B. e b +EBL e b l +Ebn e b n +EBNF e b n f +EBOV e b o v +E&BR e and b r +EBR- e b r +EBR e b r +Ebru e b r u +EBS e b s +EBSL e b s l +EBT e b t +EBU e b u +EBV e b v +E.B.W. e b w +EBWs e b w's +EBZR e b z r +ECAC- e c a c +ECAC e c a c +ECA e c a +ECAR e c a r +ECB, e c b +ECB e c b +ECBJ e c b j +ECBL e c b l +ECCA e c c a +ECCC e c c c +ecc e c c +ECC e c c +ECCI e c c i +Eccl e c c l +ECCRFA e c c r f a +ECCW e c c w +ECD e c d +ec e c +Ec e c +E. C. e c +E.C. e c +EC- e c +EC e c +ece e c e +Ece e c e +ECE e c e +Ecem e c e m +ECFA e c f a +ECF e c f +ECFR e c f r +ECFU e c f u +ecg e c g +ECG e c g +ECH e c h +ECHL e c h l +ECHR e c h r +ECI e c i +ECJ e c j +ECLAC e c l a c +ECLA e c l a +ECLC e c l c +ECL e c l +ECLI e c l i +ECLSS e c l s s +ecma e c m a +ECMA e c m a +ECMC e c m c +ECMDB e c m d b +E.C.M. e c m +ECM e c m +ECMI e c m i +ECML e c m l +ECMLRUS e c m l r u s +ECMWF e c m w f +ECN e c n +ECNP e c n p +ECNs e c n's +ECNS e c n s +ECNZ e c n z +ECP&DA's e c p and d a's +ECP e c p +ECPR e c p r +ECQ e c q +ECR e c r +eCRM e c r m +ECRR e c r r +ECR's e c r's +ECSA e c s a +EC's e c's +E. C. S. e c s +E.C.S. e c s +ECS e c s +ect e c t +E. C. T. e c t +ECT e c t +ECTLO e c t l o +ECTN e c t n +Ecto- e c t o +ECTS e c t s +ECV e c v +ECVs e c v's +ECWA e c w a +ECW e c w +edb e d b +EDB e d b +EDC e d c +E. D. e d +E.D. e d +EDF e d f +Edh e d h +EDH e d h +edhe e d h e +EDHF e d h f +EDIB e d i b +EDI e d i +EDK e d k +EDL e d l +EDMA e d m a +EDM- e d m +EDM e d m +EDMs e d m's +EDMW e d m w +Edmx e d m x +edn e d n +Edn e d n +EDN e d n +EDP e d p +EDQH e d q h +E.D.R. e d r +EDRP e d r p +EDSA e d s a +EDSC e d s c +eds e d s +Eds e d's +E. D. S. e d s +EDS- e d s +EDS e d s +EDSP e d s p +EDTA e d t a +EDT e d t +EDVAC e d v a c +EDWDO e d w d o +Edw e d w +EDXRD e d x r d +EEA e e a +EEAF e e a f +EEAS e e a s +EEBC e e b c +Eeb e e b +EEC e e c +EECS e e c s +E. E. e e +E.E. e e +Eef e e f +EEF e e f +Eega e e g a +EEI e e i +EEI's e e i's +EEJF e e j f +EELC e e l c +eene e e n e +EEOC e e o c +EEPCO e e p c o +eep e e p +EEP e e p +EERC e e r c +EERI e e r i +Ees e e's +EES e e s +EEST e e s t +EEUU e e u u +eeuw e e u w +Eeuw e e u w +EEZs e e z's +EFA e f a +EFAS e f a s +EFCC e f c c +efc e f c +EFC e f c +EFCJ e f c j +EFD e f d +ef e f +Ef e f +E. F. e f +E.F. e f +EF- e f +EF e f +E. F. J. e f j +E. F. K. e f k +EFL e f l +EFM e f m +EFNB e f n b +EFPA e f p a +EFP e f p +EFQUEL e f q u e l +EFR e f r +EFRU e f r u +EFSA e f s a +eFS e f s +Efs e f's +EFSET e f s e t +EFTPOS e f t p o s +EFUA e f u a +Efu e f u +EFV e f v +EFVR e f v r +EFVS e f v s +E. F. W. e f w +EFX e f x +EFY e f y +E. G. A. e g a +EGA e g a +Egba e g b a +EGBA e g b a +EGBT e g b t +EGC e g c +EGD e g d +EGF- e g f +EGF e g f +egfl e g f l +EGFL e g f l +e.g. for example +e. g. for example +EGFR e g f r +EG&G e g and g +E. G. H. e g h +Egi e g i +EGL e g l +EGM e g m +E&GR e and g r +EGR e g r +EGREM e g r e m +EGSC e g s c +EGX e g x +egy e g y +EGY e g y +Egyl e g y l +EHAAT e h a a t +EHAs e h a's +EHC e h c +EHCI e h c i +EHD e h d +E. H. e h +E.H. e h +ehf e h f +EHF e h f +E. H. M. e h m +EHP e h p +EHRC e h r c +EHR e h r +EHS e h s +EHSH e h s h +Ehttp e h t t p +EHV- e h v +EIA- e i a +EIA e i a +EIC e i c +EiCs e i c's +EIC's e i c's +E. I. e i +E.I. e i +EIES e i e s +eIF e i f +EIF e i f +EIFF e i f f +EIF's e i f's +EIT e i t +EITI e i t i +Eitr e i t r +EITs e i t's +EIU e i u +E. J. A. e j a +EJB e j b +EJBs e j b's +EJC e j c +ej e j +E. J. e j +E.J. e j +EJ e j +E. J. H. e j h +E.J.H. e j h +EJH e j h +EJHL e j h l +EJMA e j m a +E. J. M. e j m +EJML e j m l +E. J. R. e j r +E.J.S. e j s +EJSM e j s m +EJV e j v +EKB e k b +EKBO e k b o +EKCO's e k c o's +EKD e k d +E. K. e k +E.K. e k +EKF e k f +EKG e k g +eki e k i +EKIZ e k i z +EKL e k l +EKLR e k l r +Ekma e k m a +EKNU e k n u +Ekow e k o w +eks e k s +Eks e k's +EKS- e k s +EKS e k s +E. K. U. e k u +EKU e k u +E. L. C. e l c +E. L. e l +E.L. e l +ELH e l h +ELTs e l t's +ELUs e l u's +ELV e l v +EMA e m a +EMAS e m a s +Embd e m b d +EMB- e m b +EMB e m b +eMC e m c +EMC e m c +EMD e m d +EMD's e m d's +EMDs e m d's +EMDS e m d s +Emea e m e a +EMEA e m e a +E&M e and m +E. M. e m +E.M. e m +EMF e m f +Emge e m g e +EMG- e m g +EMG e m g +EML- e m l +EMLL e m l l +E.M.M. e m m +EMNLP e m n l p +EMP- e m p +EMP e m p +emra e m r a +EMR e m r +EMSC e m s c +E.M.S. e m s +EMTE e m t e +EMT e m t +EMV e m v +E&NA e and n a +Enas e n a's +ENAS e n a s +EnBW e n b w +ENC e n c +EncFS e n c f s +Encyc e n c y c +E.N.D. e n d +ENEC e n e c +E. N. e n +E.N. e n +Enes e n e's +engl e n g l +Engl e n g l +ENGM e n g m +Engr e n g r +Eni e n i +ENI e n i +enn e n n +Enn e n n +ENP e n p +ENR e n r +ens e n s +Ens e n's +ENS e n s +Enso e n s o +ENSO e n s o +ENTJs e n t j's +ENTP e n t p +ENTV e n t v +Env e n v +ENV e n v +EOC e o c +EOC's e o c's +EoD e o d +EOD e o d +E. O. e o +E.O. e o +EOFFTV e o f f t v +EOG e o g +Eois e o i's +EOKA e o k a +eok e o k +Eole e o l e +Eol e o l +EOL e o l +Eolss e o l s's +Eom e o m +EOOW e o o w +eop e o p +eoptta e o p t t a +Eora e o r a +EOR e o r +Eorl e o r l +Eors e o r's +EOS- e o s +EOSHD e o s h d +EOTC e o t c +EOTDC e o t d c +EOT- e o t +EOU e o u +E.O.W. e o w +E&P e and p +Epe e p e +E. P. E. e p e +EPEG e p e g +ep e p +Ep e p +E. P. e p +E.P. e p +EP- e p +EP, e p +EP e p +EPF e p f +EPFL e p f l +EPG e p g +EPHAR e p h a r +EPHB e p h b +Eph e p h +EPH e p h +Ephs e p h's +EPIA e p i a +epi e p i +Epi e p i +EPI e p i +E.P.J. e p j +EPL e p l +EPLF e p l f +EPM- e p m +EPM e p m +EPOC e p o c +ePO e p o +EPO e p o +epos' e p o's +epos e p o s +Epos e p o's +EPRDF e p r d f +EPR e p r +EPRI e p r i +EPRO e p r o +EPSC e p s c +E.P.s e p's +EPT e p t +EPV e p v +EPZA e p z a +EPZ e p z +EQAO e q a o +eq e q +Eq e q +EQ- e q +EQ e q +EQG e q g +EQN e q n +EQP e q p +EQS e q s +EQT e q t +E.R.A. e r a +ERAF e r a f +ERAU e r a u +ERCB e r c b +ERC e r c +ERCES e r c e s +ERCIM e r c i m +ERCS e r c s +E. R. D. e r d +E. R. e r +E.R. e r +ERF e r f +ERH e r h +ERJs e r j's +ERK e r k +ERP e r p +ERPM e r p m +ERPMRP e r p m r p +ERRC e r r c +E. R. R. e r r +E.R.R. e r r +ERSAR e r s a r +ERT e r t +Eru e r u +ERU e r u +ERUUF e r u u f +Eruv e r u v +Erv e r v +ERW e r w +ES3 e s three +Esa e s a +E.S.A. e s a +ESA- e s a +ESA e s a +Esam e s a m +Esa's e s a's +ESA's e s a's +Esat e s a t +ESB e s b +ESC e s c +ESCHL e s c h l +ESCs e s c's +Esd e s d +ESD e s d +ESDI e s d i +E.S.E. e s e +E. S. e s +E.S. e s +ESF e s f +ESFG e s f g +E.S.G. e s g +ESG e s g +ESGR e s g r +esi e s i +ESI e s i +ESL e s l +ESM e s m +ESMLC e s m l c +ESMT e s m t +ESNAGI e s n a g i +ESN e s n +ESPA e s p a +ESPC e s p c +ESPD e s p d +ESP e s p +espn e s p n +ESPN, e s p n +ESPN e s p n +ESPNhttp e s p n h t t p +ESPN's e s p n's +ESPNU e s p n u +ESPNW's e s p n w's +esq e s q +Esq e s q +Esq. esquire +Esraa e s r a a +Esra e s r a +ESRB e s r b +ESRC e s r c +Esref e s r e f +ESR- e s r +ESR e s r +ESRF e s r f +Esri e s r i +ESRI- e s r i +ESRI e s r i +ESSR e s s r +estd e s t d +Estd e s t d +EST e s t +ESTP e s t p +esu e s u +ESU e s u +ESU's e s u's +Esva e s v a +ESV e s v +ESWAT e s w a t +ESW e s w +Etad e t a d +ETA e t a +ETAF e t a f +ETA's e t a's +ETASU e t a s u +ETB e t b +ETBs e t b's +E.T.C. e t c +ETCO's e t c o's +ETCS e t c s +ETCSL e t c s l +ETD e t d +E. T. e t +E.T. e t +ETF e t f +ETFs e t f's +ETFS e t f s +Et'hem e t h e m +ETH e t h +Eti e t i +ETI e t i +ETIM e t i m +ETIM's e t i m's +etj e t j +ETJ e t j +ETL e t l +ETNZ e t n z +Eto e t o +ETO e t o +ETRM e t r m +ETRS e t r s +ETSEIB e t s e i b +ets e t s +Ets e t's +ET's e t's +ETs e t's +ETS- e t s +ETS e t s +Etsi e t s i +ETSI e t s i +ett e t t +Ett e t t +ETT e t t +Ettre e t t r e +Etts e t t's +ETU e t u +ETV e t v +Etz e t z +EUA e u a +EUB e u b +EUBs e u b's +EUBS e u b s +EUCAP e u c a p +EUCE e u c e +EUC- e u c +EUC e u c +EUCOM's e u c o m's +EUDEC e u d e c +EUD e u d +E. U. e u +E.U. e u +EU- e u +EU e u +eup e u p +EUP e u p +Eurwg e u r w g +EUSA e u s a +Euse e u s e +EU's e u's +EUS e u s +EUSEW e u s e w +Eusi e u s i +EUV e u v +EUX e u x +EVAAP e v a a p +EvaGT e v a g t +EVDC e v d c +EVD e v d +EVDO e v d o +E. V. e v +E.V. e v +EVEX e v e x +EVIT e v i t +evl e v l +EVL e v l +EVM e v m +Evna e v n a +EVN e v n +EVNS e v n s +evnt e v n t +E.V.O. e v o +E.V.O.L. e v o l +EVP e v p +EVR e v r +EVs e v's +EVS- e v s +EVS e v s +evv e v v +EVV e v v +Ewa's e w a's +EWD e w d +EWEB e w e b +E. W. e w +E.W. e w +EWF- e w f +EWF e w f +EWF's e w f's +Ewha e w h a +EWH e w h +E.W.K. e w k +EWLA e w l a +EWL e w l +EWO e w o +EWOs e w o's +EWP e w p +EW's e w's +EWS- e w s +EWS e w s +EWTN e w t n +Ewu e w u +EWU e w u +excl e x c l +exd e x d +E.X. e x +exhb e x h b +exh e x h +EXI e x i +EXIF e x i f +EXIN e x i n +EXL e x l +EXLM e x l m +E. X. M. e x m +Exptl e x p t l +EXR e x r +exsul e x s u l +EXT e x t +EYA e y a +EYCN e y c n +EYD e y d +E&Y e and y +E. Y. e y +EY e y +Eyk e y k +eyu e y u +Ezaa e z a a +ez e z +Ez e z +EZ- e z +EZ e z +Ezh e z h +EZH e z h +EZO e z o +EZR e z r +EZTV e z t v +Ezu e z u +EZW e z w +Ezy e z y +Faaa f a a a +faa f a a +Faa f a a +FAA- f a a +FAA f a a +faama f a a m a +FAANP f a a n p +FabH f a b h +FABM f a b m +FabR f a b r +F.A.B.'s f a b's +F.A.C.E. f a c e +FACR f a c r +F.A.C.S. f a c s +FADD f a d d +Fadl f a d l +FADS f a d s +FAEM f a e m +fa f a +Fa f a +F. A. f a +F.A. f a +FA- f a +FA f a +Faf f a f +FAFG f a f g +Fafhrd f a f h r d +FAFL f a f l +F. A. G. f a g +F.A.H. f a h +fai f a i +Fai f a i +FAI- f a i +FAI f a i +FAIM f a i m +FAIP f a i p +FAIPs f a i p's +Faiq f a i q +fajn f a j n +FAK f a k +Fal f a l +FAL f a l +F.A.M.E. f a m e +F.A.M. f a m +FAQ f a q +FARC's f a r c's +FARDC f a r d c +F.A.R. f a r +farw f a r w +FASA f a s a +FASB f a s b +fasc f a s c +Fasc f a s c +fas f a s +Fas f a's +FAs f a's +F.A.S. f a s +FAS f a s +FASG f a s g +FasL f a s l +FASRE f a s r e +FATF f a t f +FAUP f a u p +FAVC f a v c +FBA f b a +FBD f b d +FBFA f b f a +F. B. f b +F.B. f b +FB- f b +FB f b +F.B.G.s f b g's +F.B.I. f b i +FBI- f b i +FBI f b i +FBI's f b i's +FBK f b k +FBLA- f b l a +FBL f b l +FBMW f b m w +FBN f b n +FBO f b o +FBOs f b o's +FBPA f b p a +FBR f b r +FBS f b s +FBSN f b s n +FBSU f b s u +FBT f b t +FCA f c a +fcb f c b +FCB f c b +FCBF f c b f +F.C.B.I. f c b i +FCBL f c b l +FCBs f c b's +F.C.C. f c c +FCC f c c +FCD f c d +F&C f and c +fc f c +F. C. f c +F.C. f c +FCF f c f +FCGR f c g r +F. C. H. f c h +F.C.H.L. f c h l +FCIAC f c i a c +FCIC f c i c +FCI f c i +FCIP f c i p +FCK f c k +FCL f c l +FCN- f c n +FCNM f c n m +FCNZ f c n z +FCO f c o +FCP f c p +F.C.P.R.E.M.I.X. f c p r e m i x +FCPS f c p s +FCRLA f c r l a +F.C.'s f c's +FC's f c's +FCS f c s +FCT f c t +FCU f c u +FCUL f c u l +FCV- f c v +FCV f c v +F. C. W. f c w +FCW f c w +FCW's f c w's +FDA f d a +FDCC f d c c +FD&C f d and c +FDCPA f d c p a +FDCPAs f d c p a's +FDD f d d +FDDI f d d i +FDE f d e +F. D. f d +F.D. f d +FDFL f d f l +FDGB- f d g b +FDGB f d g b +FDG f d g +FDICs f d i c's +FdI f d i +FDI f d i +FDIO f d i o +FDJ f d j +FDL f d l +FDLT f d l t +FDM f d m +FDMNES f d m n e s +FDNY f d n y +FDP f d p +FDP's f d p's +FDQ, f d q +FDR f d r +FDU f d u +F. E. f e +F.E. f e +FEFK f e f k +FEFSI f e f s i +FEFY f e f y +FEG f e g +FEGs f e g's +FEP f e p +F.E.R.S. f e r s +Fes f e's +FES f e s +FFA f f a +FFAK f f a k +ffc f f c +FFC f f c +FFC's f f c's +FFDO f f d o +ff f f +F. F. f f +F.F. f f +FF- f f +FF f f +FFF f f f +FFG f f g +FFH f f h +FFI f f i +FFK- f f k +FFK f f k +FFL f f l +FFL's f f l's +FFME f f m e +ffm f f m +FFOM f f o m +FFP f f p +FFPIR f f p i r +FFR f f r +FFSA f f s a +FF's f f's +FFs f f's +FFS f f s +FFU f f u +FFV f f v +FFWD f f w d +FGCU f g c u +FGFA f g f a +FGF f g f +F. G. f g +F.G. f g +FGFR f g f r +FGID f g i d +fgk f g k +FGL f g l +FGM f g m +FGR f g r +FGs f g's +FGS f g s +FGU f g u +FGV f g v +F. H. A. f h a +FHA- f h a +FHA f h a +FHAR f h a r +F. H. C. f h c +FHFA f h f a +F. H. f h +F.H. f h +FHI's f h i's +FHL f h l +fhm f h m +FHM f h m +FHM's f h m's +FHQ f h q +FHSAA f h s a a +FHS f h s +FHWA f h w a +F. H. W. f h w +FIAC f i a c +fiadh f i a d h +fia f i a +FIA f i a +FIAPO f i a p o +FIA's f i a's +FIAS f i a s +FIBCO f i b c o +F. I. B. f i b +FiBL f i b l +FIBT f i b t +FIC f i c +Fi'd f i d +FIDH f i d h +F.I f +F&I f and i +F. I. f i +F.I. f i +FIFTA f i f t a +FIGC f i g c +Figl f i g l +FIH f i h +FIH's f i h's +fija f i j a +FIJL f i j l +FIK f i k +F.I.M. f i m +FIM f i m +FIMI- f i m i +FIMI f i m i +Fio f i o +FiO f i o +FIO f i o +F.I.R. f i r +F.I.T.T. f i t t +FIU f i u +FIVB f i v b +F. J. A. f j a +FJE f j e +F. J. f j +F.J. f j +F.J.G. f j g +FJK f j k +F. J. M. f j m +FKA f k a +FKBP f k b p +F. K. f k +F.K. f k +FKK f k k +FKL's f k l's +FKS f k s +FKY f k y +Fla f l a +FLB f l b +FLCL f l c l +FLCS f l c s +FLD f l d +FLDS f l d s +FLEC f l e c +FLE f l e +Fles f l e's +FLEST f l e s t +FLETC f l e t c +fl f l +F. L. f l +F.L. f l +FL- f l +FL f l +FLH f l h +fli f l i +FLI f l i +FLI's f l i's +FLL f l l +F.L.M. f l m +FLM f l m +FLNB f l n b +FLN f l n +FLP f l p +FLPP f l p p +FLQ f l q +FLRA f l r a +FLR f l r +FLRL f l r l +FLS f l s +FLSW f l s w +FLT f l t +FLTK f l t k +FLTR f l t r +FLTS f l t s +FLV f l v +FLW f l w +flyr f l y r +FMA f m a +FMARS f m a r s +FMC f m c +FMCG f m c g +FMCSA f m c s a +FMCS f m c s +FMF f m f +fm f m +F. M. f m +F.M. f m +FM- f m +FM f m +FMH f m h +FMHS f m h s +FMI f m i +FMJD f m j d +FMLN f m l n +FMM f m m +FMN f m n +FMNJ f m n j +FMNP f m n p +FMPA's f m p a's +FMP f m p +FMQB f m q b +FMR f m r +fMRI f m r i +FMRP f m r p +FMRU f m r u +FM's f m's +FMs f m's +FMS- f m s +FMS f m s +FMSF's f m s f's +FMSO f m s o +FMV f m v +FMW f m w +FMX f m x +FMY f m y +FNAC f n a c +F. N. A. f n a +FNA f n a +FNB f n b +FNC f n c +F. N. D. f n d +FNE f n e +F. N. f n +F.N. f n +FNIC f n i c +FNI f n i +FNLA f n l a +FNLC f n l c +FNLC's f n l c's +FNL f n l +FNO f n o +FNP f n p +FNPI f n p i +FNSEA f n s e a +FNU f n u d s a +FOF f o f +F. O. f o +FPA- f p a +FPA f p a +FPB f p b +FPC f p c +FPCP f p c p +F.P.D. f p d +FPD- f p d +FPDs f p d's +fp f p +F. P. f p +F.P. f p +FP- f p +FP f p +FPGA f p g a +FPGAs f p g a's +FPI f p i +FPJ f p j +FPK f p k +F. P. L. f p l +FPL f p l +FPMR f p m r +FPM&SA f p m and s a +FPO f p o +FPP f p p +FPPS f p p s +F.P.R. f p r +FPR f p r +FPSC f p s c +fps f p s +FPS- f p s +FPS f p s +FPSO f p s o +FPSs f p s's +FPTP- f p t p +FPTP f p t p +FPU f p u +FQAD f q a d +F.Q. f q +FRA f r a +FRA's f r a's +FRAXA f r a x a +FRB f r b +FRBNF f r b n f +FRCC f r c c +F. R. C. f r c +FRC f r c +FRCNA f r c n a +FRCP f r c p +FRCS f r c s +FRDF f r d f +F.R.D. f r d +fr f r +F. R. f r +F.R. f r +FR- f r +FR f r +FRFS f r f s +FRFT f r f t +FRG f r g +F.R.G.S. f r g s +F.R.H.S. f r h s +F.R.I.B.A. f r i b a +FRMN f r m n +FRMR f r m r +FRMS f r m s +F. R. P. f r p +FRP f r p +FRR f r r +F.R.S.A. f r s a +FRSA f r s a +FRSC f r s c +FRSE f r s e +frs f r s +F. R. S. f r s +F.R.S. f r s +FRS f r s +FRSL f r s l +Fru f r u +FRU f r u +FRV f r v +FRWT f r w t +Frwydr f r w y d r +FSA f s a +FSB f s b +FSC- f s c +FSC f s c +FSCS f s c s +FSE f s e +fsf f s f +FSF f s f +FSFH f s f h +FSFLA f s f l a +fs f s +F. s f's +Fs f's +F. S. f s +F.S. f s +FS f s +FSFS f s f s +FSG f s g +FSGS f s g s +FSH f s h +FSIC f s i c +FSI f s i +FSIL f s i l +FSK f s k +FSKN f s k n +FSLF f s l f +FSL f s l +FSLN f s l n +FSM f s m +FSM's f s m's +fsn f s n +FSN f s n +FSO f s o +FSP f s p +FSPS f s p s +FSR f s r +FSRU f s r u +FSSB f s s b +FSS f s s +FSSM f s s m +FSSRU f s s r u +FSSs f s s's +FST f s t +FSU f s u +FSU's f s u's +FSV f s v +FTA f t a +FTAs f t a's +F.T.B. f t b +FTC f t c +FTD f t d +FTDI f t d i +FTE f t e +FTF f t f +Ft. Fort +F. T. f t +F.T. f t +FTI f t i +FTII f t i i +FTJ f t j +FTK f t k +FTL f t l +FTM f t m +FTN f t n +FTO f t o +ftp f t p +FTP f t p +FTPI f t p i +FTPL f t p l +FTRA f t r a +FTR f t r +FtsA f t s a +FT's f t's +FTS f t s +FTT f t t +FTTH f t t h +FTUC f t u c +Ftuh f t u h +FTU's f t u's +FTV f t v +FVA- f v a +F. V. B. f v b +F. V. f v +F.V. f v +FVGM f v g m +FVHS f v h s +FVJC f v j c +FVL f v l +FVP f v p +FVW f v w +FVWM f v w m +FWAA f w a a +FWA f w a +FWCD f w c d +FWD f w d +FWE f w e +F&W f and w +F. W. f w +F.W. f w +FWH f w h +FWI f w i +FWMW f w m w +FWO f w o +fwr f w r +F.W.R. f w r +F. W. S. f w s +F.W.S. f w s +FWS f w s +FWX f w x +FXCM's f x c m's +FXE f x e +FXFL f x f l +fx f x +FX f x +FXI f x i +F.X.R. f x r +FX's f x's +FXS f x s +FXX f x x +FXX's f x x's +FXXT f x x t +Fyb f y b +FYCO f y c o +F.Y. f y +F.Y.I. f y i +FYI f y i +Fyn f y n +FYN f y n +FYP f y p +fyr f y r +F.Y.R. f y r +FYR f y r +FYT f y t +FYU f y u +Fyw f y w +FZCI f z c i +FZD f z d +F.Z. f z +FZG f z g +FZJD f z j d +FZKA f z k a +Gaac g a a c +GAAF g a a f +G.A.A. g a a +G. A. g a +G.A. g a +G.A.R. g a r +GASL g a s l +GATA g a t a +GATV g a t v +GATX g a t x +G. A. W. g a w +GBA g b a +GBAG g b a g +GBASE g b a s e +GBA's g b a's +GBB g b b +GBBI g b b i +GBCA g b c a +GBC g b c +GBCM g b c m +GBD g b d +Gbe g b e +GbE g b e +GBE g b e +G. B. g b +G.B. g b +GBGC g b g c +GBGM g b g m +GBH g b h +GBIB g b i b +GBIF g b i f +GBI g b i +GBK g b k +GBLA- g b l a +GBL g b l +GBMA g b m a +G. B. M. g b m +GB&NDR g b and n d r +GBP g b p +GBR g b r +GB's g b's +GBS g b s +GBV- g b v +GBV g b v +GBX g b x +GBYLA g b y l a +GCAC g c a c +GCAF g c a f +GCA g c a +G. C. B. g c b +GCB g c b +GCC g c c +GCCN g c c n +GCC's g c c's +GCCS g c c s +GCD g c d +G.C.E. g c e +GCEP g c e p +GCF g c f +G&C g and c +G. C. g c +G.C. g c +GCHQ g c h q +GCI g c i +GCIP g c i p +GCIT's g c i t's +GCIV g c i v +GCJ g c j +GCL g c l +GCMC g c m c +G.C.M. g c m +GCM g c m +GCMG g c m g +GCN g c n +GCNT g c n t +GCOEC g c o e c +GCOS g c o s +GCPD g c p d +GCPH g c p h +GCR- g c r +GCR g c r +GCRIO g c r i o +GCSE g c s e +GCSEs g c s e's +GC&SF g c and s f +GCS g c s +GCSI g c s i +GCT- g c t +GCU g c u +GCV g c v +GCVO g c v o +GCVS g c v s +GDA g d a +Gdal g d a l +GDAL g d a l +GDAP g d a p +GDB g d b +GDC g d c +GDD g d d +GDDM g d d m +GDDR g d d r +Gde g d e +G. D. F. g d f +GDF g d f +gd g d +G. D. g d +G.D. g d +GD g d +GDI g d i +G.D.L. g d l +GDNFR- g d n f r +GDN g d n +G.D.O.D. g d o d +Gdow g d o w +G.D.P. g d p +GDP- g d p +GDP g d p +GDPs g d p's +gdr g d r +GDR g d r +GDR's g d r's +GDS g d s +GDST g d s t +GDT g d t +GDV g d v +Gebr g e b r +Gebt g e b t +GEC g e c +Ged g e d +GED g e d +GEF g e f +GEGB g e g b +ge g e +G. E. g e +G.E. g e +GE- g e +GE g e +GEHA g e h a +GEHX g e h x +Gek g e k +G.E.M. g e m +Gen. general +G.E.O. g e o +G. E. P. g e p +geq g e q +Geu g e u +GEU g e u +Gev g e v +GeV g e v +GEV g e v +Gfa g f a +GFA g f a +GF&A g f and a +GFC g f c +GFD g f d +GFDL g f d l +GFE g f e +GFF g f f +G. F. g f +G.F. g f +GFM g f m +GFP- g f p +GFP g f p +G. F. R. g f r +GFR g f r +GFS g f s +GFSN g f s n +GFSR g f s r +GFT g f t +GFWC g f w c +GFW g f w +GFY g f y +G. G. g g +G.G. g g +G. G. J. g g j +GGL g g l +GGM g g m +GGMRC g g m r c +GGS g g s +G.H.A. g h a +GHB g h b +GHC g h c +GHD g h d +Ghe g h e +G. H. g h +G.H. g h +GHGs g h g's +Ghir g h i r +GHK g h k +GHMC g h m c +G.H.N. g h n +G.H.Q. g h q +GHQ g h q +ghra g h r a +GHR g h r +GH&SA g h and s a +GHSA g h s a +GHSFHA g h s f h a +GHS g h s +GHSR g h s r +GHSU g h s u +GHU g h u +G.H.W. g h w +GICL g i c l +Giei g i e i +GIFV g i f v +G. I. g i +G.I. g i +G.J.B. g j b +G. J. g j +G.J. g j +G. K. g k +G.K. g k +Gla g l a +GLA g l a +GLB g l b +GLBT g l b t +GLBTQ g l b t q +GLC- g l c +GLC g l c +G&L g and l +G. L. g l +G.L. g l +gli g l i +Gli g l i +GLI g l i +Glis g l i's +GLK g l k +GLL g l l +GLLI g l l i +GLM g l m +glnA g l n a +G.L.O.R.Y. g l o r y +Glos g l o's +GLP- g l p +GLRS g l r s +GLS g l s +GLT g l t +GLVC g l v c +GLX- g l x +GLX g l x +GLYX- g l y x +GMAC g m a c +gma g m a +GMA- g m a +GMA g m a +GMAM g m a m +GMA's g m a's +GMAT g m a t +GMB g m b +GmbH g m b h +GMBH g m b h +GMB's g m b's +GMCC g m c c +GMC g m c +GMCL g m c l +GMC's g m c's +GMDSS g m d s s +GME g m e +Gmel g m e l +GMES g m e s +GMFF g m f f +GMF g m f +GMG g m g +gm g m +G. M. g m +G.M. g m +GM- g m +GM g m +GMG's g m g's +gmin g m i n +GMM g m m +GMO g m o +GMOs g m o's +GMPC g m p c +GMPE g m p e +GMP g m p +GMPTE g m p t e +GMR g m r +GMRL g m r l +GM's g m's +GMs g m's +GMS g m s +gmt g m t +GMT g m t +GMTV g m t v +Gmul g m u l +GNAA g n a a +GNA g n a +gnb g n b +GNB g n b +GNCC g n c c +G. N. C. g n c +GNC g n c +G. N. g n +G.N. g n +GNL g n l +GNP&BR g n p and b r +GNPDA g n p d a +gnp g n p +GNP g n p +GNPs g n p's +GNRD g n r d +GNR g n r +GNR's g n r's +GNS g n s +GNSS g n s s +GNT g n t +G.O. g o +G.O.O.D. g o o d +GOPB g o p b +G.O.P. g o p +GOP- g o p +GOP g o p +GOPIO g o p i o +GOP's g o p's +GOQ g o q +GPA- g p a +GPA g p a +GPB g p b +G.P.C. g p c +GPC g p c +GPCR g p c r +GPCRs g p c r's +GPD g p d +GPdI g p d i +GPDSC g p d s c +GPF g p f +GPFS g p f s +G&P g and p +GPG g p g +gp g p +G. P. g p +G.P. g p +GP- g p +GP g p +GPGPU g p g p u +GPI g p i +GpIIb g p i i b +GPIO g p i o +GPL g p l +GPMGs g p m g's +G.P.O. g p o +GPO g p o +GPOPS- g p o p s +GPP g p p +GPRA g p r a +GPRF g p r f +GPR g p r +GPRs g p r's +GPRS g p r s +GPSC g p s c +GPS- g p s +GPS g p s +GPT g p t +GPU g p u +GPUs g p u's +GPX g p x +G. Q. g q +GQ g q +GQNYGK g q n y g k +GQ's g q's +GQT's g q t's +G.R.A.B. g r a b +grac g r a c +gra g r a +Gra g r a +GRA g r a +Grbac g r b a c +GRB g r b +GRBs g r b's +grc g r c +GRC g r c +GRCs g r c's +GRDA g r d a +GRDC g r d c +GRDF- g r d f +G.R.D. g r d +GRD g r d +gre g r e +Gre g r e +GRE g r e +GRF g r f +GRG g r g +gr g r +G. R. g r +G.R. g r +GR- g r +GR g r +GRK g r k +G.R.L. g r l +GRL g r l +GRMG g r m g +GRM- g r m +GRM g r m +GRO g r o +GRP g r p +grrl g r r l +G. R. S. g r s +GRS g r s +GRT g r t +GRU g r u +GRX g r x +Gryf g r y f +gry g r y +Gry g r y +GRY g r y +grz g r z +GSA g s a +GSAPP g s a p p +GSAS g s a s +GSB g s b +GSC g s c +GSDF g s d f +GSD g s d +G.S.E. g s e +GSE g s e +GSFC g s f c +GSF g s f +G&S g and s +GSG- g s g +GSG g s g +Gs g's +G. S. g s +G.S. g s +GS- g s +GS g s +GSHD g s h d +GSh- g s h +GSH g s h +GSI g s i +GSIs g s i's +GSIS g s i s +GSK- g s k +GSK g s k +GSL g s l +GSLV g s l v +GSMA g s m a +GSM- g s m +GSM g s m +GSNAS g s n a s +G. S. N. g s n +GSN g s n +GSNM g s n m +GSN's g s n's +GSOC- g s o c +GSO g s o +GSOM's g s o m's +GSOp g s o p +GSPC g s p c +G. S. P. g s p +GSP g s p +GSR g s r +GSSE g s s e +GSS- g s s +GSS g s s +GSSP g s s p +GSTA g s t a +G.S.T. g s t +GST- g s t +GST g s t +GSU g s u +GSUSA g s u s a +GSVD g s v d +GSVS g s v s +GSX g s x +GTAA g t a a +GTA g t a +GTAs g t a's +GTB g t b +GTBK g t b k +GTBP g t b p +GTC g t c +GTCR g t c r +GTD g t d +GTEC g t e c +GTE g t e +GTF g t f +GTFT g t f t +GTFU g t f u +gt g t +G. T. g t +G.T. g t +GT- g t +GT g t +G. T. H. g t h +GTi g t i +GTI g t i +GTK g t k +GTL g t l +GTMO g t m o +G. T. O. g t o +GTO g t o +GTPBP g t p b p +GTP- g t p +GTP g t p +GTPR g t p r +GTRA g t r a +GTR g t r +GTRI g t r i +GTs g t's +GTS g t s +GTSV g t s v +GTT g t t +GTTP g t t p +GTU g t u +GTV- g t v +GTV g t v +GTW- g t w +GTW g t w +GTW's g t w's +GTX g t x +G. U. g u +G.U. g u +GUI's g u i's +GUIs g u i's +G.U.Y. g u y +GVA g v a +GVAV g v a v +GVBA g v b a +GVC g v c +G. V. g v +G.V. g v +GVHSS g v h s s +GVJZ g v j z +GVK g v k +GvpA g v p a +GVP- g v p +GVP g v p +GVRD g v r d +GVSU g v s u +GVT g v t +GVU g v u +GVVV g v v v +GVW g v w +GVWR g v w r +GWA g w a +GWB g w b +G. W. C. g w c +GWe g w e +Gwet g w e t +G.W.F. g w f +GWF g w f +gw g w +G. W. g w +G.W. g w +GW g w +G. W. H. g w h +GWHS g w h s +Gwi g w i +GWK g w k +G.W.L. g w l +GWO g w o +GWOT g w o t +gwr g w r +GWR g w r +GWR's g w r's +GW's g w's +G. W. S. g w s +GWS g w s +GWU g w u +GXG g x g +GX- g x +GX g x +GXP g x p +GYAN's g y a n's +GYC g y c +GYF g y f +Gy g y +G. Y. g y +GY- g y +GY g y +Gyn g y n +GYN g y n +Gyps g y p's +gyu g y u +Gyu g y u +GZA g z a +GZ g z +GZR g z r +GZSZ- g z s z +HAFV h a f v +H. A. h a +H.A. h a +H&A h and a +HBA h b a +HBA's h b a's +HBBO h b b o +HBC h b c +HBCo h b c o +HBC's h b c's +HBCU h b c u +HBES h b e s +HBF h b f +HBGAs h b g a's +H. B. h b +H.B. h b +HB h b +HBI h b i +HBK- h b k +HBK h b k +HBLX h b l x +HBMP h b m p +HBO h b o +HBO's h b o's +HBPU h b p u +H&BR h and b r +HBR h b r +HBRN h b r n +HBRY h b r y +HB's h b's +HBS h b s +HBSS h b s s +HBU's h b u's +HBV h b v +HBW h b w +HCA h c a +HCAW h c a w +HCBE h c b e +HCB h c b +HCBS h c b s +HCCA h c c a +HCCB h c c b +HCCC h c c c +HCC h c c +HCDCH h c d c h +HCD- h c d +HCE h c e +HCEs h c e's +HCF h c f +H. C. G. h c g +HCGVN h c g v n +H. C. h c +H.C. h c +HC h c +HCH h c h +HCHS h c h s +HCI h c i +HCJB h c j b +hcl h c l +HCL h c l +HClO h c l o +HCMC's h c m c's +HCME h c m e +HCM h c m +HCN h c n +HCO h c o +HCoV h c o v +HCPA h c p a +H. C. P. h c p +HCP h c p +HCPs h c p's +HCR h c r +HCS h c s +HCT h c t +HCTV's h c t v's +HCUP h c u p +HCV h c v +HCVHDB- h c v h d b +Hcy h c y +HDAC h d a c +Hdad h d a d +hDAF h d a f +HDA h d a +HDB h d b +HDBK- h d b k +HDCAM h d c a m +HDC h d c +HDCP h d c p +HDD h d d +HDDs h d d's +HDFC h d f c +H.D.F. h d f +HDFM h d f m +H.D.G. h d g +HDG h d g +hd h d +H. D. h d +H.D. h d +HD- h d +HD h d +hdh h d h +HDi h d i +HDI h d i +HDLC h d l c +HDL- h d l +HDL h d l +HDLS h d l s +HDM h d m +HDMI h d m i +HDPE h d p e +HDP h d p +HDR h d r +HDRO h d r o +HDRR h d r r +H. E. h e +H.E. h e +hezb h e z b +Hezb h e z b +HFA h f a +HFB h f b +HFC h f c +HFCS h f c s +HFDF h f d f +HFF h f f +HFF's h f f's +H&F h and f +H. F. h f +H.F. h f +HFI h f i +H. F. J. h f j +HFNB h f n b +HFPA h f p a +HFP h f p +HFPPV h f p p v +HFRS h f r s +HFS h f s +HFTP h f t p +H.G.B. h g b +hgcA h g c a +HGC h g c +HGF h g f +hg h g +H. G. h g +H.G. h g +HG- h g +HG h g +HGH h g h +HGNC h g n c +HgO h g o +H. G. O. h g o +HGPIN h g p i n +HGPs h g p's +HGTV h g t v +HGTV's h g t v's +HgU h g u +HGVs h g v's +HGY h g y +HHA h h a +H. H. B. h h b +HHC h h c +HHD h h d +HHDP h h d p +HHG h h g +H&H h and h +HHHDB h h h d b +H. H. h h +H.H. h h +HHPC h h p c +HHSAA h h s a a +HHS h h s +H.H.T. h h t +H. I. h i +H.I. h i +H.I.V.E. h i v e +HIV- h i v +HIV h i v +HIY h i y +Hizb h i z b +hja h j a +HJC h j c +H. J. h j +H.J. h j +HJ- h j +HJ h j +HJK h j k +H.J.M. h j m +HJN h j n +H. J. R. h j r +H.J.R. h j r +HJT- h j t +H. J. W. h j w +HJW h j w +HKAA h k a a +Hkam h k a m +HKB h k b +HKCEC h k c e c +HKCEE h k c e e +HKDF h k d f +HKD h k d +HKDSE h k d s e +HKFC h k f c +H&K h and k +H. K. h k +H.K. h k +HK- h k +HK h k +H. K. J. h k j +HKK h k k +HKMA h k m a +HKN h k n +H.K.P. h k p +HKP h k p +HKSAR h k s a r +HKSCS- h k s c s +HK's h k's +HKTB- h k t b +HKT h k t +HKTWU h k t w u +HKU h k u +Hla h l a +HLA- h l a +HLA h l a +HLBN h l b n +HLD- h l d +HLE h l e +HLH h l h +H. L. h l +H.L. h l +HLL h l l +HLLS h l l s +HLN h l n +HLN's h l n's +HLS h l s +HLT h l t +HLTV h l t v +Hluk h l u k +hlutr h l u t r +HLV h l v +Hly h l y +HMAC h m a c +HMA- h m a +HMA h m a +Hman h m a n +H.M.A.S. h m a s +HMAS h m a s +HMB h m b +HMC h m c +HMCS h m c s +HMDA h m d a +HMD h m d +HMDI h m d i +HMDP h m d p +HME h m e +HMEL h m e l +HMF h m f +HMGA h m g a +HMG- h m g +HMG h m g +HMGIC h m g i c +HMGN h m g n +H&M h and m +HMH- h m h +HMH h m h +hm h m +H. M. h m +H.M. h m +HM- h m +HM h m +HMI h m i +HMIS h m i s +HMMC h m m c +HMM- h m m +HMM h m m +HMMWV h m m w v +HMN h m n +HMNZS h m n z s +HMNZT h m n z t +HMO h m o +HMOs h m o's +HMPC h m p c +HMP h m p +HMRC h m r c +hMRE h m r e +H&M's h and m's +H. M. S. h m s +H.M.S. h m s +HMS h m s +HMSN h m s n +H.M.S.O. h m s o +HMSO, h m s o +HMSO h m s o +HNF- h n f +H. N. h n +H.N. h n +HNI h n i +HNK h n k +HNL- h n l +HNL h n l +HNLMS h n l m s +HNMT h n m t +HNN h n n +HNO h n o +HNS h n s +H. O. h o +H.O. h o +HPA- h p a +HPA h p a +H.P.B. h p b +hpc h p c +HPC h p c +HPCT h p c t +HPDD- h p d d +H. P. D. h p d +HPD h p d +HPE h p e +HPH h p h +hp h p +H. P. h p +H.P. h p +HP- h p +HP h p +HPI h p i +HPLC h p l c +HPL h p l +HPP h p p +HPRA h p r a +HPR h p r +HPRT h p r t +HP's h p's +HPS h p s +H. P. T. h p t +HPV h p v +HQAA h q a a +HQDA h q d a +H.Q. h q +HQ- h q +HQ h q +HRG h r g +H&R h and r +H.R.H. h r h +HRH h r h +H. R. h r +H.R. h r +HR- h r +HR h r +HRK h r k +HRL h r l +HRM h r m +hroa h r o a +HRo h r o +HRO h r o +HRP h r p +HRSA h r s a +HRSA's h r s a's +HRSG h r s g +hrs h r s +HRs h r's +HRST h r s t +HRT h r t +HRV h r v +HRW h r w +HRX h r x +HSA h s a +HSAN h s a n +HSBC h s b c +HSB h s b +HSCA h s c a +HSC h s c +hscy h s c y +HSD h s d +HSDPA h s d p a +Hsee h s e e +HSE h s e +HSE's h s e's +HSF h s f +HSG h s g +HSHB h s h b +H.S.H. h s h +hs h s +Hs h's +H. S. h s +H.S. h s +HS- h s +HS h s +HSHS h s h s +hsi h s i +HSJ h s j +HSK h s k +HSL- h s l +HSL h s l +hSlo h s l o +H.S.M. h s m +HSM h s m +HSMR h s m r +HSN h s n +HSNY's h s n y's +HSPA h s p a +HSPA's h s p a's +HSPG h s p g +HSPH h s p h +HSP h s p +HSP's h s p's +HSPs h s p's +HSRC h s r c +HSR h s r +HSSCCT h s s c c t +HSSF h s s f +HSS h s s +HST h s t +HST's h s t's +HSTs h s t's +HSTS h s t s +hsv h s v +HSV- h s v +HSV h s v +HSX h s x +HSY h s y +HSYK's h s y k's +HSZ h s z +HTA- h t a +HTA h t a +hTAS h t a s +HTAs h t a's +htc h t c +HTC- h t c +HTC h t c +HTC's h t c's +HTGL h t g l +HTHC h t h c +ht h t +H. T. h t +H.T. h t +HT- h t +HT h t +HTIB h t i b +hti h t i +Htin h t i n +HTK h t k +HTLA h t l a +HTLV- h t l v +HTLV h t l v +HTML h t m l +HTM's h t m's +Htoo h t o o +HTPB h t p b +HTPC h t p c +HTP h t p +HtrA h t r a +HTR h t r +HTRs h t r's +HTS h t s +http h t t p +HTTP- h t t p +HTTP h t t p +https h t t p s +HTTPS h t t p s +HTV h t v +HTV's h t v's +Htwa h t w a +HTW h t w +HTX h t x +H. U. h u +HVC h v c +HVCs h v c's +hvcv h v c v +HVDC- h v d c +HVDC h v d c +hvem h v e m +Hvem h v e m +HVF h v f +HVHS h v h s +H. V. h v +H.V. h v +H.W.A. h w a +H. W. F. h w f +H. W. h w +H.W. h w +H.W.L. h w l +HWL h w l +HWM h w m +HWRT h w r t +HWT h w t +HWV h w v +hwy h w y +Hwy h w y +hxt h x t +H. Y. h y +H.Y. h y +H. Z. h z +HZ&PC h z and p c +iaaf i a a f +IAAF i a a f +IAAF's i a a f's +IAA i a a +IAAPA i a a p a +IAAP i a a p +IaaS i a a s +IAAS i a a s +IABSE i a b s e +Iaca i a c a +IACC i a c c +IACD i a c d +IAC i a c +Iacob i a c o b +IACR i a c r +IAC's i a c's +IACTs i a c t's +Iacub i a c u b +IACUC i a c u c +IACW i a c w +IAD i a d +IAD's i a d's +IAEA i a e a +IAEG i a e g +I.A.E. i a e +IAE i a e +IAF i a f +IAF's i a f's +IAG i a g +IAG's i a g's +iagt i a g t +IAHP i a h p +IAHRC i a h r c +I. A. i a +I.A. i a +I.A.M. i a m +IAO i a o +Iapa i a p a +IAPHC i a p h c +IAP- i a p +IAP i a p +iar i a r +Iar i a r +IAR- i a r +IAR i a r +IAST i a s t +IATA i a t a +I.A.T. i a t +IAT i a t +IATR i a t r +IAUC i a u c +IAUCs i a u c's +IAU i a u +IAV i a v +IAWTV i a w t v +Iax i a x +IAX i a x +Ibac i b a c +Ibaes i b a e's +IBA's i b a's +IBB i b b +IBC i b c +IBCs i b c's +IBCT i b c t +IBDA'A i b d a a +Ibda i b d a +ibdal i b d a l +IBDB i b d b +IBDE i b d e +IBD i b d +IBE i b e +IBF i b f +IBGE i b g e +IBH i b h +I. B. i b +I.B. i b +IBJJF i b j j f +IBL i b l +IBLT i b l t +IBMA's i b m a's +IBMC i b m c +Ibm i b m +I.B.M. i b m +IBM- i b m +IBM i b m +IBM's i b m's +IBMXF i b m x f +Ibne i b n e +ibn i b n +IBO i b o +IBPA i b p a +IBP i b p +Ibra i b r a +IBRA i b r a +IBRC i b r c +IBR i b r +IBRO i b r o +Ibsa i b s a +IBSA i b s a +IBSF i b s f +Ibs i b's +IBS i b s +IBSL i b s l +IBTC i b t c +iBT i b t +IBTS i b t s +Ibu i b u +IBU i b u +IBV i b v +IBWFF i b w f f +iby i b y +ICBA i c b a +ICBC i c b c +ICB i c b +ICBL i c b l +ICBM i c b m +ICBMs i c b m's +ICBP i c b p +ICBS i c b s +ICBTT i c b t t +ICCC i c c c +ICCC's i c c c's +ICCEC i c c e c +ICCF i c c f +Icche i c c h e +I.C.C. i c c +ICC- i c c +ICC i c c +ICCID i c c i d +ICCI i c c i +ICCR i c c r +ICC's i c c's +ICCS i c c s +ICCW i c c w +ICDC i c d c +ICD- i c d +ICD i c d +ICDS- i c d s +ICDS i c d s +I.C.E. i c e +ICFF i c f f +icf i c f +ICF- i c f +ICF i c f +ICFR i c f r +ICG i c g +ICHC i c h c +I&C i and c +ic i c +Ic i c +I. C. i c +I.C. i c +IC i c +Ici i c i +ICI i c i +ICJ i c j +ICL i c l +ICL's i c l's +ICMA i c m a +ICME i c m e +I.C.M. i c m +ICM i c m +iCN i c n +ICN i c n +Ico i c o +ICO i c o +ICOP i c o p +ICPC i c p c +ICPD i c p d +ICP i c p +ICP's i c p's +ICQ i c q +ICRC i c r c +ICRF i c r f +ICR i c r +IcRn i c r n +ICRP i c r p +ICRS i c r s +ICRW i c r w +ICSA i c s a +ICSB i c s b +ICSC i c s c +ICSD- i c s d +ICSE i c s e +ICSG i c s g +ics i c s +ICs i c's +ICS i c s +ICSS i c s s +ICSSR i c s s r +ICTA i c t a +ICT i c t +ICTM i c t m +ICTP i c t p +ICTSF i c t s f +ICTs i c t's +ICTS i c t s +ICTU i c t u +ICTUR i c t u r +ICTVdB i c t v d b +ICTV's i c t v's +ICTY i c t y +ICU i c u +ICUN i c u n +ICU's i c u's +ICv i c v +ICV i c v +ICVS i c v s +ICWA i c w a +ICWC i c w c +ICW i c w +ICW's i c w's +iCyt i c y t +ICZ i c z +ICZN i c z n +IDAF i d a f +IDBF i d b f +IDB i d b +IDBI i d b i +IDC i d c +Iddaa i d d a a +Idd i d d +ID'd i d d +IDEF i d e f +IDEG- i d e g +IDE i d e +IDFA i d f a +IDFG i d f g +IDF i d f +IDFL i d f l +IDF's i d f's +IDG i d g +I. D. H. i d h +IDH- i d h +IDH i d h +id i d +I. D. i d +I.D. i d +ID- i d +ID i d +Idi i d i +Idir i d i r +IDIS i d i s +IDLHs i d l h's +IDL i d l +Idm i d m +IDM i d m +IDMR i d m r +IDMS i d m s +IDNA i d n a +IDN i d n +IDNR i d n r +IDNR's i d n r's +IDPs i d p's +IDRC i d r c +IDRO i d r o +IDSA i d s a +IDSA's i d s a's +IDSF i d s f +ids i d s +ID's i d's +IDs i d's +IDV i d v +IDW i d w +IDWO i d w o +IDW's i d w's +IDx i d x +IDX i d x +IEA- i e a +IEA i e a +I.E.M. i e m +IEM i e m +I.E.S. i e s +IES i e s +i.e. that is +Ifa i f a +IFA- i f a +IFA i f a +IFBB i f b b +IFBC i f b c +I.F.B. i f b +IFCC- i f c c +IFCC i f c c +ifc i f c +IFC i f c +IFC's i f c's +IfF i f f +I. F. F. i f f +IFF i f f +IFFI i f f i +IFFK i f f k +Ifft i f f t +IFHA i f h a +IFHP i f h p +ifi i f i +Ifi i f i +IFI i f i +IFIP i f i p +IFIs i f i's +IFK i f k +IFLA i f l a +IFL i f l +IfM i f m +IFM i f m +IFN- i f n +IFN i f n +Ifni i f n i +IFNs i f n's +IFO i f o +Ifop i f o p +IFP i f p +IFPI i f p i +IFPRI i f p r i +IFRC i f r c +IFR i f r +IFRS i f r s +IFRSs i f r s's +IFSB i f s b +IFSC i f s c +IFSTA i f s t a +IFTA i f t a +IFTF i f t f +IFT i f t +Iga i g a +IgA i g a +IGA i g a +IGA's i g a's +IGBT i g b t +IGC i g c +IGCP i g c p +IGCSE i g c s e +IGD i g d +IGF- i g f +IGF i g f +IGFI i g f i +IGFs i g f's +IGIB i g i b +'ig i g +Ig i g +I.G. i g +IG i g +igi i g i +IGI i g i +IgM i g m +IGM i g m +IGMP i g m p +ign i g n +Ign i g n +IGN i g n +IHF i h f +IHGS i h g s +IHH i h h +Ih i h +I. H. i h +IH i h +ihi i h i +IHI i h i +IHL i h l +IHL's i h l's +IHMC i h m c +IHME i h m e +ihm i h m +ihn i h n +Ihn i h n +IHOM i h o m +Ihor i h o r +IHPK i h p k +IHRC i h r c +IHSAA- i h s a a +IHSAA i h s a a +IHSA i h s a +IHS i h s +Iht i h t +IIA i i a +IIb i i b +IIB- i i b +IIB i i b +IIc i i c +IIDC i i d c +IID i i d +IIDI i i d i +IIDS i i d s +IIDX i i d x +IIED i i e d +IIFA i i f a +IIF i i f +IIfx i i f x +Iiga i i g a +IIga i i g a +IIG i i g +IIgs i i g's +IIGs i i g's +IIGS i i g s +IIGS's i i g s's +IIHF i i h f +IIHR i i h r +IIHS i i h s +IIIA i i i a +IIIb i i i b +IIIB i i i b +IIIBy i i i b y +IIIc i i i c +IIId i i i d +IIIF i i i f +I. I. i i +I.I. i i +ija i j a +Ija i j a +IJA i j a +IJF i j f +IJGL i j g l +IJHCD i j h c d +IJHL i j h l +ij i j +I. J. i j +IJ- i j +IJ i j +IJN i j n +Ijok i j o k +IJSB i j s b +IJSE i j s e +IJSEM i j s e m +IJS i j s +Ijui i j u i +IJVM i j v m +IKBN i k b n +IKCO i k c o +IKF i k f +Ikh i k h +I.K. i k +IKK- i k k +IKK i k k +IKL i k l +IKr i k r +Iksa i k s a +IKTA i k t a +Iku i k u +Ilbe i l b e +ILB i l b +ILC i l c +ILCS i l c s +ILD i l d +ILDIS i l d i s +ILFC i l f c +ILF i l f +IL&FS i l and f s +ili i l i +Ili i l i +ILI i l i +I. L. i l +I.L. i l +Ilm i l m +ILM i l m +ILM's i l m's +ILN i l n +ILP i l p +ILR i l r +ILRS i l r s +ilu i l u +Ilu i l u +ILU i l u +IMbd i m b d +IMBD i m b d +IMB i m b +IMCB i m c b +IMCI i m c i +imc i m c +IMC i m c +imdb i m d b +IMDb. i m d b +IMDb i m d b +IMDB- i m d b +IMDB. i m d b +IMDB i m d b +IMD i m d +IMD's i m d's +ime i m e +IME i m e +IMF, i m f +IMF i m f +IMG i m g +I&M i and m +IMI i m i +I. M. i m +I.M. i m +IMIS i m i s +IMK i m k +Iml i m l +IMMEX i m m e x +Imm i m m +Imms' i m m's +IMMU- i m m u +imoa i m o a +IMO's i m o's +IMPA i m p a +IMPDH i m p d h +impr i m p r +Impr i m p r +IMPSA i m p s a +IMR i m r +IMSLP i m s l p +iMSNs i m s n's +Imst i m s t +IMTA i m t a +IMT- i m t +IMT i m t +IMTV i m t v +IMUK i m u k +IMU's i m u's +IMWF i m w f +INAC i n a c +Inba i n b a +INBA i n b a +INBF i n b f +inb i n b +incl i n c l +INCT- i n c t +INDC i n d c +ind i n d +Ind i n d +IND i n d +INFJ i n f j +I.N.F.O. i n f o +Infs i n f's +ING i n g +INGR i n g r +inHg i n h g +INH i n h +INI i n i +I. N. i n +I.N. i n +InlB i n l b +INL i n l +INM i n m +INPD i n p d +INPE i n p e +InP i n p +INP i n p +INPP i n p p +INRA- i n r a +Inre i n r e +I.N.R.I. i n r i +INR i n r +INSB i n s b +INSDC i n s d c +INSD i n s d +Inspx i n s p x +INSS i n s s +INTF i n t f +Ints i n t's +INTs i n t's +Intu i n t u +INVA i n v a +inv i n v +INXS i n x s +INXS's i n x s's +Ioba i o b a +IOCG i o c g +IOC- i o c +IOC i o c +IOCP i o c p +IODP i o d p +IODs i o d's +IOE i o e +IOFB i o f b +IOF i o f +io. i o +io i o +.I.o. i o +Io. i o +Io i o +.IO i o +I/O i o +IO- i o +IO i o +Ioka i o k a +Iok i o k +IOK- i o k +IOL i o l +IoM i o m +IOM i o m +IOPI i o p i +IOP i o p +IOPs i o p's +IORG i o r g +IOR- i o r +IOR i o r +IORM i o r m +IOSA i o s a +IOSB i o s b +iOS- i o s +iOS i o s +Io's i o's +I/Os i o's +I.O.'s i o's +IOS i o s +IOSR i o s r +Iosu i o s u +IoT i o t +IOT i o t +I.O.U. i o u +IOU i o u +IoW i o w +IOW i o w +IPA i p a +IPA's i p a's +IPB i p b +IPCC i p c c +IPCC's i p c c's +IPC i p c +IPCRI i p c r i +IPCs i p c's +IPDA i p d a +IPDI i p d i +IPD i p d +IPE i p e +IPFA i p f a +IPFI i p f i +IPF i p f +IPFP i p f p +IPFW i p f w +IPG i p g +IPH i p h +ip i p +Ip i p +I.P. i p +IP- i p +IP i p +IPL i p l +IPMG i p m g +IPM i p m +IPNI i p n i +IPN i p n +Ipo i p o +I.P.O. i p o +IPO i p o +IPP i p p +IPPL i p p l +IPPs i p p's +IPPT i p p t +Ippu i p p u +iPPV i p p v +IPR i p r +iPSC i p s c +IPSC i p s c +iPSCs i p s c's +ipse i p s e +IPSF i p s f +iPS i p s +IPs i p's +I.P.S. i p s +IPS i p s +IPTA i p t a +IPTC i p t c +IPTG i p t g +IPT i p t +IPTL i p t l +IPTV i p t v +IPU i p u +IPUM i p u m +IPv i p v +IPWA i p w a +IPW i p w +IPX i p x +iQ i q +I.Q. i q +IQ i q +IRAC i r a c +I.R.A. i r a +IRB i r b +IRBM i r b m +IRCA i r c a +IRC i r c +IRCM i r c m +IRCTC i r c t c +IRCT i r c t +IRD i r d +IRDS i r d s +IREC i r e c +I.R.E. i r e +IRE i r e +IRFCA i r f c a +IRFC i r f c +IRF i r f +IRFU i r f u +IRGC i r g c +Irgm i r g m +IRHG i r h g +IRHT i r h t +IRIB i r i b +Irig i r i g +IRI i r i +Iril i r i l +IRIN i r i n +i'r i r +ir i r +Ir i r +I. R. i r +I.R. i r +IR- i r +IR i r +IRIX i r i x +Irla i r l a +IRL i r l +IRM i r m +Irmis i r m i's +IRM's i r m's +IRNE i r n e +IRN- i r n +IRN i r n +iro i r o +Iro i r o +IRO i r o +IRP i r p +IRP's i r p's +IRPS i r p s +IRQ i r q +Irra i r r a +IRRI i r r i +IRR i r r +IRs i r's +I.R.S. i r s +IRS- i r s +IRS i r s +IRSN i r s n +I.R.T. i r t +IRT i r t +iru i r u +Iru i r u +ISA i s a +ISAv i s a v +Isba i s b a +ISBA i s b a +ISBER i s b e r +ISBHF i s b h f +ISB i s b +isbn i s b n +ISBN i s b n +ISBNs i s b n's +ISBO i s b o +ISCB i s c b +ISCC- i s c c +ISCE i s c e +isCf i s c f +ISCI i s c i +iSC i s c +Isc i s c +ISC- i s c +ISC i s c +ISCM i s c m +ISCM's i s c m's +ISCP i s c p +ISDA i s d a +ISDB- i s d b +Isd i s d +ISD i s d +isdn i s d n +ISDN i s d n +ISDS i s d s +ISDT i s d t +ISFI i s f i +ISF i s f +Isgec i s g e c +ISG i s g +ISHC i s h c +ishq i s h q +Ishq i s h q +ISHS i s h s +I. S. i s +I.S. i s +ISKB i s k b +ISK i s k +Isl i s l +ISL i s l +ISMF i s m f +ISMIR i s m i r +ISMN- i s m n +ISMNs i s m n's +isn i s n +ISN i s n +ISNTUC i s n t u c +ISOGG i s o g g +ISO- i s o +ISO i s o +ISO's i s o's +I.S.P.C.K. i s p c k +ISPF i s p f +ISPI i s p i +ISP i s p +ISPL i s p l +ISPR i s p r +ISPs i s p's +Isra'il i s r a i l +Isra i s r a +ISRA i s r a +ISR i s r +ISRN i s r n +ISRO i s r o +ISRP i s r p +ISSCC i s s c c +ISSF i s s f +iss i s s +Iss i s's +ISS i s s +ISSN- i s s n +ISSN i s s n +ISSNs i s s n's +ISSSSP i s s s s p +ISSUU i s s u u +ISTAF i s t a f +ISTD i s t d +Isu i s u +ISU i s u +ISU's i s u's +ISWC i s w c +ISWI i s w i +ISW i s w +I.T.A. i t a +ITA i t a +ITB i t b +ITC i t c +Ite i t e +ITE i t e +ITF i t f +ITG i t g +ITHF i t h f +I.T.H.M. i t h m +ITHs i t h's +iti i t i +Iti i t i +ITI i t i +I.T. i t +itk i t k +Itk i t k +ITK i t k +ITM i t m +ITMO i t m o +ITN i t n +ITNNs i t n n's +ITN's i t n's +Itoi i t o i +ITPF i t p f +iTP i t p +ITP i t p +ITRD i t r d +Itse i t s e +ITSF i t s f +ITTF i t t f +itt i t t +ITT i t t +ITUC i t u c +Itu i t u +ITU- i t u +ITU i t u +ITV i t v +ITV's i t v's +ITWF i t w f +ITW i t w +Itz i t z +IUB i u b +I.U.C.N.B. i u c n b +Iucn i u c n +IUCN- i u c n +IUCN i u c n +IUCN's i u c n's +IUD i u d +IUDs i u d's +IU i u +IUT i u t +IUU i u u +Iuz i u z +IVAA i v a a +IVAW i v a w +IVB i v b +I. V. i v +I.V. i v +IVL i v l +IVLP i v l p +IVM's i v m's +IVP i v p +IVPP i v p p +IVPTC i v p t c +IVRCL i v r c l +IVs i v's +Ivu i v u +IVWA i v w a +IWA i w a +Iwas i w a's +Iwaz i w a z +IWBs i w b's +IWC i w c +IWD i w d +IWF i w f +IWFL i w f l +IWF's i w f's +IWFS i w f s +IWG i w g +IWGP i w g p +iwi i w i +iw i w +I. W. i w +IW- i w +IW i w +IWL i w l +IWMF i w m f +IWM i w m +IWPR i w p r +iwrg i w r g +IWRG i w r g +IWR i w r +IWRS i w r s +IWSA i w s a +iwspy i w s p y +Iwuh i w u h +IWU's i w u's +I.W.W. i w w +IWW i w w +IXA i x a +IXb i x b +IXBs i x b's +IXC i x c +IXCs i x c's +IXe i x e +IX i x +iXL i x l +IXO i x o +ixtle i x t l e +IXV i x v +Iya i y a +IYA i y a +Iyar i y a r +IYC i y c +iyem i y e m +IYHF i y h f +Iyi i y i +iy i y +I. Y. i y +I.Y. i y +IY i y +J.A.A. j a a +J. A. B. j a b +Jaf j a f +J.A.G. j a g +JAG j a g +JAIR j a i r +J. A. j a +J.A.K.E. j a k e +J. A. N. j a n +J.A.P. j a p +J.A.S. j a s +JBA j b a +JBBA j b b a +JBB j b b +JBC j b c +JBG j b g +J&B j and b +jb j b +J. B. j b +J.B. j b +JB j b +J.B.L.D. j b l d +JBL j b l +J.B.M. j b m +JBM j b m +JB's j b's +J. B. S. j b s +J.B.S. j b s +JBT j b t +JBZ j b z +JCA j c a +JCB j c b +JCC j c c +JCF j c f +JCFS j c f s +J.C.G. j c g +JCG j c g +JCGM j c g m +JCIB j c i b +JCI j c i +jcis j c i s +jc j c +J. C. j c +J.C. j c +JC j c +JCJC j c j c +J. C. L. j c l +JCPA j c p a +J. C. P. j c p +JCP j c p +JCPV j c p v +JCRB j c r b +JCR j c r +JCRs j c r's +J.C.S. j c s +JCS j c s +JCSR j c s r +JCVI j c v i +J. C. W. j c w +JCW j c w +J. D. A. j d a +JDA j d a +JDBC j d b c +JDC j d c +JdeBP j d e b p +J.D.E. j d e +JDE j d e +JDENET j d e n e t +J.D.F. j d f +JDF j d f +jdi j d i +JDI j d i +jd j d +J. D. j d +J.D. j d +JD- j d +JD j d +jdk j d k +JDK j d k +J.D.M. j d m +JDM j d m +JDO j d o +JDRF j d r f +J&D's j and d's +J.D.s j d's +JDT j d t +JDU j d u +JDV j d v +J. E. A. j e a +J.E.A.L. j e a l +J.E.B. j e b +J. E. C. j e c +J. E. E. j e e +J. E. j e +J.E. j e +J.F.G. j f g +JFH j f h +jf j f +J. F. j f +J.F. j f +JF- j f +JF j f +JFK j f k +JFN j f n +JFQA j f q a +JFS j f s +J. G. A. j g a +J.G.B. j g b +JGI j g i +J. G. j g +J.G. j g +J. G. L. j g l +JGLS j g l s +J. G. M. j g m +J.G.M. j g m +JGO j g o +JGP j g p +JGR j g r +JGR's j g r's +JGSDF j g s d f +JGTC j g t c +JGU j g u +J.H.B. j h b +JHB j h b +J. H. C. j h c +JHC j h c +JHED j h e d +J.H.F. j h f +J.H.H. j h h +jh j h +J. H. j h +J.H. j h +JH- j h +JH j h +JHL j h l +J. H. M. j h m +J.H.R. j h r +JHs j h's +JHS j h s +JHSVs j h s v's +JHud j h u d +JHU- j h u +JHU j h u +J. I. j i +J.I. j i +J.J.A. j j a +JJB j j b +J. J. C. j j c +J.J.G. j j g +J&J j and j +J. J. j j +J.J. j j +JJ j j +JJK j j k +J. J. L. j j l +J.J.M. j j m +J.J.N. j j n +JJN j j n +Jka j k a +JKA j k a +JKC j k c +jkd j k d +JKH j k h +J&K j and k +J.K. J. j k j +J. K. j k +J.K. j k +JK j k +JKNPP j k n p p +J. K. S. j k s +JKT j k t +jkx j k x +JKX j k x +JLA j l a +J.L.B. j l b +JLB j l b +JLC j l c +J. L. E. j l e +J.L.E. j l e +JLG j l g +JLI j l i +J. L. j l +J.L. j l +J.L.L. j l l +JLM j l m +JLO's j l o's +JLPGA j l p g a +JLP j l p +JLS j l s +JLT j l t +JMA j m a +JMBG j m b g +J.M.C. j m c +JMC j m c +J. M. D. j m d +JMD j m d +J. M. E. j m e +JMI j m i +J. M. J. j m j +J.M.J. j m j +J. M. j m +J.M. j m +JMKR j m k r +J. M. L. j m l +JML j m l +JMM j m m +JMP j m p +JMS j m s +JMU j m u +JMV j m v +J. M. W. j m w +J.M.W. j m w +JMX j m x +JNA j n a +jnb j n b +JNF j n f +JNG- j n g +JNG j n g +JNIH- j n i h +JNI j n i +J. N. j n +J.N. j n +JN j n +JNK j n k +J. N. L. j n l +Jno j n o +JNPT j n p t +jnr j n r +JNR j n r +JNS's j n s's +JOJ j o j +J. O. j o +J.O. j o +J.P.D.B. j p d b +J. P. F. j p f +JPF j p f +jpg j p g +JPG j p g +JPH j p h +J&P j and p +jp j p +J.P. j p +JP- j p +JP j p +J.P.R. j p r +J.Q. j q +JQ j q +J.R.A. j r a +JRA j r a +J.R.C. j r c +JRC j r c +J.R.E. j r e +JRG j r g +JRHU j r h u +J. R. I. j r i +J&R j and r +J. R. j r +J.R. j r +JR j r +JRJ's j r j's +Jr. junior +JRPG j r p g +J. R. P. j r p +J. R. R. j r r +J.R.R. j r r +J.R.'s j r's +JRSP j r s p +J. R. T. j r t +JRU j r u +JRX j r x +JSA j s a +JSAP j s a p +JSA's j s a's +jsb j s b +JSCA j s c a +JSC j s c +J.S.D. j s d +JSD j s d +JSE j s e +JSF j s f +JSH j s h +Js j's +J. S. j s +J.S. j s +JS j s +J.S.K. j s k +J.S.L. j s l +JSL j s l +J. S. M. j s m +JSM j s m +JSNN j s n n +JSOC j s o c +JSO j s o +JSP j s p +JSPS j s p s +JSR j s r +JSS j s s +JSW j s w +JSW's j s w's +JSX j s x +JTA j t a +J.T.B. j t b +JTB j t b +JTC j t c +JTF- j t f +JTF j t f +JTG j t g +JTI j t i +J&T j and t +J. T. j t +J.T. j t +JT j t +JT&KW j t and k w +JTL j t l +JTM- j t m +JTO j t o +JTR j t r +JTRO j t r o +JTS j t s +JTTF j t t f +JTT j t t +JTV j t v +J. U. j u +J.U.L.I.A. j u l i a +J.V.B. j v b +JVB j v b +JVC j v c +J.V.E. j v e +JVG j v g +JVH j v h +J&V j and v +J. V. j v +J.V. j v +JV- j v +JV j v +JVM j v m +JVNW j v n w +JVP j v p +JVRA j v r a +JVS j v s +Jwa j w a +J. W. A. j w a +J. W. B. j w b +JWB j w b +J.W.C. U.S. j w c u s +JWHA j w h a +JWH- j w h +J.W.J. j w j +J. W. j w +J.W. j w +JWM j w m +J. W. P. j w p +JWP j w p +JWRC j w r c +J. W. S. j w s +J.W.S. j w s +JWS j w s +JWST j w s t +JWT j w t +jx j x +JX- j x +JX j x +J.X.W.P. j x w p +JYJ j y j +JYJ's j y j's +J. Y. j y +J.Y. j y +JY j y +Jym j y m +Jymn j y m n +JYP j y p +J. Y. S. j y s +J. Z. j z +J.Z. j z +JZ- j z +JZ j z +K.A.A. k a a +K. A. k a +K.A. k a +K.A.N. k a n +K. A. R. k a r +K.A.S. k a s +KBBI k b b i +KBB k b b +KBCI k b c i +KBC k b c +KBCO k b c o +KBD k b d +KBEH- k b e h +KBE k b e +KBEV- k b e v +KBFC k b f c +KBFL k b f l +KBFR k b f r +KBGD k b g d +KBG k b g +KBIG k b i g +kbi k b i +K&B k and b +K. B. k b +K.B. k b +KBKR k b k r +KBKS k b k s +KBKW k b k w +KBL k b l +KBMT- k b m t +KBMT k b m t +KBND k b n d +KBNZ- k b n z +KBNZ k b n z +KBO k b o +KBRC k b r c +KBR k b r +KBSC- k b s c +KBS k b s +KBSN k b s n +KCB k c b +KCBS- k c b s +KCBS k c b s +KCCC k c c c +KCCI k c c i +KCC k c c +KCCO k c c o +KCDC k c d c +K. C. D. k c d +KCD k c d +KCED k c e d +KCET k c e t +KCG k c g +KCGW- k c g w +KCHK- k c h k +KCHS k c h s +K.C.I.E. k c i e +K. C. k c +K.C. k c +KCK k c k +KCKM k c k m +KCLU k c l u +K.C.M.G. k c m g +KCMG k c m g +KCMO- k c m o +KCMU- k c m u +KCNA k c n a +KCNH k c n h +KCNJ k c n j +KCN k c n +KCNN k c n n +KCNQ k c n q +KCNV k c n v +KCPD k c p d +KCPI k c p i +KCPM k c p m +KCPQ k c p q +KCPQ's k c p q's +KCQL k c q l +KCRA k c r a +KCRC k c r c +KCRH k c r h +KCR k c r +KCRW k c r w +KCSD- k c s d +KCSD k c s d +KCSG k c s g +K.C.S.I. k c s i +KCSI k c s i +K.C.'s k c's +KCS k c s +KCSP k c s p +KCTD k c t d +KCT k c t +KCTL k c t l +KCTV k c t v +KCUB k c u b +KCU k c u +KCVO k c v o +KCYX k c y x +kDa k d a +KDA k d a +kdal k d a l +KDAL k d a l +KDB k d b +KDCE k d c e +KDCO k d c o +KDDG k d d g +KDDI k d d i +KDD k d d +KDE- k d e +KDE k d e +KDEX- k d e x +KDFW k d f w +KDFX k d f x +K. D. G. k d g +KDGS k d g s +KDHS k d h s +KDIS- k d i s +KDKA- k d k a +KDKA k d k a +K&D k and d +kd k d +K. D. k d +K.D. k d +KD- k d +KD k d +KDP k d p +KDPM k d p m +KDR k d r +K. D.'s k d's +K.D.'s k d's +KDS k d s +ke k e +Ke- k e +Ke k e +K. E. k e +K.E. k e +KE k e +KFAC k f a c +KFAED k f a e d +KFAI k f a i +KFA k f a +KFBK k f b k +KFBT k f b t +KFCC k f c c +KFCD k f c d +kfc k f c +K.F.C. k f c +KFC k f c +KFC's k f c's +KFDI- k f d i +KFD k f d +KFDM- k f d m +KFDM k f d m +KFEM k f e m +KFFL k f f l +KFH k f h +KFI k f i +KFJB k f j b +K.F. k f +KFLX k f l x +KFMB- k f m b +KFMB's k f m b's +KFMG- k f m g +KFMJ k f m j +K. F. M. k f m +K.F.M. k f m +KFOR k f o r +KFQC k f q c +KFQ k f q +KFRC k f r c +KFRC's k f r c's +KFRD k f r d +KFRG k f r g +KFRH k f r h +KFRO k f r o +KFSD k f s d +KFSN- k f s n +KFSN k f s n +KFST k f s t +KFTA- k f t a +KFT k f t +KFTL- k f t l +KFTL k f t l +KFUK- k f u k +KFUM- k f u m +KFUM's k f u m's +KFVD k f v d +KFV k f v +KFWB k f w b +KFXO k f x o +KFYO- k f y o +KFYO's k f y o's +KFYR- k f y r +KGA k g a +K.G.B. k g b +KGB- k g b +KGB k g b +KGBX- k g b x +KGC k g c +KGPH k g p h +KGP k g p +KGRI k g r i +kgr k g r +KGRK k g r k +KGS- k g s +KGS k g s +kgt k g t +KGT k g t +KGTV k g t v +KgU k g u +KGU k g u +KGUN k g u n +kgv k g v +K.G.V. k g v +KGWB k g w b +KGW k g w +KHHZ k h h z +KHI k h i +Khizr k h i z r +KHJ- k h j +KHJ k h j +Kh- k h +K. H. k h +K.H. k h +KH- k h +KH k h +KHK k h k +KHKV k h k v +Khlav k h l a v +KHL k h l +KHL's k h l's +Khmu k h m u +KHMY k h m y +KHOJ k h o j +KHOW k h o w +KHQA k h q a +KHQ k h q +Khri k h r i +Khru k h r u +KHRW k h r w +KHSAA k h s a a +KHSC- k h s c +KHS k h s +KHTL k h t l +KHTZ k h t z +KHUI k h u i +KHUT k h u t +KHWI k h w i +K.I.D. k i d +K. I. k i +K.I. k i +K.I.M. k i m +KIP k i p +K.I.S.S. k i s s +KJCE k j c e +KJCT k j c t +KJEF k j e f +Kjer k j e r +KJHK k j h k +KJI k j i +KJIN k j i n +kj k j +K. J. k j +K.J. k j +KJ k j +KJKP k j k p +KJMM k j m m +KJNE k j n e +KJNW k j n w +Kjop k j o p +KJo's k j o's +KJQY k j q y +KJV k j v +KJZI k j z i +KKBL k k b l +KKBQ k k b q +KKCR k k c r +KKDA k k d a +KKDS- k k d s +K.K.E. k k e +KKE k k e +K. K. k k +K.K. k k +KKMC k k m c +KKMI k k m i +KKM k k m +KKMX k k m x +KKRG k k r g +KKR k k r +KKSF k k s f +KK's k k's +KKSY k k s y +KKT k k t +KKWB- k k w b +KLA k l a +KLBK k l b k +KLBM k l b m +KLCI k l c i +KLC k l c +KLDS k l d s +Kle k l e +KLE k l e +KLF k l f +KLGH k l g h +KLH k l h +KLK k l k +kl k l +K. L. k l +K.L. k l +KL k l +KLKS k l k s +KLLP k l l p +KLLV k l l v +KLM k l m +KLN's k l n's +KLQQ k l q q +KLQT k l q t +KLRY k l r y +KLSC k l s c +KLSD k l s d +KLS- k l s +KLS k l s +KLSR- k l s r +KLSX k l s x +KLT k l t +KLX k l x +KMB k m b +KMCI- k m c i +KMC k m c +KMCX- k m c x +KMD k m d +KMGO k m g o +KMGT k m g t +KMIH k m i h +KMIR k m i r +KMITL k m i t l +KMJC- k m j c +KMJ k m j +K&M k and m +KMK k m k +km k m +K. M. k m +K.M. k m +KM- k m +KM k m +KMLA k m l a +KML k m l +KMME k m m e +KMML k m m l +KMRL k m r l +KMS k m s +KMSP k m s p +KMT k m t +KMTP k m t p +KMTV k m t v +KMVA k m v a +KMVQ- k m v q +KMXW k m x w +KMZG- k m z g +KMZ k m z +KNFM k n f m +KNHP k n h p +K&N k and n +kn k n +K. N. k n +K.N. k n +KN k n +KNKT k n k t +KNLA k n l a +KNMI k n m i +KNNV k n n v +KNPN k n p n +KNPR k n p r +KNPU k n p u +KNRE k n r e +KNRS k n r s +KNS k n s +KNSM k n s m +KNST- k n s t +KNST k n s t +KNTH k n t h +K.N.T. k n t +KNTN k n t n +KNTU k n t u +KNVA's k n v a's +KNVB k n v b +KNVN k n v n +KNWA- k n w a +KNX- k n x +KNX k n x +KNXT k n x t +KNXV- k n x v +K.O.D. k o d +k'o k o +K. O. k o +K.O. k o +KOTC k o t c +KOTD k o t d +K.O.T. k o t +KOWL k o w l +K. P. A. C. k p a c +KPAC- k p a c +KPAC k p a c +KPA k p a +KPAN k p a n +KPCC k p c c +KPC k p c +KPD k p d +KPDR- k p d r +KPE k p e +KPFT- k p f t +KPIF k p i f +KPI- k p i +KPI k p i +KPIs k p i's +K&P k and p +K. P. k p +K.P. k p +KP k p +KPLC k p l c +KPL k p l +KPLZ k p l z +KPMG k p m g +KPM k p m +KPNA k p n a +KPNB k p n b +KPO k p o +KPPC- k p p c +Kppen k p p e n +KPPV k p p v +KPRC- k p r c +KPS k p s +KPSL- k p s l +kptm k p t m +KPTV- k p t v +KPTV k p t v +KPU k p u +KPVD k p v d +KPVX k p v x +KPWR k p w r +KPXE k p x e +KPXO- k p x o +KPZK- k p z k +KQA k q a +KQBU- k q b u +KQCD- k q c d +KQED k q e d +KQEG- k q e g +KQHN k q h n +KQKK k q k k +KQKS k q k s +KQLT k q l t +KQLZ k q l z +KQMO k q m o +KQRS- k q r s +KQV k q v +KQXR k q x r +KRBM k r b m +krc k r c +KRCR k r c r +KRCs k r c's +KRF k r f +KRH k r h +K.R.I.T. k r i t +K.R.I.T.'s k r i t's +Krka k r k a +KRKC k r k c +KRK k r k +kr k r +K. R. k r +K.R. k r +KR k r +KRMT k r m t +Krne k r n e +KRNS k r n s +KRNV- k r n v +KRNV k r n v +KROQ- k r o q +KROQ k r o q +kroz k r o z +Kroz k r o z +KRPS k r p s +KRRT k r r t +K. R. S. k r s +KRS- k r s +KRS k r s +KRT k r t +Kru k r u +KRU k r u +KRWC k r w c +KRX k r x +K.R.Y. k r y +KRZA k r z a +ksa k s a +KSA k s a +K. S. B. k s b +KSBW- k s b w +KSBW k s b w +KSBY k s b y +KSCB k s c b +KSC k s c +KSCO k s c o +KSC's k s c's +KSCS k s c s +KSDB k s d b +KSD- k s d +KSDO k s d o +KSEB k s e b +KSEG k s e g +KSE k s e +KSEQ k s e q +kset k s e t +KSET k s e t +Kseur k s e u r +Ksevt k s e v t +KSFO k s f o +KSG k s g +KSHB k s h b +KSI's k s i's +KSJR k s j r +KSKJ k s k j +KSKK k s k k +K.S.K. k s k +KSK k s k +ks k s +K. S. k s +K.S. k s +KS k s +KSLA- k s l a +KSLC k s l c +KSL k s l +KSLM k s l m +KSLU k s l u +KSMB k s m b +KSNB- k s n b +KSNR k s n r +KSNV k s n v +KSP k s p +KSPS k s p s +KSTE k s t e +KSTH k s t h +KST k s t +KSTP- k s t p +KSTP k s t p +KSTV- k s t v +KSU- k s u +KSU k s u +K.S.V. k s v +KSWD k s w d +KSWT k s w t +KSWW- k s w w +KSWW k s w w +KSYL k s y l +KSZE- k s z e +KSZR k s z r +KTAC- k t a c +Ktav k t a v +KTAV k t a v +KTBS k t b s +KTCC k t c c +KTC k t c +KTCZ k t c z +KTDA k t d a +KTDD k t d d +KTE k t e +KTFA- k t f a +KTH k t h +KTHV- k t h v +KT&K k t and k +kt k t +K. T. k t +K.T. k t +KT- k t +KT k t +KTKZ k t k z +KTLA k t l a +K. T. M. k t m +KTM k t m +KTMS- k t m s +KTNE- k t n e +KTN k t n +KTOK k t o k +KTO k t o +KTRE k t r e +KTRH k t r h +KTRK k t r k +KTR k t r +KT's k t's +KTSM k t s m +KTT k t t +KTTN k t t n +KTTV k t t v +KTU k t u +KTUL- k t u l +KTUM k t u m +KTUU- k t u u +KTVA k t v a +KTVK k t v k +KTVS k t v s +KTVT k t v t +KTVU k t v u +KTVZ k t v z +KTWD's k t w d's +KTWN- k t w n +KTWO k t w o +KTXC- k t x c +KTX k t x +KTXL k t x l +KTXS- k t x s +KTZR- k t z r +Kuaa k u a a +Kud k u d +KUFM k u f m +KUGB k u g b +kuih k u i h +K. U. k u +K.U. k u +Kutb k u t b +KUTV k u t v +KUUU k u u u +KUWL k u w l +KUYI k u y i +KVAB k v a b +KVBC k v b c +KVB k v b +K.V.G.K. k v g k +KVHV k v h v +Kvik k v i k +KVI k v i +Kvit k v i t +KVIT k v i t +KVK k v k +K. V. k v +K.V. k v +KVLO k v l o +KVLY- k v l y +KVLY k v l y +KVM k v m +KVMRT k v m r t +KVMX k v m x +KVNG k v n g +KVN k v n +KVP k v p +KVTV k v t v +KVVS's k v v s's +KVVV k v v v +Kvyat k v y a t +KVZ k v z +kwa k w a +KWBM k w b m +KWC k w c +KWD k w d +KWEI k w e i +kwe k w e +KWG k w g +KWJJ k w j j +KWKH k w k h +KWKW k w k w +KWMR k w m r +KWMT k w m t +KWNA k w n a +KWNK k w n k +KWOA k w o a +KWP k w p +KWPT k w p t +KWQC k w q c +KWRE k w r e +KWRU k w r u +KWSB k w s b +KWSX k w s x +KWU k w u +KWVE- k w v e +KWWL's k w w l's +KXAL- k x a l +KXAN k x a n +KXAS k x a s +KXHD- k x h d +KXI k x i +KXJB- k x j b +KXJB k x j b +KXKS k x k s +KXKW- k x k w +KX k x +KXLX k x l x +KXLY k x l y +KXMC k x m c +KXNA k x n a +KXOL's k x o l's +KXTA k x t a +KXTN k x t n +KXTX k x t x +KYAY k y a y +KYBE k y b e +KYEZ k y e z +KYLX- k y l x +KYNM k y n m +Kyse k y s e +KYSL k y s l +KYTC k y t c +kyt k y t +Kyt k y t +KYW- k y w +KYW k y w +kz k z +K. Z. k z +KZ k z +KZLZ k z l z +KZM- k z m +KZMP k z m p +KZMU k z m u +KZQX k z q x +KZZQ k z z q +L. A. G. l a g +L. A. l a +L.A.'s l a's +Lay's l a y's +L.B.A. l b a +LBA l b a +LBCC l b c c +LBC l b c +LBC's l b c's +LBE- l b e +LBE l b e +LBF l b f +LBi l b i +LBJ l b j +LBJ's l b j's +L. B. l b +L.B. l b +LB l b +LBL l b l +LBM l b m +LBN l b n +LBNL l b n l +LBP l b p +LBPs l b p's +LBR l b r +LBS l b s +LBV l b v +LBW l b w +LCAC l c a c +LCA l c a +LCAs l c a's +LCAS l c a s +L.C.B. l c b +LCBL l c b l +LCBM l c b m +lcc l c c +LCC l c c +LCCN l c c n +LCCs l c c's +LCCS l c c s +LCDB l c d b +LCD- l c d +LCD l c d +LCDP l c d p +LC&DR l c and d r +LCDR l c d r +LCDs l c d's +L.C.E. l c e +LCFC l c f c +LCF l c f +LCH l c h +LCI l c i +LCIs l c i's +L. C. l c +L.C. l c +LC- l c +LC l c +LCL l c l +LCMC l c m c +LCM l c m +LCMR l c m r +LCMV l c m v +lcn l c n +LCO l c o +LCP l c p +LCQ l c q +LCR l c r +LCSB l c s b +LCSC l c s c +LC's l c's +LCS- l c s +LCS l c s +LCSs l c s's +LCST l c s t +LCT- l c t +LCT l c t +LCTs l c t's +LCU l c u +LCV l c v +LCVP l c v p +LCVPs l c v p's +LCZ l c z +Lda l d a +LDA l d a +LDAP l d a p +LDB l d b +LDBV l d b v +L.D.C. l d c +LDC l d c +LDCM l d c m +LDCs l d c's +LDD l d d +LDDP l d d p +LDF l d f +LDH l d h +L.D.I. l d i +LDK l d k +L. D. l d +L.D. l d +LDL- l d l +LDL l d l +LDLR l d l r +LDM l d m +LDMR l d m r +LDN l d n +LDP l d p +LDS l d s +LDU l d u +LDV l d v +LEB l e b +L. E. l e +L.E. l e +LFA- l f a +LFA l f a +L.F.C. l f c +LFC l f c +L.F.D. l f d +LFE l f e +LFFCs l f f c's +LFF l f f +LFG l f g +LFHC l f h c +LFH l f h +L. F. l f +L.F. l f +LFL l f l +LFM l f m +LFOC l f o c +LFO l f o +LFOM l f o m +LFPB l f p b +LFP l f p +LFQD l f q d +LFRJ l f r j +LFR l f r +LFs l f's +LFS l f s +LFSRs l f s r's +LFTR l f t r +LFXA l f x a +LGA l g a +LGB l g b +LGBTI l g b t i +LGBT- l g b t +LGBT l g b t +LGBTQ l g b t q +LGC l g c +LGD- l g d +LGD l g d +LGI l g i +L. G. l g +L.G. l g +LG- l g +LG l g +LGMB l g m b +LGM- l g m +LGMs l g m's +LGN l g n +LGPL l g p l +LGPZ l g p z +LG&RDD l g and r d d +LGR l g r +LGs l g's +LGS l g s +LGTB l g t b +LGT's l g t's +LGU l g u +LGUs l g u's +LGV l g v +LGVs l g v's +Lha l h a +LHB l h b +L. H. C. l h c +LHC l h c +LHD l h d +LHFP l h f p +LHICE l h i c e +LHI l h i +L. H. l h +L.H. l h +LHMC l h m c +L.H.M. l h m +LHO l h o +L. H. P. l h p +LHP l h p +LHS l h s +LHW l h w +LHX l h x +LHY l h y +Li- l i +L. I. l i +L.I. l i +LJBL l j b l +Lje l j e +LJJ l j j +L. J. K. l j k +L. J. l j +L.J. l j +L.J.V. l j v +LKB l k b +LKG l k g +LKK l k k +L. K. l k +LK l k +LKL l k l +LKML l k m l +LKPR l k p r +LKRN l k r n +lks l k s +LKS l k s +LKTI l k t i +Llapi l l a p i +LLAW l l a w +L.L.B. l l b +LLB l l b +LLCC l l c c +L.L.C. l l c +LLC- l l c +LLC l l c +LLD l l d +lle l l e +LLE l l e +LLHS l l h s +lli l l i +LLI l l i +L&L l and l +LLLE l l l e +L. L. l l +L.L. l l +LL l l +LLL- l l l +LLL l l l +LLLP l l l p +LLM l l m +LLMNR l l m n r +LLPFX l l p f x +llp l l p +LLP l l p +LLPX l l p x +LLRW l l r w +LLT l l t +LLTV l l t v +llu l l u +LLVM l l v m +LLWS l l w s +LMA l m a +LMC l m c +LMCT l m c t +LMDB l m d b +LMDC l m d c +LMD l m d +LME l m e +LMFAO's l m f a o's +LMFF l m f f +LMG l m g +LMGs l m g's +LMGTE l m g t e +LMH l m h +LMHS l m h s +lm l m +L. M. l m +L.M. l m +LM- l m +LM l m +LMM l m m +LMP l m p +LMPs l m p's +LMQ l m q +LMQs l m q's +L.M.S. l m s +LMS l m s +LMT l m t +LMTP l m t p +LMU l m u +LMWH l m w h +LMX l m x +LnAIB l n a i b +LNA l n a +LNAV l n a v +LNBF l n b f +LNB l n b +L.N.C. l n c +LNCS l n c s +L.N.E.R. l n e r +LNER l n e r +LNFS l n f s +LNG l n g +LNH l n h +L&N l and n +L. N. l n +L.N. l n +L.O.C.'s l o c's +Lokk l o k k +l'OL l o l +L.O.L. l o l +L. O. l o +L.O. l o +L.O.V.E. l o v e +L.O.V. l o v +LOXL l o x l +LPA l p a +L.P.A.M. l p a m +LPAM l p a m +LPARs l p a r's +LPAVS l p a v s +LPBG l p b g +L.P.B. l p b +LPB l p b +LPC l p c +LPCM l p c m +LPDA l p d a +LPDR l p d r +LPE l p e +LPF l p f +LPFM l p f m +LPGA l p g a +LPG l p g +L.P.H. l p h +LPH- l p h +LPH l p h +LPI l p i +LPK- l p k +LPLA l p l a +L&P l and p +LPL- l p l +LPL l p l +lp l p +L. P. l p +L.P. l p +LP- l p +LP, l p +LP l p +L&PM l and p m +LPMN l p m n +LPMud l p m u d +LPMUD l p m u d +LPN l p n +LPO l p o +LPRP l p r p +LPSC l p s c +LP's l p's +LPs l p's +LPS l p s +LPSN l p s n +LPTB l p t b +LPThe l p t h e +LPTV l p t v +LQ l q +LRAD l r a d +LRA l r a +LRCD l r c d +LRC l r c +L.R.C.P. l r c p +LRCP l r c p +LRDG l r d g +LRG- l r g +LRG l r g +lr l r +L. R. l r +L.R. l r +LR l r +LRO l r o +L.R.P.C. l r p c +LRP l r p +LRPPRC l r p p r c +LRRI l r r i +LRRP l r r p +LRS l r s +LRTA l r t a +LRT- l r t +LRT l r t +LRTR l r t r +LRTs l r t's +LRVs l r v's +LRY l r y +LSAC l s a c +LSA l s a +LSBC l s b c +LSB l s b +LSC- l s c +LSC l s c +LSCS l s c s +LSDHH l s d h h +L.S.D. l s d +LSD- l s d +LSD l s d +LSDP l s d p +LSDs l s d's +LSE l s e +LSF l s f +LSG l s g +LSH l s h +LSi l s i +LSI- l s i +LSI l s i +LSJ l s j +LSK l s k +L.S.L. l s l +ls l s +Ls l's +L. S. l s +L.S. l s +LSM l s m +LSO l s o +LSP l s p +LSPN l s p n +LSQC l s q c +LSRI l s r i +L. S. R. l s r +LSS l s s +LSSP l s s p +LSSR l s s r +LST- l s t +LST l s t +LSTM l s t m +LSTs l s t's +LSUA l s u a +LSU l s u +LSU's l s u's +LSVCCs l s v c c's +LSV l s v +LSWR l s w r +LTAF l t a f +L. T. B. l t b +LTB l t b +LTBP- l t b p +LTCF l t c f +LTCI l t c i +L. T. C. l t c +L.T.C. l t c +LTC l t c +Ltda l t d a +LTDA l t d a +Ltd. limited +LTE- l t e +LTE l t e +LTFA l t f a +LTHS l t h s +LTI l t i +LTK l t k +L&T l and t +Lt. lieutenant +LTL l t l +lt l t +L. T. l t +L.T. l t +L.T.M. l t m +LTM l t m +LTMPS l t m p s +LTN l t n +ltoh l t o h +LTP l t p +LTRPC l t r p c +LTTE l t t e +LTTR l t t r +LTU l t u +LTV l t v +L. U. l u +lv l v +L. V. l v +L.V. l v +LV- l v +LV l v +LVMH l v m h +LWDB l w d b +LWD l w d +LWDS l w d s +LWE l w e +LWF l w f +LWH l w h +L. W. l w +L.W. l w +L.Y. l y +L&YR l and y r +M.A.D.E. m a d e +M.A.D. m a d +M.A.J. m a j +M.A.K. m a k +M. A. m a +M.A. m a +M&A m and a +M. A. O. m a o +M.A.O. m a o +M.A.R. m a r +M.A.S.K. m a s k +M.A.S. m a s +M.A.S.S. m a s s +M.B.A. m b a +M.B.B.S. m b b s +MBBS m b b s +MBC- m b c +MBC m b c +MBC's m b c's +MBDA m b d a +MBD m b d +M.B. D.P.M. m b d p m +M.B.E. m b e +MBE m b e +Mbewu m b e w u +MBF m b f +MBFW m b f w +MBGN m b g n +MBH- m b h +MBH m b h +mbi m b i +MBI m b i +M. B. J. m b j +MBJ m b j +MBK m b k +MBL m b l +M. B. m b +M.B. m b +MBM m b m +MBNA m b n a +mBo m b o +MBO m b o +MBPJ m b p j +MBP m b p +Mbre m b r e +mbr m b r +MBR m b r +MBSE m b s e +MBSI m b s i +MBS- m b s +MBS m b s +MBTI m b t i +MBT- m b t +MBT m b t +MBU's m b u's +MBX m b x +MCAF m c a f +MCAL m c a l +M.C.A. m c a +MCA- m c a +MCA m c a +MCA's m c a's +MCAS m c a s +MCB- m c b +MCB m c b +M. C. C. m c c +M.C.C. m c c +MCC m c c +MCC's m c c's +MCCs m c c's +MCCU m c c u +MCDA m c d a +MCDC m c d c +MCD m c d +MCDM m c d m +MCE m c e +MCFA m c f a +M. C. F. m c f +MCF m c f +MCFM m c f m +MCGJCW m c g j c w +MCG m c g +MCI m c i +MCJ m c j +MCLA m c l a +Mcl- m c l +MCL m c l +M. C. m c +M.C. m c +MCMC m c m c +M. C. M. m c m +MCM m c m +MCN m c n +MCO m c o +MCOT's m c o t's +MCPC m c p c +MCPI m c p i +MCP- m c p +MCP m c p +MCPON m c p o n +MCPP m c p p +MCQ m c q +MCRD m c r d +MCR m c r +MCRP m c r p +MCSBA m c s b a +MCs m c's +M.C. S. m c s +MCS- m c s +MCS m c s +MCST m c s t +MCTFS m c t f s +MCT m c t +MCTU m c t u +MCTV m c t v +MCU m c u +MCV m c v +MCVTS m c v t s +MCW m c w +mcyG m c y g +MCYO m c y o +MCZ m c z +MDAA m d a a +MDAH m d a h +mda- m d a +MDA m d a +mdb m d b +MDB m d b +MDC- m d c +MDC m d c +MDC's m d c's +MDCs m d c's +MDCT m d c t +mdDA m d d a +MD&DI m d and d i +Mde m d e +MDE m d e +MDF m d f +MDG m d g +MDGs m d g's +MDH m d h +MDHUs m d h u's +mDia m d i a +MDIB m d i b +MDic m d i c +MDI m d i +MDJT's m d j t's +MDK m d k +mdla m d l a +MDL m d l +MDMA- m d m a +MDMA m d m a +md m d +M. D. m d +M.D. m d +MD- m d +MD m d +MDM m d m +MDNA m d n a +M.D.N. m d n +MDPD's m d p d's +MDP m d p +MDPPP m d p p p +MDPS m d p s +MDPV m d p v +MDQ m d q +MDRC m d r c +mdr m d r +MDR- m d r +MDR m d r +MDT m d t +MDV m d v +MDX m d x +M. E. m e +M.E. m e +M.E.N. m e n +M. E. P. m e p +M.F.A. m f a +MFA m f a +MFB m f b +MFCC m f c c +MFC m f c +MFCS m f c s +MFD m f d +MFDs m f d's +MFe m f e +MFF m f f +MFG m f g +MFI m f i +MFJ m f j +MFK m f k +M. F. m f +M.F. m f +MFMF m f m f +MFM m f m +MFN m f n +MFNW m f n w +MFP m f p +MFR m f r +MFS m f s +MFS's m f s's +MFTBC m f t b c +MFT m f t +MFTs m f t's +Mgadla m g a d l a +Mgal m g a l +mga m g a +Mga m g a +MGA m g a +MGB m g b +Mgbo m g b o +MGCCC m g c c c +MGC m g c +MGE m g e +MGen m g e n +MGG m g g +MGH m g h +MGIMO m g i m o +MGIT m g i t +MGJH m g j h +MGK m g k +M.G.L. m g l +M&G m and g +M. G. m g +M.G. m g +M. G. M. m g m +MGM- m g m +MGM m g m +MGM's m g m's +MGMT m g m t +M&GN m and g n +MGN m g n +MGO m g o +MGP m g p +M&GR's m and g r's +Mha m h a +M.H.A. m h a +MHA m h a +MHB's m h b's +MHC- m h c +MHC m h c +MHCs m h c's +MHD m h d +MHI m h i +MHK m h k +MH&L m h and l +MHL m h l +M&H m and h +M. H. m h +M.H. m h +Mhor m h o r +Mhow m h o w +MHPL m h p l +M.H.P. m h p +MHP m h p +MHP's m h p's +MHRA m h r a +M. H. R. m h r +MHSA m h s a +MHSC m h s c +MHS m h s +MHT m h t +M.I.A. m i a +M.I.A.'s m i a's +M.I.C.M. m i c m +M.I.H. m i h +M&I m and i +M. I. m i +M.I. m i +M.I.N. m i n +M.I.R.V. m i r v +M.I.S. m i s +M.I.T. m i t +MJAHL's m j a h l's +M.J.A. m j a +MJA m j a +MJBHA m j b h a +MJB m j b +MJC m j c +M.J.F. m j f +MJF m j f +MJG m j g +MJHL m j h l +MJHL's m j h l's +M&J m and j +M. J. m j +M.J. m j +M. J. Y. m j y +MKBHD m k b h d +MKB m k b +MKDE m k d e +MKE m k e +MKF- m k f +MKFM m k f m +MKG m k g +MKK m k k +MKMF m k m f +M. K. m k +M.K. m k +MKNG m k n g +MKP m k p +MKRN m k r n +MKs m k's +MKS- m k s +MKS m k s +MKT m k t +MKTO m k t o +MKTV m k t v +MKZ's m k z's +M.L.A. m l a +MLA m l a +MLANA m l a n a +MLAs m l a's +MLB- m l b +MLB m l b +MLBPA m l b p a +MLCA m l c a +mlc m l c +M.L.C. m l c +MLC m l c +MLCs m l c's +MLD m l d +MLE m l e +MLF m l f +mlg m l g +MLG m l g +MLH m l h +MLIA m l i a +mli m l i +MLI m l i +MLIM m l i m +MLK m l k +MLK's m l k's +Mlle m l l e +MLL m l l +MLLT m l l t +M&L m and l +M. L. m l +M.L. m l +MLM m l m +MLND m l n d +M.L.N. m l n +MLN m l n +MLPH m l p h +MLP m l p +MLPs m l p's +M. L. R. m l r +MLR m l r +MLSE m l s e +M. L. S. m l s +M.L.S. m l s +MLS m l s +MLT m l t +MLW- m l w +MLW m l w +MLWS m l w s +MM&A m m and a +M. M. J. m m j +MMK m m k +MML m m l +M&M m and m +M. M. m m +M.M. m m +MMSA m m s a +M&M's m and m's +M. M. S. m m s +MMS- m m s +MMS m m s +MMST m m s t +MMTB's m m t b's +MMTS m m t s +MMTV m m t v +MMWR m m w r +MMX m m x +MNA m n a +MNBA m n b a +MNC m n c +MNCPPC m n c p p c +MNCs m n c's +MNDM m n d m +MND- m n d +MNDNR m n d n r +MNDO m n d o +MNDR m n d r +M&NF m and n f +MNF- m n f +MNF m n f +MNG m n g +MNI- m n i +MNI m n i +MNLA m n l a +MNLA's m n l a's +MNLF m n l f +MNM m n m +M. N. m n +M.N. m n +MNNA m n n a +MNN m n n +MNP m n p +MNPP m n p p +MNRG m n r g +MNSD m n s d +MNS m n s +MNTC m n t c +mnt m n t +MNT m n t +MNZM m n z m +MNZ m n z +MOBKL m o b k l +MOBK m o b k +M.O.B. m o b +M.O.D. m o d +M.O.D.O.K. m o d o k +M.O.G.U.E.R.A.'s m o g u e r a's +M. O. H. m o h +M. O. m o +M.O. m o +M.O.P. m o p +M.O.R. m o r +M.O.T. m o t +MPAA m p a a +MpA m p a +MPA m p a +MPAs m p a's +MPB m p b +MPBN m p b n +MPBu m p b u +MPCA m p c a +MPCI m p c i +MPC- m p c +MPC m p c +MPD m p d +MPE m p e +MPF m p f +MPG m p g +M.P.H. m p h +MPH m p h +MP&I m p and i +MPi m p i +MPI m p i +MPIO m p i o +MPKAB m p k a b +MPLAD m p l a d +MPLA m p l a +MPL m p l +MPLMs m p l m's +MPLR m p l r +MPLS m p l s +M&P m and p +MPM m p m +M. P. m p +M.P. m p +MPO m p o +MPPJ m p p j +M.P.P. m p p +MPP m p p +MPPSC m p p s c +MPPs m p p's +MPQC m p q c +MPR m p r +MPRO m p r o +MPRP m p r p +MPRS m p r s +MPSE m p s e +MPSF m p s f +M.P.'s m p's +MP's m p's +MPs m p's +MPS- m p s +MPS m p s +MPThe m p t h e +MPT m p t +MPTP- m p t p +Mpu m p u +MPU m p u +MPV m p v +MPW m p w +MPZ m p z +MQM m q m +M. Q. m q +Mra m r a +MRA m r a +M. R. B. m r b +MRB m r b +MRBs m r b's +MRCB m r c b +MRCK m r c k +MRCM m r c m +MRC- m r c +MRC m r c +M.R.C.S. m r c s +MRCS m r c s +MRDC m r d c +MRD m r d +mre m r e +MRF m r f +MR&LE m r and l e +MRL m r l +Mr. mister +MRM m r m +M. R. m r +M.R. m r +mRNA m r n a +mRNAs m r n a's +MRPGM m r p g m +MRP m r p +MRPS m r p s +MRR m r r +MRSA m r s a +M.R.S.C. m r s c +Mrs. misses +MRSM m r s m +MRT m r t +MRTs m r t's +MRTS m r t s +MRTT m r t t +MRU- m r u +MRU m r u +MSAA m s a a +MSAC m s a c +MSAD m s a d +MSA m s a +M.S.A.S. m s a s +MSAW m s a w +MSB m s b +MSBO m s b o +MSBSD m s b s d +MSBS- m s b s +MSCC m s c c +M.S.C. m s c +MSC- m s c +MSC m s c +msd m s d +MSD m s d +MSDN m s d n +MSDS m s d s +Mse m s e +MSFC m s f c +M.S.F. m s f +MSF m s f +MSFT m s f t +MSG m s g +MSI m s i +MSJ m s j +MSK m s k +MSL m s l +M&S m and s +Ms. miss +MSML m s m l +M.S.M. m s m +MSM m s m +M. S. m s +M.S. m s +MSNBC m s n b c +MSNBC's m s n b c's +MSN m s n +MSOB m s o b +MSOM m s o m +M.S.P. m s p +MSP m s p +MSPs m s p's +MSR m s r +MSRP m s r p +MSRTC m s r t c +MSSH m s s h +MSSK m s s k +MSSMLP m s s m l p +MSSM m s s m +MSS m s s +MSTA m s t a +mst m s t +MST m s t +MSTS m s t s +MSU's m s u's +MSVCC m s v c c +MSV m s v +MSVU m s v u +MSX m s x +MSY m s y +MSZ- m s z +MSZP m s z p +MTAC m t a c +Mta m t a +M.T.A. m t a +MTA- m t a +MTA m t a +MTA's m t a's +MTAs m t a's +MTBE m t b e +MTBI m t b i +MTB- m t b +MTB m t b +MTC m t c +MTDB m t d b +M.T.D. m t d +MTD m t d +MTD's m t d's +MTG m t g +MTHFR m t h f r +MTHL m t h l +MTIC m t i c +MTI m t i +MTIP- m t i p +MTJ m t j +MTK m t k +MTKO m t k o +M&T m and t +MTM m t m +MTMR m t m r +M. T. m t +M.T. m t +Mtor m t o r +MTOSI m t o s i +M.T.O.W. m t o w +MTPA m t p a +MTPC m t p c +MTP m t p +MTQ m t q +MTRCB m t r c b +MTRC m t r c +MTRJ m t r j +MTR- m t r +MTR m t r +M. T. S. m t s +MTS- m t s +MTS m t s +MTSU m t s u +MTTM m t t m +MTT m t t +MTU m t u +MTV- m t v +MTV m t v +MTVR m t v r +MTV's m t v's +mtvU m t v u +MTVu m t v u +MTVU m t v u +MTY m t y +MTZ- m t z +MTZ m t z +MUKW m u k w +M. U. m u +MUSL m u s l +M.U.s m u's +M. U.S. m u s +MVA m v a +M. V. C. m v c +M.V.C. m v c +MVC m v c +M. V. D. m v d +MVD m v d +MVH m v h +MVK m v k +MVL- m v l +M.V.M. m v m +MVM m v m +MVMs m v m's +M. V. m v +M.V. m v +M.V.O. m v o +MVO m v o +MVP- m v p +MVP m v p +MVPs m v p's +MVPS m v p s +M.V. P.T. m v p t +MVs m v's +MVS m v s +MVSN m v s n +MVSR m v s r +MVT m v t +MVV m v v +M.W.A.M. m w a m +MWA m w a +MWC m w c +MWe m w e +M. W. E. m w e +MWF m w f +MWHL m w h l +MWIFF m w i f f +MWI m w i +MWJCHL m w j c h l +MWJHL m w j h l +M. W. J. m w j +M. W. m w +M.W. m w +M. X. m x +myb m y b +myc m y c +Myc m y c +MYC m y c +MYCN- m y c n +MYCN m y c n +MyDD m y d d +M. Y. m y +M.Y. m y +MySQL m y s q l +MYSQL m y s q l +MZC m z c +MZH m z h +MZM m z m +M. Z. m z +MZP m z p +MZT m z t +NAACCR n a a c c r +NAACL n a a c l +NAAC n a a c +N.A.A.C.P. n a a c p +NAACP n a a c p +NAACP's n a a c p's +N.A.C.L. n a c l +NAFBL n a f b l +NAFC n a f c +NAFC's n a f c's +NAFH n a f h +NAFI n a f i +N. A. n a +N.A. n a +N.A.S.A. n a s a +NBADL n b a d l +N.B.A. n b a +NBA- n b a +NBA n b a +N.B.A.'s n b a's +NBA's n b a's +NBAs n b a's +NBCC n b c c +NBC- n b c +NBC n b c +NBC's n b c's +NBCSN n b c s n +NBDL n b d l +NBD n b d +NBFA's n b f a's +NBF n b f +NBG n b g +NBI n b i +NBK n b k +NBL n b l +N. B. n b +N.B. n b +N.B.N. n b n +NBN n b n +NBP n b p +NBQ n b q +NBR n b r +NBR's n b r's +NBSK n b s k +nbs n b s +NBS n b s +NBSP n b s p +NBTE n b t e +NBT n b t +NBTwo n b t w o +NBTY n b t y +NBW n b w +NCAAs n c a a's +NCAM n c a m +NCA- n c a +NCA n c a +NCAP n c a p +NCBC n c b c +NCBI- n c b i +NCBI n c b i +NCCC n c c c +NCCF n c c f +NCCMH n c c m h +NCC n c c +NCCP n c c p +NCCs n c c's +NCCS n c c s +NCCU n c c u +NCDC n c d c +NCDD's n c d d's +NCD n c d +NCES n c e s +NCFA n c f a +N.C.F. n c f +NCF n c f +NCG n c g +NCGS n c g s +NCHC n c h c +NCH n c h +NCHU n c h u +NCID n c i d +NCI n c i +NCIS n c i s +NCIS's n c i s's +NCKU n c k u +NCLB n c l b +NCLC n c l c +NCL n c l +NCLR n c l r +NCLT n c l t +NCMA n c m a +NCMC n c m c +NCMM n c m m +NCM n c m +NCMP n c m p +NCNB n c n b +N. C. n c +N.C. n c +N.C.O. n c o +NCO n c o +NCO's n c o's +NCOs n c o's +NCPA n c p a +NCPC n c p c +NCP n c p +NCPO n c p o +NCRC n c r c +NCR n c r +NCSU n c s u +NCSY n c s y +NCTA n c t a +NCTC n c t c +NCTE n c t e +NCT n c t +NCUA n c u a +NCVO n c v o +NCVS n c v s +NCVT n c v t +NCWM n c w m +NCW n c w +NDA n d a +NDE n d e +NDEP n d e p +NDFB n d f b +NDFT n d f t +N.D.G. n d g +N. D. n d +N.D. n d +N.D.N.Y. n d n y +NDPH n d p h +NDPK n d p k +N.D.P. n d p +NDP- n d p +NDP n d p +NDP's n d p's +NDRC n d r c +NDRE n d r e +NDRF n d r f +N.E.A.R. n e a r +NECW n e c w +N. E. n e +N.E. n e +N.E.R.D. n e r d +NERFU n e r f u +ner n e r +N.E.R. n e r +NER n e r +N.E.W.S.T. n e w s t +NFA n f a +NFATc n f a t c +NFAT n f a t +NFB n f b +NFB's n f b's +NFC n f c +NFC's n f c's +NFD n f d +NFEA n f e a +nfed n f e d +NFFC n f f c +NFF n f f +NFH n f h +NFHS n f h s +NFIB n f i b +NFI n f i +NFISD n f i s d +N.F.L. n f l +NFL n f l +NFLPA n f l p a +NFL's n f l's +N. F. n f +N.F. n f +NFO n f o +NFPA n f p a +NFPF n f p f +NFP n f p +NFPW n f p w +NFRS n f r s +NFS n f s +NGC n g c +Nge n g e +NGF- n g f +NGF n g f +N.G.L. n g l +N. G. n g +N.G. n g +NGO n g o +NGO's n g o's +NGOs n g o's +NGRC n g r c +N.G.R. n g r +NGR n g r +NGRR n g r r +NGS- n g s +NGS n g s +NGSS n g s s +NGST n g s t +NGTC n g t c +Nha n h a +NHA n h a +NHCEs n h c e's +NHC n h c +NHCP n h c p +NHCs n h c's +NHD n h d +NHHD n h h d +NHHI n h h i +nhi n h i +NHI n h i +NHK n h k +NHK's n h k's +N.H.L. n h l +NHM&W n h m and w +N. H. n h +N.H. n h +NHP n h p +NHPs n h p's +NHPS n h p s +NHRA n h r a +NHRC n h r c +NHSCT n h s c t +NHS- n h s +NHS n h s +NHST n h s t +NHW n h w +N.I.B.B.L.E. n i b b l e +NIBC n i b c +NIBR n i b r +N. I. n i +N.I. n i +N'I n i +N.J.A.C. n j a c +N. J. A. n j a +NJA n j a +N. J. C. n j c +NJC n j c +NJIT n j i t +N. J. M. n j m +NJM n j m +N. J. n j +N.J. n j +NJN n j n +Njoo n j o o +NJPS n j p s +NJPW n j p w +N.J.S.A. n j s a +N.J.'s n j's +NKL n k l +N. K. n k +N.K. n k +N. K. N. n k n +NKP n k p +NKP's n k p's +NKR n k r +NKT n k t +NKU n k u +nkvd n k v d +NKVD n k v d +NKVM n k v m +nkv n k v +NKX n k x +NLAES n l a e s +NLAI n l a i +NLA n l a +NLB n l b +NLCF n l c f +NLC n l c +NLCS n l c s +NLDC n l d c +NLD n l d +NLD's n l d's +NLDS n l d s +N. L. n l +N.L. n l +NLP n l p +NLRB n l r b +NLRP n l r p +NLRs n l r's +NLW n l w +NLX n l x +NMAA n m a a +NMA n m a +NMBS n m b s +NMBU n m b u +NMCA n m c a +NMCB n m c b +NMC n m c +N. M. n m +N.M. n m +NMP n m p +NMR n m r +NMRW n m r w +NMT n m t +NMU n m u +NMV n m v +NMW n m w +NNCL n n c l +NNFL n n f l +NNF n n f +N. N. n n +N.N. n n +NNSA n n s a +NNSS n n s s +NNSU n n s u +NNSW n n s w +NNW- n n w +No. number +N.O.R. n o r +NPA- n p a +NPA n p a +NPBD n p b d +NPBL n p b l +NPB n p b +NPC n p c +NPCs n p c's +NPDC n p d c +NPD n p d +NPF- n p f +NPF n p f +NPF's n p f's +NPGL n p g l +NPG n p g +NPGS n p g s +NPH n p h +NPHS n p h s +NPIM n p i m +NPI n p i +NPJ n p j +NPK n p k +NPL n p l +NPMA n p m a +NPM n p m +NPMs n p m's +N. P. n p +N.P. n p +NP- n p +NP n p +NPO n p o +NPP n p p +NPP's n p p's +NPRL n p r l +NPRN n p r n +NPR- n p r +NPR n p r +NPRR n p r r +NPR's n p r's +NPRSO n p r s o +NPSC n p s c +NPSG n p s g +NPSL n p s l +NP's n p's +NPs n p's +NPS n p s +NPTI n p t i +NPT n p t +NPV n p v +NPWE n p w e +NPWS n p w s +NPY n p y +NQAI n q a i +NQEA n q e a +NQHS n q h s +N. Q. n q +nri n r i +Nri n r i +NRI n r i +NRIs n r i's +NRJ n r j +NRJs n r j's +NRK n r k +NRLA n r l a +NRL n r l +NRL's n r l's +NRMA n r m a +NRM n r m +NRN n r n +nr n r +N. R. n r +N.R. n r +NSA- n s a +NSA n s a +NSAP n s a p +NSA's n s a's +NSB- n s b +NSB n s b +NSC- n s c +NSC n s c +NSD n s d +NSE n s e +NSFE n s f e +NSF n s f +NSFW n s f w +NSG n s g +NSI n s i +NSL n s l +NSM n s m +NSN n s n +N. S. n s +N.S. n s +NSO n s o +NSOs n s o's +NSPCC n s p c c +NSPC n s p c +NSP n s p +NSRI n s r i +NSRL n s r l +NSR n s r +NSSCD n s s c d +NSSDC n s s d c +NSS- n s s +NSS n s s +NSTA n s t a +NST n s t +NSU n s u +NSV n s v +NSVT n s v t +NSWBLF n s w b l f +NSWC- n s w c +NSWC n s w c +NSWCV n s w c v +NSWEC n s w e c +NSWGR n s w g r +N.S.W. n s w +NSW- n s w +NSW n s w +Nta n t a +NTA n t a +NTA's n t a's +ntb n t b +NTB n t b +NTC n t c +NTD n t d +NTFL n t f l +NTF n t f +NTI n t i +NTKF n t k f +NTL n t l +N. T. n t +N.T. n t +NTRK- n t r k +NTR n t r +NTR's n t r's +NTSB n t s b +NTSB's n t s b's +NTSC n t s c +NTS n t s +NTTF n t t f +NTT n t t +NTTR n t t r +NTUC n t u c +NTU n t u +NTVB n t v b +NTV n t v +ntw n t w +N.U. n u +NVA n v a +NVAO n v a o +NVC n v c +NVDA n v d a +NvDA's n v d a's +NVFC n v f c +NVGOP n v g o p +NVHJ's n v h j's +NVH n v h +NVIDIA's n v i d i a's +NVIDIA n v i d i a +NVI n v i +NVL n v l +N. V. n v +N.V. n v +NWAFU n w a f u +nwa n w a +N.W.A. n w a +NWA- n w a +NWA n w a +NWA's n w a's +N.W.F.P. n w f p +NWFP n w f p +NWMP n w m p +N&W n and w +NWN n w n +N. W. n w +N.W. n w +NWPD n w p d +N.W.P. n w p +NWP n w p +NWS n w s +N.W.T. n w t +NWT n w t +nyc n y c +N.Y.C. n y c +NYC- n y c +NYC n y c +NYC's n y c's +N.Y. G.O.P. n y g o p +N.Y.L. n y l +N. Y. n y +N.Y. n y +N.Y.P.D. n y p d +NYPD n y p d +NYPD's n y p d's +NYPL n y p l +N.Y.P. n y p +NY's n y's +N.Y.S. n y s +N.Y.S.V. n y s v +N.Y.U. n y u +NYU- n y u +NYU n y u +NYU's n y u's +NYW&B- n y w and b +NYYC n y y c +NZAID n z a i d +NZAOD n z a o d +NZCA n z c a +NZDT n z d t +NZEF n z e f +NZETC n z e t c +NZFC n z f c +NZF n z f +N'Zif n z i f +NZiK n z i k +N'Zi n z i +NZIV n z i v +NZL n z l +NZLP n z l p +N.Z. n z +NZPA n z p a +NZR- n z r +NZSAS n z s a s +NZ's n z's +NZS n z s +NZTA n z t a +N.Z.W.P.W. n z w p w +O.A.C. o a c +O. A. o a +O.A. o a +O.A.R. o a r +O.A.S. o a s +O.B.E. o b e +obl o b l +Oblt o b l t +O.B. o b +O. C. o c +O.C. o c +Octl o c t l +O.C.T. o c t +O. D. o d +O.E. o e +O.F.M. o f m +O.F. o f +ofr o f r +O.F.R. o f r +OFR o f r +O.F.T.B. o f t b +OGL o g l +O&G o and g +O. G. o g +O.G. o g +O.G.S. o g s +OGS o g s +O.H.A. o h a +O. H. o h +O.H. o h +OHV o h v +O. I. o i +O.I. o i +O. J. o j +O.J. o j +OJ o j +OJSC o j s c +OKBM o k b m +OKB- o k b +OKB o k b +OKC o k c +OK'd o k d +OKd o k d +OKD o k d +oke o k e +Oke o k e +OKH o k h +O.K.I. o k i +OKK- o k k +OKK o k k +OKM o k m +O&K o and k +O. K. o k +O.K. o k +O.L.F.A.L. o l f a l +O. L. K. o l k +O. L. o l +O.L. o l +Olo o l o +Olov o l o v +OLPC o l p c +OLPH o l p h +ols o l s +OLs o l's +OLS o l s +OLSR o l s r +OLTL o l t l +OLVT o l v t +olvwm o l v w m +olwm o l w m +OMB o m b +OMC o m c +OMCS o m c s +OMD o m d +O&MFL o and m f l +OMF o m f +omg o m g +OMG o m g +OMGs o m g's +O. M. o m +O.M. o m +OmOm o m o m +Om's o m's +OMTP o m t p +OMVG o m v g +OMW o m w +OMX o m x +ONCHR o n c h r +ONC o n c +oncu o n c u +ONDH o n d h +ond o n d +onf o n f +ONF o n f +ONGC o n g c +ONIR o n i r +ONJSC o n j s c +ONM o n m +ONMR o n m r +O. N. o n +O.N. o n +O&O o and o +OOOA o o o a +O. O. o o +O.O. o o +OO o o +OOO's o o o's +Oop o o p +OOP o o p +OOPSLA o o p s l a +oor o o r +oose o o s e +Oo's o o's +OOTP o o t p +Ootw o o t w +OOUR o o u r +OPAC o p a c +OPAG o p a g +O.P.A. o p a +OPBF o p b f +OPB o p b +OPC o p c +OPCS o p c s +OPCW o p c w +OPD- o p d +OPD o p d +O.P.I. o p i +OPIRG o p i r g +OPJHL o p j h l +OPLC o p l c +OPL o p l +OPMB o p m b +OPM o p m +OPMs o p m's +OPN o p n +O. P. o p +O.P. o p +opr o p r +Opr o p r +OPR o p r +O.R.C. o r c +ORECA o r e c a +ORFs o r f's +ORMO o r m o +ORNL o r n l +OR&N o r and n +O. R. o r +osaa o s a a +OSAA o s a a +osa o s a +Osa o s a +O.S.A. o s a +OSA o s a +O.S.B. o s b +OSB o s b +OSBs o s b's +O.S.N. o s n +OSN o s n +O. S. o s +O.S. o s +OSP o s p +OSR o s r +OSTM o s t m +O.S.T. o s t +OSTP o s t p +OSTs o s t's +osv o s v +OSV- o s v +OSV o s v +OTB o t b +OTC o t c +OTJ o t j +OTL o t l +OTMH o t m h +OTO o t o +O.T. o t +OTP o t p +OTR o t r +OTs o t's +OTS- o t s +OTS o t s +Otu o t u +OTU o t u +otv o t v +O.U. o u +OU- o u +OU o u +OUP o u p +OUSA o u s a +OVA's o v a's +ovca o v c a +Ovca o v c a +OVC o v c +OVC's o v c's +Ovda o v d a +OVF o v f +OVM o v m +Ovo o v o +OVO o v o +ov o v +Ov o v +O. V. o v +O.V. o v +OV- o v +OV o v +OVP o v p +OVS o v s +OVT o v t +OVW o v w +O.W.A. o w a +OWBT o w b t +OWCs o w c's +OWGR o w g r +OWHA's o w h a's +OWIU o w i u +OWM o w m +O. W. o w +O.W. o w +P. A. C. p a c +P. A. J. p a j +P.A.J. p a j +P. A. M. p a m +P.A.M. p a m +pa p a +P. A. p a +P.A. p a +PA- p a +PA p a +PAQ p a q +P.A.R. p a r +P. A. S. p a s +PBAA p b a a +PBA- p b a +PBA p b a +PBA's p b a's +PBB p b b +PBCC p b c c +pBCE p b c e +pbc p b c +P.B.C. p b c +PBF p b f +PBG p b g +PBIL p b i l +PBI p b i +PBK p b k +PBL p b l +PBM p b m +PBMR p b m r +PBO p b o +pb p b +pB- p b +P. B. p b +P.B. p b +PB- p b +PB p b +PBP p b p +PBR p b r +PBS p b s +PBT p b t +PBX p b x +PBY- p b y +PBY p b y +P. C. A. p c a +PCA p c a +PCB p c b +PCB's p c b's +PCBs p c b's +PCBS p c b s +PCC- p c c +PCC p c c +PCCS p c c s +PCCW p c c w +PCCW's p c c w's +PCDDs p c d d's +PCDHB p c d h b +PCDH p c d h +PCD p c d +PCE p c e +PCeU p c e u +PCFCL p c f c l +PCFL p c f l +PCF p c f +PCFS p c f s +PCG p c g +PCGS p c g s +PCHA p c h a +PCHA's p c h a's +P.C.H. p c h +PCH p c h +PCHR p c h r +PCIe p c i e +pci p c i +PCI- p c i +PCI p c i +PCJHL p c j h l +P. C. J. p c j +PCJ p c j +PCK p c k +PCLM p c l m +pcl p c l +PCL p c l +PCMCIA p c m c i a +PCMNO p c m n o +PCM p c m +PCMS p c m s +PCNA- p c n a +PCNA p c n a +PCN p c n +PcoA p c o a +PCOE p c o e +PCO p c o +pc p c +P. C. p c +P.C. p c +PC- p c +PC p c +PCPFL p c p f l +PCP p c p +PCPV p c p v +PCRC p c r c +PCRE p c r e +PCRev p c r e v +PCRM p c r m +PCR- p c r +PCR p c r +PCSK p c s k +PCSOM p c s o m +pcs p c s +P.C.s p c's +PC's p c's +PCTL p c t l +PCT p c t +PCTV p c t v +PCU p c u +PCU's p c u's +PCW p c w +PCX p c x +pDAB p d a b +PDAB p d a b +PDA p d a +PDAs p d a's +PDBML p d b m l +PDB p d b +pdbp p d b p +PDBsum p d b s u m +PDCI p d c i +PDC- p d c +PDC p d c +PDCPD p d c p d +PDC's p d c's +PDCs p d c's +PD&D p d and d +PDD- p d d +PDD p d d +PDE p d e +PDEs p d e's +PDES p d e s +pdf p d f +PDF p d f +PDFs p d f's +PDFT p d f t +PDGF- p d g f +PDGF p d g f +PDG p d g +PDHJ p d h j +PDH p d h +PDI- p d i +PDI p d i +PDJ p d j +PDK p d k +PDL p d l +PDN p d n +PDO p d o +P&D p and d +P. D. p d +P.D. p d +PD- p d +PD p d +PDP- p d p +PDP p d p +PDP's p d p's +PDPs p d p's +P. D. Q. p d q +PDR p d r +PDSA p d s a +PDSI p d s i +PD's p d's +PDs p d's +P.D.S. p d s +PDS p d s +PDSP p d s p +PDT p d t +P.E.I. p e i +P.E.I.'s p e i's +P.E.N. p e n +P. E. p e +P.E. p e +P.F.L. p f l +PF's p f's +PFs p f's +PFS p f s +PFU p f u +PFV p f v +PFW&C p f w and c +P.G.A. p g a +PGA p g a +PGM p g m +PGMs p g m's +PG&N p g and n +P&G p and g +P. G. p g +P.G. p g +P.G.T. p g t +PHD p h d +P. H. G. p h g +PHH p h h +PHHS p h h s +PHLF p h l f +Phlo p h l o +PHL p h l +PHN p h n +P&H p and h +P. H. p h +P.H. p h +php p h p +PHP- p h p +PHP p h p +PHPs p h p's +P.I.D.E. p i d e +P&I p and i +P. I. p i +P.I. p i +P. I. W. p i w +Piz p i z +PJB p j b +PJC p j c +PJD p j d +P. J. F. p j f +P.J.K. p j k +pj p j +P. J. p j +P.J. p j +PJ- p j +PJ p j +PJ's p j's +PJs p j's +P.J.T. p j t +P. K. p k +P.K. p k +PK- p k +PK p k +PLCC p l c c +plc p l c +PLC- p l c +PLC p l c +PLC's p l c's +PLCs p l c's +P.L.O. p l o +P. L. p l +P.L. p l +PLP p l p +PLX- p l x +PLX p l x +P. M. A. p m a +PMC- p m c +PMC p m c +PMG p m g +PML- p m l +PML p m l +PMLP p m l p +PMMA p m m a +PMMoV p m m o v +PMM p m m +PMMS p m m s +PMMT p m m t +PMOI p m o i +PMO p m o +PMPC p m p c +PMPF p m p f +pm p m +P. M. p m +P.M. p m +PM- p m +PM p m +PMP p m p +PMP's p m p's +PMRN p m r n +PMRO p m r o +PMR p m r +PMRR p m r r +PMSE p m s e +PMSL p m s l +PMSM p m s m +PM's p m's +PMs p m's +P. M. S. p m s +PMS p m s +PMSSY p m s s y +PMT p m t +PMVY p m v y +PMWA p m w a +PNaCl p n a c l +pna p n a +PNA p n a +Pnau p n a u +pnb p n b +PNB p n b +PNC p n c +PNE p n e +PNE's p n e's +PNEs p n e's +PNETs p n e t's +pneus p n e u s +PNFA p n f a +PNF p n f +PNGIA p n g i a +png p n g +PNG p n g +PNH p n h +PNI p n i +PNL p n l +PNL's p n l's +PNMT p n m t +PNNL p n n l +PNNs p n n's +PNoy p n o y +pn p n +P. N. p n +P.N. p n +PN- p n +PN p n +PNP p n p +P.N.R.A. p n r a +P.O.D. p o d +P.O.D.'s p o d's +P&O p and o +P. O. p o +P.O. p o +P.O.S. p o s +P.O.V. p o v +P.O.W. p o w +P.O.W.'s p o w's +PPACA p p a c a +PPA p p a +PPBS p p b s +PPC p p c +PPD- p p d +PPD p p d +PPE p p e +PPF p p f +PPG p p g +P&PH p and p h +PPH p p h +PPi p p i +P.P.I. p p i +PPI p p i +PPJ p p j +PPKM p p k m +PPK p p k +PPL p p l +PPM p p m +PPNB p p n b +PPN p p n +PPO p p o +P. P. p p +P.P. p p +PPRP p p r p +PPR p p r +PP's p p's +PPS p p s +PPT p p t +PPTV p p t v +PPV p p v +PPVs p p v's +PPy p p y +PQBP- p q b p +PQDT p q d t +PQM- p q m +PQ- p q +PQ p q +PQQ p q q +PQ's p q's +PQS p q s +PRB- p r b +PRB p r b +PRCA p r c a +PRC- p r c +PRC p r c +PRCS p r c s +PRDM p r d m +PRD p r d +PRD's p r d's +P.R.I.M.E. p r i m e +pr p r +P. R. p r +P.R. p r +PR- p r +PR p r +P.S.A. p s a +P.S.C. p s c +P.S.K. p s k +PSP- p s p +PSP p s p +P. s p's +P.'s p's +Ps- p s +Ps p's +P. S. p s +P.S. p s +PSQL p s q l +PSR p s r +PSRU p s r u +PSSA- p s s a +PSSA p s s a +PSSA's p s s a's +PSSAs p s s a's +PSSI p s s i +PSS p s s +PSS's p s s's +PST p s t +PSU p s u +PSV p s v +PSW p s w +pTA p t a +PTA p t a +PTA's p t a's +PTAs p t a's +PTB p t b +PTBT p t b t +PTCH p t c h +PTC p t c +Pte p t e +PTEs p t e's +PTFE p t f e +ptf p t f +PTF p t f +PTH p t h +Ptie p t i e +PTI- p t i +PTI p t i +PTI's p t i's +PTK p t k +PTLLS p t l l s +PTL p t l +PTLs p t l's +PTNNT p t n n t +Ptol p t o l +PTO p t o +PTPN p t p n +PTP p t p +pt p t +P. T. p t +P.T. p t +PT- p t +PT p t +PTSD p t s d +PTSE p t s e +PTS- p t s +PTS p t s +PTTGC p t t g c +PTTG p t t g +PTTOW p t t o w +PTT p t t +PTTs p t t's +PTUN p t u n +PTV p t v +PTV's p t v's +P'Twa p t w a +PTY p t y +P.U.F. p u f +Puiu p u i u +PUKKE p u k k e +PUK p u k +Pul p u l +P. U. M. p u m +PVA p v a +PVAs p v a's +PVB p v b +P.V.C. p v c +PVC p v c +PvdA p v d a +PVEM p v e m +pve p v e +PVH p v h +P.V.L. p v l +PVL p v l +PVN p v n +PVO p v o +PVP p v p +Pv- p v +P. V. p v +P.V. p v +PV- p v +PV p v +pvr p v r +PVR p v r +PVRS p v r s +PVs p v's +PVS p v s +PVU p v u +PWA p w a +PWB p w b +PWC p w c +PWD p w d +PWF p w f +P. W. G. p w g +P.W.G. p w g +PWG p w g +PWI p w i +pwll p w l l +PWM p w m +P.W.O. p w o +P&W p and w +P. W. p w +P.W. p w +PW- p w +PW p w +Pyi p y i +PYI p y i +Pyk p y k +PYK p y k +Pyl p y l +PyL p y l +PYP p y p +P. Y. p y +Pyu p y u +Pyw p y w +Pyx p y x +PZB p z b +PZL- p z l +PZL p z l +PZP p z p +P. Z. p z +Q. A. P. q a p +QAP q a p +Q. A. q a +QA q a +Q&A q and a +Q&A's q and a's +Q&As q and a's +QbA q b a +QBE q b e +QBH q b h +QBL q b l +Q.B. q b +QB q b +Q.C.B. q c b +QCD q c d +Q.C. q c +QD q d +QDS q d s +QEA q e a +QEC q e c +Q.E.D. q e d +QED q e d +Q.E.H. q e h +Q. E. q e +Q.H.C. q h c +QHP q h p +Q.H. q h +Q.I. q i +Q. J. q j +QJ q j +Q. J. R. q j r +Q. N. q n +QPF q p f +QPFS q p f s +QPM q p m +QPO q p o +QPOs q p o's +QPP q p p +QP q p +Q.P.R. q p r +QPR q p r +QQ q q +QRL q r l +QRL's q r l's +QRNA q r n a +QROPS q r o p s +QRP q r p +QR q r +QRS q r s +QRT q r t +QRV q r v +QSAR q s a r +QSES q s e s +QSI q s i +QSK- q s k +QSL q s l +QSM q s m +QSO q s o +QST q s t +QSY q s y +QSZ- q s z +QTE- q t e +QVC q v c +QVD q v d +QVM q v m +Q.V. q v +R.A.B. r a b +R. A. E. r a e +R.A.F. r a f +R.A.J. r a j +R. A. r a +R.A. r a +R&A r and a +RAV r a v +R&AW r and a w +RAZR r a z r +RBAC r b a c +RbAg r b a g +RBA r b a +RBBP r b b p +RBC r b c +RBCs r b c's +RBD r b d +RBE r b e +RBGE r b g e +RBG r b g +RBI r b i +RBIs r b i's +R. B. J. r b j +R.B.J. r b j +RBK- r b k +RBK r b k +R.B.L. r b l +RBL r b l +RBMG r b m g +RBMG's r b m g's +RBM r b m +RBMY r b m y +RBO r b o +RBP r b p +R&B- r and b +R&B r and b +R. B. r b +R.B. r b +RBR r b r +RBS r b s +RBTCO's r b t c o's +RBTH r b t h +RBWH r b w h +RBW r b w +RBX r b x +RBZ r b z +RCAC r c a c +RCAF r c a f +rca r c a +R.C.A. r c a +RCA- r c a +RCA r c a +RCA's r c a's +RCBC r c b c +RCB r c b +RCCA r c c a +RCCD r c c d +RCCL r c c l +RCCM r c c m +RCC r c c +RCI r c i +R. C. K. r c k +RCL r c l +R.C.M. r c m +RCM r c m +RCN r c n +RCPO r c p o +RCP r c p +RCPT r c p t +R&C r and c +rc r c +R. C. r c +R.C. r c +RCRD r c r d +RCR- r c r +RCR r c r +RCSB r c s b +RCS r c s +RCT r c t +RCTs r c t's +RCTS r c t s +RCTV r c t v +RCV r c v +RCW r c w +RDB r d b +RDC- r d c +RDC r d c +RDD r d d +RdE r d e +RDFC r d f c +RDF r d f +R.D.G. r d g +R&D- r and d +R&D r and d +R. D. r d +R.D. r d +R.E.A. r e a +R. E. B. r e b +R.E.D. r e d +R.E.L. r e l +R.E.M. r e m +R.E.M.'s r e m's +R.E.O. r e o +REPL r e p l +REPLs r e p l's +R.E.P. r e p +R. E. r e +R.E. r e +R.E.R. r e r +R.F.A. r f a +R.F.C. r f c +R. F. r f +R.F. r f +R. F.S. r f s +R.F.W. r f w +RFW r f w +RFX r f x +RGB r g b +RGD r g d +RGF r g f +RGG r g g +RGI r g i +RGK r g k +RGMA r g m a +RGNL r g n l +RGPH r g p h +R&G r and g +R. G. r g +R.G. r g +RGR r g r +RGS- r g s +RGS r g s +RGS's r g s's +RGTP r g t p +RGU r g u +RGV r g v +RGX r g x +R. H. C. r h c +RHC r h c +RHD r h d +RHHF r h h f +RHH r h h +RHHS r h h s +RHIBs r h i b's +RHIC r h i c +RHI r h i +Rhiw r h i w +RHK r h k +rhl r h l +RHM r h m +RhoG r h o g +Rho's r h o's +RHP r h p +R. H. r h +R.H. r h +R.H.S.J. r h s j +R. I. C. r i c +R.I.C. r i c +R. I. P. r i p +R.I.P. r i p +R&I r and i +R. I. r i +R.I. r i +riu r i u +Riu r i u +rivs r i v s +Rivu r i v u +RIXS r i x s +Rixt r i x t +RJB r j b +RJD- r j d +RJD r j d +RJE r j e +rjf r j f +RJHS r j h s +R. J. J. r j j +RJJ r j j +RJL r j l +RJN r j n +R. J. r j +R.J. r j +RJ r j +RJR r j r +RJ's r j's +RJTD r j t d +R. K. B. r k b +RKD r k d +RKG- r k g +RKI r k i +RKKA r k k a +RKL r k l +R.K.O. r k o +RKO- r k o +RKO r k o +RKO's r k o's +R. K. r k +R.K. r k +RLM r l m +RLM's r l m's +R. L. r l +R.L. r l +RL r l +RLS- r l s +RLV r l v +rly r l y +RMAF r m a f +RMAG r m a g +RMA r m a +RMB r m b +RMCH r m c h +RMCL r m c l +R.M.C. r m c +RMC r m c +RMDs r m d's +R.M.E.S. r m e s +RMFL r m f l +R.M.F. r m f +RMF r m f +RMG r m g +R. M. H. r m h +RMI r m i +RMIT r m i t +RMIT's r m i t's +RMJM r m j m +R.M.K. r m k +RMK r m k +R. M. L. r m l +RML r m l +RMLs r m l's +RMM r m m +RMP r m p +rm r m +R. M. r m +R.M. r m +RM r m +RMR r m r +RMRS r m r s +RMSD r m s d +RMSDs r m s d's +RMSE r m s e +RMs r m's +RMS r m s +R. M. W. r m w +R.M.W. r m w +RMW r m w +RMX r m x +RNAO r n a o +rna r n a +RNA- r n a +RNA r n a +RNA's r n a's +RNAs r n a's +RNAS r n a s +RNC r n c +RND r n d +RNE r n e +Rnet r n e t +RNF r n f +RNG r n g +Rnic r n i c +RNJD r n j d +RNK r n k +RNLAF r n l a f +RNLI r n l i +RNLI's r n l i's +RNNs r n n's +RNOH r n o h +RNP r n p +RNPs r n p's +RNPS r n p s +R. N. r n +R.N. r n +RN- r n +RN r n +R.N.R. r n r +RNZ r n z +R.O.C.K. r o c k +R.O.C. r o c +ROKMC r o k m c +ROKN r o k n +rOmpB r o m p b +Rooi r o o i +ROP r o p +R. O. r o +R.O. r o +ROVs r o v's +Roxb r o x b +Roxx r o x x +RPA r p a +RPAYC r p a y c +RPB r p b +RP&C r p and c +rpc r p c +RPC r p c +Rpe r p e +RPE r p e +RPF r p f +RPGA r p g a +rpg r p g +RPG- r p g +RPG r p g +RPG's r p g's +RPGs r p g's +RPI r p i +RPI's r p i's +RPK r p k +RPL r p l +rpm r p m +RPM r p m +RPMS r p m s +RPO r p o +RPP r p p +R. P. r p +R.P. r p +RP- r p +RP r p +RPs r p's +R.P.S. r p s +RPS r p s +RPT r p t +RPVE r p v e +RPV r p v +R. Q. r q +R.Q. r q +RQ- r q +RQW r q w +rra r r a +RRA r r a +RRC r r c +RRDE r r d e +rrd r r d +Rreli r r e l i +rre r r e +RRE r r e +RRG r r g +R. R. H. r r h +RRH r r h +RRKM r r k m +R.R.K. r r k +rRNA r r n a +rRNAs r r n a's +RRN r r n +RRP r r p +R&R r and r +rr r r +R. R. r r +R.R. r r +RR- r r +RR r r +RRR r r r +RRSR r r s r +RRS r r s +RSAF r s a f +R. S. A. r s a +RSA r s a +RSCG r s c g +RSCJ r s c j +R.S.C. r s c +RSC r s c +RSCS r s c s +RSD r s d +RSE r s e +RSF r s f +RSFSR r s f s r +RSG- r s g +RSG r s g +RSHA r s h a +rsh r s h +RSHS r s h s +RSICC r s i c c +RSID r s i d +RSI r s i +Rsis r s i's +RSI's r s i's +RSIS r s i s +RSK r s k +RSL r s l +rsly r s l y +RsmA r s m a +RSMC r s m c +RSMI r s m i +RSML r s m l +RSM r s m +RSM's r s m's +RSNO r s n o +RSN r s n +RSNZ r s n z +R. S. O. r s o +RSO r s o +RSPB r s p b +RSPCA r s p c a +RSpec r s p e c +RSPK r s p k +RSPO r s p o +R. S. P. r s p +RSP r s p +RSR r s r +rs r s +Rs r's +R. S. r s +R.S. r s +RS- r s +RS r s +RSSI r s s i +R. S. S. r s s +RSS- r s s +RSS r s s +RSSSF r s s s f +RSTC r s t c +RST r s t +RSu r s u +R.S.U. r s u +RSU r s u +RSU's r s u's +RSVP r s v p +RSV r s v +RSX r s x +RTAFB r t a f b +RTA r t a +RTBF r t b f +rtb r t b +RTB r t b +RTCG's r t c g's +RTC r t c +RTCs r t c's +RTD r t d +RTEC r t e c +RTEjr r t e j r +RTeOR r t e o r +RTE r t e +RTE's r t e's +RTFB r t f b +RTFM r t f m +RTF r t f +RTF's r t f's +RTFS r t f s +RTHK r t h k +RTHK's r t h k's +RTHL r t h l +RTIP r t i p +RTI r t i +RTKL r t k l +RTK r t k +RTLM r t l m +RTL r t l +RTL's r t l's +RTML r t m l +RTMP r t m p +RTM r t m +RTNDA- r t n d a +RTN r t n +RTO r t o +RTOs r t o's +RTOS r t o s +rtPA r t p a +RTP r t p +RTR r t r +rt r t +R. T. r t +R.T. r t +RT- r t +RT r t +rts r t s +RTS- r t s +RTS r t s +RTS's r t s's +RTTOV r t t o v +RTT r t t +RTTY r t t y +RTUK r t u k +RTU r t u +RTVC r t v c +RTVE r t v e +RTVFBiH r t v f b i h +RTV r t v +RTVV r t v v +RTW r t w +RTXC r t x c +RTX r t x +RTZ r t z +Ruao r u a o +RUC r u c +RUC's r u c's +RUFC r u f c +Rukn r u k n +Ruk r u k +RUMC r u m c +RUNX r u n x +Rupf r u p f +Rupr r u p r +rup r u p +Rup r u p +RUP r u p +R.U.R. r u r +RUR r u r +R. U. r u +R.U. r u +RU r u +RUSD r u s d +RutB r u t b +Ruu r u u +RUV r u v +Ruwa r u w a +Ruy r u y +Ruyt r u y t +RVAH- r v a h +RVAR r v a r +Rvat r v a t +RVC r v c +RVCT r v c t +RVD r v d +R. V. E. r v e +RVE r v e +RVGK r v g k +R.V.G. r v g +R. V. J. r v j +R.V.J. r v j +RVM r v m +RVNG r v n g +Rvo r v o +RVO r v o +RVR r v r +R. V. r v +R.V. r v +RV r v +rvs r v s +RVTD's r v t d's +RVU r v u +RVV- r v v +rwa r w a +Rwa r w a +RWA r w a +rwb r w b +RWB r w b +RWC r w c +RWD r w d +RWDSU r w d s u +RWE r w e +RWEs r w e's +RWFC r w f c +RWIS r w i s +rwjf r w j f +R.W.R.J. r w r j +R. W. r w +R.W. r w +RW r w +RWSL r w s l +R. W. S. r w s +RWS r w s +Rxa r x a +RXL r x l +RX- r x +RX r x +RZR r z r +rz r z +R. Z. r z +RZ r z +RZS r z s +S.A.B. s a b +S.A.D. s a d +SAIC- s a i c +SAIC s a i c +Sa'id s a i d +S.A.I. s a i +SAIT's s a i t's +SAKEC s a k e c +S. A. L. s a l +S.A.P.A. s a p a +S.A.P.I. s a p i +S. A. R. s a r +S.A.R. s a r +S. A. s a +S.A. s a +SA s a +S.A.S. s a s +SAS s a s +S.A.V.A. s a v a +Saxl s a x l +Sa'yo s a y o +SAZU s a z u +SBAC's s b a c's +Sbai s b a i +S.B.A. s b a +SBA s b a +SBBK s b b k +SBB- s b b +SBB s b b +SBCM s b c m +SBCMT s b c m t +sbc s b c +SBC s b c +SBCs s b c's +SBDE s b d e +SBD s b d +SBE s b e +SBF s b f +SBI s b i +SBKP s b k p +sbk s b k +SBK s b k +SBL s b l +SBML s b m l +SBMNH s b m n h +SBM s b m +SBN s b n +SBOE s b o e +SBOL s b o l +SBOP s b o p +Sborz s b o r z +SBP- s b p +SBP s b p +SBRJ s b r j +sb s b +S. B. s b +S.B. s b +SB- s b +SB s b +SBSE s b s e +SBS s b s +SBS's s b s's +SBTDC s b t d c +SBT s b t +SBTU s b t u +Sbu s b u +SBU s b u +SBY s b y +SBZ- s b z +SBZ s b z +S.C.A. s c a +SCA s c a +SCBA s c b a +SCB s c b +SCBWI s c b w i +SCCA s c c a +SCCA's s c c a's +SCCC s c c c +SCCI s c c i +SCCP s c c p +S.C.C. s c c +SCC s c c +scr s c r +SCR s c r +SCRs s c r's +SCRS s c r s +SCRTC s c r t c +scry s c r y +sc s c +S. C. s c +S.C. s c +SC- s c +SC s c +S.C.S.C. s c s c +SC's s c's +SCS s c s +SCTC s c t c +SCTE s c t e +SCTO s c t o +SCTP s c t p +SCT s c t +SCTS s c t s +SCTV s c t v +SCUAA s c u a a +Scuf s c u f +SCU's s c u's +SCW s c w +Scymn s c y m n +SD&AE s d and a e +SDAP s d a p +SDAPS s d a p s +SDA s d a +SDAS s d a s +SDASS s d a s s +SDAT s d a t +SDAX s d a x +SDB s d b +SDCC s d c c +SDCG s d c g +SDC s d c +SDDI s d d i +SDDOT s d d o t +SDD s d d +SDDS s d d s +Sdei s d e i +sde s d e +Sde s d e +SDF s d f +SDG&E s d g and e +SDHA- s d h a +SDHA s d h a +SDHC s d h c +SDHD s d h d +SDHHD s d h h d +SDH s d h +SDI, s d i +SDI s d i +SDJ s d j +sdk s d k +SDK s d k +SDK's s d k's +SDLC s d l c +SDLP s d l p +SDLP's s d l p's +S. D. L. s d l +S.D.N.Y. s d n y +S. D. s d +S.D. s d +SDSM&T's s d s m and t's +S. D. S. s d s +S.E.C. s e c +Sejms s e j m's +sejr s e j r +Sekl s e k l +Sek s e k +SEK s e k +S. E. s e +S.E. s e +SESL s e s l +ses s e s +Ses s e's +SEs s e's +S.E.S. s e s +SES- s e s +SES s e s +S.E.S.'s s e s's +S.E.X. s e x +Seyh s e y h +SFACS- s f a c s +sfadb s f a d b +SFA s f a +SFA's s f a's +Sfax s f a x +S.F.B.J. s f b j +SFB s f b +SFCC s f c c +SFCH s f c h +SFC s f c +SFDR s f d r +SFD s f d +SFE s f e +SFES s f e s +SFFAS s f f a s +SFFCo s f f c o +SFFH s f f h +SFF s f f +SFG s f g +SFI s f i +S. F. L. s f l +SFL s f l +sfn s f n +SFN s f n +SFOD- s f o d +SFOR s f o r +SFO s f o +SFPA s f p a +SFPD s f p d +SFP s f p +SFRA s f r a +SFRJ s f r j +sFRP- s f r p +SFR s f r +'sf s f +sf s f +S. F. s f +S.F. s f +SF- s f +SF s f +SFSG s f s g +SFSR s f s r +sfs s f s +S.F.'s s f's +SFS- s f s +SFS s f s +SFSS s f s s +SFSU s f s u +SFU s f u +SFWA- s f w a +SFWA s f w a +SFX s f x +SFX's s f x's +SGAE s g a e +SGAP s g a p +SGA s g a +SGA's s g a's +sgb s g b +SGB s g b +S.G.C. s g c +SGC s g c +SGD s g d +SGE s g e +S. G. F. s g f +SGF s g f +SGH- s g h +SGH s g h +Sgip s g i p +SGI s g i +SGL s g l +sgml s g m l +SGML- s g m l +SGML s g m l +SGP s g p +SGRAM s g r a m +sgra s g r a +SGR s g r +S. G. s g +S.G. s g +SGSN s g s n +SGSNs s g s n's +SGS s g s +SGSY s g s y +Sgt. sergeant +sgt s g t +SGT s g t +SGU s g u +SGV s g v +SGX s g x +SHBG s h b g +SHB s h b +SHBT s h b t +SHCA s h c a +Shch- s h c h +SHC s h c +SHG s h g +SHH s h h +S.H.I.E.L.D.'s s h i e l d's +S.H.I.E.L. s h i e l +SHL- s h l +SHL s h l +Shma s h m a +SHMD s h m d +SHM s h m +SHN s h n +S. H. s h +S.H. s h +S.I.D. s i d +SIF s i f +S.I.R. s i r +S. I. s i +S.I. s i +S.I.T. s i t +SJAM s j a m +SJCH s j c h +SJC s j c +SJDA s j d a +S.J.D. s j d +sjef s j e f +SJEM s j e m +S. J. J. F. s j j f +SJK s j k +S.J.L. s j l +SJL s j l +SJM s j m +Sjon s j o n +SJPCD s j p c d +SJP s j p +SJPT s j p t +SJR s j r +SJR's s j r's +S. J. s j +S.J. s j +SJ s j +SKB- s k b +SKB s k b +SKC s k c +SKD s k d +S. K. F. s k f +SKF- s k f +SKF s k f +SKG s k g +SKH s k h +SKJ s k j +SKPC s k p c +SKP s k p +SKR s k r +SKSD s k s d +S. K. s k +S.K. s k +SK- s k +SK s k +S. K. S. s k s +S.L.A.A.'s s l a a's +SLAF s l a f +sla s l a +SLA s l a +SLAs s l a's +SLCO s l c o +SLC- s l c +SLC s l c +SLDL s l d l +SLD- s l d +SLD s l d +S.L.E. s l e +SLF s l f +SLG s l g +SLHS s l h s +S.L.I.F.E.R. s l i f e r +SLL s l l +SLMC s l m c +S. L. M. s l m +SLM s l m +SLN s l n +SLPIM s l p i m +SLP s l p +SLRC s l r c +SLR s l r +S&L s and l +SLS&E s l s and e +SLSF s l s f +SLSK s l s k +S. L. s l +S.L. s l +SL- s l +SL s l +SLS s l s +SLVR s l v r +SLV s l v +S.M.A.R.T. s m a r t +S.M.A.S.H. s m a s h +SMA s m a +SMB s m b +SMe s m e +SME s m e +SME's s m e's +SMEs s m e's +SMF s m f +SMG- s m g +SMG s m g +SMHI s m h i +SMH s m h +SmI s m i +SMI s m i +SMJR s m j r +SMK s m k +SMLS s m l s +SMMT s m m t +SMN s m n +SMNS s m n s +SMP s m p +SMP's s m p's +SMPSs s m p s's +SMPTE s m p t e +SMRJ s m r j +smr s m r +SMR- s m r +SMR s m r +S&M s and m +sm s m +S. M. s m +S.M. s m +SM s m +S.M.'s s m's +SMs s m s +S.M.S. s m s +SMS. s m s +SMS s m s +SMS's s m s's +SMSU s m s u +SMTP s m t p +S.M.T. s m t +SMT s m t +SMTV s m t v +SMU s m u +SMW s m w +SMX s m x +Smyl s m y l +SMYS s m y s +SNA s n a +SNBA s n b a +SNB s n b +SNCB s n c b +SNCC s n c c +SNCF s n c f +SNC- s n c +SNC s n c +SNDC s n d c +SND s n d +SNEP- s n e p +SNEP s n e p +SNESjr s n e s j r +SNES s n e s +SNET s n e t +SNF s n f +SNFU s n f u +sngle s n g l e +SNGM- s n g m +SNG s n g +SNJ- s n j +SNK s n k +SNLA s n l a +SNL s n l +SNLS s n l s +SNMCMG s n m c m g +SNMC s n m c +SNMMA s n m m a +SNMP s n m p +SNNPR s n n p r +SNNR s n n r +SNPJ s n p j +SNP s n p +SNPs s n p's +SNRI s n r i +SNR s n r +SNSD's s n s d's +SnSe s n s e +sn- s n +S. N. s n +S.N. s n +SN- s n +SN s n +SNS s n s +S.O.E. s o e +S. O. s o +S.O. s o +Sos s o's +S.O.S. s o s +SOS s o s +Sovn s o v n +Sov s o v +SOX s o x +S. O. Y. s o y +S&P 500 s and p five hundred +S.P.A.L. s p a l +SPB s p b +SPCAs s p c a's +SPCG s p c g +SPCK s p c k +S.P.C. s p c +SPC s p c +SPDI s p d i +SPD- s p d +SPD s p d +Spe s p e +SPE s p e +SPES s p e s +SPFH s p f h +SPFL s p f l +SPF s p f +SPG s p g +SPHL s p h l +SPH- s p h +SPH s p h +SPINE's s p i n e's +SPIN's s p i n's +SPIR s p i r +SPI s p i +S.P.I.T. s p i t +SPJA s p j a +SPK s p k +SPLA- s p l a +SPLA s p l a +SPLC s p l c +SPLM- s p l m +SPL s p l +SPME s p m e +SPML s p m l +SPMRL s p m r l +SPM s p m +SPNJ s p n j +SPNM s p n m +SPNN s p n n +SPN s p n +Spoa s p o a +SPOC s p o c +SPOF s p o f +SPO s p o +SPOU s p o u +SpPIn s p p i n +SPP s p p +SPP's s p p's +SPQA s p q a +SPRL s p r l +SPRM s p r m +SPR s p r +SPRU s p r u +S&P s and p +SPSA s p s a +SPSL s p s l +S. P. s p +S.P. s p +SP- s p +SP s p +SP's s p's +SPs s p's +SPS- s p s +SPS s p s +SPSS s p s s +SPTA s p t a +SPT s p t +SPUC s p u c +SPUP s p u p +SPU s p u +SPUs s p u's +SPV s p v +SPX- s p x +SQA s q a +SQBB s q b b +SQI- s q i +SQI s q i +sql s q l +SQL- s q l +SQL s q l +SQM s q m +SQQ- s q q +sq s q +S. Q. s q +SQ s q +Sra s r a +SRA s r a +SRAs s r a's +Srba s r b a +SRBIJA s r b i j a +Srbi s r b i +SRBOC s r b o c +SRBP s r b p +SRB s r b +SRBs s r b's +SRBY s r b y +SRCC s r c c +SRCL s r c l +SRC s r c +SRC's s r c's +SRCS s r c s +S.R.E. s r e +SRE s r e +SRFC s r f c +S.R.F. s r f +SRF s r f +S.R.G. s r g +SRG s r g +SRGs s r g's +Srhir s r h i r +SRH s r h +S. R. J. s r j +SRK- s r k +SRK s r k +SRK's s r k's +SRLGs s r l g's +S.R.L. s r l +SRL s r l +SRMC s r m c +S.R.M. s r m +SRM s r m +SRMs s r m's +Srni s r n i +SRN s r n +srp s r p +SRPT s r p t +S. R. R. s r r +SRR s r r +sr s r +S. R. s r +S.R. s r +SR- s r +SR s r +SRS s r s +SRT- s r t +SRT s r t +SRT's s r t's +Srul s r u l +SRU s r u +SRU's s r u's +SRV s r v +srx s r x +SRY s r y +SRZ- s r z +SSAA s s a a +SSAB s s a b +SSAC s s a c +SSAR s s a r +SSA s s a +SSAs s s a's +SSBSE s s b s e +S.S.B. s s b +SSB s s b +SSCCC s s c c c +S.S.C. s s c +SSC- s s c +SSC s s c +SSCV s s c v +SSDB s s d b +SSDL s s d l +SSDP s s d p +S.S.D. s s d +SSD s s d +SSDs s s d's +SSE s s e +SSFL s s f l +SSF s s f +SSGRC s s g r c +SSG- s s g +SSG s s g +SSHSA's s s h s a's +SSH s s h +SSI s s i +SSIS s s i s +SSJA s s j a +SSKI's s s k i's +SSK s s k +SSLAM s s l a m +ssl s s l +SSL s s l +SSLT s s l t +SSME s s m e +SSM- s s m +SSM s s m +SSN- s s n +SSN s s n +SSOD s s o d +SSOF s s o f +SSO s s o +SSoSV s s o s v +SSPA s s p a +SSPH s s p h +SSPR s s p r +SSP s s p +SSPX s s p x +SSQ s s q +SSRAA s s r a a +SSRF s s r f +SSRI s s r i +SSRIs s s r i's +SSRN s s r n +SSRP s s r p +SSR s s r +S&S s and s +SSSC s s s c +SSSI s s s i +SSSR s s s r +ss s s +S. s s's +Ss s's +S. S. s s +S.S. s s +SS- s s +SSS s s s +SSTC- s s t c +SSTH s s t h +SSTL- s s t l +SSTL s s t l +SSTR s s t r +SST s s t +Ssu s s u +SSU s s u +SSVC s s v c +SSV s s v +SSWAHS s s w a h s +SSWC s s w c +ssw s s w +SSW s s w +SSX s s x +Ssy s s y +ST&AJ s t and a j +S.T.A.L.K.E.R. s t a l k e r +S.T.A.T.U.S. s t a t u s +STB s t b +STCC- s t c c +STCC s t c c +S.T.C. s t c +STC s t c +STCW s t c w +STDP s t d p +STDs s t d's +STD- s t d +STD s t d +STF s t f +stfv s t f v +STGs s t g's +STG s t g +STIs s t i's +STIS s t i s +STi s t i +STI- s t i +STI s t i +STK s t k +stl s t l +S.T.L. s t l +STL s t l +STMB s t m b +STMIK s t m i k +STM's s t m's +STM s t m +STNS s t n s +STN- s t n +STN s t n +STPI s t p i +STPNS s t p n s +STPRI s t p r i +STP s t p +S.T.R.I.D.E. s t r i d e +STRV s t r v +Stryj s t r y j +STRZ s t r z +St. saint +S&T s and t +STSAT- s t s a t +STScI s t s c i +ST's s t's +STS- s t s +STS s t s +S. T. s t +S.T. s t +ST- s t +STT s t t +STVL s t v l +STVS s t v s +STV s t v +STXBP s t x b p +STX s t x +S.U.C. s u c +SUDV s u d v +suo s u o +Suo s u o +S. U. s u +SUSV s u s v +Susz s u s z +SUTs s u t's +SUT s u t +Suu s u u +SUVF s u v f +SUVs s u v's +SUV- s u v +SUV s u v +SUWN s u w n +SUW s u w +Suy s u y +Svac s v a c +svar s v a r +SVA s v a +SVB s v b +SVC s v c +SVD s v d +sve s v e +Sve s v e +SVGA s v g a +SVG s v g +SVGT s v g t +SVIA s v i a +SVM's s v m's +SVMs s v m's +SVM s v m +svn s v n +svom s v o m +SVOPC s v o p c +SVO s v o +SVP s v p +SVPW s v p w +SVSCEP s v s c e p +SVSC s v s c +SVS s v s +sv s v +S. V. s v +S.V. s v +SV- s v +SV s v +SVTs s v t's +SVT s v t +S.V.U. s v u +SVU s v u +SVV s v v +SVW s v w +SVYASA s v y a s a +SVZ s v z +SWABC s w a b c +SWAC s w a c +S.W.A. s w a +SWC s w c +SWD- s w d +SWD s w d +S.W.E.A.T. s w e a t +Swe s w e +SWE s w e +SWF s w f +SWG s w g +SWHL s w h l +SWHS s w h s +SWH s w h +SWJN s w j n +S. W. K. s w k +SWMRS s w m r s +SWM s w m +SWNH s w n h +SWOC s w o c +S.W.O.R.D. s w o r d +SWPA s w p a +SWPL s w p l +SWP s w p +SwRI s w r i +SWR- s w r +SWR s w r +S&W s and w +SWS s w s +sw s w +S. W. s w +S.W. s w +SW- s w +SW s w +SWTPC s w t p c +SWT s w t +SWWTP s w w t p +SXCT s x c t +SXN s x n +SXSW s x s w +sx s x +S.X. s x +SX- s x +SX s x +SXY s x y +SXZ s x z +SysML s y s m l +SysRq s y s r q +Sys s y's +SYS s y s +SysV s y s v +S. Y. s y +S.Y. s y +SyT s y t +syv s y v +Syxx s y x x +SZA s z a +Szasz s z a s z +SZD- s z d +SZDSZ s z d s z +Szer s z e r +szkic s z k i c +Szklo s z k l o +Szlak s z l a k +SzMME s z m m e +Szpir s z p i r +SZSE s z s e +sz s z +S. Z. s z +SZ s z +Szu s z u +Szyk s z y k +SZZ s z z +taf t a f +Taf t a f +TAF t a f +T.A.P. t a p +T.A.S. t a s +T. A. t a +T.A. t a +T&A t and a +TAZ t a z +TBA t b a +TBCA t b c a +TBCs t b c's +TBCS t b c s +TBD t b d +TBE t b e +TBF t b f +TBHS t b h s +TBI t b i +TBK- t b k +TBK t b k +TBL t b l +TBMA t b m a +TBMM t b m m +TBMs t b m's +T.B.M. t b m +TBM t b m +TBNJ t b n j +TBN t b n +TBP- t b p +TBP t b p +TBSC t b s c +TBS t b s +T. B. t b +T.B. t b +TB- t b +TB t b +TBTG t b t g +TBT t b t +TBV t b v +TBWA t b w a +TBX t b x +TCAR t c a r +TCA t c a +TCC t c c +TCDB t c d b +TCDC t c d c +TCDD t c d d +TCDOG t c d o g +TCDSB t c d s b +TCEB t c e b +T.C.E. t c e +TCE t c e +TCFAQ t c f a q +TCF t c f +TCGA t c g a +TCG- t c g +TCG t c g +TCHC t c h c +TCHRD t c h r d +TCH t c h +TCiAP t c i a p +TCI t c i +TCKs t c k's +TCLP t c l p +TCL t c l +TCM t c m +TCO t c o +TCPL t c p l +TCPMP t c p m p +TCP's t c p's +TCP- t c p +TCP t c p +TCR t c r +T. C. S. t c s +TCS t c s +tc t c +Tc- t c +T. C. t c +T.C. t c +TC- t c +TC t c +TCT t c t +TCU's t c u's +TCUs t c u's +tcu t c u +TCU t c u +TCV t c v +TCWC t c w c +TCWP t c w p +TCW t c w +TDA t d a +tdb t d b +TDCC t d c c +TDCi t d c i +TDCJ t d c j +TDC's t d c's +TDC t d c +TDD t d d +TDE t d e +TDF t d f +TDH t d h +TdIF t d i f +TDI t d i +TDK t d k +TDLAS t d l a s +TDMA- t d m a +TDMA t d m a +TDME t d m e +TDM- t d m +TDM t d m +TDO t d o +TDP t d p +TDRS t d r s +TDR t d r +TDSB's t d s b's +TD's t d's +TDs t d's +T. D. t d +T.D. t d +TDT t d t +Teatr t e a t r +TEBD t e b d +T. E. t e +T.E. t e +TEVT t e v t +TFAP t f a p +TFAS t f a s +TFA t f a +TFC t f c +TFCU t f c u +TFF t f f +TFG t f g +T.F.H. t f h +TFH t f h +TFIH t f i h +TFIID t f i i d +TFK t f k +TFL t f l +TFM t f m +TFN t f n +TFO t f o +TFP t f p +TFR t f r +TFSA t f s a +TFSI t f s i +TFSP t f s p +TFS t f s +T&F t and f +TFTC t f t c +tf t f +T. F. t f +T.F. t f +TF- t f +TF t f +TFTR t f t r +TFT t f t +TFVC t f v c +TFWA t f w a +TFW t f w +TGA t g a +T. G. C. t g c +TGC t g c +tge t g e +T.G.E. t g e +TGE t g e +tgf t g f +TGF- t g f +TGF t g f +TGG t g g +TGIF t g i f +TGL t g l +TGM's t g m's +TGM t g m +TGP t g p +TGS t g s +tg t g +T. G. t g +T.G. t g +TG t g +TGVs t g v's +tgv t g v +TGV- t g v +TGV t g v +THB t h b +THCD- t h c d +THCF t h c f +THC- t h c +THC t h c +T.H.E.M. t h e m +T.H.F. t h f +THF t h f +THG t h g +THHK t h h k +T.H.I.N.K. B.I.G. t h i n k b i g +THJ- t h j +THLL t h l l +THL t h l +THMP t h m p +THM t h m +THNN t h n n +Thok t h o k +T.H.P. t h p +THQ's t h q's +THQ t h q +THR's t h r's +THR t h r +ThSe t h s e +THSR t h s r +T. H. S. t h s +T. H. t h +T.H. t h +T.H.U.N.D.E.R. t h u n d e r +THW t h w +THX t h x +TIAA- t i a a +TIAA t i a a +T. I. A. t i a +TIFR t i f r +TIF t i f +T.I.'s t i's +T.I. t i +Tiu t i u +tiv t i v +Tiv t i v +TIYM t i y m +Tiy's t i y's +TJD- t j d +TJFR t j f r +T.J.F. t j f +T. J. J. t j j +TJJ t j j +TJP t j p +TJRC t j r c +T. J. S. t j s +T. J. t j +T.J. t j +TJ t j +t'ju t j u +TJX t j x +tjz t j z +TKAG t k a g +TKA's t k a's +TKA t k a +T. K. B. t k b +TKB- t k b +TKCA- t k c a +TKD t k d +TKE t k e +TKI t k i +tko t k o +Tko t k o +TKO- t k o +TKO t k o +TKP t k p +TK's t k's +TKS t k s +tk t k +T. K. t k +T.K. t k +TK- t k +TK t k +TKT t k t +Tlas t l a's +TLA t l a +TLC's t l c's +TLC t l c +TlCu t l c u +TLDs t l d's +TLDS t l d s +TLD t l d +TLE t l e +TLF t l f +TLG t l g +TLH t l h +tli t l i +TLI t l i +TLM t l m +TLN t l n +tlp t l p +TLP t l p +TLRs t l r's +TLR t l r +TLs t l's +TLS t l s +TLTB t l t b +tl t l +T. L. t l +T.L. t l +TL- t l +TL t l +Tluk t l u k +TLU's t l u's +Tluszcz t l u s z c z +TLV- t l v +TLV t l v +TMA- t m a +TMA t m a +TMBG t m b g +TMB t m b +tmc t m c +TMC t m c +TMDL t m d l +TMD t m d +TMEM t m e m +TMF t m f +TMGs t m g's +TMG t m g +TMI t m i +TMJ t m j +T. M. M. t m m +TMMTX t m m t x +TMNT t m n t +TMOK t m o k +tmos t m o s +TMO's t m o's +TMOS t m o s +TMO t m o +TMPRSS t m p r s s +TMP t m p +tmRNA t m r n a +TMRS t m r s +TMR t m r +TMSI t m s i +TMSs t m s's +T.M.s t m's +TM's t m's +TMS t m s +tm t m +T. M. t m +T.M. t m +TM- t m +TM t m +T.M.T. t m t +TMT t m t +TMU t m u +TMX t m x +TMZ t m z +TNA's t n a's +TNAS t n a s +tna t n a +TNA t n a +tnbc t n b c +TNCA t n c a +TNCC t n c c +TNCDSB t n c d s b +TNC- t n c +TNC t n c +TNFA t n f a +TNFRSF t n f r s f +TNFSF t n f s f +TNF- t n f +TNF t n f +TNGHT t n g h t +TNG t n g +TNIP t n i p +TNI t n i +TNK- t n k +TNL t n l +TNMM t n m m +TNMS t n m s +TNM t n m +TNNC t n n c +TNN t n n +TNO t n o +TNPL t n p l +TNP t n p +TNQ t n q +TNRIS t n r i s +TNRP t n r p +TNR t n r +TNSDL t n s d l +TNSTC- t n s t c +TNSTC t n s t c +TNS- t n s +TNS t n s +TNTAs t n t a's +tn t n +T. N. t n +T.N. t n +TN- t n +TN t n +TNT's t n t's +TNT t n t +TNX- t n x +T.O.'s t o's +T. O. t o +T.O. t o +TOTP t o t p +tou t o u +Tou t o u +ToU t o u +TOU t o u +TPAC t p a c +TPAO t p a o +tPA t p a +TPA- t p a +TPA t p a +TPB t p b +TPC- t p c +TPC t p c +TPEC t p e c +TPF t p f +TPG- t p g +TPG t p g +TPH t p h +TPI t p i +TPLF t p l f +TPMS t p m s +TPM t p m +TPO t p o +TPP t p p +tpr t p r +TPR t p r +TPS- t p s +TPS t p s +tp t p +T. P. t p +T.P. t p +TP- t p +TP t p +TPU t p u +TPVs t p v's +TPWS t p w s +TPW t p w +TQR t q r +TQS t q s +T.Q. t q +TQ t q +tra t r a +Tra t r a +TRA t r a +TRAXX t r a x x +Trbic t r b i c +T. R. B. t r b +TRB t r b +Trcek t r c e k +TRC t r c +TRDB- t r d b +TRD t r d +TRFA t r f a +TRF t r f +TRG t r g +TRHS t r h s +TRH t r h +T.R.I.B.E. t r i b e +TRIZ t r i z +TrkA t r k a +TRL- t r l +TRL t r l +Trmcic t r m c i c +TRMM t r m m +T.R.M.P.A. t r m p a +T. R. M. t r m +TRM- t r m +tRNA t r n a +TRNC t r n c +TRPC t r p c +TRPM t r p m +TRPP t r p p +TRP's t r p's +TRPs t r p's +TRP t r p +TRPV t r p v +TRPY t r p y +TRSC t r s c +TRSI t r s i +trs t r s +T.R.S. t r s +TRS t r s +TRSV t r s v +tr t r +T. R. t r +T.R. t r +TR- t r +TR t r +TRT t r t +T.R.U. t r u +truTV t r u t v +TruTV t r u t v +Trve t r v e +TRVL t r v l +TRV t r v +TRW t r w +TRX t r x +TRZ t r z +Tsa t s a +TSA t s a +TSB t s b +TSCC t s c c +TSC- t s c +TSC t s c +TSF t s f +TSG- t s g +TSG t s g +TSH t s h +TSIO- t s i o +TSI t s i +tsit t s i t +Tsiv t s i v +TSJDF t s j d f +TSLA t s l a +TSLC t s l c +TSL t s l +TSN t s n +T.S.O.L. t s o l +tso t s o +Tso t s o +T.S.O. t s o +TSO t s o +TSP t s p +TSQ- t s q +TSRA t s r a +TSRTC t s r t c +tsr t s r +TSR t s r +TSSA t s s a +TSS t s s +TSTA t s t a +TSTC t s t c +Ts t's +T. S. t s +T.S. t s +TS- t s +TS t s +TST t s t +tsus t s u s +Tsvi t s v i +TSV t s v +TSW t s w +TSX t s x +TTAB t t a b +Tta t t a +TTA t t a +TTBB t t b b +TTCP t t c p +TTC's t t c's +TTC t t c +TTDC t t d c +TTD t t d +tteok t t e o k +tte t t e +TTFF t t f f +TTHS t t h s +TTH t t h +TTI t t i +TTKG t t k g +TTKST t t k s t +TTL- t t l +TTL t t l +T.T.N. t t n +ttp t t p +TTP t t p +TTR t t r +TTS t t s +T&T t and t +tt- t t +T. T. t t +T.T. t t +TT- t t +TT t t +TTU t t u +TTV t t v +TTW t t w +TUAW t u a w +TUBB t u b b +TUDCA t u d c a +TUHUS t u h u s +TUKP's t u k p's +T'uqu t u q u +TUSCC t u s c c +TUSC t u s c +T.U. t u +TU- t u +TU t u +Tuzk t u z k +tvaan t v a a n +Tvam t v a m +TVARK t v a r k +tva t v a +TVA t v a +TVB's t v b's +TVB t v b +TVCM t v c m +TVC t v c +TVD t v d +TVETs t v e t's +TVE t v e +TVF t v f +TVGN t v g n +TVGOS t v g o s +TVii t v i i +TVIn t v i n +TVi t v i +TVI t v i +TVL t v l +TVMK t v m k +TVM t v m +TVN t v n +TVNZ's t v n z's +TVNZ t v n z +tvo t v o +Tvo t v o +TVO t v o +TVP t v p +TVRi t v r i +tvr t v r +TVR t v r +TVSpy t v s p y +tvs t v s +TV's t v's +TVs t v's +TVS t v s +tVTA t v t a +TVT- t v t +TVT t v t +tv t v +T. V. t v +T.V. t v +TV- t v +TV t v +TVXQ's t v x q's +TVXQ t v x q +TVX t v x +TWAP t w a p +TWA's t w a's +Twa t w a +TWA t w a +T. W. B. t w b +TWCS t w c s +TWC t w c +TWF t w f +Twi t w i +TWI t w i +TWK t w k +T.W.P. t w p +TWP t w p +TWR- t w r +TWR t w r +TWTs t w t's +TWT t w t +T. W. t w +T.W. t w +TW t w +T.W.U. t w u +TWU t w u +TXC t x c +TxDOT t x d o t +TXII t x i i +TXJS t x j s +TXK t x k +TXMM t x m m +TXNDC t x n d c +TXP t x p +TXTC t x t c +TXT t x t +T.X. t x +TX- t x +TX t x +TXU t x u +tya t y a +TYC t y c +TYIB t y i b +TYIN t y i n +Tyk t y k +Tza'ar t z a a r +Tze t z e +TZL t z l +Tzrif t z r i f +Tzuh t z u h +TZUM t z u m +Tzvi t z v i +UAAP's u a a p's +UAAP u a a p +UAB's u a b's +UAB u a b +UAC- u a c +UAC u a c +UADY u a d y +UAE's u a e's +U.A.E. u a e +UAE- u a e +UAE u a e +UAF u a f +UAHC u a h c +UAIC u a i c +UAI u a i +UALR u a l r +UAL u a l +UALVP u a l v p +UAM u a m +UANL u a n l +UAN u a n +UAOC u a o c +UAP u a p +UAR's u a r's +UARS u a r s +UAR u a r +UASLP u a s l p +UASL u a s l +Ua's u a's +UAs u a's +UAS u a s +uat u a t +U.A. u a +UA u a +UAVs u a v's +UAV u a v +U.A.W. u a w +UAW- u a w +UAW u a w +Uba u b a +UBA u b a +UBBC u b b c +UBB u b b +UbcM u b c m +UBC's u b c's +UBC u b c +UBD u b d +Ube u b e +UBE u b e +ubi u b i +Ubi u b i +U.B.I. u b i +UBI u b i +UBM's u b m's +UBM u b m +UBOS u b o s +UBO u b o +UBPR u b p r +UBP u b p +UBRE u b r e +UBRS u b r s +UB's u b's +UBS u b s +UB- u b +UB u b +UBU u b u +UBV u b v +UBX u b x +UCAC u c a c +Ucar u c a r +UCAR u c a r +Uca u c a +UCA u c a +UCAV u c a v +UCBH u c b h +UCBTLA u c b t l a +UCB u c b +UCCE u c c e +UCCJ u c c j +UCCS u c c s +UCC- u c c +UCC u c c +UCDA u c d a +UCDP u c d p +UCD u c d +UCF's u c f's +UCF u c f +UCG u c g +UCIEP u c i e p +UCISA- u c i s a +UCI's u c i's +UCI u c i +UCLA's u c l a's +UCLA- u c l a +UCLA u c l a +UCLH u c l h +UCL u c l +Ucmak u c m a k +UCMJ u c m j +UCMMA u c m m a +UCMP u c m p +UCM u c m +Ucn u c n +UCOS u c o s +UCO u c o +UCP u c p +UCREF u c r e f +UCR u c r +UCSB u c s b +UCSC u c s c +UCSD's u c s d's +UCSD u c s d +UCSF u c s f +UCSN u c s n +uCs u c's +UCS u c s +UCTI u c t i +UCT u c t +Uc u c +U.C. u c +UC- u c +UC u c +Ucuncu u c u n c u +UCU u c u +UCVTS u c v t s +UCW u c w +Uczta u c z t a +UDAR u d a r +UDA's u d a's +Uda u d a +UDA u d a +UDC u d c +UDF u d f +UDG u d g +UDHR u d h r +UDICHI u d i c h i +Udit u d i t +UDK u d k +UDN u d n +Udny u d n y +UDP- u d p +UDP u d p +UDRP u d r p +UDR u d r +UDS u d s +UDTs u d t's +UDT u d t +ud u d +Ud u d +U. D. u d +UD u d +udu u d u +Udu u d u +UDYCO u d y c o +UEA u e a +UEBT u e b t +UEC u e c +Ueda's u e d a's +Uéda u e acute d a +UEFA's u e f a's +UEFA u e f a +UEFI u e f i +UEFS u e f s +UEF u e f +UEGCL u e g c l +UEI u e i +UET u e t +U. E. u e +UE u e +UFABC u f a b c +UFA's u f a's +UFCO u f c o +UFC's u f c's +UFC u f c +UFCW u f c w +UFD u f d +UFE u f e +UFF u f f +UFIA u f i a +UFIP u f i p +UFI u f i +UFJ u f j +UFL's u f l's +UFL u f l +UFM u f m +UFOFU u f o f u +UFORE u f o r e +UFO's u f o's +UFOs u f o's +Ufot u f o t +ufo u f o +Ufo u f o +UFO- u f o +UFO u f o +UFPE u f p e +UFPLS u f p l s +UFPR u f p r +UFRGS u f r g s +UFRJ u f r j +UFSB u f s b +UFSM u f s m +UF's u f's +UFS u f s +UFTP u f t p +UFT u f t +U. F. u f +UF- u f +UF u f +UFU u f u +UFW u f w +Uga u g a +UGA u g a +UGCCWA u g c c w a +UGC- u g c +UGC u g c +UGEED- u g e e d +Uge u g e +UGF- u g f +UGK u g k +UGME u g m e +Ugni u g n i +UGP u g p +Ugra u g r a +Ugrszke u g r s z k e +UGS u g s +UGT u g t +Ug u g +UG u g +UHD u h d +UHF u h f +Uhha u h h a +UHMW u h m w +uhn u h n +UHOA u h o a +UHPT u h p t +UHP- u h p +UHP u h p +UHRA u h r a +UHRF u h r f +UHSAA u h s a a +UHTCs u h t c's +UHTI u h t i +Uhud u h u d +U.H. u h +uhur u h u r +UIAA u i a a +Uiam u i a m +UIA u i a +UIAW u i a w +Uibh u i b h +Uible u i b l e +UIC u i c +UID u i d +UIFL u i f l +Uig u i g +UIL u i l +UIMC u i m c +UIM u i m +UIN u i n +UIP u i p +uisae u i s a e +UISD u i s d +UiS u i s +UI's u i's +UIS u i s +UiTM u i t m +uit u i t +Uit u i t +UIT u i t +UI- u i +UI u i +UIV u i v +Uiy u i y +UJA u j a +UJC u j c +Ujed u j e d +UJEP u j e p +Ujsag u j s a g +UJS u j s +uj u j +U.J. u j +UJ u j +Uka u k a +UKA u k a +UKCC u k c c +UKC u k c +Ukhra u k h r a +Ukic u k i c +UKIP's u k i p's +Uki u k i +UKM u k m +UKNC u k n c +Ukoh u k o h +Uko u k o +UKPC u k p c +UKRDA's u k r d a's +UKRDA u k r d a +ukr u k r +Ukr u k r +UKR u k r +UK's u k's +UKTV's u k t v's +UKTV u k t v +Ukui u k u i +u'k u k +uk u k +Uk u k +U.K. u k +UK- u k +UK u k +UKUP u k u p +UKVRN u k v r n +UKW u k w +Ukwu u k w u +ULC- u l c +ULC u l c +ULDB u l d b +ULEB u l e b +ULEV u l e v +ULFA u l f a +Ulic u l i c +Ull u l l +Ulms u l m's +UL's u l's +ULS u l s +UlSU u l s u +Uluj u l u j +U.L. u l +UL u l +ulus u l u s +Ulus u l u's +ULV u l v +Ulwa u l w a +Ulwe u l w e +UMBC u m b c +Umbr u m b r +UMCC u m c c +UMC u m c +UMD u m d +umelcu u m e l c u +UMe u m e +UMF u m f +UMG u m g +UMHB u m h b +UMH u m h +UMKC's u m k c's +UMKC u m k c +UMK u m k +Umla u m l a +UML u m l +Umme u m m e +UMMSM u m m s m +UMNO's u m n o's +Umno u m n o +UMNO u m n o +UMN u m n +UMO u m o +UMPP u m p p +UMP's u m p's +Umptee- u m p t e e +Umri u m r i +UM's u m's +UMTS u m t s +UMTV u m t v +UMUC u m u c +U. M. u m +U.M. u m +UMWA's u m w a's +UMWA u m w a +UMW's u m w's +UNAB u n a b +UNAFF u n a f f +UNAH u n a h +UNAMIR u n a m i r +UNAPACK's u n a p a c k's +UNB u n b +UNCAC u n c a c +UNCAF u n c a f +UNCG's u n c g's +UNCG u n c g +UNCHE u n c h e +UNCHS u n c h s +UNCMAC u n c m a c +UNCRO u n c r o +UNC's u n c's +UNCTAD u n c t a d +UNC- u n c +UNC u n c +UNCW u n c w +UNFCCC u n f c c c +UNFICYP u n f i c y p +UNFPA u n f p a +UNFP u n f p +UNF- u n f +UNF u n f +UNFWP u n f w p +UNGC u n g c +UNHCR u n h c r +UNHRC's u n h r c's +UNH u n h +UNJLC u n j l c +Unli u n l i +UNL u n l +Unlu u n l u +UNLV u n l v +UNMCK u n m c k +UNMC- u n m c +UNMC u n m c +UNMEE's u n m e e's +UNMEE u n m e e +UNMIH u n m i h +UNMIK u n m i k +UNMIL u n m i l +UNMOVIC u n m o v i c +unm u n m +UNM u n m +UNNC u n n c +unnd u n n d +UNODC u n o d c +UNOMIG u n o m i g +UNPA u n p a +UNPD u n p d +UNPO u n p o +UNP u n p +UNRA u n r a +UNRSGN u n r s g n +UNRWA u n r w a +UNSCOM u n s c o m +UNSCR u n s c r +UNSC's u n s c's +UNSC u n s c +UNSh u n s h +Unst u n s t +Uns u n's +U.N.'s u n's +UNSW u n s w +UNTSO u n t s o +UNTS u n t s +Unt u n t +UNT u n t +U.N. u n +UNU u n u +UNV u n v +UNWE u n w e +UNWTO u n w t o +Unz u n z +UOCl u o c l +UODA u o d a +UofM u o f m +UOHI u o h i +Uoho u o h o +UOJCA u o j c a +UOL u o l +UOMINI u o m i n i +UoMs u o m's +UOP u o p +uORF u o r f +UOR u o r +UO's u o's +UO u o +UoW u o w +UPABA u p a b a +UPBs u p b's +UPCI u p c i +UPC u p c +UPDRS u p d r s +UPDS u p d s +Upd u p d +UPD u p d +UPEC u p e c +UPFA- u p f a +UPFA u p f a +UPF's u p f's +Upf u p f +UPF u p f +UPGMA u p g m a +UPHSD u p h s d +UPIN u p i n +Upir u p i r +UPI's u p i's +UPI u p i +UPLA u p l a +UPLB u p l b +UPL u p l +UPMC u p m c +UPMSS u p m s s +UPND u p n d +UPNE u p n e +UPnP u p n p +UPN u p n +UPOV u p o v +UPPP u p p p +Uppu u p p u +UPRR u p r r +UPR u p r +UPSC u p s c +U.P.S.E.B. u p s e b +UPSIDC u p s i d c +UPSID u p s i d +UPSI u p s i +UPSMF u p s m f +UPTI u p t i +UPTU u p t u +U.P. u p +UPW u p w +UPX u p x +UPyD u p y d +UQAIB u q a i b +UQAM's u q a m's +UQC u q c +U.Q.P. u q p +UQP u q p +uq u q +UQ u q +URAA u r a a +URAC u r a c +URAP- u r a p +URAP u r a p +URBACT u r b a c t +URBED u r b e d +Urbz u r b z +URCL u r c l +URCSA u r c s a +URCs u r c's +URC u r c +Urdd u r d d +Urei u r e i +urf u r f +Urla u r l a +URLhttp u r l h t t p +URLs u r l's +URL u r l +URNU u r n u +UROC u r o c +URRACA u r r a c a +URSB u r s b +URSEC u r s e c +URSS u r s s +URW's u r w's +URW u r w +URZ u r z +USAACE u s a a c e +USAAC u s a a c +U.S.A.A.F. u s a a f +USAAF u s a a f +USAB u s a b +USACE u s a c e +USAC u s a c +USAFE u s a f e +USAF u s a f +USAHA u s a h a +USAID's u s a i d's +USAID- u s a i d +USAID u s a i d +Usal u s a l +usan u s a n +Usan u s a n +USAN u s a n +usao u s a o +USAO u s a o +USAPA u s a p a +USARPS u s a r p s +USASA u s a s a +USA's u s a's +usata u s a t a +USATF u s a t f +USAT u s a t +usa u s a +.USA u s a +U.S.A.. u s a +U.S.A. u s a +U.S.A u s a +USA- u s a +USA. u s a +USA u s a +USAya u s a y a +USBA u s b a +USBC's u s b c's +USBC u s b c +USBs u s b's +USB- u s b +USB u s b +USBWA u s b w a +USCCB u s c c b +USCF u s c f +USCGAUX u s c g a u x +USCGC u s c g c +USCG u s c g +USCHS u s c h s +Uscie u s c i e +USCIRF u s c i r f +USCIS u s c i s +USCITA u s c i t a +USCOB u s c o b +USCRP u s c r p +U.S.C.'s u s c's +USC's u s c's +USCT u s c t +U.S.C. u s c +USC- u s c +USC u s c +USDA's u s d a's +U.S.D.A. u s d a +USDA- u s d a +USDA u s d a +USDoE u s d o e +USDOJ u s d o j +USDP u s d p +USDTV u s d t v +usd u s d +USD u s d +USEER u s e e r +USENIX u s e n i x +USFbA u s f b a +USFE u s f e +USFF u s f f +USFLPA u s f l p a +USFL u s f l +USFS u s f s +USF u s f +USF&WS u s f and w s +USFWS u s f w s +USFW u s f w +USGA u s g a +U.S.G.S. u s g s +USGS- u s g s +USGS u s g s +U.S. H.R. u s h r +UShs u s h's +Usia u s i a +USIA u s i a +usih u s i h +USIP's u s i p's +USIP u s i p +USISL u s i s l +USIS u s i s +USIU u s i u +USJA u s j a +USJ u s j +USLES u s l e s +USLHE u s l h e +USLMRA u s l m r a +USLS- u s l s +USLTA u s l t a +USL- u s l +USL u s l +Uslu u s l u +Usmar u s m a r +USMA u s m a +USMC M u s m c +USMCR u s m c r +USMC's u s m c's +USMC u s m c +USMLE u s m l e +USML u s m l +USMMA u s m m a +USM u s m +Usna u s n a +USNA u s n a +USNG u s n g +Usnic u s n i c +USNM u s n m +USNO u s n o +USNR u s n r +USNSCS u s n s c s +USNS u s n s +USNTDP u s n t d p +U.S.N. u s n +USN u s n +USOC's u s o c's +USOC u s o c +Usoi u s o i +Usos u s o's +Uso u s o +USO u s o +USPHL u s p h l +USPO u s p o +USPPD u s p p d +U.S.P.Q. u s p q +USPSA u s p s a +USPs u s p's +USPS- u s p s +USPS u s p s +USPTA u s p t a +USPTO u s p t o +U.S.P. u s p +USP u s p +USRA u s r a +USRC u s r c +USSA u s s a +USSBA u s s b a +USSB u s s b +USSD u s s d +USSF's u s s f's +USSF u s s f +USSR's u s s r's +USSR u s s r +U.S.'s u s's +US's u s's +U.S.S. u s s +USS u s s +Usti u s t i +Ustka u s t k a +USTR's u s t r's +USTR u s t r +UST's u s t's +Usui u s u i +usum u s u m +U. S. u s +U.S. u s +Usut u s u t +USVC u s v c +Usvit u s v i t +USVI u s v i +U.S.V. u s v +USWA u s w a +USWNT's u s w n t's +USWNT u s w n t +U.S.W. u s w +USW u s w +Uta's u t a's +uta u t a +Uta u t a +UTA u t a +UTB u t b +Utca u t c a +UTC- u t c +UTC u t c +Utd's u t d's +Utd u t d +utea u t e a +UTEP u t e p +Utes u t e's +UTET u t e t +UTF- u t f +UTF u t f +Uth u t h +uti u t i +Uti u t i +UTJ u t j +UTMB u t m b +UTMF u t m f +UTM u t m +Utne u t n e +Utnur u t n u r +Uto u t o +UTO u t o +UTPB u t p b +UTP u t p +utrci u t r c i +UTRGV u t r g v +UTR u t r +utsav u t s a v +Utsav u t s a v +UTSC u t s c +UTSI u t s i +UT's u t's +UTS u t s +Utsu u t s u +UTTR u t t r +U.T. u t +Utu u t u +Utva u t v a +UTVA u t v a +UTV u t v +UUA u u a +UUCP u u c p +Uuh u u h +UUKKY u u k k y +Uul u u l +Uulu u u l u +UUP u u p +Uusi u u s i +UUs u u's +Uuto u u t o +UUT u u t +Uvac u v a c +UVB u v b +UVC u v c +Uvea u v e a +UVF u v f +UVIMB u v i m b +UVI u v i +uvnitr u v n i t r +Uvo u v o +UVT u v t +UVU u v u +U.V. u v +UV u v +UWAP u w a p +Uwasa u w a s a +UWASA u w a s a +U.W.A. u w a +UWA u w a +UWB u w b +UWC u w c +UWFi u w f i +UWF u w f +UWG u w g +UWH u w h +UWI u w i +UWM's u w m's +UWP u w p +UWRF u w r f +UWSP's u w s p's +UWSU u w s u +UW's u w's +UWS u w s +UW- u w +UW u w +UWW u w w +VASP v a s p +VA's v a's +V. A. v a +V.A. v a +VA- v a +VA v a +V&A v and a +Vav v a v +VAV v a v +VAW- v a w +Vay v a y +VBA v b a +VBBS v b b s +VBE v b e +VBF- v b f +VBI v b i +VBM v b m +VBR v b r +vb v b +V. B. v b +V.B. v b +VB- v b +VB v b +VCA's v c a's +VCA v c a +VCCS v c c s +VCDs v c d's +VCD v c d +VCE v c e +VCH v c h +VCIT v c i t +VCI v c i +VCJ v c j +V. C. M. v c m +VCO v c o +VCP v c p +VCQ v c q +VCRs v c r's +VCR v c r +VCSELs v c s e l's +VCSEL v c s e l +VCs v c's +VCS v c s +VCTs v c t's +VCT v c t +VCU v c u +vc v c +V. C. v c +V.C. v c +VC- v c +VC v c +VCXIV v c x i v +VCX- v c x +VCY v c y +VDAC v d a c +vda v d a +Vda v d a +VDCs v d c's +VDC v d c +vdiq v d i q +VDJ v d j +VDL's v d l's +VDL- v d l +VDL v d l +vdm v d m +VDM v d m +VDP v d p +VDR v d r +VDSL v d s l +VDUP v d u p +VDU v d u +V. D. v d +V.D. v d +VD- v d +VD v d +VDV v d v +V. D. W. v d w +ve v e +Ve v e +V. E. v e +VE v e +vez v e z +Vez v e z +VEZ v e z +V.F.A. v f a +VFA- v f a +VFA v f a +VFC v f c +VFDS v f d s +V.F.D. v f d +VFD v f d +VFIL v f i l +VFLI v f l i +VFL's v f l's +VFL v f l +VFMC v f m c +VFM v f m +vfp v f p +VFP- v f p +vfr v f r +VFR v f r +VF's v f's +VFS v f s +VFTS v f t s +VFTX v f t x +VFU v f u +V. F. v f +V.F. v f +VF- v f +VF v f +VFW- v f w +VFW v f w +VFX v f x +VGA v g a +VGC- v g c +V'Ger v g e r +VGIK v g i k +VGKO v g k o +VGMA v g m a +vgmdb v g m d b +VGMDB v g m d b +VGM v g m +VGo v g o +VGP v g p +Vgr- v g r +VGSCs v g s c's +VGSoM v g s o m +VGTU v g t u +VGU v g u +V. G. v g +V.G. v g +VG- v g +VG v g +VGV v g v +VGX v g x +VHB v h b +VHC v h c +VHD v h d +VHF v h f +VHL v h l +VHP v h p +VHR v h r +VHSL v h s l +VHS v h s +V. H. v h +VH- v h +VH v h +V.I.C.'s v i c's +Vict v i c t +VICT v i c t +viita v i i t a +vijf v i j f +vij v i j +Vij v i j +V.I.P.s v i p's +VIPs v i p's +V.I.P. v i p +VIP- v i p +VIP v i p +V. I. v i +V.I. v i +V. J. J. v j j +VJL v j l +VJs v j's +VJTF v j t f +V. J. v j +V.J. v j +VJ- v j +VJ v j +VKG v k g +VKh- v k h +VKIBC's v k i b c's +V. K. N. v k n +VKOS v k o s +VKS v k s +V. K. v k +V.K. v k +VK v k +Vlah v l a h +VLA v l a +VLBA v l b a +VLBI v l b i +VLB v l b +VLCCs v l c c's +VLCS v l c s +VLC v l c +VLDB v l d b +VLDL v l d l +vlei v l e i +VLE v l e +VLEX v l e x +VLF- v l f +VLF v l f +Vlijt v l i j t +VLN v l n +VLQ v l q +VLR v l r +VLSI v l s i +VLS v l s +VLT v l t +V. L. v l +V.L. v l +VL v l +VMAs v m a's +VMAT- v m a t +VMAT v m a t +VMA- v m a +VMA v m a +VMBO- v m b o +VMCAS v m c a s +VMCM v m c m +VME v m e +VMFM v m f m +VMF- v m f +VMF v m f +VMG v m g +VMI's v m i's +VMI v m i +VMK v m k +VMM- v m m +VMM v m m +VMO- v m o +VMPS v m p s +VMS v m s +VMT v m t +vm v m +V. M. v m +V.M. v m +VM- v m +VM v m +VMX- v m x +VNAF v n a f +VNAV v n a v +VNCH v n c h +VNC v n c +vner v n e r +V.N.E. v n e +VNI v n i +VNO- v n o +VNO v n o +VNPT v n p t +VNQDD v n q d d +VNR v n r +VNSA v n s a +VNS v n s +VNTH v n t h +VNTR v n t r +VNU v n u +V. N. v n +V.N. v n +VN- v n +VN v n +V.O. v o +VO v o +Vov v o v +VOX's v o x's +Voz v o z +VPAL v p a l +VPB- v p b +VPD v p d +VPH v p h +vpis v p i s +V. P. I. v p i +VPI v p i +VPLS v p l s +VPL v p l +VPM v p m +VPNs v p n's +VPN v p n +VPO's v p o's +VPP v p p +VPRO's v p r o's +VPRO v p r o +VPS v p s +vpu v p u +V. P. v p +V.P. v p +VP- v p +VP v p +VQT v q t +vq v q +VQ v q +vrak v r a k +VRA v r a +Vrba v r b a +Vrbuv v r b u v +VRB- v r b +VRD v r d +Vrej v r e j +vrem v r e m +VRE v r e +VRF v r f +Vrin v r i n +VRI v r i +vrj v r j +VRLA v r l a +vrn v r n +vroee v r o e e +vrou v r o u +vrouw v r o u w +Vrouw v r o u w +VRO v r o +VRR v r r +Vrsac v r s a c +VRSA v r s a +VR's v r's +VRS v r s +Vrtis v r t i's +VRT's v r t's +VRT v r t +V&R v and r +vr v r +V. R. v r +V.R. v r +VR- v r +VR v r +VRV v r v +VSANs v s a n's +VSAN v s a n +VSAP's v s a p's +VSATs v s a t's +VSA- v s a +VSB's v s b's +VSB v s b +VSCP v s c p +VSC v s c +VSD v s d +Vsekh v s e k h +vse v s e +VSE v s e +VSFV v s f v +VSG v s g +VSI v s i +VSM v s m +VSNL v s n l +vso v s o +VSO v s o +VSPs v s p's +VSP v s p +VSS v s s +VSTM v s t m +VST v s t +VSU v s u +vs. versus +_vs._ versus +VSV v s v +VSW v s w +VSX v s x +vsyo v s y o +VSZ v s z +VTA v t a +VTB v t b +VTCO v t c o +VTD v t d +VTEC v t e c +VTE v t eL +Vtic v t i c +VTi v t i +VTL v t l +VTM- v t m +VTM v t m +VTR v t r +VTSK v t s k +V&T's v and t's +VTS v t s +VTU v t u +V&T v and t +VTVL v t v l +V.T. v t +VT- v t +VT v t +VTV v t v +Vuur v u u r +VUU v u u +V.V.B. v v b +VVCS v v c s +VVD v v d +VVIPs v v i p's +VVI v v i +VVMC v v m c +VVN- v v n +VVO v v o +VVS v v s +VVT v v t +V. V. v v +V.V. v v +VV v v +VWI- v w i +VWM v w m +VWR v w r +VW's v w's +VWs v w's +VWS v w s +VW- v w +VW v w +VXL v x l +VXR v x r +VX- v x +VX v x +Vyg v y g +vyr v y r +vy v y +VY v y +vz v z +V. Z. v z +WAAAAAGH w a a a a a g h +WAAAF w a a a f +WAAC w a a c +WAAF w a a f +WAAI w a a i +WAAV w a a v +Waay w a a y +WABB w a b b +WABC- w a b c +WABC w a b c +WABD w a b d +WABG's w a b g's +WABG w a b g +W. A. C. w a c +W.A.C. w a c +Wa'il w a i l +WAIO w a i o +W.A.J. w a j +Wakf w a k f +W.A.K.O. w a k o +WAKR- w a k r +wa'l w a l +WANFL w a n f l +WAOK w a o k +waqf w a q f +waqt w a q t +Waqt w a q t +WAQZ w a q z +WARH w a r h +W.A.R. w a r +WASC w a s c +Wasl w a s l +WASL w a s l +W. A. S. w a s +W.A.S. w a s +Watfa w a t f a +WATL w a t l +WATW w a t w +wau w a u +Wau w a u +WAU w a u +WAVF w a v f +WAVM w a v m +W. A. w a +W.A. w a +WA w a +WAWLI w a w l i +waw w a w +WAWZ w a w z +WAYH w a y h +waza w a z a +Waza w a z a +WBAK- w b a k +WBAL's w b a l's +WBAL- w b a l +WBAM w b a m +WBA w b a +WBBL w b b l +WBBM- w b b m +WBBM w b b m +WBBP w b b p +WBCA w b c a +WBCN- w b c n +WBCN w b c n +W.B.C. w b c +WBC w b c +WBCY w b c y +WBEV w b e v +WBEZ w b e z +WBFF- w b f f +WBFJ w b f j +WBFO w b f o +WBF w b f +WBGU- w b g u +WBG w b g +WBHY w b h y +WBIC w b i c +WBIL w b i l +WBIR- w b i r +WBJEE w b j e e +WBKI- w b k i +WBKO- w b k o +WBKO w b k o +WBK w b k +WBLQ w b l q +WBME w b m e +WBNI w b n i +WBNX w b n x +WBON w b o n +WBO w b o +WBQC w b q c +WBRC w b r c +WBRE- w b r e +WBRE w b r e +WBRO w b r o +WBRZ w b r z +WBs w b's +WBS w b s +WBTI w b t i +WBT's w b t's +WBT w b t +WBTW w b t w +WBTZ w b t z +WBUR- w b u r +WBUR w b u r +WBVE w b v e +WBV w b v +W. B. w b +W.B. w b +WB- w b +WB w b +WBWT- w b w t +WBXH w b x h +WBZB w b z b +WBZT- w b z t +WBZ- w b z +WBZ w b z +WCAA w c a a +WCAC- w c a c +WCAG w c a g +WCAU- w c a u +WCAU w c a u +WCA w c a +WCBA w c b a +WCBI- w c b i +WCBN w c b n +W&CBR w and c b r +WCBR w c b r +WCBS- w c b s +WCBS w c b s +WCB w c b +WCCES w c c e s +WCCG w c c g +WCCO- w c c o +WCCO w c c o +WCCP- w c c p +WCC's w c c's +WCC w c c +WCDA w c d a +WCEO w c e o +WCFL w c f l +WCF w c f +WCG w c g +WCHA w c h a +WCHL's w c h l's +WCHL w c h l +WCHS w c h s +WCHV w c h v +WCIU w c i u +WCKD w c k d +WCKY w c k y +WCLN w c l n +WCLU w c l u +WCLV w c l v +WCL w c l +WCMA w c m a +WCMC w c m c +WCMFA w c m f a +WCMH w c m h +WCMR w c m r +WCM w c m +WCNB w c n b +WCNG- w c n g +WCOZ w c o z +WCPO w c p o +WCPW w c p w +WCRC w c r c +WCRE w c r e +WCRL w c r l +WCSA w c s a +WCSM- w c s m +WCSM w c s m +WCS w c s +WCSY- w c s y +WCTD w c t d +WCTG w c t g +WCTI- w c t i +W.C.T.U. w c t u +WCTU w c t u +WCTV w c t v +WCT w c t +WCTX w c t x +WCVB's w c v b's +WCVB w c v b +WCVE w c v e +WCVP- w c v p +WCWA w c w a +wc w c +W. C. w c +W.C. w c +WC- w c +WC w c +WCWC w c w c +WCW w c w +WCWW- w c w w +WCXR w c x r +WCYB w c y b +WCZE w c z e +WCZU- w c z u +WDAF- w d a f +WDAF w d a f +WDA w d a +WDCN- w d c n +WDC w d c +WDDM w d d m +WDFN w d f n +WDF w d f +WDGY w d g y +WDH w d h +WDIA w d i a +WDIF w d i f +WDIG w d i g +WDIS w d i s +WDIV w d i v +WDJM- w d j m +WDJT w d j t +WDLA w d l a +WDL w d l +WDM- w d m +WDM w d m +WDNN w d n n +WDNS w d n s +WDNT w d n t +WDOD- w d o d +WDOK- w d o k +WDOK w d o k +WDO w d o +WDRE w d r e +WDR w d r +WDSE w d s e +WDSN w d s n +WDSO w d s o +WDSU w d s u +WDS- w d s +WDS w d s +WDTM w d t m +WDUQ w d u q +WDVE w d v e +WDVR w d v r +W. D. w d +W.D. w d +WD- w d +WDWS w d w s +WDW w d w +WDXZ w d x z +WDYZ w d y z +W. E. B. w e b +W.E.B. w e b +W. E. H. w e h +W.E.H. w e h +WEVD- w e v d +WEVD w e v d +WEVV w e v v +W. E. w e +W.E. w e +WEZQ w e z q +WFAA- w f a a +WFAA w f a a +WFAL w f a l +WFAN w f a n +WFBC- w f b c +WFB w f b +WFCA w f c a +WFCB- w f c b +WFC w f c +WFDC w f d c +WFDD w f d d +WFDF w f d f +WFDU w f d u +WFD w f d +WFFF- w f f f +WFGF w f g f +WFHE w f h e +W.F.H. w f h +WFH w f h +WFIKKN w f i k k n +WFIL w f i l +WFIRST w f i r s t +WFLA- w f l a +WFLN- w f l n +WFL's w f l's +WFL w f l +WFLX w f l x +WFLZ- w f l z +WFMT w f m t +WFMU w f m u +W. F. M. w f m +WFM w f m +WFMZ- w f m z +WF&NW w f and n w +WFNZ w f n z +WFOY w f o y +WFPC w f p c +WFPF w f p f +WFPMA w f p m a +W.F.P. w f p +WFP w f p +WFRX- w f r x +WFSBP w f s b p +WFS w f s +WFTDA w f t d a +WFTM w f t m +WFTV w f t v +WFT w f t +WFVA w f v a +W&F w and f +WFWA w f w a +W. F. w f +W.F. w f +WF w f +WFWM w f w m +WFXR w f x r +WFXW- w f x w +wga w g a +WGA w g a +WGBH- w g b h +WGBH w g b h +WGBI w g b i +W. G. B. w g b +WGB w g b +WGCB w g c b +W.G.C. w g c +WGC- w g c +WGC w g c +WGEM- w g e m +WGEM w g e m +WGFT w g f t +WGGH w g g h +WGHP w g h p +WGH w g h +WGHW w g h w +WGI w g i +WGN's w g n's +WGNT w g n t +wgn w g n +WGN- w g n +WGN w g n +WGOK w g o k +WGO w g o +WGP w g p +WGPX w g p x +WGRM- w g r m +WGRP w g r p +WGRT w g r t +WGRV w g r v +WGRZ- w g r z +WGSA w g s a +WGSS w g s s +WGS- w g s +WGS w g s +WGTN- w g t n +WGUN w g u n +WGVU- w g v u +wg w g +W. G. w g +W.G. w g +WG w g +WGWG- w g w g +WGWW w g w w +WGZR w g z r +W.H.B. w h b +WHCA w h c a +WHCB w h c b +WHCC w h c c +W. H. C. w h c +W.H.C. w h c +WHC w h c +WHDG w h d g +WHDH- w h d h +WHDI w h d i +W.H.D. w h d +WHEC- w h e c +WHEC w h e c +WHFA w h f a +WHFM w h f m +WHFS- w h f s +WHFS w h f s +WHHS w h h s +W.H.H. w h h +WHJA w h j a +W.H.J. w h j +WHJY w h j y +WHKT w h k t +WHL's w h l's +WHL w h l +WHNE- w h n e +WHNO w h n o +WHP- w h p +WHP w h p +WHRC w h r c +WHSG- w h s g +WHSN w h s n +WHSS w h s s +W.H.S. w h s +WHS w h s +W. H. T. w h t +WHTZ w h t z +W&H w and h +W. H. w h +W.H. w h +WH w h +Whyld w h y l d +WHYN- w h y n +WHYP- w h y p +WHYT w h y t +W.I.B.C. w i b c +Wica w i c a +WICA- w i c a +wici w i c i +WIC's w i c's +WICU w i c u +Wif w i f +WIF w i f +WIHB- w i h b +WIJD w i j d +Wijk w i j k +WIKQ- w i k q +WIP w i p +W.I.S.E. w i s e +W.I.T.C.H. w i t c h +Wiwa w i w a +W. I. w i +WIXY's w i x y's +WJAC- w j a c +WJAL w j a l +WJAR w j a r +wjaz w j a z +WJBB- w j b b +WJBC w j b c +WJBF w j b f +WJBK- w j b k +WJBK w j b k +WJBR w j b r +WJCI w j c i +WJC w j c +WJEC w j e c +WJEF w j e f +WJER w j e r +WJET w j e t +W. J. J. O. w j j o +W.J.J.O. w j j o +WJJZ w j j z +WJKA's w j k a's +WJKA w j k a +WJKS w j k s +WJLA- w j l a +WJLA w j l a +WJMK w j m k +WJMN- w j m n +WJM w j m +WJOI w j o i +WJRD w j r d +WJR w j r +WJSC w j s c +W&J's w and j's +WJTD w j t d +WJUX w j u x +W&J w and j +W. J. w j +W.J. w j +WJ w j +WJXX w j x x +WJYL w j y l +WJYM w j y m +WJYS- w j y s +WJZA w j z a +WJZJ w j z j +WJZ w j z +WKAG w k a g +WKAQ- w k a q +WKAQ w k a q +WKAR- w k a r +WKAR w k a r +WKA w k a +WKBD w k b d +WKBF's w k b f's +WKB w k b +WKBW w k b w +W. K. C. w k c +WKDM w k d m +WKDN w k d n +WKDZ w k d z +WKFS w k f s +WKHG- w k h g +W.K.H. w k h +WKH w k h +WKIK w k i k +WKIP w k i p +WKKB w k k b +WKKD w k k d +WKKZ w k k z +WKLH w k l h +WKLK- w k l k +WKNA- w k n a +WKNDS w k n d s +WKNR- w k n r +WKN w k n +WKQI w k q i +WKQX- w k q x +WKRC- w k r c +WKRK- w k r k +WKRR w k r r +WKSE w k s e +WKSM w k s m +WKSU w k s u +WKTU's w k t u's +WKTU w k t u +W.K.V. w k v +W. K. w k +W.K. w k +WKXJ w k x j +WKX w k x +WKYS's w k y s's +WKYT w k y t +WKY w k y +W.L.A.K. w l a k +WLB w l b +WLCH w l c h +WLDM- w l d m +W&LE w and l e +Wley w l e y +WLFM- w l f m +WLGH w l g h +WLH w l h +WLHZ- w l h z +WLIE- w l i e +WLII w l i i +WLIR w l i r +WLIX- w l i x +WLJY w l j y +WLKT w l k t +WLKY w l k y +WLLM w l l m +WLNE- w l n e +WLNP w l n p +WLNQ w l n q +WLNS w l n s +WLPA w l p a +WLPR w l p r +WLPWR w l p w r +wlrs w l r s +WLSG w l s g +WLS- w l s +WLS w l s +WLTM w l t m +WLTQ- w l t q +WLUK's w l u k's +WLUK w l u k +WLUP- w l u p +WLWC w l w c +W. L. w l +W.L. w l +WL- w l +WL w l +WLW- w l w +WLW w l w +WLYH's w l y h's +WLYN w l y n +WLY w l y +WLZK w l z k +WMAC w m a c +WMAG w m a g +WMAN- w m a n +WMAP w m a p +WMAQ- w m a q +WMAQ w m a q +WMAR- w m a r +WMATA's w m a t a's +WMATA w m a t a +W.M.A. w m a +WMA w m a +WMAZ w m a z +WMBD- w m b d +WMBG w m b g +WMCAT w m c a t +WMCA w m c a +WMCT- w m c t +WMDB w m d b +WMDI w m d i +WMD w m d +WMEC- w m e c +WMEE w m e e +WMEN w m e n +WMET w m e t +WME w m e +WMEX w m e x +WMFC w m f c +WMFM w m f m +WMFP w m f p +W.M.F. w m f +WMF w m f +WMGF w m g f +WMG w m g +WMGY w m g y +WMHG w m h g +WMHT w m h t +WMIX w m i x +WMJR w m j r +WMJZ w m j z +WMKG- w m k g +WMKQ w m k q +WMKW w m k w +wml w m l +WMLW w m l w +WMLY w m l y +WMLZ- w m l z +WMMS w m m s +W. M. M. w m m +WMNF w m n f +WMNI- w m n i +WMN w m n +WMOB w m o b +WMO w m o +WMRA w m r a +WMRO w m r o +WMSG w m s g +W.M.S. w m s +WMS w m s +WMTL- w m t l +WMTS w m t s +WMT w m t +WMTW w m t w +WMUB w m u b +WMU w m u +WMVM w m v m +WMVP- w m v p +WMV w m v +W&M w and m +W. M. w m +W.M. w m +WM- w m +WM w m +WMWM w m w m +WMXB w m x b +WMX w m x +WMYE w m y e +WMYL w m y l +WNAK w n a k +W.N.B.A. w n b a +WNBA w n b a +WNBC w n b c +WNBL w n b l +WNBR w n b r +WNB w n b +WNCN w n c n +WNCT- w n c t +WNC w n c +WNCX w n c x +WND w n d +WNED w n e d +WNEG- w n e g +WNEL w n e l +WNEM w n e m +WNEP w n e p +WNET w n e t +WNEW's w n e w's +WNEW w n e w +WNFM w n f m +WNGL w n g l +WNHC- w n h c +WNIC- w n i c +WNIT w n i t +WNJN w n j n +WNJO w n j o +WNJY w n j y +WNK w n k +WNLO w n l o +WNLU w n l u +WNL w n l +WNMX w n m x +WNNS- w n n s +WNO w n o +WNPT w n p t +WNRN w n r n +WNR's w n r's +WNRV w n r v +WNSH w n s h +WNSR w n s r +WNTM w n t m +Wnt- w n t +WNT w n t +WNUA w n u a +WNUF w n u f +WNUSP w n u s p +WNWBL w n w b l +W. N. w n +W.N. w n +WN w n +WNWO w n w o +WNWS w n w s +WNW w n w +WNYA w n y a +WNYC's w n y c's +WNYC w n y c +WNYM w n y m +WNYO- w n y o +WNY w n y +WNYW- w n y w +WNYZ- w n y z +WNYZ w n y z +wnzaa w n z a a +WOAA w o a a +WOAK w o a k +WOA w o a +WOBC- w o b c +WOC w o c +W&OD w and o d +W.O.G. w o g +WOGX's w o g x's +WOJG w o j g +WOKZ- w o k z +WOLH w o l h +WOOM w o o m +WOPC w o p c +Worh w o r h +WOSM w o s m +WOTM- w o t m +W. O. w o +W.O. w o +WOWOW w o w o w +WOXY- w o x y +WOXY w o x y +WOZN w o z n +WPAC w p a c +WPA- w p a +WPA w p a +WPBC w p b c +WPBF- w p b f +WPBSA w p b s a +WPBS w p b s +WPBT w p b t +WPCH- w p c h +WPCQ- w p c q +W. P. C. w p c +WPC w p c +WPDH w p d h +WPD w p d +WPFF w p f f +WPFL w p f l +WPF w p f +WPGC w p g c +WPGG- w p g g +WPHG- w p h g +WPHL w p h l +WPH w p h +WPIAL w p i a l +WPI w p i +WPIX- w p i x +WPIX w p i x +WPLA w p l a +WPLB- w p l b +WPLG w p l g +WPLS w p l s +WPMW w p m w +WPO w p o +WPPT w p p t +WPP- w p p +WPP w p p +WPRI w p r i +WPRO w p r o +WPRP w p r p +WPSC w p s c +WPSL w p s l +WPS w p s +WPTB w p t b +WPTD's w p t d's +wpt w p t +WPT w p t +WPTY w p t y +W. P. U. w p u +wp w p +W. P. w p +W.P. w p +WP- w p +WP w p +WPXN w p x n +WPYR w p y r +WQDE w q d e +WQDR- w q d r +WQHT w q h t +WQHU- w q h u +WQIV w q i v +WQLR w q l r +WQLT- w q l t +WQLZ w q l z +WQMS w q m s +WQOK w q o k +WQSJ- w q s j +WQSO w q s o +WQSX w q s x +WQVC- w q v c +WQ w q +WQXI w q x i +WQXR w q x r +W. R. A. S. w r a s +WRAT w r a t +WRBU w r b u +WRCB w r c b +WRCN w r c n +WRC- w r c +WRC w r c +WRDL w r d l +WRDW- w r d w +Wrec w r e c +WRFD w r f d +WRFK w r f k +WRFM w r f m +WRFX w r f x +WRGO w r g o +WRGP w r g p +WRGT- w r g t +W. R. G. w r g +WRHA w r h a +WRHC w r h c +WRHI w r h i +W.R.I. w r i +WRJK- w r j k +WRJN- w r j n +WRKA w r k a +WRKO w r k o +WRKT w r k t +W.R.K. w r k +WRKY w r k y +WRNS w r n s +WRN w r n +WRNY w r n y +WRNZ w r n z +WROJ w r o j +WROK w r o k +WROO w r o o +WRPT w r p t +WRQQ w r q q +WRRK- w r r k +WRSW- w r s w +WRTA w r t a +WRTC w r t c +WRUV w r u v +WRU w r u +WRVL w r v l +WRVS w r v s +WRWB w r w b +W. R. w r +W.R. w r +WR- w r +WR w r +W.R.W. w r w +WRXT w r x t +WSAR w s a r +WSAV w s a v +W.S.A. w s a +WSA w s a +WSAZ w s a z +WSBG w s b g +WSBM w s b m +WSBT w s b t +WSB- w s b +WSB w s b +WSCA's w s c a's +WSCR w s c r +W. S. C. w s c +WSC w s c +WSDD w s d d +WSDG w s d g +WSDOT w s d o t +WSDP w s d p +WSDR w s d r +WSEE- w s e e +WSEG w s e g +WSEK w s e k +WSER- w s e r +WSE w s e +WSFA w s f a +WSFL w s f l +WSFM w s f m +WSFS w s f s +WSFX w s f x +WSGE w s g e +WSGW w s g w +WSHL w s h l +WSHU w s h u +WSH w s h +WSIPC w s i p c +WSIS w s i s +WSJM w s j m +WSJO w s j o +WSJ w s j +WSKG- w s k g +WSK- w s k +WSLU w s l u +WSL w s l +WSMG- w s m g +WSMK w s m k +W.S.M. w s m +WSM- w s m +WSM w s m +WSNJ w s n j +WSNS w s n s +WSNT w s n t +WSN w s n +WSNX- w s n x +WSOF w s o f +WSOPE w s o p e +WSOP's w s o p's +WSOP, w s o p +WSOP w s o p +WSORR w s o r r +WSO w s o +WSOY w s o y +WSPA- w s p a +WSPA w s p a +WSPC w s p c +WSPD w s p d +WSPN w s p n +WSPS w s p s +WSPU w s p u +WSP w s p +WSRA w s r a +WSRE's w s r e's +WSRF w s r f +WSSA w s s a +WSSCC w s s c c +WSSSA- w s s s a +WSSSA w s s s a +WSS w s s +WSTE w s t e +WSTR- w s t r +WSTR w s t r +WSUA w s u a +WSUD w s u d +WSUE w s u e +WSUS w s u s +WSU w s u +WSVF- w s v f +WSV w s v +WSVZ w s v z +WSWI w s w i +ws w s +W. S. w s +W.S. w s +WS- w s +WS w s +WSW w s w +WSYN w s y n +WSYX w s y x +WSYY- w s y y +WSZE- w s z e +WTAA w t a a +WTAB- w t a b +WTAE- w t a e +WTAE w t a e +WTAF w t a f +WTAG w t a g +WTAM's w t a m's +W. T. A. w t a +WTA w t a +WTAW w t a w +WTCC w t c c +W. T. C. w t c +W.T.C. w t c +WTC w t c +WTDY w t d y +WTEL w t e l +WTEV's w t e v's +WTEV w t e v +WTF w t f +WTGB- w t g b +WTGB w t g b +WTHR's w t h r's +WTHS w t h s +WTIU w t i u +WTI w t i +WTIX w t i x +WTKG w t k g +WTKO w t k o +WTKR w t k r +WTKS- w t k s +WTKS w t k s +WTLS w t l s +WTMA w t m a +WTNH w t n h +WTNO- w t n o +WTN w t n +WTOK- w t o k +WTOP- w t o p +WTOP w t o p +WTO's w t o's +WTOS w t o s +WTO w t o +WTPA w t p a +WTPL- w t p l +WTPM- w t p m +WTPQ w t p q +WTRF- w t r f +WTR w t r +WTSP- w t s p +WTSQ- w t s q +WTs w t's +WTS w t s +WTTF w t t f +WTTM w t t m +WTTs w t t's +WTT w t t +WTTW w t t w +WTTZ w t t z +WTVA- w t v a +WTVA w t v a +WTVC w t v c +WTVD w t v d +WTVF- w t v f +WTVI w t v i +WTVM w t v m +WTVU w t v u +WTVW w t v w +WTVX w t v x +WTWF w t w f +W. T. w t +W.T. w t +WT- w t +WT w t +WTX w t x +WUAB w u a b +WUAP w u a p +WUAs w u a's +WUC w u c +Wudl w u d l +Wuhr w u h r +Wuhu w u h u +WUKB w u k b +WUPG w u p g +WUPN w u p n +WUPZ w u p z +Wu's w u's +WUSW w u s w +WUTK w u t k +WUVC w u v c +wuv w u v +W. U. w u +Wuz w u z +WVAN- w v a n +WVa w v a +WVBX w v b x +WVCA w v c a +WVFJ- w v f j +WVIR- w v i r +WVIT w v i t +WVIZ- w v i z +WVJC w v j c +WVJP w v j p +WVLZ w v l z +WVNI w v n i +WVNS- w v n s +WVNY w v n y +W. V. O. w v o +WVO w v o +WVPA w v p a +WVPO w v p o +WVPX- w v p x +WVSSAC w v s s a c +WVST- w v s t +WVSU w v s u +WVTF- w v t f +WVTU's w v t u's +WVTU w v t u +WVUE w v u e +WVU w v u +WVUW w v u w +W. V. w v +W.V. w v +WV- w v +WV w v +W- w +WWAA w w a a +WWAC- w w a c +WWAMI w w a m i +WWASP w w a s p +WWA w w a +WWAX w w a x +WWBZ w w b z +WWCD w w c d +WWC w w c +WWDB's w w d b's +WWDC- w w d c +WWDC w w d c +WWDR w w d r +WWD w w d +WWEN- w w e n +WWE's w w e's +Wwe w w e +WWE w w e +WWF's w w f's +WWF- w w f +WWF w w f +WWGC w w g c +WWHT w w h t +WWHW w w h w +WWIL- w w i l +WWIS w w i s +WWJP w w j p +WWJ- w w j +WWKB w w k b +WWKL w w k l +WWML w w m l +WWMM w w m m +WWMX w w m x +WWMY w w m y +WWN w w n +WWNW w w n w +WWNY w w n y +WWOX w w o x +WWPG w w p g +WWP w w p +WWPW w w p w +WWRFC w w r f c +WWRV w w r v +WWSS w w s s +WWS w w s +WWTI's w w t i's +WWTI w w t i +WWTN w w t n +WWU w w u +WWVA w w v a +WWVR w w v r +WWV w w v +WWWF w w w f +WWWQ's w w w q's +W. W. w w +W.W. w w +WW- w w +WW w w +WWW w w w +WWWW w w w w +WWYD w w y d +WXB w x b +WXCN w x c n +WXCY- w x c y +WXDU w x d u +WXEL- w x e l +WXEL w x e l +WXII- w x i i +WXIL w x i l +WXIN's w x i n's +WXIN w x i n +WXJM's w x j m's +WXJ w x j +WXL- w x l +WXN w x n +WXQW w x q w +WXRK- w x r k +WXSR- w x s r +WXTG w x t g +WXTH- w x t h +WXW w x w +wx w x +WX w x +W.Y. w y +WY w y +wyzc w y z c +WZBC- w z b c +WZBC w z b c +WZFG w z f g +WZFT w z f t +WZGC w z g c +WZJQ w z j q +WZKC w z k c +WZLR w z l r +WZLX- w z l x +WZLX w z l x +WZRB w z r b +WZRD w z r d +WZST w z s t +WZT- w z t +W. Z. w z +WZ w z +WZX w z x +WZZM- w z z m +WZZM w z z m +WZZX w z z x +Xav x a v +XAV x a v +xa x a +Xa x a +XA- x a +XA x a +xbg x b g +XBMC x b m c +XBM x b m +Xbra x b r a +XBRL x b r l +XBV x b v +XB- x b +XB x b +XCB x c b +XCE x c e +XCMS x c m s +XCOM x c o m +XCOR x c o r +xCo x c o +XCR x c r +XCT x c t +XCVI x c v i +XCV x c v +X. C. x c +XC- x c +XC x c +XCX x c x +xda x d a +XDDM x d d m +XDE- x d e +XDH x d h +XDK x d k +XDRs x d r's +XDR- x d r +XDR x d r +XD's x d's +XDS x d s +X. D. x d +XD x d +Xfce x f c e +XFC x f c +XFDL x f d l +XFD x f d +XFL x f l +XFM x f m +XFR- x f r +XFS x f s +XFU x f u +xf x f +X.F. x f +XF- x f +XF x f +XHVFC x h v f c +xh x h +X. H. x h +XH x h +xix x i x +XIX- x i x +XJD x j d +XJ- x j +XJ x j +XKE x k e +XKL x k l +xk x k +XK x k +XL x l +XMB x m b +xmc x m c +xml x m l +XML- x m l +XML x m l +XMMS x m m s +XMM- x m m +XMPP x m p p +XMP x m p +XMRV x m r v +XMSN x m s n +XM's x m's +XMU x m u +X.M. x m +XM x m +XN x n +xO x o +X.O. x o +XO- x o +XO x o +XPA x p a +XPD x p d +XPe x p e +XPL x p l +XPN x p n +XP's x p's +XPS x p s +XPT x p t +XPW x p w +XP- x p +XP x p +X.Q. x q +XQ x q +XRCC x r c c +XRCO x r c o +XRDS x r d s +XRD x r d +XRE x r e +XR x r +XSD x s d +xSi- x s i +XSi x s i +XSI x s i +XSLT x s l t +XSL- x s l +xsr x s r +XS x s +XTB x t b +XTC x t c +XTG x t g +XTwas x t w a's +xt x t +XT x t +XVAS x v a +XV- x v +XV x v +XWA x w a +XWB x w b +XWF x w f +XWIS x w i s +X. W. x w +XYNU x y n u +XYP x y p +xy x y +XY x y +xyz x y z +xyZ x y z +XYZ x y z +XZ x z +Y. A. y a +Y.A. y a +YA- y a +YBA y b a +YBL y b l +YBNL y b n l +YBN y b n +YBR y b r +YBT- y b t +YBX y b x +Y. B. y b +Y.B. y b +YB- y b +YB y b +YBYS y b y s +YCC y c c +YCD y c d +ycia y c i a +ycie y c i e +YCL y c l +YCO y c o +YCU y c u +YCV y c v +yc y c +Y. C. y c +Y.C. y c +YC- y c +YC y c +YCYW y c y w +YDA y d a +Ydby y d b y +Yde y d e +YDG y d g +YdiB y d i b +YDK y d k +YDM- y d m +YDNC y d n c +yd y d +Y. D. y d +Y.D. y d +YD y d +Y.E. y e +YFCMD y f c m d +YFCs y f c's +YFCU y f c u +YFC- y f c +YFC y f c +YFD- y f d +yfle y f l e +YF&R y f and r +YF- y f +YF y f +YGB y g b +YGEX y g e x +YGLA y g l a +YGL y g l +YG's y g's +yg y g +Y. G. y g +Y.G. y g +YG- y g +YG y g +YHA y h a +YHWH y h w h +Y. H. y h +YH- y h +YH y h +YIF y i f +YIG y i g +YITP y i t p +Y. I. y i +Y.I. y i +YJO y j o +yj y j +Y. J. y j +YJ- y j +YJ y j +Ykt y k t +Y. K. y k +Y.K. y k +YK y k +YKY y k y +Yle y l e +YLE y l e +YLF y l f +yl- y l +yl y l +Y. L. y l +YL- y l +YL y l +YMCA's y m c a's +Y.M.C.A. y m c a +YMCA. y m c a +YMCA y m c a +YMF y m f +Ymke y m k e +Y.M.M. y m m +YMM y m m +YMO y m o +YMS- y m s +ym y m +Y. M. y m +YM y m +yndi y n d i +Yndi y n d i +yne y n e +Yngve y n g v e +Ynis y n i's +YNK y n k +YNU y n u +yn y n +Yn y n +Y. N. y n +Y.N. y n +YN- y n +YN y n +Y.O. y o +YO y o +ypa y p a +YPC y p c +YPF y p f +YPG y p g +YPM y p m +YPO y p o +Y.P.P. y p p +YPP y p p +Y.P.S. y p s +YPT- y p t +YPT y p t +YPU y p u +Y.P. y p +YP- y p +YP y p +Y. Q. y q +YQ y q +yra y r a +Yra y r a +YRC y r c +YRF y r f +YRK y r k +YRM y r m +YRT y r t +Y&R y and r +YSD- y s d +YSK'da y s k d a +YSK'ya y s k y a +YSK y s k +YSL y s l +YSRCP y s r c p +YSR y s r +YSU's y s u's +YSU y s u +Ys y's +Y.S. y s +YS- y s +YS y s +YSY y s y +yta y t a +YTB y t b +Ytre y t r e +YTS y t s +YTV's y t v's +YTV y t v +Y&T y and t +Y. T. y t +Y.T. y t +YT y t +Y. V. y v +YWCA- y w c a +YWCA. y w c a +YWCA y w c a +YWC y w c +Y. W. y w +Y.Y. y y +Z. A. B. z a b +Z. A. z a +Z.A. z a +ZBC z b c +ZBS z b s +ZB z b +ZCE z c e +ZCGWM z c g w m +ZCMI z c m i +ZCTA z c t a +ZCY z c y +ZC z c +Zdar z d a r +zda z d a +ZDF z d f +ZDR z d r +Z.E.R.O. z e r o +ZFC z f c +ZFK z f k +ZFM z f m +ZFP z f p +ZFS z f s +ZFX z f x +ZF z f +ZGE z g e +ZGI z g i +zg z g +Z.G. z g +ZG z g +zh z h +Z. H. z h +Z.H. z h +ZH z h +zijn z i j n +zij z i j +Zij z i j +Z. I. z i +Z. J. z j +ZKK z k k +ZKM z k m +Z.K. z k +Z.L. z l +Z.M. z m +ZNA z n a +ZNF z n f +ZNK z n k +ZnO z n o +ZNW z n w +ZPAP z p a p +Zpav z p a v +ZPAV z p a v +ZPA z p a +ZPG- z p g +ZPK z p k +ZPU- z p u +Z.P. z p +ZP- z p +ZP z p +ZQ z q +ZRC z r c +ZrI z r i +ZRK z r k +ZSC z s c +ZSE z s e +ZSF z s f +ZSG's z s g's +ZSIS z s i s +ZSL z s l +ZSO z s o +ZSSS z s s s +Zsuzsa z s u z s a +ZSU- z s u +ZTE z t e +ZWYCI z w y c i +Z.W. z w +Z.X.V. z x v +Z.X. z x +ZYF z y f +Z. Y. z y +Z.Y. z y +Z. Z. z z +Z.Z. z z diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data/whitelist_alternatives.tsv b/tts/NeMo/nemo_text_processing/text_normalization/data/whitelist_alternatives.tsv new file mode 100644 index 0000000..8cea774 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data/whitelist_alternatives.tsv @@ -0,0 +1,17 @@ +Hon. Honorable +Hon. Honourable +St. Street +St Street +St. Saint +St Saint +Dr. Drive +Dr. Doctor +Mr. Mister +Mrs. Misses +Ms. Miss +Mr Mister +Mrs Misses +Ms Miss +&Co. and Co. +§ section += equals \ No newline at end of file diff --git a/tts/NeMo/nemo_text_processing/text_normalization/data_loader_utils.py b/tts/NeMo/nemo_text_processing/text_normalization/data_loader_utils.py new file mode 100644 index 0000000..1aaac7a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/data_loader_utils.py @@ -0,0 +1,269 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import csv +import json +import os +import re +from collections import defaultdict, namedtuple +from typing import Dict, List, Optional, Set, Tuple + +EOS_TYPE = "EOS" +PUNCT_TYPE = "PUNCT" +PLAIN_TYPE = "PLAIN" +Instance = namedtuple('Instance', 'token_type un_normalized normalized') +known_types = [ + "PLAIN", + "DATE", + "CARDINAL", + "LETTERS", + "VERBATIM", + "MEASURE", + "DECIMAL", + "ORDINAL", + "DIGIT", + "MONEY", + "TELEPHONE", + "ELECTRONIC", + "FRACTION", + "TIME", + "ADDRESS", +] + + +def load_kaggle_text_norm_file(file_path: str) -> List[Instance]: + """ + https://www.kaggle.com/richardwilliamsproat/text-normalization-for-english-russian-and-polish + Loads text file in the Kaggle Google text normalization file format: \t\t<`self` if trivial class or normalized text> + E.g. + PLAIN Brillantaisia + PLAIN is + PLAIN a + PLAIN genus + PLAIN of + PLAIN plant + PLAIN in + PLAIN family + PLAIN Acanthaceae + PUNCT . sil + + + Args: + file_path: file path to text file + + Returns: flat list of instances + """ + res = [] + with open(file_path, 'r') as fp: + for line in fp: + parts = line.strip().split("\t") + if parts[0] == "": + res.append(Instance(token_type=EOS_TYPE, un_normalized="", normalized="")) + else: + l_type, l_token, l_normalized = parts + l_token = l_token.lower() + l_normalized = l_normalized.lower() + + if l_type == PLAIN_TYPE: + res.append(Instance(token_type=l_type, un_normalized=l_token, normalized=l_token)) + elif l_type != PUNCT_TYPE: + res.append(Instance(token_type=l_type, un_normalized=l_token, normalized=l_normalized)) + return res + + +def load_files(file_paths: List[str], load_func=load_kaggle_text_norm_file) -> List[Instance]: + """ + Load given list of text files using the `load_func` function. + + Args: + file_paths: list of file paths + load_func: loading function + + Returns: flat list of instances + """ + res = [] + for file_path in file_paths: + res.extend(load_func(file_path=file_path)) + return res + + +def clean_generic(text: str) -> str: + """ + Cleans text without affecting semiotic classes. + + Args: + text: string + + Returns: cleaned string + """ + text = text.strip() + text = text.lower() + return text + + +def evaluate(preds: List[str], labels: List[str], input: Optional[List[str]] = None, verbose: bool = True) -> float: + """ + Evaluates accuracy given predictions and labels. + + Args: + preds: predictions + labels: labels + input: optional, only needed for verbosity + verbose: if true prints [input], golden labels and predictions + + Returns accuracy + """ + acc = 0 + nums = len(preds) + for i in range(nums): + pred_norm = clean_generic(preds[i]) + label_norm = clean_generic(labels[i]) + if pred_norm == label_norm: + acc = acc + 1 + else: + if input: + print(f"inpu: {json.dumps(input[i])}") + print(f"gold: {json.dumps(label_norm)}") + print(f"pred: {json.dumps(pred_norm)}") + return acc / nums + + +def training_data_to_tokens( + data: List[Instance], category: Optional[str] = None +) -> Dict[str, Tuple[List[str], List[str]]]: + """ + Filters the instance list by category if provided and converts it into a map from token type to list of un_normalized and normalized strings + + Args: + data: list of instances + category: optional semiotic class category name + + Returns Dict: token type -> (list of un_normalized strings, list of normalized strings) + """ + result = defaultdict(lambda: ([], [])) + for instance in data: + if instance.token_type != EOS_TYPE: + if category is None or instance.token_type == category: + result[instance.token_type][0].append(instance.un_normalized) + result[instance.token_type][1].append(instance.normalized) + return result + + +def training_data_to_sentences(data: List[Instance]) -> Tuple[List[str], List[str], List[Set[str]]]: + """ + Takes instance list, creates list of sentences split by EOS_Token + Args: + data: list of instances + Returns (list of unnormalized sentences, list of normalized sentences, list of sets of categories in a sentence) + """ + # split data at EOS boundaries + sentences = [] + sentence = [] + categories = [] + sentence_categories = set() + + for instance in data: + if instance.token_type == EOS_TYPE: + sentences.append(sentence) + sentence = [] + categories.append(sentence_categories) + sentence_categories = set() + else: + sentence.append(instance) + sentence_categories.update([instance.token_type]) + un_normalized = [" ".join([instance.un_normalized for instance in sentence]) for sentence in sentences] + normalized = [" ".join([instance.normalized for instance in sentence]) for sentence in sentences] + return un_normalized, normalized, categories + + +def load_labels(abs_path): + """ + loads relative path file as dictionary + + Args: + abs_path: absolute path + + Returns dictionary of mappings + """ + label_tsv = open(abs_path) + labels = list(csv.reader(label_tsv, delimiter="\t")) + return labels + + +def get_abs_path(rel_path): + """ + Get absolute path + + Args: + rel_path: relative path to this file + + Returns absolute path + """ + return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path + + +def post_process_punctuation(text: str) -> str: + """ + Normalized quotes and spaces + + Args: + text: text + + Returns: text with normalized spaces and quotes + """ + text = ( + text.replace('( ', '(') + .replace(' )', ')') + .replace('{ ', '{') + .replace(' }', '}') + .replace('[ ', '[') + .replace(' ]', ']') + .replace(' ', ' ') + .replace('”', '"') + .replace("’", "'") + .replace("»", '"') + .replace("«", '"') + .replace("\\", "") + .replace("„", '"') + .replace("´", "'") + .replace("’", "'") + .replace('“', '"') + .replace("‘", "'") + .replace('`', "'") + .replace('- -', "--") + ) + + for punct in "!,.:;?": + text = text.replace(f' {punct}', punct) + return text.strip() + + +def pre_process(text: str) -> str: + """ + Adds space around punctuation marks + + Args: + text: string that may include semiotic classes + + Returns: text with spaces around punctuation marks + """ + space_both = '*<=>^[]{}' + for punct in space_both: + text = text.replace(punct, ' ' + punct + ' ') + + text = text.replace('--', ' ' + '--' + ' ') + # remove extra space + text = re.sub(r' +', ' ', text) + return text diff --git a/tts/NeMo/nemo_text_processing/text_normalization/graph_utils.py b/tts/NeMo/nemo_text_processing/text_normalization/graph_utils.py new file mode 100644 index 0000000..71cdc62 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/graph_utils.py @@ -0,0 +1,216 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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 os +import string +from pathlib import Path + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path + +try: + import pynini + from pynini import Far + from pynini.examples import plurals + from pynini.lib import byte, pynutil, utf8 + + NEMO_CHAR = utf8.VALID_UTF8_CHAR + + NEMO_DIGIT = byte.DIGIT + NEMO_LOWER = pynini.union(*string.ascii_lowercase).optimize() + NEMO_UPPER = pynini.union(*string.ascii_uppercase).optimize() + NEMO_ALPHA = pynini.union(NEMO_LOWER, NEMO_UPPER).optimize() + NEMO_ALNUM = pynini.union(NEMO_DIGIT, NEMO_ALPHA).optimize() + NEMO_HEX = pynini.union(*string.hexdigits).optimize() + NEMO_NON_BREAKING_SPACE = u"\u00A0" + NEMO_SPACE = " " + NEMO_WHITE_SPACE = pynini.union(" ", "\t", "\n", "\r", u"\u00A0").optimize() + NEMO_NOT_SPACE = pynini.difference(NEMO_CHAR, NEMO_WHITE_SPACE).optimize() + NEMO_NOT_QUOTE = pynini.difference(NEMO_CHAR, r'"').optimize() + + NEMO_PUNCT = pynini.union(*map(pynini.escape, string.punctuation)).optimize() + NEMO_GRAPH = pynini.union(NEMO_ALNUM, NEMO_PUNCT).optimize() + + NEMO_SIGMA = pynini.closure(NEMO_CHAR) + + delete_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE)) + insert_space = pynutil.insert(" ") + delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") + + suppletive = pynini.string_file(get_abs_path("data/suppletive.tsv")) + # _v = pynini.union("a", "e", "i", "o", "u") + _c = pynini.union( + "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z" + ) + _ies = NEMO_SIGMA + _c + pynini.cross("y", "ies") + _es = NEMO_SIGMA + pynini.union("s", "sh", "ch", "x", "z") + pynutil.insert("es") + _s = NEMO_SIGMA + pynutil.insert("s") + + graph_plural = plurals._priority_union( + suppletive, plurals._priority_union(_ies, plurals._priority_union(_es, _s, NEMO_SIGMA), NEMO_SIGMA), NEMO_SIGMA + ).optimize() + + SINGULAR_TO_PLURAL = graph_plural + PLURAL_TO_SINGULAR = pynini.invert(graph_plural) + TO_LOWER = pynini.union(*[pynini.cross(x, y) for x, y in zip(string.ascii_uppercase, string.ascii_lowercase)]) + TO_UPPER = pynini.invert(TO_LOWER) + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + # Create placeholders + NEMO_CHAR = None + + NEMO_DIGIT = None + NEMO_LOWER = None + NEMO_UPPER = None + NEMO_ALPHA = None + NEMO_ALNUM = None + NEMO_HEX = None + NEMO_NON_BREAKING_SPACE = u"\u00A0" + NEMO_SPACE = " " + NEMO_WHITE_SPACE = None + NEMO_NOT_SPACE = None + NEMO_NOT_QUOTE = None + + NEMO_PUNCT = None + NEMO_GRAPH = None + + NEMO_SIGMA = None + + delete_space = None + insert_space = None + delete_extra_space = None + + suppletive = None + # _v = pynini.union("a", "e", "i", "o", "u") + _c = None + _ies = None + _es = None + _s = None + + graph_plural = None + + SINGULAR_TO_PLURAL = None + PLURAL_TO_SINGULAR = None + TO_LOWER = None + TO_UPPER = None + + PYNINI_AVAILABLE = False + + +def get_plurals(fst): + """ + Given singular returns plurals + + Args: + fst: Fst + + Returns plurals to given singular forms + """ + return SINGULAR_TO_PLURAL @ fst + + +def get_singulars(fst): + """ + Given plural returns singulars + + Args: + fst: Fst + + Returns singulars to given plural forms + """ + return PLURAL_TO_SINGULAR @ fst + + +def convert_space(fst) -> 'pynini.FstLike': + """ + Converts space to nonbreaking space. + Used only in tagger grammars for transducing token values within quotes, e.g. name: "hello kitty" + This is making transducer significantly slower, so only use when there could be potential spaces within quotes, otherwise leave it. + + Args: + fst: input fst + + Returns output fst where breaking spaces are converted to non breaking spaces + """ + return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) + + +class GraphFst: + """ + Base class for all grammar fsts. + + Args: + name: name of grammar class + kind: either 'classify' or 'verbalize' + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, name: str, kind: str, deterministic: bool = True): + self.name = name + self.kind = str + self._fst = None + self.deterministic = deterministic + + self.far_path = Path(os.path.dirname(__file__) + '/grammars/' + kind + '/' + name + '.far') + if self.far_exist(): + self._fst = Far(self.far_path, mode="r", arc_type="standard", far_type="default").get_fst() + + def far_exist(self) -> bool: + """ + Returns true if FAR can be loaded + """ + return self.far_path.exists() + + @property + def fst(self) -> 'pynini.FstLike': + return self._fst + + @fst.setter + def fst(self, fst): + self._fst = fst + + def add_tokens(self, fst) -> 'pynini.FstLike': + """ + Wraps class name around to given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + return pynutil.insert(f"{self.name} {{ ") + fst + pynutil.insert(" }") + + def delete_tokens(self, fst) -> 'pynini.FstLike': + """ + Deletes class name wrap around output of given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + res = ( + pynutil.delete(f"{self.name}") + + delete_space + + pynutil.delete("{") + + delete_space + + fst + + delete_space + + pynutil.delete("}") + ) + return res @ pynini.cdrewrite(pynini.cross(u"\u00A0", " "), "", "", NEMO_SIGMA) diff --git a/tts/NeMo/nemo_text_processing/text_normalization/normalize.py b/tts/NeMo/nemo_text_processing/text_normalization/normalize.py new file mode 100644 index 0000000..353025a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/normalize.py @@ -0,0 +1,246 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +from argparse import ArgumentParser +from collections import OrderedDict +from typing import List + +from nemo_text_processing.text_normalization.data_loader_utils import post_process_punctuation, pre_process +from nemo_text_processing.text_normalization.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.text_normalization.token_parser import PRESERVE_ORDER_KEY, TokenParser +from nemo_text_processing.text_normalization.verbalizers.verbalize_final import VerbalizeFinalFst +from tqdm import tqdm + +try: + import pynini + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class Normalizer: + """ + Normalizer class that converts text from written to spoken form. + Useful for TTS preprocessing. + + Args: + input_case: expected input capitalization + """ + + def __init__(self, input_case: str): + assert input_case in ["lower_cased", "cased"] + + self.tagger = ClassifyFst(input_case=input_case, deterministic=True) + self.verbalizer = VerbalizeFinalFst(deterministic=True) + self.parser = TokenParser() + + def normalize_list(self, texts: List[str], verbose=False) -> List[str]: + """ + NeMo text normalizer + + Args: + texts: list of input strings + verbose: whether to print intermediate meta information + + Returns converted list input strings + """ + res = [] + for input in tqdm(texts): + try: + text = self.normalize(input, verbose=verbose) + except: + print(input) + raise Exception + res.append(text) + return res + + def normalize( + self, text: str, verbose: bool, punct_pre_process: bool = False, punct_post_process: bool = False + ) -> str: + """ + Main function. Normalizes tokens from written to spoken form + e.g. 12 kg -> twelve kilograms + + Args: + text: string that may include semiotic classes + verbose: whether to print intermediate meta information + punct_pre_process: whether to perform punctuation pre-processing, for example, [25] -> [ 25 ] + punct_post_process: whether to normalize punctuation + + Returns: spoken form + """ + if punct_pre_process: + text = pre_process(text) + text = text.strip() + if not text: + if verbose: + print(text) + return text + text = pynini.escape(text) + tagged_lattice = self.find_tags(text) + tagged_text = self.select_tag(tagged_lattice) + if verbose: + print(tagged_text) + self.parser(tagged_text) + tokens = self.parser.parse() + tags_reordered = self.generate_permutations(tokens) + for tagged_text in tags_reordered: + tagged_text = pynini.escape(tagged_text) + verbalizer_lattice = self.find_verbalizer(tagged_text) + if verbalizer_lattice.num_states() == 0: + continue + output = self.select_verbalizer(verbalizer_lattice) + if punct_post_process: + output = post_process_punctuation(output) + return output + raise ValueError() + + def _permute(self, d: OrderedDict) -> List[str]: + """ + Creates reorderings of dictionary elements and serializes as strings + + Args: + d: (nested) dictionary of key value pairs + + Return permutations of different string serializations of key value pairs + """ + l = [] + if PRESERVE_ORDER_KEY in d.keys(): + d_permutations = [d.items()] + else: + d_permutations = itertools.permutations(d.items()) + for perm in d_permutations: + subl = [""] + for k, v in perm: + if isinstance(v, str): + subl = ["".join(x) for x in itertools.product(subl, [f"{k}: \"{v}\" "])] + elif isinstance(v, OrderedDict): + rec = self._permute(v) + subl = ["".join(x) for x in itertools.product(subl, [f" {k} {{ "], rec, [f" }} "])] + elif isinstance(v, bool): + subl = ["".join(x) for x in itertools.product(subl, [f"{k}: true "])] + else: + raise ValueError() + l.extend(subl) + return l + + def generate_permutations(self, tokens: List[dict]): + """ + Generates permutations of string serializations of list of dictionaries + + Args: + tokens: list of dictionaries + + Returns string serialization of list of dictionaries + """ + + def _helper(prefix: str, tokens: List[dict], idx: int): + """ + Generates permutations of string serializations of given dictionary + + Args: + tokens: list of dictionaries + prefix: prefix string + idx: index of next dictionary + + Returns string serialization of dictionary + """ + if idx == len(tokens): + yield prefix + return + token_options = self._permute(tokens[idx]) + for token_option in token_options: + yield from _helper(prefix + token_option, tokens, idx + 1) + + return _helper("", tokens, 0) + + def find_tags(self, text: str) -> 'pynini.FstLike': + """ + Given text use tagger Fst to tag text + + Args: + text: sentence + + Returns: tagged lattice + """ + lattice = text @ self.tagger.fst + return lattice + + def select_tag(self, lattice: 'pynini.FstLike') -> str: + """ + Given tagged lattice return shortest path + + Args: + tagged_text: tagged text + + Returns: shortest path + """ + tagged_text = pynini.shortestpath(lattice, nshortest=1, unique=True).string() + return tagged_text + + def find_verbalizer(self, tagged_text: str) -> 'pynini.FstLike': + """ + Given tagged text creates verbalization lattice + This is context-independent. + + Args: + tagged_text: input text + + Returns: verbalized lattice + """ + lattice = tagged_text @ self.verbalizer.fst + return lattice + + def select_verbalizer(self, lattice: 'pynini.FstLike') -> str: + """ + Given verbalized lattice return shortest path + + Args: + lattice: verbalization lattice + + Returns: shortest path + """ + output = pynini.shortestpath(lattice, nshortest=1, unique=True).string() + return output + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("input_string", help="input string", type=str) + parser.add_argument( + "--input_case", help="input capitalization", choices=["lower_cased", "cased"], default="cased", type=str + ) + parser.add_argument("--verbose", help="print info for debugging", action='store_true') + parser.add_argument( + "--punct_post_process", help="set to True to enable punctuation post processing", action="store_true" + ) + parser.add_argument( + "--punct_pre_process", help="set to True to enable punctuation pre processing", action="store_true" + ) + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + normalizer = Normalizer(input_case=args.input_case) + print( + normalizer.normalize( + args.input_string, + verbose=args.verbose, + punct_pre_process=args.punct_pre_process, + punct_post_process=args.punct_post_process, + ) + ) diff --git a/tts/NeMo/nemo_text_processing/text_normalization/normalize_with_audio.py b/tts/NeMo/nemo_text_processing/text_normalization/normalize_with_audio.py new file mode 100644 index 0000000..4df248f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/normalize_with_audio.py @@ -0,0 +1,327 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import time +from argparse import ArgumentParser +from typing import List, Tuple + +from joblib import Parallel, delayed +from nemo_text_processing.text_normalization.data_loader_utils import post_process_punctuation, pre_process +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.taggers.tokenize_and_classify import ClassifyFst +from nemo_text_processing.text_normalization.verbalizers.verbalize_final import VerbalizeFinalFst + +from nemo.collections.asr.metrics.wer import word_error_rate +from nemo.collections.asr.models import ASRModel + +try: + import pynini + from pynini.lib import rewrite + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + +""" +The script provides multiple normalization options and chooses the best one that minimizes CER of the ASR output +(most of the semiotic classes use deterministic=False flag). + +To run this script with a .json manifest file: + python normalize_with_audio.py \ + --audio_data PATH/TO/MANIFEST.JSON \ + --model QuartzNet15x5Base-En \ + --verbose + + The manifest file should contain the following fields: + "audio_filepath" - path to the audio file + "text" - raw text + "transcript" - ASR model prediction (optional) + + +To run with a single audio file, specify path to audio and text with: + python normalize_with_audio.py \ + --audio_data PATH/TO/AUDIO.WAV \ + --text raw text OR PATH/TO/.TXT/FILE + --model QuartzNet15x5Base-En \ + --verbose + +To see possible normalization options for a text input without an audio file (could be used for debugging), run: + python python normalize_with_audio.py --text "RAW TEXT" +""" + + +class NormalizerWithAudio(Normalizer): + """ + Normalizer class that converts text from written to spoken form. + Useful for TTS preprocessing. + + Args: + input_case: expected input capitalization + """ + + def __init__(self, input_case: str): + super().__init__(input_case) + + self.tagger = ClassifyFst(input_case=input_case, deterministic=False) + self.verbalizer = VerbalizeFinalFst(deterministic=False) + + def normalize( + self, + text: str, + n_tagged: int, + punct_pre_process: bool = True, + punct_post_process: bool = True, + verbose: bool = False, + ) -> str: + """ + Main function. Normalizes tokens from written to spoken form + e.g. 12 kg -> twelve kilograms + + Args: + text: string that may include semiotic classes + n_tagged: number of tagged options to consider, -1 - to get all possible tagged options + punct_pre_process: whether to perform punctuation pre-processing, for example, [25] -> [ 25 ] + punct_post_process: whether to normalize punctuation + verbose: whether to print intermediate meta information + + Returns: + normalized text options (usually there are multiple ways of normalizing a given semiotic class) + """ + if punct_pre_process: + text = pre_process(text) + text = text.strip() + if not text: + if verbose: + print(text) + return text + + text = pynini.escape(text) + if n_tagged == -1: + tagged_texts = rewrite.rewrites(text, self.tagger.fst) + else: + tagged_texts = rewrite.top_rewrites(text, self.tagger.fst, nshortest=n_tagged) + + normalized_texts = [] + for tagged_text in tagged_texts: + self._verbalize(tagged_text, normalized_texts) + if len(normalized_texts) == 0: + raise ValueError() + if punct_post_process: + normalized_texts = [post_process_punctuation(t) for t in normalized_texts] + normalized_texts = set(normalized_texts) + return normalized_texts + + def _verbalize(self, tagged_text: str, normalized_texts: List[str]): + """ + Verbalizes tagged text + + Args: + tagged_text: text with tags + normalized_texts: list of possible normalization options + """ + + def get_verbalized_text(tagged_text): + tagged_text = pynini.escape(tagged_text) + return rewrite.rewrites(tagged_text, self.verbalizer.fst) + + try: + normalized_texts.extend(get_verbalized_text(tagged_text)) + except pynini.lib.rewrite.Error: + self.parser(tagged_text) + tokens = self.parser.parse() + tags_reordered = self.generate_permutations(tokens) + for tagged_text_reordered in tags_reordered: + try: + normalized_texts.extend(get_verbalized_text(tagged_text_reordered)) + except pynini.lib.rewrite.Error: + continue + + def select_best_match( + self, normalized_texts: List[str], transcript: str, verbose: bool = False, remove_punct: bool = False + ): + """ + Selects the best normalization option based on the lowest CER + + Args: + normalized_texts: normalized text options + transcript: ASR model transcript of the audio file corresponding to the normalized text + verbose: whether to print intermediate meta information + remove_punct: whether to remove punctuation before calculating CER + + Returns: + normalized text with the lowest CER and CER value + """ + normalized_texts = calculate_cer(normalized_texts, transcript, remove_punct) + normalized_texts = sorted(normalized_texts, key=lambda x: x[1]) + normalized_text, cer = normalized_texts[0] + + if verbose: + print('-' * 30) + for option in normalized_texts: + print(option) + print('-' * 30) + return normalized_text, cer + + +def calculate_cer(normalized_texts: List[str], transcript: str, remove_punct=False) -> List[Tuple[str, float]]: + """ + Calculates character error rate (CER) + + Args: + normalized_texts: normalized text options + transcript: ASR model output + + Returns: normalized options with corresponding CER + """ + normalized_options = [] + for text in normalized_texts: + text_clean = text.replace('-', ' ').lower() + if remove_punct: + for punct in "!?:;,.-()*+-/<=>@^_": + text_clean = text_clean.replace(punct, "") + cer = round(word_error_rate([transcript], [text_clean], use_cer=True) * 100, 2) + normalized_options.append((text, cer)) + return normalized_options + + +def get_asr_model(asr_model: ASRModel): + """ + Returns ASR Model + + Args: + asr_model: NeMo ASR model + """ + if os.path.exists(args.model): + asr_model = ASRModel.restore_from(asr_model) + elif args.model in ASRModel.get_available_model_names(): + asr_model = ASRModel.from_pretrained(asr_model) + else: + raise ValueError( + f'Provide path to the pretrained checkpoint or choose from {ASRModel.get_available_model_names()}' + ) + return asr_model + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--text", help="input string or path to a .txt file", default=None, type=str) + parser.add_argument( + "--input_case", help="input capitalization", choices=["lower_cased", "cased"], default="cased", type=str + ) + parser.add_argument("--audio_data", help="path to an audio file or .json manifest") + parser.add_argument( + '--model', type=str, default='QuartzNet15x5Base-En', help='Pre-trained model name or path to model checkpoint' + ) + parser.add_argument( + "--n_tagged", + type=int, + default=1000, + help="number of tagged options to consider, -1 - return all possible tagged options", + ) + parser.add_argument("--verbose", help="print info for debugging", action="store_true") + parser.add_argument("--remove_punct", help="remove punctuation before calculating cer", action="store_true") + parser.add_argument( + "--no_punct_pre_process", help="set to True to disable punctuation pre processing", action="store_true" + ) + parser.add_argument( + "--no_punct_post_process", help="set to True to disable punctuation post processing", action="store_true" + ) + return parser.parse_args() + + +def _normalize_line(normalizer: NormalizerWithAudio, line: str, asr_model: ASRModel = None): + line = json.loads(line) + audio = line['audio_filepath'] + if 'transcript' in line: + transcript = line['transcript'] + else: + transcript = asr_model.transcribe([audio])[0] + + normalized_texts = normalizer.normalize( + text=line['text'], + verbose=args.verbose, + n_tagged=args.n_tagged, + punct_pre_process=not args.no_punct_pre_process, + punct_post_process=not args.no_punct_post_process, + ) + normalized_text, cer = normalizer.select_best_match(normalized_texts, transcript, args.verbose, args.remove_punct) + line['nemo_normalized'] = normalized_text + line['CER_nemo_normalized'] = cer + return line + + +def normalize_manifest(args): + """ + Args: + args.audio_data: path to .json manifest file. + """ + normalizer = NormalizerWithAudio(input_case=args.input_case) + manifest_out = args.audio_data.replace('.json', '_normalized.json') + asr_model = None + with open(args.audio_data, 'r') as f: + with open(manifest_out, 'w') as f_out: + lines = f.readlines() + first_line = json.loads(lines[0]) + if 'transcript' not in first_line: + asr_model = get_asr_model(args.model) + normalized_lines = Parallel(n_jobs=-1)( + delayed(_normalize_line)(normalizer, line, asr_model) for line in lines + ) + + for line in normalized_lines: + f_out.write(json.dumps(line, ensure_ascii=False) + '\n') + print(f'Normalized version saved at {manifest_out}') + + +if __name__ == "__main__": + args = parse_args() + + start = time.time() + if args.text: + normalizer = NormalizerWithAudio(input_case=args.input_case) + if os.path.exists(args.text): + with open(args.text, 'r') as f: + args.text = f.read().strip() + normalized_texts = normalizer.normalize( + text=args.text, + verbose=args.verbose, + n_tagged=args.n_tagged, + punct_pre_process=not args.no_punct_pre_process, + punct_post_process=not args.no_punct_post_process, + ) + if args.audio_data: + asr_model = get_asr_model(args.model) + transcript = asr_model.transcribe([args.audio_data])[0] + normalized_text, cer = normalizer.select_best_match( + normalized_texts, transcript, args.verbose, args.remove_punct + ) + print(f'Transcript: {transcript}') + print(f'Normalized: {normalized_text}') + else: + print('Normalization options:') + for norm_text in normalized_texts: + print(norm_text) + elif not os.path.exists(args.audio_data): + raise ValueError(f'{args.audio_data} not found.') + elif args.audio_data.endswith('.json'): + normalize_manifest(args) + else: + raise ValueError( + "Provide either path to .json manifest in '--audio_data' OR " + + "'--audio_data' path to audio file and '--text' path to a text file OR" + "'--text' string text (for debugging without audio)" + ) + print(f'Execution time: {round((time.time() - start)/60, 2)} min.') diff --git a/tts/NeMo/nemo_text_processing/text_normalization/run_evaluate.py b/tts/NeMo/nemo_text_processing/text_normalization/run_evaluate.py new file mode 100644 index 0000000..3065a09 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/run_evaluate.py @@ -0,0 +1,115 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser + +from nemo_text_processing.text_normalization.clean_eval_data import filter_loaded_data +from nemo_text_processing.text_normalization.data_loader_utils import ( + evaluate, + known_types, + load_files, + training_data_to_sentences, + training_data_to_tokens, +) +from nemo_text_processing.text_normalization.normalize import Normalizer + + +''' +Runs Evaluation on data in the format of : \t\t<`self` if trivial class or normalized text> +like the Google text normalization data https://www.kaggle.com/richardwilliamsproat/text-normalization-for-english-russian-and-polish +''' + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--input", help="input file path", type=str) + parser.add_argument( + "--input_case", help="input capitalization", choices=["lower_cased", "cased"], default="cased", type=str + ) + parser.add_argument( + "--cat", + dest="category", + help="focus on class only (" + ", ".join(known_types) + ")", + type=str, + default=None, + choices=known_types, + ) + parser.add_argument("--filter", action='store_true', help="clean data for normalization purposes") + return parser.parse_args() + + +if __name__ == "__main__": + # Example usage: + # python run_evaluate.py --input= --cat= --filter + args = parse_args() + file_path = args.input + normalizer = Normalizer(input_case=args.input_case) + + print("Loading training data: " + file_path) + training_data = load_files([file_path]) + + if args.filter: + training_data = filter_loaded_data(training_data) + + if args.category is None: + print("Sentence level evaluation...") + sentences_un_normalized, sentences_normalized, _ = training_data_to_sentences(training_data) + print("- Data: " + str(len(sentences_normalized)) + " sentences") + sentences_prediction = normalizer.normalize_list(sentences_un_normalized) + print("- Normalized. Evaluating...") + sentences_accuracy = evaluate( + preds=sentences_prediction, labels=sentences_normalized, input=sentences_un_normalized + ) + print("- Accuracy: " + str(sentences_accuracy)) + + print("Token level evaluation...") + tokens_per_type = training_data_to_tokens(training_data, category=args.category) + token_accuracy = {} + for token_type in tokens_per_type: + print("- Token type: " + token_type) + tokens_un_normalized, tokens_normalized = tokens_per_type[token_type] + print(" - Data: " + str(len(tokens_normalized)) + " tokens") + tokens_prediction = normalizer.normalize_list(tokens_un_normalized) + print(" - Denormalized. Evaluating...") + token_accuracy[token_type] = evaluate( + preds=tokens_prediction, labels=tokens_normalized, input=tokens_un_normalized + ) + print(" - Accuracy: " + str(token_accuracy[token_type])) + token_count_per_type = {token_type: len(tokens_per_type[token_type][0]) for token_type in tokens_per_type} + token_weighted_accuracy = [ + token_count_per_type[token_type] * accuracy for token_type, accuracy in token_accuracy.items() + ] + print("- Accuracy: " + str(sum(token_weighted_accuracy) / sum(token_count_per_type.values()))) + print(" - Total: " + str(sum(token_count_per_type.values())), '\n') + + print(" - Total: " + str(sum(token_count_per_type.values())), '\n') + + for token_type in token_accuracy: + if token_type not in known_types: + raise ValueError("Unexpected token type: " + token_type) + + if args.category is None: + c1 = ['Class', 'sent level'] + known_types + c2 = ['Num Tokens', len(sentences_normalized)] + [ + token_count_per_type[known_type] if known_type in tokens_per_type else '0' for known_type in known_types + ] + c3 = ['Normalization', sentences_accuracy] + [ + token_accuracy[known_type] if known_type in token_accuracy else '0' for known_type in known_types + ] + + for i in range(len(c1)): + print(f'{str(c1[i]):10s} | {str(c2[i]):10s} | {str(c3[i]):5s}') + else: + print(f'numbers\t{token_count_per_type[args.category]}') + print(f'Normalization\t{token_accuracy[args.category]}') diff --git a/tts/NeMo/nemo_text_processing/text_normalization/run_predict.py b/tts/NeMo/nemo_text_processing/text_normalization/run_predict.py new file mode 100644 index 0000000..3059dfe --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/run_predict.py @@ -0,0 +1,78 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from argparse import ArgumentParser +from typing import List + +from nemo_text_processing.text_normalization.normalize import Normalizer + + +''' +Runs normalization prediction on text data +''' + + +def load_file(file_path: str) -> List[str]: + """ + Load given text file into list of string. + + Args: + file_path: file path + + Returns: flat list of string + """ + res = [] + with open(file_path, 'r') as fp: + for line in fp: + res.append(line) + return res + + +def write_file(file_path: str, data: List[str]): + """ + Writes out list of string to file. + + Args: + file_path: file path + data: list of string + + """ + with open(file_path, 'w') as fp: + for line in data: + fp.write(line + '\n') + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--input", help="input file path", required=True, type=str) + parser.add_argument("--output", help="output file path", required=True, type=str) + parser.add_argument( + "--input_case", help="input capitalization", choices=["lower_cased", "cased"], default="cased", type=str + ) + parser.add_argument("--verbose", help="print meta info for debugging", action='store_true') + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + file_path = args.input + normalizer = Normalizer(input_case=args.input_case) + + print("Loading data: " + file_path) + data = load_file(file_path) + + print("- Data: " + str(len(data)) + " sentences") + normalizer_prediction = normalizer.normalize_list(data, verbose=args.verbose) + write_file(args.output, normalizer_prediction) + print(f"- Normalized. Writing out to {args.output}") diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/cardinal.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/cardinal.py new file mode 100644 index 0000000..2d01a49 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/cardinal.py @@ -0,0 +1,115 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path, load_labels +from nemo_text_processing.text_normalization.graph_utils import NEMO_ALPHA, NEMO_DIGIT, GraphFst, insert_space +from nemo_text_processing.text_normalization.taggers.date import get_hundreds_graph + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class CardinalFst(GraphFst): + """ + Finite state transducer for classifying cardinals, e.g. + -23 -> cardinal { negative: "true" integer: "twenty three" } } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="cardinal", kind="classify", deterministic=deterministic) + + graph = pynini.Far(get_abs_path("data/numbers/cardinal_number_name.far")).get_fst() + self.graph_hundred_component_at_least_one_none_zero_digit = ( + pynini.closure(NEMO_DIGIT, 2, 3) | pynini.difference(NEMO_DIGIT, pynini.accep("0")) + ) @ graph + self.graph = ( + pynini.closure(NEMO_DIGIT, 1, 3) + + pynini.closure(pynini.closure(pynutil.delete(","), 0, 1) + NEMO_DIGIT + NEMO_DIGIT + NEMO_DIGIT) + ) @ graph + + graph_digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + graph_zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + single_digits_graph = pynutil.add_weight(pynini.invert(graph_digit | graph_zero), 1.2) | pynutil.add_weight( + pynini.cross("0", "oh"), 1.1 + ) + self.single_digits_graph = single_digits_graph + pynini.closure(pynutil.insert(" ") + single_digits_graph) + + if not deterministic: + single_digits_graph_with_commas = pynini.closure( + self.single_digits_graph + pynutil.insert(" "), 1, 3 + ) + pynini.closure( + pynutil.delete(",") + + single_digits_graph + + pynutil.insert(" ") + + single_digits_graph + + pynutil.insert(" ") + + single_digits_graph, + 1, + ) + self.graph |= self.single_digits_graph | get_hundreds_graph() | single_digits_graph_with_commas + self.range_graph = ( + pynini.closure(pynutil.insert("from "), 0, 1) + + self.graph + + (pynini.cross("-", " to ") | pynini.cross("-", " ")) + + self.graph + ) + + self.range_graph |= self.graph + (pynini.cross("x", " by ") | pynini.cross(" x ", " by ")) + self.graph + self.range_graph = self.range_graph.optimize() + + optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) + final_graph = self.graph | pynutil.add_weight(self.get_serial_graph(), 1.2) + + if not deterministic: + final_graph |= self.range_graph + + final_graph = optional_minus_graph + pynutil.insert("integer: \"") + final_graph + pynutil.insert("\"") + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() + + def get_serial_graph(self): + """ + Finite state transducer for classifying serial. + The serial is a combination of digits, letters and dashes, e.g.: + c325-b -> tokens { serial { value: "c three two five b" } } + """ + alpha = NEMO_ALPHA + + if self.deterministic: + num_graph = self.single_digits_graph + else: + num_graph = self.graph + letter_pronunciation = pynini.string_map(load_labels(get_abs_path("data/letter_pronunciation.tsv"))) + alpha |= letter_pronunciation + + delimiter = insert_space | pynini.cross("-", " ") | pynini.cross("/", " ") + letter_num = pynini.closure(alpha + delimiter, 1) + num_graph + num_letter = pynini.closure(num_graph + delimiter, 1) + alpha + next_alpha_or_num = pynini.closure(delimiter + (alpha | num_graph)) + serial_graph = (letter_num | num_letter) + next_alpha_or_num + + if not self.deterministic: + serial_graph += pynini.closure(pynini.accep("s") | pynini.cross("s", "es"), 0, 1) + return serial_graph diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/date.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/date.py new file mode 100644 index 0000000..8c7c6a7 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/date.py @@ -0,0 +1,201 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path, load_labels +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_CHAR, + NEMO_DIGIT, + NEMO_SIGMA, + TO_LOWER, + GraphFst, + delete_extra_space, + delete_space, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + graph_teen = pynini.invert(pynini.string_file(get_abs_path("data/numbers/teen.tsv"))).optimize() + graph_digit = pynini.invert(pynini.string_file(get_abs_path("data/numbers/digit.tsv"))).optimize() + ties_graph = pynini.invert(pynini.string_file(get_abs_path("data/numbers/ties.tsv"))).optimize() + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + # Add placeholders for global variables + graph_teen = None + graph_digit = None + ties_graph = None + + PYNINI_AVAILABLE = True + + +def get_ties_graph(deterministic: bool = True): + """ + Returns two digit transducer, e.g. + 03 -> o three + 12 -> thirteen + 20 -> twenty + """ + graph = graph_teen | ties_graph + pynutil.delete("0") | ties_graph + insert_space + graph_digit + + if deterministic: + graph = graph | pynini.cross("0", "o") + insert_space + graph_digit + else: + graph = ( + graph + | (pynini.cross("0", "oh") | pynini.cross("0", "o") | pynini.cross("0", "zero")) + + insert_space + + graph_digit + ) + + return graph.optimize() + + +def get_hundreds_graph(deterministic: bool = True): + """ + Returns a four digit transducer which is combination of ties/teen or digits + (using hundred instead of thousand format), e.g. + 1219 -> twelve nineteen + 3900 -> thirty nine hundred + """ + graph_ties = get_ties_graph(deterministic) + graph = ( + graph_ties + insert_space + graph_ties + | graph_teen + insert_space + pynini.cross("00", "hundred") + | (graph_teen + insert_space + (ties_graph | pynini.cross("1", "ten")) + pynutil.delete("0s")) + @ pynini.cdrewrite(pynini.cross("y", "ies") | pynutil.insert("s"), "", "[EOS]", NEMO_SIGMA) + | pynutil.add_weight( + graph_digit + + insert_space + + pynini.cross("00", "thousand") + + (pynutil.delete("0") | insert_space + graph_digit), + weight=-0.001, + ) + ) + return graph + + +def _get_year_graph(deterministic: bool = True): + """ + Transducer for year, only from 1000 - 2999 e.g. + 1290 -> twelve nineteen + 2000 - 2009 will be verbalized as two thousand. + """ + graph = get_hundreds_graph(deterministic) + graph = ( + pynini.union("1", "2") + + NEMO_DIGIT + + NEMO_DIGIT + + NEMO_DIGIT + + pynini.closure(pynini.cross(" s", "s") | "s", 0, 1) + ) @ graph + return graph + + +class DateFst(GraphFst): + """ + Finite state transducer for classifying date, e.g. + jan. 5, 2012 -> date { month: "january" day: "five" year: "twenty twelve" preserve_order: true } + jan. 5 -> date { month: "january" day: "five" preserve_order: true } + 5 january 2012 -> date { day: "five" month: "january" year: "twenty twelve" preserve_order: true } + 2012-01-05 -> date { year: "twenty twelve" month: "january" day: "five" } + 2012.01.05 -> date { year: "twenty twelve" month: "january" day: "five" } + 2012/01/05 -> date { year: "twenty twelve" month: "january" day: "five" } + 2012 -> date { year: "twenty twelve" } + + Args: + ordinal: OrdinalFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal: GraphFst, deterministic: bool): + super().__init__(name="date", kind="classify", deterministic=deterministic) + + month_graph = pynini.string_file(get_abs_path("data/months/names.tsv")).optimize() + month_graph |= (TO_LOWER + pynini.closure(NEMO_CHAR)) @ month_graph + month_abbr_graph = pynini.string_file(get_abs_path("data/months/abbr.tsv")).optimize() + month_abbr_graph = ( + month_abbr_graph | (TO_LOWER + pynini.closure(NEMO_CHAR)) @ month_abbr_graph + ) + pynini.closure(pynutil.delete("."), 0, 1) + month_graph |= month_abbr_graph + + # to support all caps names + names_all_caps = [[x[0].upper()] for x in load_labels(get_abs_path("data/months/names.tsv"))] + abbr_all_caps = [(x.upper(), y) for x, y in load_labels(get_abs_path("data/months/abbr.tsv"))] + month_graph |= pynini.string_map(names_all_caps) | ( + pynini.string_map(abbr_all_caps) + pynini.closure(pynutil.delete("."), 0, 1) + ) + + month_numbers_graph = pynini.string_file(get_abs_path("data/months/numbers.tsv")).optimize() + cardinal_graph = cardinal.graph_hundred_component_at_least_one_none_zero_digit + + year_graph = _get_year_graph(deterministic) + + YEAR_WEIGHT = 0.001 + year_graph_standalone = ( + pynutil.insert("year: \"") + pynutil.add_weight(year_graph, YEAR_WEIGHT) + pynutil.insert("\"") + ) + + month_graph = pynutil.insert("month: \"") + month_graph + pynutil.insert("\"") + month_numbers_graph = pynutil.insert("month: \"") + month_numbers_graph + pynutil.insert("\"") + + day_graph = ( + pynutil.insert("day: \"") + + ((pynini.union("1", "2", "3") + NEMO_DIGIT) | NEMO_DIGIT) @ cardinal_graph + + pynutil.insert("\"") + ) + optional_day_graph = pynini.closure(delete_extra_space + day_graph, 0, 1) + + year_graph = pynutil.insert("year: \"") + year_graph + pynutil.insert("\"") + optional_graph_year = pynini.closure(delete_extra_space + year_graph, 0, 1,) + graph_mdy = ( + month_graph + + optional_day_graph + + delete_space + + pynini.closure(pynutil.delete(","), 0, 1) + + optional_graph_year + ) + + delete_sep = pynutil.delete(pynini.union("-", "/", ".")) + graph_mdy |= ( + month_numbers_graph + + delete_sep + + insert_space + + pynini.closure(pynutil.delete("0"), 0, 1) + + day_graph + + delete_sep + + insert_space + + year_graph + ) + + graph_dmy = day_graph + delete_extra_space + month_graph + optional_graph_year + graph_ymd = ( + year_graph + + delete_sep + + insert_space + + month_numbers_graph + + delete_sep + + insert_space + + pynini.closure(pynutil.delete("0"), 0, 1) + + day_graph + ) + + final_graph = (graph_mdy | graph_dmy) + pynutil.insert(" preserve_order: true") + final_graph |= graph_ymd | year_graph_standalone + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/decimal.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/decimal.py new file mode 100644 index 0000000..c4eba3f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/decimal.py @@ -0,0 +1,101 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_extra_space, delete_space + +try: + import pynini + from pynini.lib import pynutil + + delete_space = pynutil.delete(" ") + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +def get_quantity(decimal: 'pynini.FstLike', cardinal_up_to_hundred: 'pynini.FstLike') -> 'pynini.FstLike': + """ + Returns FST that transforms either a cardinal or decimal followed by a quantity into a numeral, + e.g. 1 million -> integer_part: "one" quantity: "million" + e.g. 1.5 million -> integer_part: "one" fractional_part: "five" quantity: "million" + + Args: + decimal: decimal FST + cardinal_up_to_hundred: cardinal FST + """ + numbers = cardinal_up_to_hundred + suffix = pynini.union("million", "billion", "trillion", "quadrillion", "quintillion", "sextillion") + res = ( + pynutil.insert("integer_part: \"") + + numbers + + pynutil.insert("\"") + + delete_extra_space + + pynutil.insert("quantity: \"") + + suffix + + pynutil.insert("\"") + ) + res |= decimal + delete_extra_space + pynutil.insert("quantity: \"") + (suffix | "thousand") + pynutil.insert("\"") + return res + + +class DecimalFst(GraphFst): + """ + Finite state transducer for classifying decimal, e.g. + -12.5006 billion -> decimal { negative: "true" integer_part: "12" fractional_part: "five o o six" quantity: "billion" } + 1 billion -> decimal { integer_part: "one" quantity: "billion" } + + cardinal: CardinalFst + """ + + def __init__(self, cardinal: GraphFst, deterministic: bool): + super().__init__(name="decimal", kind="classify", deterministic=deterministic) + + cardinal_graph = cardinal.graph + cardinal_graph_hundred_component_at_least_one_none_zero_digit = ( + cardinal.graph_hundred_component_at_least_one_none_zero_digit + ) + + graph_decimal = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + graph_decimal |= pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + + graph_decimal = ( + pynini.cross("zero", "0") + | graph_decimal + | (graph_decimal | pynini.cross("o", "0")) + + pynini.closure(delete_space + (graph_decimal | pynini.cross("o", "0")), 1) + ) + self.graph = pynini.invert(graph_decimal).optimize() + if not deterministic: + self.graph = self.graph | cardinal_graph + + point = pynutil.delete(".") + optional_graph_negative = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) + + graph_fractional = pynutil.insert("fractional_part: \"") + self.graph + pynutil.insert("\"") + graph_integer = pynutil.insert("integer_part: \"") + cardinal_graph + pynutil.insert("\"") + final_graph_wo_sign = ( + pynini.closure(graph_integer + pynutil.insert(" "), 0, 1) + point + pynutil.insert(" ") + graph_fractional + ) + + self.final_graph_wo_negative = final_graph_wo_sign | get_quantity( + final_graph_wo_sign, cardinal_graph_hundred_component_at_least_one_none_zero_digit + ) + + final_graph = optional_graph_negative + self.final_graph_wo_negative + + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/electronic.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/electronic.py new file mode 100644 index 0000000..097a8cd --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/electronic.py @@ -0,0 +1,63 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.graph_utils import NEMO_ALPHA, NEMO_DIGIT, GraphFst, get_abs_path + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class ElectronicFst(GraphFst): + """ + Finite state transducer for classifying electronic: as URLs, email addresses, etc. + e.g. cdf1@abc.edu -> tokens { electronic { username: "cdf1" domain: "abc.edu" } } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="electronic", kind="classify", deterministic=deterministic) + + accepted_symbols = [] + with open(get_abs_path("data/electronic/symbols.tsv"), 'r') as f: + for line in f: + symbol, _ = line.split('\t') + accepted_symbols.append(pynini.accep(symbol)) + + username = ( + pynutil.insert("username: \"") + + NEMO_ALPHA + + pynini.closure(NEMO_ALPHA | NEMO_DIGIT | pynini.union(*accepted_symbols)) + + pynutil.insert("\"") + + pynini.cross('@', ' ') + ) + domain_graph = ( + NEMO_ALPHA + + (pynini.closure(NEMO_ALPHA | NEMO_DIGIT | pynini.accep('-') | pynini.accep('.'))) + + (NEMO_ALPHA | NEMO_DIGIT) + ) + domain_graph = pynutil.insert("domain: \"") + domain_graph + pynutil.insert("\"") + graph = username + domain_graph + + final_graph = self.add_tokens(graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/fraction.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/fraction.py new file mode 100644 index 0000000..0feb5ce --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/fraction.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class FractionFst(GraphFst): + """ + Finite state transducer for classifying fraction + "23 4/5" -> + tokens { fraction { integer: "twenty three" numerator: "four" denominator: "five" } } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal, deterministic: bool = True): + super().__init__(name="fraction", kind="classify", deterministic=deterministic) + cardinal_graph = cardinal.graph + + integer = pynutil.insert("integer: \"") + cardinal_graph + pynutil.insert("\"") + pynini.accep(" ") + numerator = ( + pynutil.insert("numerator: \"") + cardinal_graph + (pynini.cross("/", "\" ") | pynini.cross(" / ", "\" ")) + ) + denominator = pynutil.insert("denominator: \"") + cardinal_graph + pynutil.insert("\"") + + self.graph = pynini.closure(integer, 0, 1) + numerator + denominator + final_graph = self.add_tokens(self.graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/measure.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/measure.py new file mode 100644 index 0000000..a0475c5 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/measure.py @@ -0,0 +1,162 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_ALPHA, + NEMO_NON_BREAKING_SPACE, + NEMO_SIGMA, + SINGULAR_TO_PLURAL, + GraphFst, + convert_space, + delete_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class MeasureFst(GraphFst): + """ + Finite state transducer for classifying measure, suppletive aware, e.g. + -12kg -> measure { negative: "true" cardinal { integer: "twelve" } units: "kilograms" } + 1kg -> measure { cardinal { integer: "one" } units: "kilogram" } + .5kg -> measure { decimal { fractional_part: "five" } units: "kilograms" } + + Args: + cardinal: CardinalFst + decimal: DecimalFst + fraction: FractionFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal: GraphFst, decimal: GraphFst, fraction: GraphFst, deterministic: bool = True): + super().__init__(name="measure", kind="classify", deterministic=deterministic) + cardinal_graph = cardinal.graph + + if not deterministic: + cardinal_graph |= cardinal.range_graph + + graph_unit = pynini.string_file(get_abs_path("data/measurements.tsv")) + graph_unit_plural = convert_space(graph_unit @ SINGULAR_TO_PLURAL) + graph_unit = convert_space(graph_unit) + optional_graph_negative = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) + + graph_unit2 = pynini.cross("/", "per") + delete_space + pynutil.insert(NEMO_NON_BREAKING_SPACE) + graph_unit + + optional_graph_unit2 = pynini.closure( + delete_space + pynutil.insert(NEMO_NON_BREAKING_SPACE) + graph_unit2, 0, 1, + ) + + unit_plural = ( + pynutil.insert("units: \"") + + (graph_unit_plural + optional_graph_unit2 | graph_unit2) + + pynutil.insert("\"") + ) + + unit_singular = ( + pynutil.insert("units: \"") + (graph_unit + optional_graph_unit2 | graph_unit2) + pynutil.insert("\"") + ) + + subgraph_decimal = ( + pynutil.insert("decimal { ") + + optional_graph_negative + + decimal.final_graph_wo_negative + + delete_space + + pynutil.insert(" } ") + + unit_plural + ) + + subgraph_cardinal = ( + pynutil.insert("cardinal { ") + + optional_graph_negative + + pynutil.insert("integer: \"") + + ((NEMO_SIGMA - "1") @ cardinal_graph) + + delete_space + + pynutil.insert("\"") + + pynutil.insert(" } ") + + unit_plural + ) + + subgraph_cardinal |= ( + pynutil.insert("cardinal { ") + + optional_graph_negative + + pynutil.insert("integer: \"") + + pynini.cross("1", "one") + + delete_space + + pynutil.insert("\"") + + pynutil.insert(" } ") + + unit_singular + ) + + cardinal_dash_alpha = ( + pynutil.insert("cardinal { integer: \"") + + cardinal_graph + + pynini.cross('-', '') + + pynutil.insert("\" } units: \"") + + pynini.closure(NEMO_ALPHA, 1) + + pynutil.insert("\"") + ) + + alpha_dash_cardinal = ( + pynutil.insert("units: \"") + + pynini.closure(NEMO_ALPHA, 1) + + pynini.cross('-', '') + + pynutil.insert("\"") + + pynutil.insert(" cardinal { integer: \"") + + cardinal_graph + + pynutil.insert("\" } preserve_order: true") + ) + + decimal_dash_alpha = ( + pynutil.insert("decimal { ") + + decimal.final_graph_wo_negative + + pynini.cross('-', '') + + pynutil.insert(" } units: \"") + + pynini.closure(NEMO_ALPHA, 1) + + pynutil.insert("\"") + ) + + alpha_dash_decimal = ( + pynutil.insert("units: \"") + + pynini.closure(NEMO_ALPHA, 1) + + pynini.cross('-', '') + + pynutil.insert("\"") + + pynutil.insert(" decimal { ") + + decimal.final_graph_wo_negative + + pynutil.insert(" } preserve_order: true") + ) + + subgraph_fraction = ( + pynutil.insert("fraction { ") + fraction.graph + delete_space + pynutil.insert(" } ") + unit_plural + ) + + final_graph = ( + subgraph_decimal + | subgraph_cardinal + | cardinal_dash_alpha + | alpha_dash_cardinal + | decimal_dash_alpha + | alpha_dash_decimal + | subgraph_fraction + ) + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/money.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/money.py new file mode 100644 index 0000000..5965934 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/money.py @@ -0,0 +1,86 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_SIGMA, + SINGULAR_TO_PLURAL, + GraphFst, + convert_space, + insert_space, +) +from nemo_text_processing.text_normalization.taggers.date import get_hundreds_graph + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class MoneyFst(GraphFst): + """ + Finite state transducer for classifying money, suppletive aware, e.g. + $12.05 -> money { currency: "dollars" integer_part: "twelve" fractional_part: "o five" } + $1 -> money { currency: "dollar" integer_part: "one" } + + Args: + cardinal: CardinalFst + decimal: DecimalFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal: GraphFst, decimal: GraphFst, deterministic: bool = True): + super().__init__(name="money", kind="classify", deterministic=deterministic) + cardinal_graph = cardinal.graph + graph_decimal_final = decimal.final_graph_wo_negative + + unit_singular = pynini.string_file(get_abs_path("data/currency/currency.tsv")) + unit_plural = convert_space(unit_singular @ SINGULAR_TO_PLURAL) + unit_singular = convert_space(unit_singular) + + graph_unit_singular = pynutil.insert("currency: \"") + unit_singular + pynutil.insert("\"") + graph_unit_plural = pynutil.insert("currency: \"") + unit_plural + pynutil.insert("\"") + + singular_graph = ( + graph_unit_singular + pynutil.insert(" integer_part: \"") + pynini.cross("1", "one") + pynutil.insert("\"") + ) + + graph_decimal = graph_unit_plural + insert_space + graph_decimal_final + + if deterministic: + graph_integer = ( + graph_unit_plural + + pynutil.insert(" integer_part: \"") + + ((NEMO_SIGMA - "1") @ cardinal_graph) + + pynutil.insert("\"") + ) + else: + graph_integer = ( + graph_unit_plural + + pynutil.insert(" integer_part: \"") + + ((NEMO_SIGMA - "1") @ (get_hundreds_graph(deterministic) | cardinal_graph)) + + pynutil.insert("\"") + ) + graph_decimal |= singular_graph + insert_space + graph_decimal_final + + graph_integer |= singular_graph + + final_graph = graph_integer | graph_decimal + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/ordinal.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/ordinal.py new file mode 100644 index 0000000..49e4527 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/ordinal.py @@ -0,0 +1,49 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_DIGIT, GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ImportError, ModuleNotFoundError): + PYNINI_AVAILABLE = False + + +class OrdinalFst(GraphFst): + """ + Finite state transducer for classifying ordinal, e.g. + 13th -> ordinal { integer: "thirteen" } + + Args: + cardinal: CardinalFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal: GraphFst, deterministic: bool = True): + super().__init__(name="ordinal", kind="classify", deterministic=deterministic) + + cardinal_graph = cardinal.graph + endings = ["rd", "th", "st", "nd"] + endings += [x.upper() for x in endings] + self.graph = ( + (pynini.closure(NEMO_DIGIT | pynini.accep(",")) + pynutil.delete(pynini.union(*endings))) @ cardinal_graph + ).optimize() + final_graph = pynutil.insert("integer: \"") + self.graph + pynutil.insert("\"") + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/punctuation.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/punctuation.py new file mode 100644 index 0000000..6a42e2d --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/punctuation.py @@ -0,0 +1,46 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = False +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class PunctuationFst(GraphFst): + """ + Finite state transducer for classifying punctuation + e.g. a, -> tokens { name: "a" } tokens { name: "," } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="punctuation", kind="classify", deterministic=deterministic) + + s = "!#$%&\'()*+,-./:;<=>?@^_`{|}~\"" + punct = pynini.union(*s) + + graph = pynutil.insert("name: \"") + punct + pynutil.insert("\"") + + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/roman.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/roman.py new file mode 100644 index 0000000..136d0fb --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/roman.py @@ -0,0 +1,61 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.data_loader_utils import load_labels +from nemo_text_processing.text_normalization.graph_utils import GraphFst, get_abs_path, insert_space +from nemo_text_processing.text_normalization.taggers.cardinal import CardinalFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class RomanFst(GraphFst): + """ + Finite state transducer for classifying electronic: as URLs, email addresses, etc. + e.g. cdf1@abc.edu -> tokens { electronic { username: "cdf1" domain: "abc.edu" } } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="roman", kind="classify", deterministic=deterministic) + + def _load_roman(file: str): + roman = load_labels(get_abs_path(file)) + roman_numerals = [(x, y) for x, y in roman] + [(x.upper(), y) for x, y in roman] + return pynini.string_map(roman_numerals) + + cardinal_graph = CardinalFst(deterministic=True).graph + digit_teen = _load_roman("data/roman/digit_teen.tsv") @ cardinal_graph + ties = _load_roman("data/roman/ties.tsv") @ cardinal_graph + hundreds = _load_roman("data/roman/hundreds.tsv") @ cardinal_graph + + graph = ( + (ties | digit_teen | hundreds) + | (ties + insert_space + digit_teen) + | (hundreds + pynini.closure(insert_space + ties, 0, 1) + pynini.closure(insert_space + digit_teen, 0, 1)) + ).optimize() + + graph = pynutil.insert("integer: \"") + graph + pynutil.insert("\"") + graph = self.add_tokens(graph) + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/telephone.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/telephone.py new file mode 100644 index 0000000..fa2ec78 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/telephone.py @@ -0,0 +1,91 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_space, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TelephoneFst(GraphFst): + """ + Finite state transducer for classifying telephone, which includes country code, number part and extension + country code optional: +*** + number part: ***-***-****, or (***) ***-**** + extension optional: 1-9999 + E.g + +1 123-123-5678-1 -> telephone { country_code: "one" number_part: "one two three, one two three, five six seven eight" extension: "one" } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="telephone", kind="classify", deterministic=deterministic) + + add_separator = pynutil.insert(", ") # between components + digit = pynini.invert(pynini.string_file(get_abs_path("data/numbers/digit.tsv"))).optimize() | pynini.cross( + "0", "o" + ) + + country_code = ( + pynutil.insert("country_code: \"") + + pynutil.delete("+") + + pynini.closure(digit + insert_space, 0, 2) + + digit + + pynutil.insert("\"") + ) + optional_country_code = pynini.closure( + country_code + pynini.closure(pynutil.delete("-"), 0, 1) + delete_space + insert_space, 0, 1 + ) + number_part = ( + ( + (pynini.closure(digit + insert_space, 2, 2) + digit + pynutil.delete("-")) + | ( + pynutil.delete("(") + + pynini.closure(digit + insert_space, 2, 2) + + digit + + pynutil.delete(")") + + pynini.closure(pynutil.delete("-"), 0, 1) + + delete_space + ) + ) + + add_separator + + pynini.closure(digit + insert_space, 2, 2) + + digit + + pynutil.delete("-") + + add_separator + + pynini.closure(digit + insert_space, 3, 3) + + digit + ) + number_part = pynutil.insert("number_part: \"") + number_part + pynutil.insert("\"") + extension = ( + pynutil.insert("extension : \"") + + pynini.closure(digit + insert_space, 0, 3) + + digit + + pynutil.insert("\"") + ) + optional_extension = pynini.closure(insert_space + pynutil.delete("-") + extension, 0, 1) + + graph = optional_country_code + number_part + optional_extension + final_graph = self.add_tokens(graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/time.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/time.py new file mode 100644 index 0000000..7da3f56 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/time.py @@ -0,0 +1,115 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_DIGIT, + GraphFst, + convert_space, + delete_space, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TimeFst(GraphFst): + """ + Finite state transducer for classifying time, e.g. + 12:30 a.m. est -> time { hours: "twelve" minutes: "thirty" suffix: "a m" zone: "e s t" } + 2.30 a.m. -> time { hours: "two" minutes: "thirty" suffix: "a m" } + 02.30 a.m. -> time { hours: "two" minutes: "thirty" suffix: "a m" } + 2.00 a.m. -> time { hours: "two" suffix: "a m" } + 2 a.m. -> time { hours: "two" suffix: "a m" } + 02:00 -> time { hours: "two" } + 2:00 -> time { hours: "two" } + + Args: + cardinal: CardinalFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal: GraphFst, deterministic: bool = True): + super().__init__(name="time", kind="classify", deterministic=deterministic) + suffix_graph = pynini.string_file(get_abs_path("data/time_suffix.tsv")) + time_zone_graph = pynini.string_file(get_abs_path("data/time_zone.tsv")) + + # only used for < 1000 thousand -> 0 weight + cardinal = cardinal.graph + + labels_hour = [str(x) for x in range(0, 24)] + labels_minute_single = [str(x) for x in range(1, 10)] + labels_minute_double = [str(x) for x in range(10, 60)] + + delete_leading_zero_to_double_digit = (NEMO_DIGIT + NEMO_DIGIT) | ( + pynini.closure(pynutil.delete("0"), 0, 1) + NEMO_DIGIT + ) + + graph_hour = delete_leading_zero_to_double_digit @ pynini.union(*labels_hour) @ cardinal + + graph_minute_single = pynini.union(*labels_minute_single) @ cardinal + graph_minute_double = pynini.union(*labels_minute_double) @ cardinal + + final_graph_hour = pynutil.insert("hours: \"") + graph_hour + pynutil.insert("\"") + final_graph_minute = ( + pynutil.insert("minutes: \"") + + (pynini.cross("0", "o") + insert_space + graph_minute_single | graph_minute_double) + + pynutil.insert("\"") + ) + final_suffix = pynutil.insert("suffix: \"") + convert_space(suffix_graph) + pynutil.insert("\"") + final_suffix_optional = pynini.closure(delete_space + insert_space + final_suffix, 0, 1) + final_time_zone_optional = pynini.closure( + delete_space + + insert_space + + pynutil.insert("zone: \"") + + convert_space(time_zone_graph) + + pynutil.insert("\""), + 0, + 1, + ) + + # 2:30 pm, 02:30, 2:00 + graph_hm = ( + final_graph_hour + + pynutil.delete(":") + + (pynutil.delete("00") | insert_space + final_graph_minute) + + final_suffix_optional + + final_time_zone_optional + ) + + # 2.xx pm/am + graph_hm2 = ( + final_graph_hour + + pynutil.delete(".") + + (pynutil.delete("00") | insert_space + final_graph_minute) + + delete_space + + insert_space + + final_suffix + + final_time_zone_optional + ) + # 2 pm est + graph_h = final_graph_hour + delete_space + insert_space + final_suffix + final_time_zone_optional + final_graph = (graph_hm | graph_h | graph_hm2).optimize() + + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/tokenize_and_classify.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/tokenize_and_classify.py new file mode 100644 index 0000000..1bef666 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/tokenize_and_classify.py @@ -0,0 +1,107 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_extra_space, delete_space +from nemo_text_processing.text_normalization.taggers.cardinal import CardinalFst +from nemo_text_processing.text_normalization.taggers.date import DateFst +from nemo_text_processing.text_normalization.taggers.decimal import DecimalFst +from nemo_text_processing.text_normalization.taggers.electronic import ElectronicFst +from nemo_text_processing.text_normalization.taggers.fraction import FractionFst +from nemo_text_processing.text_normalization.taggers.measure import MeasureFst +from nemo_text_processing.text_normalization.taggers.money import MoneyFst +from nemo_text_processing.text_normalization.taggers.ordinal import OrdinalFst +from nemo_text_processing.text_normalization.taggers.punctuation import PunctuationFst +from nemo_text_processing.text_normalization.taggers.roman import RomanFst +from nemo_text_processing.text_normalization.taggers.telephone import TelephoneFst +from nemo_text_processing.text_normalization.taggers.time import TimeFst +from nemo_text_processing.text_normalization.taggers.whitelist import WhiteListFst +from nemo_text_processing.text_normalization.taggers.word import WordFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class ClassifyFst(GraphFst): + """ + Final class that composes all other classification grammars. This class can process an entire sentence including punctuation. + For deployment, this grammar will be compiled and exported to OpenFst Finate State Archiv (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + + Args: + input_case: accepting either "lower_cased" or "cased" input. + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, input_case: str, deterministic: bool = True): + super().__init__(name="tokenize_and_classify", kind="classify", deterministic=deterministic) + + cardinal = CardinalFst(deterministic=deterministic) + cardinal_graph = cardinal.fst + + ordinal = OrdinalFst(cardinal=cardinal, deterministic=deterministic) + ordinal_graph = ordinal.fst + + decimal = DecimalFst(cardinal=cardinal, deterministic=deterministic) + decimal_graph = decimal.fst + fraction = FractionFst(deterministic=deterministic, cardinal=cardinal) + fraction_graph = fraction.fst + + measure = MeasureFst(cardinal=cardinal, decimal=decimal, fraction=fraction, deterministic=deterministic) + measure_graph = measure.fst + date_graph = DateFst(cardinal=cardinal, deterministic=deterministic).fst + word_graph = WordFst(deterministic=deterministic).fst + time_graph = TimeFst(cardinal=cardinal, deterministic=deterministic).fst + telephone_graph = TelephoneFst(deterministic=deterministic).fst + electonic_graph = ElectronicFst(deterministic=deterministic).fst + money_graph = MoneyFst(cardinal=cardinal, decimal=decimal, deterministic=deterministic).fst + whitelist_graph = WhiteListFst(input_case=input_case, deterministic=deterministic).fst + punct_graph = PunctuationFst(deterministic=deterministic).fst + + classify = ( + pynutil.add_weight(whitelist_graph, 1.01) + | pynutil.add_weight(time_graph, 1.1) + | pynutil.add_weight(date_graph, 1.09) + | pynutil.add_weight(decimal_graph, 1.1) + | pynutil.add_weight(measure_graph, 1.1) + | pynutil.add_weight(cardinal_graph, 1.1) + | pynutil.add_weight(ordinal_graph, 1.1) + | pynutil.add_weight(money_graph, 1.1) + | pynutil.add_weight(telephone_graph, 1.1) + | pynutil.add_weight(electonic_graph, 1.1) + | pynutil.add_weight(fraction_graph, 1.1) + | pynutil.add_weight(word_graph, 100) + ) + + if not deterministic: + roman_graph = RomanFst(deterministic=deterministic).fst + # the weight matches the word_graph weight for "I" cases in long sentences with multiple semiotic tokens + classify |= pynutil.add_weight(roman_graph, 100) + + punct = pynutil.insert("tokens { ") + pynutil.add_weight(punct_graph, weight=1.1) + pynutil.insert(" }") + token = pynutil.insert("tokens { ") + classify + pynutil.insert(" }") + token_plus_punct = ( + pynini.closure(punct + pynutil.insert(" ")) + token + pynini.closure(pynutil.insert(" ") + punct) + ) + + graph = token_plus_punct + pynini.closure(delete_extra_space + token_plus_punct) + graph = delete_space + graph + delete_space + + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/whitelist.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/whitelist.py new file mode 100644 index 0000000..50c883f --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/whitelist.py @@ -0,0 +1,68 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path, load_labels +from nemo_text_processing.text_normalization.graph_utils import GraphFst, convert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WhiteListFst(GraphFst): + """ + Finite state transducer for classifying whitelist, e.g. + misses -> tokens { name: "mrs" } + for non-deterministic case: "Dr. Abc" -> + tokens { name: "drive" } tokens { name: "Abc" } + tokens { name: "doctor" } tokens { name: "Abc" } + tokens { name: "Dr." } tokens { name: "Abc" } + This class has highest priority among all classifier grammars. Whitelisted tokens are defined and loaded from "data/whitelist.tsv". + + Args: + input_case: accepting either "lower_cased" or "cased" input. + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, input_case: str, deterministic: bool = True): + super().__init__(name="whitelist", kind="classify") + + def _get_whitelist_graph(input_case, file="data/whitelist.tsv"): + whitelist = load_labels(get_abs_path(file)) + if input_case == "lower_cased": + whitelist = [(x.lower(), y) for x, y in whitelist] + else: + whitelist = [(x, y) for x, y in whitelist] + graph = pynini.string_map(whitelist) + return graph + + def _get_whitelist_non_deterministic_graph(file="data/whitelist_alternatives.tsv"): + whitelist = load_labels(get_abs_path(file)) + whitelist_lower = [(x.lower(), y.lower()) for x, y in whitelist] + whitelist_cased = [(x, y) for x, y in whitelist] + graph = pynini.string_map(whitelist_lower + whitelist_cased) + return graph + + graph = _get_whitelist_graph(input_case) + if not deterministic: + graph |= _get_whitelist_graph("lower_cased") | _get_whitelist_non_deterministic_graph() + + graph = pynutil.insert("name: \"") + convert_space(graph) + pynutil.insert("\"") + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/taggers/word.py b/tts/NeMo/nemo_text_processing/text_normalization/taggers/word.py new file mode 100644 index 0000000..6ff35ee --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/taggers/word.py @@ -0,0 +1,41 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_SPACE, GraphFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WordFst(GraphFst): + """ + Finite state transducer for classifying word. Considers sentence boundary exceptions. + e.g. sleep -> tokens { name: "sleep" } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="word", kind="classify", deterministic=deterministic) + + word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") + self.fst = word.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/token_parser.py b/tts/NeMo/nemo_text_processing/text_normalization/token_parser.py new file mode 100644 index 0000000..d3f7fd9 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/token_parser.py @@ -0,0 +1,192 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import string +from collections import OrderedDict +from typing import Dict, List, Union + +PRESERVE_ORDER_KEY = "preserve_order" +EOS = "" + + +class TokenParser: + """ + Parses tokenized/classified text, e.g. 'tokens { money { integer: "20" currency: "$" } } tokens { name: "left"}' + + Args + text: tokenized text + """ + + def __call__(self, text): + """ + Setup function + + Args: + text: text to be parsed + + """ + self.text = text + self.len_text = len(text) + self.char = text[0] # cannot handle empty string + self.index = 0 + + def parse(self) -> List[dict]: + """ + Main function. Implements grammar: + A -> space F space F space F ... space + + Returns list of dictionaries + """ + l = list() + while self.parse_ws(): + token = self.parse_token() + if not token: + break + l.append(token) + return l + + def parse_token(self) -> Dict[str, Union[str, dict]]: + """ + Implements grammar: + F-> no_space KG no_space + + Returns: K, G as dictionary values + """ + d = OrderedDict() + key = self.parse_string_key() + if key is None: + return None + self.parse_ws() + if key == PRESERVE_ORDER_KEY: + self.parse_char(":") + self.parse_ws() + value = self.parse_chars("true") + else: + value = self.parse_token_value() + + d[key] = value + return d + + def parse_token_value(self) -> Union[str, dict]: + """ + Implements grammar: + G-> no_space :"VALUE" no_space | no_space {A} no_space + + Returns: string or dictionary + """ + if self.char == ":": + self.parse_char(":") + self.parse_ws() + self.parse_char("\"") + value_string = self.parse_string_value() + self.parse_char("\"") + return value_string + elif self.char == "{": + d = OrderedDict() + self.parse_char("{") + list_token_dicts = self.parse() + # flatten tokens + for tok_dict in list_token_dicts: + for k, v in tok_dict.items(): + d[k] = v + self.parse_char("}") + return d + else: + raise ValueError() + + def parse_char(self, exp) -> bool: + """ + Parses character + + Args: + exp: character to read in + + Returns true if successful + """ + assert self.char == exp + self.read() + return True + + def parse_chars(self, exp) -> bool: + """ + Parses characters + + Args: + exp: characters to read in + + Returns true if successful + """ + ok = False + for x in exp: + ok |= self.parse_char(x) + return ok + + def parse_string_key(self) -> str: + """ + Parses string key, can only contain ascii and '_' characters + + Returns parsed string key + """ + assert self.char not in string.whitespace and self.char != EOS + incl_criterium = string.ascii_letters + "_" + l = [] + while self.char in incl_criterium: + l.append(self.char) + if not self.read(): + raise ValueError() + + if not l: + return None + return "".join(l) + + def parse_string_value(self) -> str: + """ + Parses string value, ends with quote followed by space + + Returns parsed string value + """ + assert self.char not in string.whitespace and self.char != EOS + l = [] + while self.char != "\"" or self.text[self.index + 1] != " ": + l.append(self.char) + if not self.read(): + raise ValueError() + + if not l: + return None + return "".join(l) + + def parse_ws(self): + """ + Deletes whitespaces. + + Returns true if not EOS after parsing + """ + not_eos = self.char != EOS + while not_eos and self.char == " ": + not_eos = self.read() + return not_eos + + def read(self): + """ + Reads in next char. + + Returns true if not EOS + """ + if self.index < self.len_text - 1: # should be unique + self.index += 1 + self.char = self.text[self.index] + return True + self.char = EOS + return False diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/__init__.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/__init__.py new file mode 100644 index 0000000..bc443be --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/cardinal.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/cardinal.py new file mode 100644 index 0000000..bdf7a2a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/cardinal.py @@ -0,0 +1,56 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class CardinalFst(GraphFst): + """ + Finite state transducer for verbalizing cardinal, e.g. + cardinal { negative: "true" integer: "23" } -> minus twenty three + + Args: + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic) + + self.optional_sign = pynini.closure(pynini.cross("negative: \"true\"", "minus ") + delete_space, 0, 1) + + if deterministic: + integer = pynini.closure(NEMO_NOT_QUOTE, 1) + else: + integer = ( + pynini.closure(NEMO_NOT_QUOTE) + + pynini.closure(pynini.cross("hundred ", "") | pynini.cross("hundred ", "hundred and "), 0, 1) + + pynini.closure(NEMO_NOT_QUOTE) + ) + + self.integer = delete_space + pynutil.delete("\"") + integer + pynutil.delete("\"") + integer = pynutil.delete("integer:") + self.integer + + self.numbers = self.optional_sign + integer + delete_tokens = self.delete_tokens(self.numbers) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/date.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/date.py new file mode 100644 index 0000000..0819592 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/date.py @@ -0,0 +1,100 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_NOT_QUOTE, + GraphFst, + delete_extra_space, + delete_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class DateFst(GraphFst): + """ + Finite state transducer for verbalizing date, e.g. + date { month: "february" day: "five" year: "twenty twelve" preserve_order: true } -> february fifth twenty twelve + date { day: "five" month: "february" year: "twenty twelve" preserve_order: true } -> the fifth of february twenty twelve + + Args: + ordinal: OrdinalFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, ordinal: GraphFst, deterministic: bool = True): + super().__init__(name="date", kind="verbalize", deterministic=deterministic) + + month = pynini.closure(NEMO_NOT_QUOTE, 1) + day_cardinal = ( + pynutil.delete("day:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + day = day_cardinal @ ordinal.suffix + + if not deterministic: + month |= pynutil.insert(" of ") + month + day |= day_cardinal + + month = pynutil.delete("month:") + delete_space + pynutil.delete("\"") + month + pynutil.delete("\"") + + year = ( + pynutil.delete("year:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + delete_space + + pynutil.delete("\"") + ) + + # month (day) year + graph_mdy = ( + month + pynini.closure(delete_extra_space + day, 0, 1) + pynini.closure(delete_extra_space + year, 0, 1) + ) + + # day month year + graph_dmy = ( + pynutil.insert("the ") + + day + + delete_extra_space + + pynutil.insert("of ") + + month + + pynini.closure(delete_extra_space + year, 0, 1) + ) + + optional_preserve_order = pynini.closure( + pynutil.delete("preserve_order:") + delete_space + pynutil.delete("true") + delete_space + | pynutil.delete("field_order:") + + delete_space + + pynutil.delete("\"") + + NEMO_NOT_QUOTE + + pynutil.delete("\"") + + delete_space + ) + + final_graph = (graph_mdy | year | graph_dmy) + delete_space + optional_preserve_order + + delete_tokens = self.delete_tokens(final_graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/decimal.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/decimal.py new file mode 100644 index 0000000..9ebefeb --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/decimal.py @@ -0,0 +1,74 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class DecimalFst(GraphFst): + """ + Finite state transducer for verbalizing decimal, e.g. + decimal { negative: "true" integer_part: "twelve" fractional_part: "five o o six" quantity: "billion" } -> minus twelve point five o o six billion + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, cardinal, deterministic: bool = True): + super().__init__(name="decimal", kind="verbalize", deterministic=deterministic) + + self.optional_sign = pynini.closure(pynini.cross("negative: \"true\"", "minus ") + delete_space, 0, 1) + self.integer = pynutil.delete("integer_part:") + cardinal.integer + self.optional_integer = pynini.closure(self.integer + delete_space + insert_space, 0, 1) + self.fractional_default = ( + pynutil.delete("fractional_part:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + + if deterministic: + self.fractional = pynutil.insert("point ") + self.fractional_default + else: + self.fractional = pynini.closure(pynutil.insert("point "), 0, 1) + self.fractional_default + + self.quantity = ( + delete_space + + insert_space + + pynutil.delete("quantity:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + self.optional_quantity = pynini.closure(self.quantity, 0, 1) + + graph = self.optional_sign + ( + self.integer + | (self.integer + self.quantity) + | (self.optional_integer + self.fractional + self.optional_quantity) + ) + self.numbers = graph + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/electronic.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/electronic.py new file mode 100644 index 0000000..c51f84a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/electronic.py @@ -0,0 +1,91 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_ALPHA, + NEMO_NOT_QUOTE, + GraphFst, + delete_space, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class ElectronicFst(GraphFst): + """ + Finite state transducer for verbalizing electronic + e.g. tokens { electronic { username: "cdf1" domain: "abc.edu" } } -> c d f one at a b c dot e d u + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="electronic", kind="verbalize", deterministic=deterministic) + graph_digit = pynini.invert(pynini.string_file(get_abs_path("data/numbers/digit.tsv"))).optimize() + graph_symbols = pynini.string_file(get_abs_path("data/electronic/symbols.tsv")).optimize() + user_name = ( + pynutil.delete("username:") + + delete_space + + pynutil.delete("\"") + + ( + pynini.closure( + pynutil.add_weight(graph_digit + insert_space, 1.09) + | pynutil.add_weight(pynini.closure(graph_symbols + pynutil.insert(" ")), 1.09) + | pynutil.add_weight(NEMO_NOT_QUOTE + insert_space, 1.1) + ) + ) + + pynutil.delete("\"") + ) + + domain_default = ( + pynini.closure(NEMO_NOT_QUOTE + insert_space) + + pynini.cross(".", "dot ") + + NEMO_NOT_QUOTE + + pynini.closure(insert_space + NEMO_NOT_QUOTE) + ) + + server_default = ( + pynini.closure((graph_digit | NEMO_ALPHA) + insert_space, 1) + + pynini.closure(graph_symbols + insert_space) + + pynini.closure((graph_digit | NEMO_ALPHA) + insert_space, 1) + ) + server_common = pynini.string_file(get_abs_path("data/electronic/server_name.tsv")) + insert_space + + domain_common = pynini.cross(".", "dot ") + pynini.string_file(get_abs_path("data/electronic/domain.tsv")) + + domain = ( + pynutil.delete("domain:") + + delete_space + + pynutil.delete("\"") + + (pynutil.add_weight(server_common, 1.09) | pynutil.add_weight(server_default, 1.1)) + + (pynutil.add_weight(domain_common, 1.09) | pynutil.add_weight(domain_default, 1.1)) + + delete_space + + pynutil.delete("\"") + ) + + graph = user_name + delete_space + pynutil.insert("at ") + delete_space + domain + delete_space + + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/fraction.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/fraction.py new file mode 100644 index 0000000..d49bd4b --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/fraction.py @@ -0,0 +1,72 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, insert_space +from nemo_text_processing.text_normalization.verbalizers.ordinal import OrdinalFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class FractionFst(GraphFst): + """ + Finite state transducer for verbalizing fraction + e.g. tokens { fraction { integer: "twenty three" numerator: "four" denominator: "five" } } -> + twenty three four fifth + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="fraction", kind="verbalize", deterministic=deterministic) + suffix = OrdinalFst().suffix + + integer = pynutil.delete("integer: \"") + pynini.closure(NEMO_NOT_QUOTE) + pynutil.delete("\" ") + numerator = pynutil.delete("numerator: \"") + pynini.closure(NEMO_NOT_QUOTE) + pynutil.delete("\" ") + numerator_one = pynutil.delete("numerator: \"") + pynini.accep("one") + pynutil.delete("\" ") + denominator = pynutil.delete("denominator: \"") + ( + pynini.closure(NEMO_NOT_QUOTE) @ suffix | pynini.cross('four', 'quarter') + ) + conjunction = pynutil.insert("and ") + if not deterministic: + conjunction = pynini.closure(conjunction, 0, 1) + + integer = pynini.closure(integer + insert_space + conjunction, 0, 1) + + denominator_half = pynini.cross("numerator: \"one\" denominator: \"two\"", "a half") + denominator_one_two = pynini.cross("denominator: \"one\"", "over one") | pynini.cross( + "denominator: \"two\"", "halves" + ) + fraction_default = pynutil.add_weight( + numerator + insert_space + denominator + pynutil.insert("s") + pynutil.delete("\""), 0.001 + ) + fraction_with_one = pynutil.add_weight( + numerator_one + insert_space + denominator + pynutil.delete("\""), 0.0001 + ) + + graph = integer + denominator_half | (fraction_with_one | fraction_default) + graph |= pynini.cross("numerator: \"one\" denominator: \"two\"", "one half") + graph |= (numerator | numerator_one) + insert_space + denominator_one_two + + self.graph = graph + delete_tokens = self.delete_tokens(self.graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/measure.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/measure.py new file mode 100644 index 0000000..3937efe --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/measure.py @@ -0,0 +1,76 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, GraphFst, delete_space, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class MeasureFst(GraphFst): + """ + Finite state transducer for verbalizing measure, e.g. + measure { negative: "true" cardinal { integer: "twelve" } units: "kilograms" } -> minus twelve kilograms + measure { decimal { integer_part: "twelve" fractional_part: "five" } units: "kilograms" } -> twelve point five kilograms + tokens { measure { units: "covid" decimal { integer_part: "nineteen" fractional_part: "five" } } } -> covid nineteen point five + + Args: + decimal: DecimalFst + cardinal: CardinalFst + fraction: FractionFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, decimal: GraphFst, cardinal: GraphFst, fraction: GraphFst, deterministic: bool = True): + super().__init__(name="measure", kind="verbalize", deterministic=deterministic) + optional_sign = cardinal.optional_sign + unit = pynutil.delete("units: \"") + pynini.closure(NEMO_CHAR - " ", 1) + pynutil.delete("\"") + delete_space + + graph_decimal = ( + pynutil.delete("decimal {") + + delete_space + + optional_sign + + delete_space + + decimal.numbers + + delete_space + + pynutil.delete("}") + ) + graph_cardinal = ( + pynutil.delete("cardinal {") + + delete_space + + optional_sign + + delete_space + + cardinal.numbers + + delete_space + + pynutil.delete("}") + ) + + graph_fraction = ( + pynutil.delete("fraction {") + delete_space + fraction.graph + delete_space + pynutil.delete("}") + ) + + graph = (graph_cardinal | graph_decimal | graph_fraction) + delete_space + insert_space + unit + + # SH adds "preserve_order: true" by default + preserve_order = pynutil.delete("preserve_order:") + delete_space + pynutil.delete("true") + delete_space + graph |= unit + insert_space + (graph_cardinal | graph_decimal) + delete_space + pynini.closure(preserve_order) + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/money.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/money.py new file mode 100644 index 0000000..97b9508 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/money.py @@ -0,0 +1,117 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import ( + NEMO_NOT_QUOTE, + GraphFst, + delete_space, + get_abs_path, + insert_space, +) + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + + PYNINI_AVAILABLE = False + + +class MoneyFst(GraphFst): + """ + Finite state transducer for verbalizing money, e.g. + money { integer_part: "twelve" fractional_part: "o five" currency: "dollars" } -> twelve o five dollars + + Args: + decimal: DecimalFst + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, decimal: GraphFst, deterministic: bool = True): + super().__init__(name="money", kind="verbalize", deterministic=deterministic) + + def _get_minor_currencies(file): + minor_currencies = [] + with open(get_abs_path(file), 'r') as f: + for line in f: + min_cur = line.strip() + minor_currencies.append(pynutil.insert(min_cur)) + return minor_currencies + + unit = ( + pynutil.delete("currency:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + graph = decimal.numbers + delete_space + pynutil.insert(" ") + unit + + if not deterministic: + minor_currencies_singular = _get_minor_currencies("data/currency/currency_minor_one.tsv") + minor_currencies_singular = pynini.union(*minor_currencies_singular) + minor_currencies_singular = ( + pynini.closure(NEMO_NOT_QUOTE) + + ( + pynini.accep("one") + | pynini.cross("zero one", "one") + | pynini.cross("oh one", "one") + | pynini.cross(" o one", " one") + ) + + insert_space + + minor_currencies_singular + ) + + minor_currencies_plural = _get_minor_currencies("data/currency/currency_minor.tsv") + minor_currencies_plural = insert_space + pynini.union(*minor_currencies_plural) + + fractional_default = ( + pynutil.delete("fractional_part:") + + delete_space + + pynutil.delete("\"") + + ((pynini.closure(NEMO_NOT_QUOTE, 1) + minor_currencies_plural) | minor_currencies_singular) + + pynutil.delete("\"") + ) + + # $2.00 {two zero zero dollars} -> two dollars + fractional_with_zeros = ( + pynutil.delete("fractional_part:") + + delete_space + + pynutil.delete("\"") + + pynini.cross('zero', '') + + pynini.closure(pynini.cross(' zero', '')) + + delete_space + + pynutil.delete("\"") + + delete_space + ) + + fractional = fractional_with_zeros | fractional_default + + graph |= ( + decimal.integer + + delete_space + + insert_space + + unit + + delete_space + + insert_space + + pynini.closure(pynutil.insert("and "), 0, 1) + + fractional + ) + + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/ordinal.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/ordinal.py new file mode 100644 index 0000000..20ec399 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/ordinal.py @@ -0,0 +1,63 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.data_loader_utils import get_abs_path +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, NEMO_SIGMA, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class OrdinalFst(GraphFst): + """ + Finite state transducer for verbalizing ordinal, e.g. + ordinal { integer: "thirteen" } } -> thirteenth + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="ordinal", kind="verbalize", deterministic=deterministic) + + graph_digit = pynini.string_file(get_abs_path("data/ordinals/digit.tsv")).invert() + graph_teens = pynini.string_file(get_abs_path("data/ordinals/teen.tsv")).invert() + + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + convert_rest = pynutil.insert("th", weight=0.01) + + suffix = pynini.cdrewrite( + graph_digit | graph_teens | pynutil.add_weight(pynini.cross("ty", "tieth"), weight=0.001) | convert_rest, + "", + "[EOS]", + NEMO_SIGMA, + ).optimize() + graph = graph @ suffix + self.suffix = suffix + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/roman.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/roman.py new file mode 100644 index 0000000..bb42f3c --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/roman.py @@ -0,0 +1,46 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst +from nemo_text_processing.text_normalization.verbalizers.ordinal import OrdinalFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class RomanFst(GraphFst): + """ + Finite state transducer for verbalizing roman numerals + e.g. tokens { roman { integer: "one" } } -> one + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="roman", kind="verbalize", deterministic=deterministic) + suffix = OrdinalFst().suffix + + integer = pynini.closure(NEMO_NOT_QUOTE) + integer |= pynini.closure(pynutil.insert("the "), 0, 1) + integer @ suffix + graph = pynutil.delete("integer: \"") + integer + pynutil.delete("\"") + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/telephone.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/telephone.py new file mode 100644 index 0000000..3920819 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/telephone.py @@ -0,0 +1,69 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TelephoneFst(GraphFst): + """ + Finite state transducer for verbalizing telephone numbers, e.g. + telephone { country_code: "one" number_part: "one two three, one two three, five six seven eight" extension: "one" } + -> one, one two three, one two three, five six seven eight, one + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="telephone", kind="verbalize", deterministic=deterministic) + + add_separator = pynutil.insert(",") # between components + + optional_country_code = pynini.closure( + pynutil.delete("country_code: \"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + + delete_space + + add_separator + + insert_space, + 0, + 1, + ) + + number_part = pynutil.delete("number_part: \"") + pynini.closure(NEMO_NOT_QUOTE, 1) + pynutil.delete("\"") + + optional_extension = pynini.closure( + delete_space + + add_separator + + insert_space + + pynutil.delete("extension: \"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\""), + 0, + 1, + ) + + graph = optional_country_code + number_part + optional_extension + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/time.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/time.py new file mode 100644 index 0000000..c5881c3 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/time.py @@ -0,0 +1,74 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space, insert_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class TimeFst(GraphFst): + """ + Finite state transducer for verbalizing time, e.g. + time { hours: "twelve" minutes: "thirty" suffix: "a m" zone: "e s t" } -> twelve thirty a m e s t + time { hours: "twelve" } -> twelve o'clock + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="time", kind="verbalize", deterministic=deterministic) + hour = ( + pynutil.delete("hours:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + minute = ( + pynutil.delete("minutes:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + suffix = ( + pynutil.delete("suffix:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + optional_suffix = pynini.closure(delete_space + insert_space + suffix, 0, 1) + zone = ( + pynutil.delete("zone:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_NOT_QUOTE, 1) + + pynutil.delete("\"") + ) + optional_zone = pynini.closure(delete_space + insert_space + zone, 0, 1) + graph = hour + delete_space + insert_space + minute + optional_suffix + optional_zone + graph |= hour + insert_space + pynutil.insert("o'clock") + optional_zone + graph |= hour + delete_space + insert_space + suffix + optional_zone + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize.py new file mode 100644 index 0000000..b14468a --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize.py @@ -0,0 +1,79 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst +from nemo_text_processing.text_normalization.verbalizers.cardinal import CardinalFst +from nemo_text_processing.text_normalization.verbalizers.date import DateFst +from nemo_text_processing.text_normalization.verbalizers.decimal import DecimalFst +from nemo_text_processing.text_normalization.verbalizers.electronic import ElectronicFst +from nemo_text_processing.text_normalization.verbalizers.fraction import FractionFst +from nemo_text_processing.text_normalization.verbalizers.measure import MeasureFst +from nemo_text_processing.text_normalization.verbalizers.money import MoneyFst +from nemo_text_processing.text_normalization.verbalizers.ordinal import OrdinalFst +from nemo_text_processing.text_normalization.verbalizers.roman import RomanFst +from nemo_text_processing.text_normalization.verbalizers.telephone import TelephoneFst +from nemo_text_processing.text_normalization.verbalizers.time import TimeFst +from nemo_text_processing.text_normalization.verbalizers.whitelist import WhiteListFst + + +class VerbalizeFst(GraphFst): + """ + Composes other verbalizer grammars. + For deployment, this grammar will be compiled and exported to OpenFst Finate State Archiv (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + + Args: + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="verbalize", kind="verbalize", deterministic=deterministic) + cardinal = CardinalFst(deterministic=deterministic) + cardinal_graph = cardinal.fst + decimal = DecimalFst(cardinal=cardinal, deterministic=deterministic) + decimal_graph = decimal.fst + ordinal = OrdinalFst(deterministic=deterministic) + ordinal_graph = ordinal.fst + fraction = FractionFst(deterministic=deterministic) + fraction_graph = fraction.fst + telephone_graph = TelephoneFst(deterministic=deterministic).fst + electronic_graph = ElectronicFst(deterministic=deterministic).fst + measure = MeasureFst(decimal=decimal, cardinal=cardinal, fraction=fraction, deterministic=deterministic) + measure_graph = measure.fst + time_graph = TimeFst(deterministic=deterministic).fst + date_graph = DateFst(ordinal=ordinal, deterministic=deterministic).fst + money_graph = MoneyFst(decimal=decimal, deterministic=deterministic).fst + whitelist_graph = WhiteListFst(deterministic=deterministic).fst + + graph = ( + time_graph + | date_graph + | money_graph + | measure_graph + | ordinal_graph + | decimal_graph + | cardinal_graph + | telephone_graph + | electronic_graph + | fraction_graph + | whitelist_graph + ) + + if not deterministic: + roman_graph = RomanFst(deterministic=deterministic).fst + graph |= roman_graph + + self.fst = graph diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize_final.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize_final.py new file mode 100644 index 0000000..c2b2ac8 --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/verbalize_final.py @@ -0,0 +1,54 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import GraphFst, delete_extra_space, delete_space +from nemo_text_processing.text_normalization.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.text_normalization.verbalizers.word import WordFst + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class VerbalizeFinalFst(GraphFst): + """ + Finite state transducer that verbalizes an entire sentence, e.g. + tokens { name: "its" } tokens { time { hours: "twelve" minutes: "thirty" } } tokens { name: "now" } tokens { name: "." } -> its twelve thirty now . + + Args: + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="verbalize_final", kind="verbalize", deterministic=deterministic) + verbalize = VerbalizeFst(deterministic=deterministic).fst + word = WordFst(deterministic=deterministic).fst + types = verbalize | word + graph = ( + pynutil.delete("tokens") + + delete_space + + pynutil.delete("{") + + delete_space + + types + + delete_space + + pynutil.delete("}") + ) + graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space + self.fst = graph diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/whitelist.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/whitelist.py new file mode 100644 index 0000000..5d1889d --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/whitelist.py @@ -0,0 +1,48 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WhiteListFst(GraphFst): + """ + Finite state transducer for verbalizing whitelist + e.g. tokens { name: "misses" } } -> misses + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="whitelist", kind="verbalize", deterministic=deterministic) + graph = ( + pynutil.delete("name:") + + delete_space + + pynutil.delete("\"") + + pynini.closure(NEMO_CHAR - " ", 1) + + pynutil.delete("\"") + ) + graph = graph @ pynini.cdrewrite(pynini.cross(u"\u00A0", " "), "", "", NEMO_SIGMA) + self.fst = graph.optimize() diff --git a/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/word.py b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/word.py new file mode 100644 index 0000000..8b1fcac --- /dev/null +++ b/tts/NeMo/nemo_text_processing/text_normalization/verbalizers/word.py @@ -0,0 +1,43 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +from nemo_text_processing.text_normalization.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + +try: + import pynini + from pynini.lib import pynutil + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + PYNINI_AVAILABLE = False + + +class WordFst(GraphFst): + """ + Finite state transducer for verbalizing word + e.g. tokens { name: "sleep" } -> sleep + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="word", kind="verbalize", deterministic=deterministic) + chars = pynini.closure(NEMO_CHAR - " ", 1) + char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") + graph = char @ pynini.cdrewrite(pynini.cross(u"\u00A0", " "), "", "", NEMO_SIGMA) + + self.fst = graph.optimize() diff --git a/tts/NeMo/reinstall.sh b/tts/NeMo/reinstall.sh new file mode 100755 index 0000000..8e2eb10 --- /dev/null +++ b/tts/NeMo/reinstall.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -e + +INSTALL_OPTION=${1:-"dev"} + + +PIP=pip + +echo 'Uninstalling stuff' +${PIP} uninstall -y nemo_toolkit +${PIP} uninstall -y sacrebleu + +# Kept for legacy purposes +${PIP} uninstall -y nemo_asr +${PIP} uninstall -y nemo_nlp +${PIP} uninstall -y nemo_tts +${PIP} uninstall -y nemo_simple_gan +${PIP} uninstall -y nemo_cv + +${PIP} install -U setuptools + +echo 'Installing nemo and nemo_text_processing' +if [[ "$INSTALL_OPTION" == "dev" ]]; then + ${PIP} install --editable ".[all]" +else + rm -rf dist/ + python setup.py bdist_wheel + DIST_FILE=$(find ./dist -name "*.whl" | head -n 1) + ${PIP} install "${DIST_FILE}[all]" +fi + +echo 'Installing additional nemo_text_processing conda dependency' +bash nemo_text_processing/setup.sh > /dev/null 2>&1 && echo "nemo_text_processing installed!" || echo "nemo_text_processing could not be installed!" + +if [ -x "$(command -v conda)" ]; then + echo 'Attempting update to numba installation via conda' + conda update -c numba numba -y > /dev/null 2>&1 && echo "Numba updated!" || echo "Numba could not be updated!" +fi + +echo 'All done!' diff --git a/tts/NeMo/requirements/requirements.txt b/tts/NeMo/requirements/requirements.txt new file mode 100644 index 0000000..ac7d1a3 --- /dev/null +++ b/tts/NeMo/requirements/requirements.txt @@ -0,0 +1,19 @@ +numpy>=1.18.2 +onnx>=1.7.0 +pytorch-lightning>=1.3.0 +python-dateutil +torch +wget +wrapt +ruamel.yaml +scikit-learn +omegaconf>=2.1.0 +hydra-core>=1.1.0 +transformers>=4.0.1 +sentencepiece<1.0.0 +webdataset>=0.1.48,<=0.1.62 +tqdm>=4.41.0 +opencc +pangu +jieba +numba diff --git a/tts/NeMo/requirements/requirements_asr.txt b/tts/NeMo/requirements/requirements_asr.txt new file mode 100644 index 0000000..1f8b841 --- /dev/null +++ b/tts/NeMo/requirements/requirements_asr.txt @@ -0,0 +1,24 @@ +braceexpand +editdistance +frozendict +inflect +kaldi-io +librosa +marshmallow +packaging +ruamel.yaml +soundfile +sox +unidecode +kaldi-python-io +kaldiio +scipy +pandas +g2p_en +pydub +pyannote.core +pyannote.metrics +pyamg +torch-stft +ipywidgets +matplotlib diff --git a/tts/NeMo/requirements/requirements_cv.txt b/tts/NeMo/requirements/requirements_cv.txt new file mode 100644 index 0000000..f0eabe5 --- /dev/null +++ b/tts/NeMo/requirements/requirements_cv.txt @@ -0,0 +1,2 @@ +pillow +torchvision diff --git a/tts/NeMo/requirements/requirements_docs.txt b/tts/NeMo/requirements/requirements_docs.txt new file mode 100644 index 0000000..8a380b7 --- /dev/null +++ b/tts/NeMo/requirements/requirements_docs.txt @@ -0,0 +1,6 @@ +latexcodec +sphinx>=3.0 +sphinx_rtd_theme +sphinxcontrib-bibtex +wrapt +numpy diff --git a/tts/NeMo/requirements/requirements_nlp.txt b/tts/NeMo/requirements/requirements_nlp.txt new file mode 100644 index 0000000..b2a0d4b --- /dev/null +++ b/tts/NeMo/requirements/requirements_nlp.txt @@ -0,0 +1,13 @@ +boto3 +h5py +matplotlib>=3.3.2 +sentencepiece +unidecode +youtokentome>=1.0.5 +numpy +rapidfuzz +gdown +megatron-lm==2.2.0 +inflect +sacrebleu[ja] +sacremoses>=0.0.43 diff --git a/tts/NeMo/requirements/requirements_test.txt b/tts/NeMo/requirements/requirements_test.txt new file mode 100644 index 0000000..7c62917 --- /dev/null +++ b/tts/NeMo/requirements/requirements_test.txt @@ -0,0 +1,11 @@ +black==19.10b0 +isort[requirements] < 5 +parameterized +pytest +pytest-runner +ruamel.yaml +sphinx +sphinxcontrib-bibtex +wrapt +wget +wandb diff --git a/tts/NeMo/requirements/requirements_text_processing.txt b/tts/NeMo/requirements/requirements_text_processing.txt new file mode 100644 index 0000000..9b7085f --- /dev/null +++ b/tts/NeMo/requirements/requirements_text_processing.txt @@ -0,0 +1,2 @@ +inflect +regex diff --git a/tts/NeMo/requirements/requirements_tts.txt b/tts/NeMo/requirements/requirements_tts.txt new file mode 100644 index 0000000..f872105 --- /dev/null +++ b/tts/NeMo/requirements/requirements_tts.txt @@ -0,0 +1,7 @@ +matplotlib +pypinyin +attrdict +pystoi +pesq +g2p_en +nltk diff --git a/tts/NeMo/scripts/asr_language_modeling/neural_rescorer/create_tarred_transformer_lm_dataset.py b/tts/NeMo/scripts/asr_language_modeling/neural_rescorer/create_tarred_transformer_lm_dataset.py new file mode 100644 index 0000000..6c9a836 --- /dev/null +++ b/tts/NeMo/scripts/asr_language_modeling/neural_rescorer/create_tarred_transformer_lm_dataset.py @@ -0,0 +1,318 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Execution : + +python create_tarred_tokenized_text_lm_dataset.py \ + --text_path= \ + --data_root= \ + --tokenizer_name="bert-base-cased" \ + --tokenizer_vocab_file= \ + --num_shards=64 \ + --chunk_size=8192 \ + --chunk_write_buffer=512 \ + --lower_case \ + --log +""" + + +import argparse +import glob +import json +import logging +import os +import tarfile + +import joblib +import numpy as np +from tqdm import tqdm + +from nemo.collections.nlp.modules.common.tokenizer_utils import get_tokenizer + +parser = argparse.ArgumentParser(description='Tarred Tokenized dataset for text language modelling') + +# Data path arguments +parser.add_argument('--text_path', required=True, default=None, type=str, help='Text paths, seperated by commas') +parser.add_argument('--data_root', required=True, default=None, type=str, help='Output directory') + +# General arguments +parser.add_argument( + '--chunk_write_buffer', + default=128, + type=int, + help='Number of chunks of `chunk_size` to buffer for parallel tokenization and serial write to disk', +) +parser.add_argument('--lower_case', action='store_true', help='Whether to lower case the corpus') +parser.add_argument('--log', action='store_true', help='Whether to print logs to terminal') + +# Tokenizer arguments +parser.add_argument('--tokenizer_name', required=False, default=None, type=str, help='Tokenizer name for resolution') +parser.add_argument( + '--tokenizer_model', required=False, default=None, type=str, help='Path to tokenizer model for sentencepiece' +) +parser.add_argument('--tokenizer_vocab_file', required=False, type=str, default=None, help='Path to a vocab file') +parser.add_argument( + '--tokenizer_special_tokens', default=None, type=str, nargs='+', help='List of special tokens for the tokenizer' +) + +# Tarred dataset arguments +parser.add_argument('--num_shards', default=1, type=int, help='Number of shards for the tarfile') +parser.add_argument('--chunk_size', default=8192, type=int, help='Number of rows of data concatenated into a vector') + +parser.set_defaults(log=False, lower_case=False) +args = parser.parse_args() + + +def __build_dataset_from_text(texts: str, lower_case: bool, chunk_size: int): + if ',' in texts: + texts = texts.split(',') + else: + texts = [texts] + + num_lines = 0 + text_dataset = [] + + for text in texts: + with open(text, 'r') as in_reader: + reader = tqdm(iter(lambda: in_reader.readline(), ''), desc="Read 0 lines", unit=' lines') + + for i, line in enumerate(reader): + # Clean text line + line = line.replace("\n", "").strip() + + if lower_case: + line = line.lower() + + if line: + text_dataset.append(line) + + num_lines += 1 + if num_lines % 100000 == 0: + reader.set_description(f"Read {num_lines} lines") + + if num_lines % chunk_size == 0: + yield text_dataset, num_lines + + # Empty cache + text_dataset = [] + + logging.info(f"Finished extracting manifest : {text}") + + logging.info("Finished extracting all manifests ! Number of sentences : {}".format(num_lines)) + + if len(text_dataset) != 0: + yield text_dataset, num_lines + + +def __tokenize_str(texts, tokenizer): + tokenized_text = [] + for text in texts: + tok_text = tokenizer.text_to_ids(text) + tokenized_text.extend(tok_text) + return tokenized_text + + +def __tokenize_text( + text_paths, tokenizer, tokenized_cachedir, lower_case: bool = False, chunk_size=8192, write_buffer: int = -1 +): + if write_buffer < 1: + write_buffer = max(os.cpu_count() - write_buffer, 1) + + logging.info(f"Using write chunk buffer of size {write_buffer}") + + if not os.path.exists(tokenized_cachedir): + os.makedirs(tokenized_cachedir) + + # global parameters + global_chunk_idx = 0 + chunk_paths = [] + chunk_lens = [] + + # buffer parameters + data_cache = [] + chunk_idx = 0 + + text_generator = iter(__build_dataset_from_text(text_paths, lower_case=lower_case, chunk_size=chunk_size)) + global_num_lines = 0 + last_batch = False + + with joblib.Parallel(n_jobs=-2, verbose=10) as parallel: + + while True: + try: + data, num_lines = next(text_generator) + data_cache.append(data) + + global_num_lines = num_lines + except StopIteration: + last_batch = True + + # Update counters + chunk_idx += 1 + + if (chunk_idx == write_buffer) or last_batch: + # write the chunks into disk after parallel tokenization + tokenized_data_list = parallel( + joblib.delayed(__tokenize_str)(chunk, tokenizer) for chunk in data_cache + ) + + # Sequential write cache + for chunk in tokenized_data_list: + fp = os.path.join(tokenized_cachedir, f"chunk_{global_chunk_idx}.npy") + chunk = np.asarray(chunk, dtype=np.int64) + np.save(fp, chunk, allow_pickle=False) + + chunk_paths.append(fp) + chunk_lens.append(len(chunk)) + + global_chunk_idx += 1 + + logging.info(f"Wrote a total of {global_chunk_idx} chunks to file...") + + # reset buffers + data_cache.clear() + del data_cache + + data_cache = [] + chunk_idx = 0 + + if last_batch: + logging.info("Finished tokenizing last chunk") + break + + logging.info( + f"Chunking {global_num_lines} rows into {global_num_lines // chunk_size} tasks (each chunk contains {chunk_size} elements)" + ) + return chunk_paths, chunk_lens + + +def __create_chunk(data_root, chunk_path, shard_id, compute_metrics=False): + """Creates a tarball containing the tokenized text chunks. + """ + tar = tarfile.open(os.path.join(data_root, f'text_{shard_id}.tar'), mode='a') + + # We squash the filename since we do not preserve directory structure of tokenized text in the tarball. + base, ext = os.path.splitext(chunk_path) + base = base.replace(os.pathsep, '_') + # Need the following replacement as long as WebDataset splits on first period + base = base.replace('.', '_') + squashed_filename = f'{base}{ext}' + tar.add(chunk_path, arcname=squashed_filename) + + tar.close() + + if compute_metrics: + data = np.load(chunk_path, allow_pickle=False) + chunk_len = len(data) + return (chunk_len,) + else: + return None + + +def __write_tarred_tokenized_text_dataset(data_root, num_shards, chunk_paths, chunk_lens): + num_chunks = len(chunk_paths) + + if chunk_lens is not None: + num_text = sum(chunk_lens) + shard_counts = {chunk_id: chunk_len for chunk_id, chunk_len in enumerate(chunk_lens)} + compute_metrics = False + + else: + num_text = 0 + shard_counts = {} + compute_metrics = True + + for chunk_id, chunk_path in enumerate(tqdm(chunk_paths, desc='Writing chunk ', unit=' chunks')): + shard_id = chunk_id % num_shards + metrics = __create_chunk(data_root, chunk_path, shard_id, compute_metrics=compute_metrics) + + if metrics is not None: + num_text += metrics[0] + shard_counts[chunk_id] = metrics[0] + + # write metadata + metadata_path = os.path.join(data_root, 'metadata.json') + with open(metadata_path, 'w') as f: + metadata = {'num_chunks': num_chunks, 'num_text': num_text, 'shard_count': shard_counts} + json.dump(metadata, f, indent=4) + logging.info("Metadata writen..") + + +def main(): + text_path = args.text_path + data_root = args.data_root + + if args.log: + logging.basicConfig(level=logging.INFO) + + tokenized_cachedir = os.path.join(data_root, '_tokenized_dataset_cachedir') + + if os.path.exists(tokenized_cachedir): + logging.warning( + f'Tokenized cache directory {tokenized_cachedir} already potentially contains files.' + f'In such a case, please be aware that the tarfiles will be **appended** instead of overridden!' + ) + + if not os.path.exists(data_root): + os.makedirs(data_root) + + chunk_paths = None + chunk_lens = None + + if os.path.exists(tokenized_cachedir): + paths = glob.glob(os.path.join(tokenized_cachedir, "*.npy")) + if len(paths) > 0: + logging.info("Cached tokenized numpy files found, skipping re-tokenization of dataset") + + chunk_paths = paths + chunk_lens = None + + if chunk_paths is None: + if args.tokenizer_name is None: + raise ValueError("`tokenizer_name` name is required when tokenizing the dataset for the first time.") + + if args.tokenizer_vocab_file is None: + raise ValueError("`tokenizer_vocab_file` is required when constructing the tokenized dataset") + + tokenizer = get_tokenizer( + tokenizer_name=args.tokenizer_name, + tokenizer_model=args.tokenizer_model, + vocab_file=args.tokenizer_vocab_file, + special_tokens=args.tokenizer_special_tokens, + ) + + logging.info("Built tokenizer") + + # tokenize text data into sub-words + chunk_paths, chunk_lens = __tokenize_text( + text_paths=text_path, + tokenizer=tokenizer, + tokenized_cachedir=tokenized_cachedir, + lower_case=args.lower_case, + chunk_size=args.chunk_size, + write_buffer=args.chunk_write_buffer, + ) + logging.info(f"Tokenized dataset into sub-words and serialized cache at {tokenized_cachedir}") + + # Write tarred dataset + __write_tarred_tokenized_text_dataset( + data_root, num_shards=args.num_shards, chunk_paths=chunk_paths, chunk_lens=chunk_lens + ) + + logging.info('Done preparing tokenized dataset!') + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/asr_language_modeling/neural_rescorer/eval_neural_rescorer.py b/tts/NeMo/scripts/asr_language_modeling/neural_rescorer/eval_neural_rescorer.py new file mode 100644 index 0000000..f713af6 --- /dev/null +++ b/tts/NeMo/scripts/asr_language_modeling/neural_rescorer/eval_neural_rescorer.py @@ -0,0 +1,288 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +""" +This script would evaluate a neural language model (Transformer) trained with +`examples/nlp/language_modeling/transformer_lm.py' as a rescorer for ASR systems. +Given a trained TransformerLMModel `.nemo` file, this script can be used to re-score the beams obtained from a beam +search decoder of an ASR model. + +USAGE: +1. Obtain `.tsv` file with beams and their corresponding scores. Scores can be from a regular beam search decoder or + in fusion with an N-gram LM scores. For a given beam size `beam_size` and a number of examples + for evaluation `num_eval_examples`, it should contain (`beam_size` x `num_eval_examples`) lines of + form `beam_candidate_text \t score`. This file can be generated by `scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py`. + +2. Rescore the candidates: + python eval_neural_rescorer.py + --lm_model=[path to .nemo file of the LM] + --beams_file=[path to beams .tsv file] + --beam_size=[size of the beams] + --eval_manifest=[path to eval manifest .json file] + --batch_size=[batch size used for inference on the LM model] + --alpha=[the value for the parameter rescorer_alpha] + --beta=[the value for the parameter rescorer_beta] + +You may find more info on how to use this script at: +https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/asr_language_modeling.html + +""" + +import contextlib +import json +from argparse import ArgumentParser + +import editdistance +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import torch +import tqdm + +from nemo.collections.nlp.models.language_modeling import TransformerLMModel +from nemo.utils import logging + + +class BeamScoresDataset(torch.utils.data.Dataset): + """ + Dataset to read the score file containing the beams and their score + + Args: + data_path: path to the beams file + tokenizer: tokenizer of the LM model + manifest_path: manifest `.json` file which contains the ground truths transcripts + beam_size: the number of beams per sample + max_seq_length: the maximum length of sequences + """ + + def __init__(self, data_path, tokenizer, manifest_path, beam_size=128, max_seq_length=256): + self.data = pd.read_csv(data_path, delimiter="\t", header=None) + self.tokenizer = tokenizer + self.ground_truths = [] + with open(manifest_path, 'r') as f_orig: + for line in f_orig: + item = json.loads(line) + self.ground_truths.append(item['text']) + self.beam_size = beam_size + self.max_seq_length = max_seq_length + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + text = str(self.data[0][idx]) + tokens = [self.tokenizer.bos_id] + self.tokenizer.text_to_ids(text) + [self.tokenizer.eos_id] + input_ids = [self.tokenizer.pad_id] * self.max_seq_length + input_ids[: len(tokens)] = tokens + input_ids = np.array(input_ids) + input_mask = (input_ids != self.tokenizer.pad_id).astype(np.float32) + acoustic_score = self.data[1][idx] + dist = editdistance.eval(text.split(), self.ground_truths[idx // self.beam_size].split()) + ref_len = len(self.ground_truths[idx // self.beam_size].split()) + len_in_chars = len(str(self.data[0][idx])) + return input_ids, input_mask, acoustic_score, dist, ref_len, len_in_chars, idx + + +def linear_search_wer( + dists, scores1, scores2, total_len, coef_range=[0, 10], coef_steps=10000, param_name='parameter' +): + """ + performs linear search to find the best coefficient when two set of scores are getting linearly fused. + + Args: + dists: Tesnor of the distances between the ground truth and the candidates with shape of [number of samples, beam size] + scores1: Tensor of the first set of scores with shape of [number of samples, beam size] + scores2: Tensor of the second set of scores with shape of [number of samples, beam size] + total_len: The total length of all samples + coef_range: the search range for the coefficient + coef_steps: the number of steps that the search range would get divided into + param_name: the name of the parameter to be used in the figure + + Output: + (best coefficient found, best WER achived) + """ + scale = scores1.mean().abs().item() / scores2.mean().abs().item() + left = coef_range[0] * scale + right = coef_range[1] * scale + coefs = np.linspace(left, right, coef_steps) + + best_wer = 10000 + best_coef = left + wers = [] + for coef in coefs: + scores = scores1 + coef * scores2 + wer = compute_wer(dists, scores, total_len) + wers.append(wer) + if wer < best_wer: + best_wer = wer + best_coef = coef + + plt.plot(coefs, wers) + plt.title(f'WER% after rescoring with different values of {param_name}') + plt.ylabel('WER%') + plt.xlabel(param_name) + plt.show() + return best_coef, best_wer + + +def compute_wer(dists, scores, total_len): + """ + Sorts the candidates based on the scores and calculates the WER with the new top candidates. + + Args: + dists: Tensor of the distances between the ground truth and the candidates with shape of [number of samples, beam size] + scores: Tensor of the scores for candidates with shape of [number of samples, beam size] + total_len: The total length of all samples + + Output: + WER with the new scores + """ + indices = scores.max(dim=1, keepdim=True)[1] + wer = dists.gather(dim=1, index=indices).sum() / total_len + wer = wer.item() + return wer + + +def main(): + parser = ArgumentParser() + parser.add_argument("--lm_model_file", type=str, required=True, help="path to LM model .nemo file") + parser.add_argument("--beams_file", type=str, required=True, help="path to beams .tsv file") + parser.add_argument( + "--eval_manifest", type=str, required=True, help="path to the evaluation `.json` manifest file" + ) + parser.add_argument("--beam_size", type=int, required=True, help="number of beams per candidate") + parser.add_argument("--batch_size", type=int, default=256, help="inference batch size") + parser.add_argument("--alpha", type=float, default=None, help="parameter alpha of the fusion") + parser.add_argument("--beta", type=float, default=None, help="parameter beta of the fusion") + parser.add_argument( + "--scores_output_file", default=None, type=str, help="The optional path to store the rescored beams" + ) + parser.add_argument( + "--device", default="cuda", type=str, help="The device to load the model onto to calculate the scores" + ) + parser.add_argument( + "--use_amp", action="store_true", help="Whether to use AMP if available to calculate the scores" + ) + args = parser.parse_args() + + device = args.device + if device.startswith("cuda") and not torch.cuda.is_available(): + logging.info(f"cuda is not available! switched to cpu.") + device = "cpu" + + if args.lm_model_file.endswith(".nemo"): + logging.info("Attempting to initialize from .nemo file") + model = TransformerLMModel.restore_from( + restore_path=args.lm_model_file, map_location=torch.device(device) + ).eval() + else: + raise NotImplementedError(f"Only supports .nemo files, but got: {args.model}") + + max_seq_length = model.encoder._embedding.position_embedding.pos_enc.shape[0] + dataset = BeamScoresDataset(args.beams_file, model.tokenizer, args.eval_manifest, args.beam_size, max_seq_length) + data_loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=args.batch_size) + + if args.use_amp: + if torch.cuda.is_available() and hasattr(torch.cuda, 'amp') and hasattr(torch.cuda.amp, 'autocast'): + logging.info("AMP is enabled!\n") + autocast = torch.cuda.amp.autocast + else: + + @contextlib.contextmanager + def autocast(): + yield + + logging.info(f"Rescoring with beam_size: {args.beam_size}") + logging.info("Calculating the scores...") + with autocast(): + with torch.no_grad(): + am_scores, lm_scores, dists, ref_lens, lens_in_chars = [], [], [], [], [] + for batch in tqdm.tqdm(data_loader): + input_ids, input_mask, acoustic_score, dist, ref_len, len_in_chars, idx = batch + + max_len_in_batch = input_mask.sum(dim=0).argmin().item() + input_ids, input_mask = input_ids[:, :max_len_in_batch], input_mask[:, :max_len_in_batch] + if torch.cuda.is_available(): + input_ids, input_mask = input_ids.to(device), input_mask.to(device) + dist, acoustic_score, len_in_chars = ( + dist.to(device), + acoustic_score.to(device), + len_in_chars.to(device), + ) + + log_probs = model.forward(input_ids[:, :-1], input_mask[:, :-1]) + target_log_probs = log_probs.gather(2, input_ids[:, 1:].unsqueeze(2)).squeeze(2) + neural_lm_score = torch.sum(target_log_probs * input_mask[:, 1:], dim=-1) + + am_scores.append(acoustic_score) + lm_scores.append(neural_lm_score) + dists.append(dist) + ref_lens.append(ref_len) + lens_in_chars.append(len_in_chars) + + am_scores = torch.cat(am_scores).view(-1, args.beam_size) + lm_scores = torch.cat(lm_scores).view(-1, args.beam_size) + dists = torch.cat(dists).view(-1, args.beam_size) + ref_lens = torch.cat(ref_lens).view(-1, args.beam_size) + lens_in_chars = torch.cat(lens_in_chars).view(-1, args.beam_size).to(am_scores.dtype) + + total_len = ref_lens[:, 0].sum() + model_wer = dists[:, 0].sum() / total_len + ideal_wer = dists.min(dim=1)[0].sum() / total_len + + if args.alpha is None: + logging.info("Linear search for alpha...") + coef1, _ = linear_search_wer( + dists=dists, scores1=am_scores, scores2=lm_scores, total_len=total_len, param_name='alpha' + ) + coef1 = np.round(coef1, 3) + logging.info(f"alpha={coef1} achieved the best WER.") + logging.info(f"------------------------------------------------") + else: + coef1 = args.alpha + + scores = am_scores + coef1 * lm_scores + + if args.beta is None: + logging.info("Linear search for beta...") + coef2, _ = linear_search_wer( + dists=dists, scores1=scores, scores2=lens_in_chars, total_len=total_len, param_name='beta' + ) + coef2 = np.round(coef2, 3) + logging.info(f"beta={coef2} achieved the best WER.") + logging.info(f"------------------------------------------------") + else: + coef2 = args.beta + + new_scores = am_scores + coef1 * lm_scores + coef2 * lens_in_chars + rescored_wer = compute_wer(dists, new_scores, total_len) + + logging.info(f"Input beams WER: {np.round(model_wer.item() * 100, 2)}%") + logging.info(f"------------------------------------------------") + logging.info(f" +LM rescoring WER: {np.round(rescored_wer * 100, 2)}%") + logging.info(f" with alpha={coef1}, beta={coef2}") + logging.info(f"------------------------------------------------") + logging.info(f"Best possible WER: {np.round(ideal_wer.item() * 100, 2)}%") + logging.info(f"------------------------------------------------") + + new_scores_flatten = new_scores.flatten() + if args.scores_output_file is not None: + logging.info(f'Saving the candidates with their new scores at `{args.scores_output_file}`...') + with open(args.scores_output_file, "w") as fout: + for sample_id in range(len(dataset)): + fout.write(f"{dataset.data[0][sample_id]}\t{new_scores_flatten[sample_id]}\n") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py new file mode 100644 index 0000000..6f5b224 --- /dev/null +++ b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/eval_beamsearch_ngram.py @@ -0,0 +1,345 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +# + +# This script would evaluate an N-gram language model trained with KenLM library (https://github.com/kpu/kenlm) in +# fusion with beam search decoders on top of a trained ASR model. NeMo's beam search decoders are capable of using the +# KenLM's N-gram models to find the best candidates. This script supports both character level and BPE level +# encodings and models which is detected automatically from the type of the model. +# You may train the LM model with 'scripts/ngram_lm/train_kenlm.py'. +# +# USAGE: python eval_beamsearch_ngram.py --nemo_model_file \ +# --input_manifest \ +# --beam_width \ +# --beam_alpha \ +# --beam_width \ +# --preds_output_folder \ +# --decoding_mode beam_search_ngram +# ... +# +# You may find more info on how to use this script at: +# https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/asr_language_modeling.html + + +# Please check train_kenlm.py to find out why we need TOKEN_OFFSET for BPE-based models +TOKEN_OFFSET = 100 + +import argparse +import contextlib +import json +import os +import pickle + +import editdistance +import kenlm_utils +import numpy as np +import torch +from sklearn.model_selection import ParameterGrid +from tqdm.auto import tqdm + +import nemo +import nemo.collections.asr as nemo_asr +from nemo.utils import logging + + +def beam_search_eval( + all_probs, + target_transcripts, + vocab, + ids_to_text_func=None, + preds_output_file=None, + lm_path=None, + beam_alpha=1.0, + beam_beta=0.0, + beam_width=128, + beam_batch_size=128, + progress_bar=True, +): + # creating the beam search decoder + beam_search_lm = nemo_asr.modules.BeamSearchDecoderWithLM( + vocab=vocab, + beam_width=beam_width, + alpha=beam_alpha, + beta=beam_beta, + lm_path=lm_path, + num_cpus=max(os.cpu_count(), 1), + input_tensor=False, + ) + + wer_dist_first = cer_dist_first = 0 + wer_dist_best = cer_dist_best = 0 + words_count = 0 + chars_count = 0 + sample_idx = 0 + if preds_output_file: + out_file = open(preds_output_file, 'w') + + if progress_bar: + it = tqdm( + range(int(np.ceil(len(all_probs) / beam_batch_size))), + desc=f"Beam search decoding with width={beam_width}, alpha={beam_alpha}, beta={beam_beta}", + ncols=120, + ) + else: + it = range(int(np.ceil(len(all_probs) / beam_batch_size))) + for batch_idx in it: + # disabling type checking + with nemo.core.typecheck.disable_checks(): + probs_batch = all_probs[batch_idx * beam_batch_size : (batch_idx + 1) * beam_batch_size] + beams_batch = beam_search_lm.forward(log_probs=probs_batch, log_probs_length=None,) + + for beams_idx, beams in enumerate(beams_batch): + target = target_transcripts[sample_idx + beams_idx] + target_split_w = target.split() + target_split_c = list(target) + words_count += len(target_split_w) + chars_count += len(target_split_c) + wer_dist_min = cer_dist_min = 10000 + for candidate_idx, candidate in enumerate(beams): + if ids_to_text_func is not None: + # For BPE encodings, need to shift by TOKEN_OFFSET to retrieve the original sub-word ids + pred_text = ids_to_text_func([ord(c) - TOKEN_OFFSET for c in candidate[1]]) + else: + pred_text = candidate[1] + pred_split_w = pred_text.split() + wer_dist = editdistance.eval(target_split_w, pred_split_w) + pred_split_c = list(pred_text) + cer_dist = editdistance.eval(target_split_c, pred_split_c) + + wer_dist_min = min(wer_dist_min, wer_dist) + cer_dist_min = min(cer_dist_min, cer_dist) + + if candidate_idx == 0: + # first candidate + wer_dist_first += wer_dist + cer_dist_first += cer_dist + + score = candidate[0] + if preds_output_file: + out_file.write('{}\t{}\n'.format(pred_text, score)) + wer_dist_best += wer_dist_min + cer_dist_best += cer_dist_min + sample_idx += len(probs_batch) + + if preds_output_file: + out_file.close() + logging.info(f"Stored the predictions of beam search decoding at '{preds_output_file}'.") + + if lm_path: + logging.info( + 'WER/CER with beam search decoding and N-gram model = {:.2%}/{:.2%}'.format( + wer_dist_first / words_count, cer_dist_first / chars_count + ) + ) + else: + logging.info( + 'WER/CER with beam search decoding = {:.2%}/{:.2%}'.format( + wer_dist_first / words_count, cer_dist_first / chars_count + ) + ) + logging.info( + 'Best WER/CER in candidates = {:.2%}/{:.2%}'.format(wer_dist_best / words_count, cer_dist_best / chars_count) + ) + logging.info(f"=================================================================================") + + +def main(): + parser = argparse.ArgumentParser( + description='Evaluate an ASR model with beam search decoding and n-gram KenLM language model.' + ) + parser.add_argument( + "--nemo_model_file", required=True, type=str, help="The path of the '.nemo' file of the ASR model" + ) + parser.add_argument( + "--kenlm_model_file", required=False, default=None, type=str, help="The path of the KenLM binary model file" + ) + parser.add_argument("--input_manifest", required=True, type=str, help="The manifest file of the evaluation set") + parser.add_argument( + "--preds_output_folder", default=None, type=str, help="The optional folder where the predictions are stored" + ) + parser.add_argument( + "--probs_cache_file", default=None, type=str, help="The cache file for storing the outputs of the model" + ) + parser.add_argument( + "--acoustic_batch_size", default=16, type=int, help="The batch size to calculate log probabilities" + ) + parser.add_argument( + "--device", default="cuda", type=str, help="The device to load the model onto to calculate log probabilities" + ) + parser.add_argument( + "--use_amp", action="store_true", help="Whether to use AMP if available to calculate log probabilities" + ) + parser.add_argument( + "--decoding_mode", + choices=["greedy", "beamsearch", "beamsearch_ngram"], + default="beamsearch_ngram", + type=str, + help="The decoding scheme to be used for evaluation.", + ) + parser.add_argument( + "--beam_width", + required=True, + type=int, + nargs="+", + help="The width or list of the widths for the beam search decoding", + ) + parser.add_argument( + "--beam_alpha", + required=True, + type=float, + nargs="+", + help="The alpha parameter or list of the alphas for the beam search decoding", + ) + parser.add_argument( + "--beam_beta", + required=True, + type=float, + nargs="+", + help="The beta parameter or list of the betas for the beam search decoding", + ) + parser.add_argument( + "--beam_batch_size", default=128, type=int, help="The batch size to be used for beam search decoding" + ) + args = parser.parse_args() + + asr_model = nemo_asr.models.EncDecCTCModelBPE.restore_from( + args.nemo_model_file, map_location=torch.device(args.device) + ) + + target_transcripts = [] + with open(args.input_manifest, 'r') as manifest_file: + audio_file_paths = [] + for line in tqdm(manifest_file, desc=f"Reading Manifest {args.input_manifest} ...", ncols=120): + data = json.loads(line) + target_transcripts.append(data['text']) + audio_file_paths.append(data['audio_filepath']) + + if args.probs_cache_file and os.path.exists(args.probs_cache_file): + logging.info(f"Found a pickle file of probabilities at '{args.probs_cache_file}'.") + logging.info(f"Loading the cached pickle file of probabilities from '{args.probs_cache_file}' ...") + with open(args.probs_cache_file, 'rb') as probs_file: + all_probs = pickle.load(probs_file) + + if len(all_probs) != len(audio_file_paths): + raise ValueError( + f"The number of samples in the probabilities file '{args.probs_cache_file}' does not " + f"match the manifest file. You may need to delete the probabilities cached file." + ) + else: + if args.use_amp: + if torch.cuda.is_available() and hasattr(torch.cuda, 'amp') and hasattr(torch.cuda.amp, 'autocast'): + logging.info("AMP is enabled!\n") + autocast = torch.cuda.amp.autocast + else: + + @contextlib.contextmanager + def autocast(): + yield + + with autocast(): + with torch.no_grad(): + all_logits = asr_model.transcribe(audio_file_paths, batch_size=args.acoustic_batch_size, logprobs=True) + all_probs = [kenlm_utils.softmax(logits) for logits in all_logits] + if args.probs_cache_file: + logging.info(f"Writing pickle files of probabilities at '{args.probs_cache_file}'...") + with open(args.probs_cache_file, 'wb') as f_dump: + pickle.dump(all_probs, f_dump) + + wer_dist_greedy = 0 + cer_dist_greedy = 0 + words_count = 0 + chars_count = 0 + for batch_idx, probs in enumerate(all_probs): + preds = np.argmax(probs, axis=1) + preds_tensor = torch.tensor(preds, device='cpu').unsqueeze(0) + pred_text = asr_model._wer.ctc_decoder_predictions_tensor(preds_tensor)[0] + + pred_split_w = pred_text.split() + target_split_w = target_transcripts[batch_idx].split() + pred_split_c = list(pred_text) + target_split_c = list(target_transcripts[batch_idx]) + + wer_dist = editdistance.eval(target_split_w, pred_split_w) + cer_dist = editdistance.eval(target_split_c, pred_split_c) + + wer_dist_greedy += wer_dist + cer_dist_greedy += cer_dist + words_count += len(target_split_w) + chars_count += len(target_split_c) + + logging.info('Greedy WER/CER = {:.2%}/{:.2%}'.format(wer_dist_greedy / words_count, cer_dist_greedy / chars_count)) + + encoding_level = kenlm_utils.SUPPORTED_MODELS.get(type(asr_model).__name__, None) + if not encoding_level: + logging.warning( + f"Model type '{type(asr_model).__name__}' may not be supported. Would try to train a char-level LM." + ) + encoding_level = 'char' + + vocab = asr_model.decoder.vocabulary + ids_to_text_func = None + if encoding_level == "subword": + vocab = [chr(idx + TOKEN_OFFSET) for idx in range(len(vocab))] + ids_to_text_func = asr_model.tokenizer.ids_to_text + # delete the model to free the memory + del asr_model + + if args.decoding_mode == "beamsearch_ngram": + if not os.path.exists(args.kenlm_model_file): + raise FileNotFoundError(f"Could not find the KenLM model file '{args.kenlm_model_file}'.") + lm_path = args.kenlm_model_file + else: + lm_path = None + + # 'greedy' decoding_mode would skip the beam search decoding + if args.decoding_mode in ["beamsearch_ngram", "beamsearch"]: + + params = {'beam_width': args.beam_width, 'beam_alpha': args.beam_alpha, 'beam_beta': args.beam_beta} + hp_grid = ParameterGrid(params) + hp_grid = list(hp_grid) + + logging.info(f"==============================Starting the beam search decoding===============================") + logging.info(f"Grid search size: {len(hp_grid)}") + logging.info(f"It may take some time...") + logging.info(f"==============================================================================================") + + if args.preds_output_folder and not os.path.exists(args.preds_output_folder): + os.mkdir(args.preds_output_folder) + for hp in hp_grid: + if args.preds_output_folder: + preds_output_file = os.path.join( + args.preds_output_folder, + f"preds_out_width{hp['beam_width']}_alpha{hp['beam_alpha']}_beta{hp['beam_beta']}.tsv", + ) + else: + preds_output_file = None + + beam_search_eval( + all_probs=all_probs, + target_transcripts=target_transcripts, + vocab=vocab, + ids_to_text_func=ids_to_text_func, + preds_output_file=preds_output_file, + lm_path=lm_path, + beam_width=hp["beam_width"], + beam_alpha=hp["beam_alpha"], + beam_beta=hp["beam_beta"], + beam_batch_size=args.beam_batch_size, + progress_bar=True, + ) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/asr_language_modeling/ngram_lm/install_beamsearch_decoders.sh b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/install_beamsearch_decoders.sh new file mode 100644 index 0000000..44f5fa8 --- /dev/null +++ b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/install_beamsearch_decoders.sh @@ -0,0 +1,6 @@ +git clone https://github.com/NVIDIA/OpenSeq2Seq -b ctc-decoders +mv OpenSeq2Seq/decoders . +rm -rf OpenSeq2Seq +cd decoders +./setup.sh +cd .. diff --git a/tts/NeMo/scripts/asr_language_modeling/ngram_lm/kenlm_utils.py b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/kenlm_utils.py new file mode 100644 index 0000000..ed967ce --- /dev/null +++ b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/kenlm_utils.py @@ -0,0 +1,112 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +# + +""" +Utility methods to be used for training N-gram LM with KenLM in train_kenlm.py +""" + +import json +import os + +import numpy as np +from joblib import Parallel, delayed +from tqdm.auto import tqdm + +# List of the supported models to be used with N-gram LM and beam search decoding +SUPPORTED_MODELS = { + 'EncDecCTCModelBPE': 'subword', + 'EncDecCTCModel': 'char', +} + + +def softmax(x): + e = np.exp(x - np.max(x)) + return e / e.sum(axis=-1).reshape([x.shape[0], 1]) + + +def read_train_file(path, lowercase: bool = False): + lines_read = 0 + text_dataset = [] + + with open(path, 'r') as f: + reader = tqdm(iter(lambda: f.readline(), ''), desc="Read 0 lines", unit=' lines') + for i, line in enumerate(reader): + if path.endswith('.json'): + line = json.loads(line)['text'] + + line = line.replace("\n", "").strip() + if lowercase: + line = line.lower() + + if line: + text_dataset.append(line) + + lines_read += 1 + if lines_read % 100000 == 0: + reader.set_description(f"Read {lines_read} lines") + + return text_dataset + + +def tokenize_str(texts, tokenizer, offset): + tokenized_text = [] + for text in texts: + tok_text = tokenizer.text_to_ids(text) + tok_text = [chr(token + offset) for token in tok_text] + tokenized_text.append(tok_text) + return tokenized_text + + +def tokenize_text(data, tokenizer, path, chunk_size=8192, buffer_size=32, token_offset=100): + dataset_len = len(data) + print( + f"Chunking {dataset_len} rows into {dataset_len / float(chunk_size):0.4f} tasks (each chunk contains {chunk_size} elements)" + ) + + current_step = 0 + if os.path.exists(path): + print(f"Deleting previous file : {path}") + os.remove(path) + + with Parallel(n_jobs=-2, verbose=10) as parallel: + while True: + start = current_step * chunk_size + end = min((current_step + buffer_size) * chunk_size, dataset_len) + + tokenized_data = parallel( + delayed(tokenize_str)(data[start : start + chunk_size], tokenizer, token_offset) + for start in range(start, end, chunk_size) + ) + + # Write dataset + write_dataset(tokenized_data, path) + current_step += len(tokenized_data) + print(f"Finished writing {len(tokenized_data)} chunks to {path}. Current chunk index = {current_step}") + del tokenized_data + if end >= dataset_len: + break + + +def write_dataset(chunks, path): + basedir = os.path.dirname(path) + + if not os.path.exists(basedir): + os.makedirs(basedir, exist_ok=True) + + with open(path, 'a+', encoding='utf-8') as f: + for chunk_idx in tqdm(range(len(chunks)), desc='Chunk ', total=len(chunks), unit=' chunks'): + for text in chunks[chunk_idx]: + line = ' '.join(text) + f.write(f"{line}\n") diff --git a/tts/NeMo/scripts/asr_language_modeling/ngram_lm/train_kenlm.py b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/train_kenlm.py new file mode 100644 index 0000000..a28ecfe --- /dev/null +++ b/tts/NeMo/scripts/asr_language_modeling/ngram_lm/train_kenlm.py @@ -0,0 +1,154 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +# + + +# This script would train an N-gram language model with KenLM library (https://github.com/kpu/kenlm) which can be used +# with the beam search decoders on top of the ASR models. This script supports both character level and BPE level +# encodings and models which is detected automatically from the type of the model. +# After the N-gram model is trained, and stored in the binary format, you may use +# 'scripts/ngram_lm/eval_beamsearch_ngram.py' to evaluate it on an ASR model. +# +# You need to install the KenLM library and also the beam search decoders to use this feature. Please refer +# to 'scripts/ngram_lm/install_beamsearch_decoders.sh' on how to install them. +# +# USAGE: python train_kenlm.py --nemo_model_file \ +# --train_file \ +# --kenlm_model_file \ +# --ngram_length +# +# After training is done, the binary LM model is stored at the path specified by '--kenlm_model_file'. +# You may find more info on how to use this script at: +# https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/asr/asr_language_modeling.html + +import argparse +import logging +import os +import subprocess +import sys + +import kenlm_utils +import torch + +import nemo.collections.asr as nemo_asr +from nemo.utils import logging + +""" +NeMo's beam search decoders only support char-level encodings. In order to make it work with BPE-level encodings, we +use a trick to encode the sub-word tokens of the training data as unicode characters and train a char-level KenLM. +TOKEN_OFFSET is the offset in the unicode table to be used to encode the BPE sub-words. This encoding scheme reduces +the required memory significantly, and the LM and its binary blob format require less storage space. +""" +TOKEN_OFFSET = 100 + +CHUNK_SIZE = 8192 +CHUNK_BUFFER_SIZE = 512 + + +def main(): + parser = argparse.ArgumentParser( + description='Train an N-gram language model with KenLM to be used with beam search decoder of ASR models.' + ) + parser.add_argument( + "--train_file", + required=True, + type=str, + help="Path to the training file, it can be a text file or JSON manifest", + ) + parser.add_argument( + "--nemo_model_file", required=True, type=str, help="The path of the '.nemo' file of the ASR model" + ) + parser.add_argument( + "--kenlm_model_file", required=True, type=str, help="The path to store the KenLM binary model file" + ) + parser.add_argument("--ngram_length", required=True, type=int, help="The order of N-gram LM") + parser.add_argument("--kenlm_bin_path", required=True, type=str, help="The path to the bin folder of KenLM") + parser.add_argument( + "--do_lowercase", action='store_true', help="Whether to apply lower case conversion on the training text" + ) + args = parser.parse_args() + + """ TOKENIZER SETUP """ + logging.info(f"Loading nemo model '{args.nemo_model_file}' ...") + model = nemo_asr.models.ASRModel.restore_from(args.nemo_model_file, map_location=torch.device('cpu')) + + encoding_level = kenlm_utils.SUPPORTED_MODELS.get(type(model).__name__, None) + if not encoding_level: + logging.warning( + f"Model type '{type(model).__name__}' may not be supported. Would try to train a char-level LM." + ) + encoding_level = 'char' + + """ DATASET SETUP """ + logging.info(f"Encoding the train file '{args.train_file}' ...") + dataset = kenlm_utils.read_train_file(args.train_file, lowercase=args.do_lowercase) + encoded_train_file = f"{args.kenlm_model_file}.tmp.txt" + if encoding_level == "subword": + kenlm_utils.tokenize_text( + dataset, + model.tokenizer, + path=encoded_train_file, + chunk_size=CHUNK_SIZE, + buffer_size=CHUNK_BUFFER_SIZE, + token_offset=TOKEN_OFFSET, + ) + # --discount_fallback is needed for training KenLM for BPE-based models + discount_arg = "--discount_fallback" + else: + with open(encoded_train_file, 'w', encoding='utf-8') as f: + for line in dataset: + f.write(f"{line}\n") + + discount_arg = "" + + del model + + arpa_file = f"{args.kenlm_model_file}.tmp.arpa" + """ LMPLZ ARGUMENT SETUP """ + kenlm_args = [ + os.path.join(args.kenlm_bin_path, 'lmplz'), + "-o", + f"{args.ngram_length}", + "--text", + encoded_train_file, + "--arpa", + arpa_file, + discount_arg, + ] + + ret = subprocess.run(kenlm_args, capture_output=False, text=True, stdout=sys.stdout, stderr=sys.stderr) + if ret.returncode != 0: + raise RuntimeError("Training KenLM was not successful!") + """ BINARY BUILD """ + logging.info(f"Running binary_build command \n\n{' '.join(kenlm_args)}\n\n") + kenlm_args = [ + os.path.join(args.kenlm_bin_path, "build_binary"), + "trie", + arpa_file, + args.kenlm_model_file, + ] + ret = subprocess.run(kenlm_args, capture_output=False, text=True, stdout=sys.stdout, stderr=sys.stderr) + + if ret.returncode != 0: + raise RuntimeError("Training KenLM was not successful!") + + os.remove(encoded_train_file) + logging.info(f"Deleted the temporary encoded training file '{encoded_train_file}'.") + os.remove(arpa_file) + logging.info(f"Deleted the arpa file '{arpa_file}'.") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/average_model_checkpoints.py b/tts/NeMo/scripts/average_model_checkpoints.py new file mode 100644 index 0000000..06c522f --- /dev/null +++ b/tts/NeMo/scripts/average_model_checkpoints.py @@ -0,0 +1,171 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# Copyright 2017 Johns Hopkins University (Shinji Watanabe) +# +# 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. + +""" +# Changes to script +Change the script to import the NeMo model class you would like to load a checkpoint for, +then update the model constructor to use this model class. This can be found by the line: + +<<< Change model class here ! >>> + +By default, this script imports and creates the `EncDecCTCModelBPE` class but it can be +changed to any NeMo Model. + +# Run the script + +## Saving a .nemo model file (loaded with ModelPT.restore_from(...)) +HYDRA_FULL_ERROR=1 python average_model_checkpoints.py \ + --config-path="" \ + --config-name="" \ + name= \ + +checkpoint_dir= \ + +checkpoint_paths=\"[/path/to/ptl_1.ckpt,/path/to/ptl_2.ckpt,/path/to/ptl_3.ckpt,...]\" + + +## Saving an averaged pytorch checkpoint (loaded with torch.load(...)) +HYDRA_FULL_ERROR=1 python average_model_checkpoints.py \ + --config-path="" \ + --config-name="" \ + name= \ + +checkpoint_dir= \ + +checkpoint_paths=\"[/path/to/ptl_1.ckpt,/path/to/ptl_2.ckpt,/path/to/ptl_3.ckpt,...]\" \ + +save_ckpt_only=true + +""" + +import os + +import pytorch_lightning as pl +import torch +from omegaconf import OmegaConf, open_dict + +# Change this import to the model you would like to average +from nemo.collections.asr.models import EncDecCTCModelBPE +from nemo.core.config import hydra_runner +from nemo.utils import logging + + +def process_config(cfg: OmegaConf): + if 'name' not in cfg or cfg.name is None: + raise ValueError("`cfg.name` must be provided to save a model checkpoint") + + if 'checkpoint_paths' not in cfg or cfg.checkpoint_paths is None: + raise ValueError( + "`cfg.checkpoint_paths` must be provided as a list of one or more str paths to " + "pytorch lightning checkpoints" + ) + + save_ckpt_only = False + + with open_dict(cfg): + name_prefix = cfg.name + checkpoint_paths = cfg.pop('checkpoint_paths') + + if 'checkpoint_dir' in cfg: + checkpoint_dir = cfg.pop('checkpoint_dir') + else: + checkpoint_dir = None + + if 'save_ckpt_only' in cfg: + save_ckpt_only = cfg.pop('save_ckpt_only') + + if type(checkpoint_paths) not in (list, tuple): + checkpoint_paths = str(checkpoint_paths).replace("[", "").replace("]", "") + checkpoint_paths = checkpoint_paths.split(",") + checkpoint_paths = [ckpt_path.strip() for ckpt_path in checkpoint_paths] + + if checkpoint_dir is not None: + checkpoint_paths = [os.path.join(checkpoint_dir, path) for path in checkpoint_paths] + + return name_prefix, checkpoint_paths, save_ckpt_only + + +@hydra_runner(config_path=None, config_name=None) +def main(cfg): + name_prefix, checkpoint_paths, save_ckpt_only = process_config(cfg) + + if not save_ckpt_only: + trainer = pl.Trainer(**cfg.trainer) + + # <<< Change model class here ! >>> + # Model architecture which will contain the averaged checkpoints + # Change the model constructor to the one you would like (if needed) + model = EncDecCTCModelBPE(cfg=cfg.model, trainer=trainer) + + """ < Checkpoint Averaging Logic > """ + # load state dicts + n = len(checkpoint_paths) + avg_state = None + + logging.info(f"Averaging {n} checkpoints ...") + + for ix, path in enumerate(checkpoint_paths): + checkpoint = torch.load(path, map_location='cpu') + + if 'state_dict' in checkpoint: + checkpoint = checkpoint['state_dict'] + + if ix == 0: + # Initial state + avg_state = checkpoint + + logging.info(f"Initialized average state dict with checkpoint : {path}") + else: + # Accumulated state + for k in avg_state: + avg_state[k] = avg_state[k] + checkpoint[k] + + logging.info(f"Updated average state dict with state from checkpoint : {path}") + + for k in avg_state: + if str(avg_state[k].dtype).startswith("torch.int"): + # For int type, not averaged, but only accumulated. + # e.g. BatchNorm.num_batches_tracked + pass + else: + avg_state[k] = avg_state[k] / n + + # Save model + if save_ckpt_only: + ckpt_name = name_prefix + '-averaged.ckpt' + torch.save(avg_state, ckpt_name) + + logging.info(f"Averaged pytorch checkpoint saved as : {ckpt_name}") + else: + # Set model state + logging.info("Loading averaged state dict in provided model") + model.load_state_dict(avg_state, strict=True) + + ckpt_name = name_prefix + '-averaged.nemo' + model.save_to(ckpt_name) + + logging.info(f"Averaged model saved as : {ckpt_name}") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/get_commonvoice_data.py b/tts/NeMo/scripts/dataset_processing/get_commonvoice_data.py new file mode 100644 index 0000000..b534156 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/get_commonvoice_data.py @@ -0,0 +1,178 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +# + +# Copyright (c) 2020, SeanNaren. 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. +# + +# To convert mp3 files to wav using sox, you must have installed sox with mp3 support +# For example sudo apt-get install libsox-fmt-mp3 +import argparse +import csv +import json +import logging +import multiprocessing +import os +import subprocess +import sys +import tarfile +from multiprocessing.pool import ThreadPool +from pathlib import Path +from typing import List + +import sox +from sox import Transformer +from tqdm import tqdm + +parser = argparse.ArgumentParser(description='Downloads and processes Mozilla Common Voice dataset.') +parser.add_argument("--data_root", default='CommonVoice_dataset/', type=str, help="Directory to store the dataset.") +parser.add_argument('--manifest_dir', default='./', type=str, help='Output directory for manifests') +parser.add_argument("--num_workers", default=multiprocessing.cpu_count(), type=int, help="Workers to process dataset.") +parser.add_argument('--sample_rate', default=16000, type=int, help='Sample rate') +parser.add_argument('--n_channels', default=1, type=int, help='Number of channels for output wav files') +parser.add_argument( + '--files_to_process', + nargs='+', + default=['test.tsv', 'dev.tsv', 'train.tsv'], + type=str, + help='list of *.csv file names to process', +) +parser.add_argument( + '--version', + default='cv-corpus-5.1-2020-06-22', + type=str, + help='Version of the dataset (obtainable via https://commonvoice.mozilla.org/en/datasets', +) +parser.add_argument( + '--language', + default='en', + type=str, + help='Which language to download.(default english,' + 'check https://commonvoice.mozilla.org/en/datasets for more language codes', +) +args = parser.parse_args() +COMMON_VOICE_URL = ( + f"https://voice-prod-bundler-ee1969a6ce8178826482b88e843c335139bd3fb4.s3.amazonaws.com/" + "{}/{}.tar.gz".format(args.version, args.language) +) + + +def create_manifest(data: List[tuple], output_name: str, manifest_path: str): + output_file = Path(manifest_path) / output_name + output_file.parent.mkdir(exist_ok=True, parents=True) + + with output_file.open(mode='w') as f: + for wav_path, duration, text in tqdm(data, total=len(data)): + f.write( + json.dumps({'audio_filepath': os.path.abspath(wav_path), "duration": duration, 'text': text}) + '\n' + ) + + +def process_files(csv_file, data_root, num_workers): + """ Read *.csv file description, convert mp3 to wav, process text. + Save results to data_root. + + Args: + csv_file: str, path to *.csv file with data description, usually start from 'cv-' + data_root: str, path to dir to save results; wav/ dir will be created + """ + wav_dir = os.path.join(data_root, 'wav/') + os.makedirs(wav_dir, exist_ok=True) + audio_clips_path = os.path.dirname(csv_file) + '/clips/' + + def process(x): + file_path, text = x + file_name = os.path.splitext(os.path.basename(file_path))[0] + text = text.lower().strip() + audio_path = os.path.join(audio_clips_path, file_path) + output_wav_path = os.path.join(wav_dir, file_name + '.wav') + + tfm = Transformer() + tfm.rate(samplerate=args.sample_rate) + tfm.channels(n_channels=args.n_channels) + tfm.build(input_filepath=audio_path, output_filepath=output_wav_path) + duration = sox.file_info.duration(output_wav_path) + return output_wav_path, duration, text + + logging.info('Converting mp3 to wav for {}.'.format(csv_file)) + with open(csv_file) as csvfile: + reader = csv.DictReader(csvfile, delimiter='\t') + next(reader, None) # skip the headers + data = [(row['path'], row['sentence']) for row in reader] + with ThreadPool(num_workers) as pool: + data = list(tqdm(pool.imap(process, data), total=len(data))) + return data + + +def main(): + data_root = args.data_root + os.makedirs(data_root, exist_ok=True) + + target_unpacked_dir = os.path.join(data_root, "CV_unpacked") + + if os.path.exists(target_unpacked_dir): + logging.info('Find existing folder {}'.format(target_unpacked_dir)) + else: + logging.info("Could not find Common Voice, Downloading corpus...") + + commands = [ + 'wget', + '--user-agent', + '"Mozilla/5.0 (Windows NT 10.0; WOW64) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"', + '-P', + data_root, + f'{COMMON_VOICE_URL}', + ] + commands = " ".join(commands) + subprocess.run(commands, shell=True, stderr=sys.stderr, stdout=sys.stdout, capture_output=False) + filename = f"{args.language}.tar.gz" + target_file = os.path.join(data_root, os.path.basename(filename)) + + os.makedirs(target_unpacked_dir, exist_ok=True) + logging.info("Unpacking corpus to {} ...".format(target_unpacked_dir)) + tar = tarfile.open(target_file) + tar.extractall(target_unpacked_dir) + tar.close() + + folder_path = os.path.join(target_unpacked_dir, args.version + f'/{args.language}/') + + for csv_file in args.files_to_process: + data = process_files( + csv_file=os.path.join(folder_path, csv_file), + data_root=os.path.join(data_root, os.path.splitext(csv_file)[0]), + num_workers=args.num_workers, + ) + logging.info('Creating manifests...') + create_manifest( + data=data, + output_name=f'commonvoice_{os.path.splitext(csv_file)[0]}_manifest.json', + manifest_path=args.manifest_dir, + ) + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/dataset_processing/get_hi-mia_data.py b/tts/NeMo/scripts/dataset_processing/get_hi-mia_data.py new file mode 100644 index 0000000..59dd629 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/get_hi-mia_data.py @@ -0,0 +1,185 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# USAGE: python get_aishell_data.py --data_root= + +import argparse +import json +import logging as _logging +import os +import tarfile +import urllib.request +from glob import glob + +import librosa as l +from sklearn.model_selection import StratifiedShuffleSplit +from tqdm import tqdm + +parser = argparse.ArgumentParser(description='HI-MIA Data download') +parser.add_argument("--data_root", required=True, default=None, type=str) +parser.add_argument("--log_level", default=20, type=int) +args = parser.parse_args() +logging = _logging.getLogger(__name__) +logging.addHandler(_logging.StreamHandler()) +logging.setLevel(args.log_level) + +URL = { + 'dev': "http://www.openslr.org/resources/85/dev.tar.gz", + 'test': "http://www.openslr.org/resources/85/test.tar.gz", + 'train': "http://www.openslr.org/resources/85/train.tar.gz", +} + + +def __maybe_download_file(destination: str, source: str): + """ + Downloads source to destination if it doesn't exist. + If exists, skips download + Args: + destination: local filepath + source: url of resource + + Returns: + + """ + source = URL[source] + if not os.path.exists(destination) and not os.path.exists(os.path.splitext(destination)[0]): + logging.info("{0} does not exist. Downloading ...".format(destination)) + urllib.request.urlretrieve(source, filename=destination + '.tmp') + os.rename(destination + '.tmp', destination) + logging.info("Downloaded {0}.".format(destination)) + elif os.path.exists(destination): + logging.info("Destination {0} exists. Skipping.".format(destination)) + elif os.path.exists(os.path.splitext(destination)[0]): + logging.warning( + "Assuming extracted folder %s contains the extracted files from %s. Will not download.", + os.path.basename(destination), + destination, + ) + return destination + + +def __extract_all_files(filepath: str, data_root: str, data_dir: str): + if not os.path.exists(data_dir): + extract_file(filepath, data_root) + audio_dir = os.path.join(data_dir, 'wav') + for subfolder, _, filelist in os.walk(audio_dir): + for ftar in filelist: + extract_file(os.path.join(subfolder, ftar), subfolder) + else: + logging.info('Skipping extracting. Data already there %s' % data_dir) + + +def extract_file(filepath: str, data_dir: str): + try: + tar = tarfile.open(filepath) + tar.extractall(data_dir) + tar.close() + except Exception: + logging.info('Not extracting. Maybe already there?') + + +def __remove_tarred_files(filepath: str, data_dir: str): + if os.path.exists(data_dir) and os.path.isfile(filepath): + logging.info('Deleting %s' % filepath) + os.remove(filepath) + + +def write_file(name, lines, idx): + with open(name, 'w') as fout: + for i in idx: + dic = lines[i] + json.dump(dic, fout) + fout.write('\n') + logging.info("wrote %s", name) + + +def __process_data(data_folder: str, data_set: str): + """ + To generate manifest + Args: + data_folder: source with wav files + Returns: + + """ + fullpath = os.path.abspath(data_folder) + scp = glob(fullpath + '/**/*.wav', recursive=True) + out = os.path.join(fullpath, data_set + '_all.json') + utt2spk = os.path.join(fullpath, 'utt2spk') + utt2spk_file = open(utt2spk, 'w') + id = -2 # speaker id + + if os.path.exists(out): + logging.warning( + "%s already exists and is assumed to be processed. If not, please delete %s and rerun this script", + out, + out, + ) + return + + speakers = [] + lines = [] + with open(out, 'w') as outfile: + for line in tqdm(scp): + line = line.strip() + y, sr = l.load(line, sr=None) + if sr != 16000: + y, sr = l.load(line, sr=16000) + l.output.write_wav(line, y, sr) + dur = l.get_duration(y=y, sr=sr) + if data_set == 'test': + speaker = line.split('/')[-1].split('.')[0].split('_')[0] + else: + speaker = line.split('/')[id] + speaker = list(speaker) + speaker = ''.join(speaker) + speakers.append(speaker) + meta = {"audio_filepath": line, "duration": float(dur), "label": speaker} + lines.append(meta) + json.dump(meta, outfile) + outfile.write("\n") + utt2spk_file.write(line.split('/')[-1] + "\t" + speaker + "\n") + + utt2spk_file.close() + + if data_set != 'test': + sss = StratifiedShuffleSplit(n_splits=1, test_size=0.1, random_state=42) + for train_idx, test_idx in sss.split(speakers, speakers): + print(len(train_idx)) + + out = os.path.join(fullpath, 'train.json') + write_file(out, lines, train_idx) + out = os.path.join(fullpath, 'dev.json') + write_file(out, lines, test_idx) + + +def main(): + data_root = args.data_root + for data_set in URL.keys(): + + # data_set = 'data_aishell' + logging.info("\n\nWorking on: {0}".format(data_set)) + file_path = os.path.join(data_root, data_set + ".tgz") + logging.info("Getting {0}".format(data_set)) + __maybe_download_file(file_path, data_set) + logging.info("Extracting {0}".format(data_set)) + data_folder = os.path.join(data_root, data_set) + __extract_all_files(file_path, data_root, data_folder) + __remove_tarred_files(file_path, data_folder) + logging.info("Processing {0}".format(data_set)) + __process_data(data_folder, data_set) + logging.info('Done!') + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/dataset_processing/get_librispeech_data.py b/tts/NeMo/scripts/dataset_processing/get_librispeech_data.py new file mode 100644 index 0000000..e009a23 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/get_librispeech_data.py @@ -0,0 +1,171 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +# +# USAGE: python get_librispeech_data.py --data_root= +# --data_set= --num_workers= +# where can be: dev_clean, dev_other, test_clean, +# test_other, train_clean_100, train_clean_360, train_other_500 or ALL +# You can also put more than one data_set comma-separated: +# --data_set=dev_clean,train_clean_100 +import argparse +import fnmatch +import functools +import json +import logging +import multiprocessing +import os +import subprocess +import tarfile +import urllib.request + +from sox import Transformer +from tqdm import tqdm + +parser = argparse.ArgumentParser(description='LibriSpeech Data download') +parser.add_argument("--data_root", required=True, default=None, type=str) +parser.add_argument("--data_sets", default="dev_clean", type=str) +parser.add_argument("--num_workers", default=4, type=int) +args = parser.parse_args() + +URLS = { + 'TRAIN_CLEAN_100': ("http://www.openslr.org/resources/12/train-clean-100.tar.gz"), + 'TRAIN_CLEAN_360': ("http://www.openslr.org/resources/12/train-clean-360.tar.gz"), + 'TRAIN_OTHER_500': ("http://www.openslr.org/resources/12/train-other-500.tar.gz"), + 'DEV_CLEAN': "http://www.openslr.org/resources/12/dev-clean.tar.gz", + 'DEV_OTHER': "http://www.openslr.org/resources/12/dev-other.tar.gz", + 'TEST_CLEAN': "http://www.openslr.org/resources/12/test-clean.tar.gz", + 'TEST_OTHER': "http://www.openslr.org/resources/12/test-other.tar.gz", +} + + +def __maybe_download_file(destination: str, source: str): + """ + Downloads source to destination if it doesn't exist. + If exists, skips download + Args: + destination: local filepath + source: url of resource + Returns: + """ + source = URLS[source] + if not os.path.exists(destination): + logging.info("{0} does not exist. Downloading ...".format(destination)) + urllib.request.urlretrieve(source, filename=destination + '.tmp') + os.rename(destination + '.tmp', destination) + logging.info("Downloaded {0}.".format(destination)) + else: + logging.info("Destination {0} exists. Skipping.".format(destination)) + return destination + + +def __extract_file(filepath: str, data_dir: str): + try: + tar = tarfile.open(filepath) + tar.extractall(data_dir) + tar.close() + except Exception: + logging.info('Not extracting. Maybe already there?') + + +def __process_transcript(file_path: str, dst_folder: str): + """ + Converts flac files to wav from a given transcript, capturing the metadata. + Args: + file_path: path to a source transcript with flac sources + dst_folder: path where wav files will be stored + Returns: + a list of metadata entries for processed files. + """ + entries = [] + root = os.path.dirname(file_path) + with open(file_path, encoding="utf-8") as fin: + for line in fin: + id, text = line[: line.index(" ")], line[line.index(" ") + 1 :] + transcript_text = text.lower().strip() + + # Convert FLAC file to WAV + flac_file = os.path.join(root, id + ".flac") + wav_file = os.path.join(dst_folder, id + ".wav") + if not os.path.exists(wav_file): + Transformer().build(flac_file, wav_file) + # check duration + duration = subprocess.check_output("soxi -D {0}".format(wav_file), shell=True) + + entry = {} + entry['audio_filepath'] = os.path.abspath(wav_file) + entry['duration'] = float(duration) + entry['text'] = transcript_text + entries.append(entry) + return entries + + +def __process_data(data_folder: str, dst_folder: str, manifest_file: str, num_workers: int): + """ + Converts flac to wav and build manifests's json + Args: + data_folder: source with flac files + dst_folder: where wav files will be stored + manifest_file: where to store manifest + num_workers: number of parallel workers processing files + Returns: + """ + + if not os.path.exists(dst_folder): + os.makedirs(dst_folder) + + files = [] + entries = [] + + for root, dirnames, filenames in os.walk(data_folder): + for filename in fnmatch.filter(filenames, '*.trans.txt'): + files.append(os.path.join(root, filename)) + + with multiprocessing.Pool(num_workers) as p: + processing_func = functools.partial(__process_transcript, dst_folder=dst_folder) + results = p.imap(processing_func, files) + for result in tqdm(results, total=len(files)): + entries.extend(result) + + with open(manifest_file, 'w') as fout: + for m in entries: + fout.write(json.dumps(m) + '\n') + + +def main(): + data_root = args.data_root + data_sets = args.data_sets + num_workers = args.num_workers + + if data_sets == "ALL": + data_sets = "dev_clean,dev_other,train_clean_100,train_clean_360,train_other_500,test_clean,test_other" + + for data_set in data_sets.split(','): + logging.info("\n\nWorking on: {0}".format(data_set)) + filepath = os.path.join(data_root, data_set + ".tar.gz") + logging.info("Getting {0}".format(data_set)) + __maybe_download_file(filepath, data_set.upper()) + logging.info("Extracting {0}".format(data_set)) + __extract_file(filepath, data_root) + logging.info("Processing {0}".format(data_set)) + __process_data( + os.path.join(os.path.join(data_root, "LibriSpeech"), data_set.replace("_", "-"),), + os.path.join(os.path.join(data_root, "LibriSpeech"), data_set.replace("_", "-"),) + "-processed", + os.path.join(data_root, data_set + ".json"), + num_workers=num_workers, + ) + logging.info('Done!') + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/dataset_processing/get_openslr_rir_data.py b/tts/NeMo/scripts/dataset_processing/get_openslr_rir_data.py new file mode 100644 index 0000000..f166306 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/get_openslr_rir_data.py @@ -0,0 +1,140 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# USAGE: python get_openslr_rir_data.py --data_root= +# Data is downloaded from OpenSLR's "Room Impulse Response and Noise Database" +# RIRs in multichannel files are separated into single channel files and +# a json file that can be used as in input to NeMo is created + +import argparse +import glob +import json +import logging +import os +import subprocess +import urllib.request +from shutil import copy, move +from zipfile import ZipFile + +parser = argparse.ArgumentParser(description='OpenSLR RIR Data download and process') +parser.add_argument("--data_root", required=True, default=None, type=str) +args = parser.parse_args() + +URLS = { + 'SLR28': ("http://www.openslr.org/resources/28/rirs_noises.zip"), +} + + +def __maybe_download_file(destination: str, source: str): + """ + Downloads source to destination if it doesn't exist. + If exists, skips download + Args: + destination: local filepath + source: url of resource + Returns: + """ + source = URLS[source] + if not os.path.exists(destination): + logging.info("{0} does not exist. Downloading ...".format(destination)) + urllib.request.urlretrieve(source, filename=destination + '.tmp') + os.rename(destination + '.tmp', destination) + logging.info("Downloaded {0}.".format(destination)) + else: + logging.info("Destination {0} exists. Skipping.".format(destination)) + return destination + + +def __extract_file(filepath: str, data_dir: str): + try: + with ZipFile(filepath, 'r') as zipObj: + zipObj.extractall(data_dir) + except Exception: + logging.info('Not extracting. Maybe already there?') + + +def __process_data(data_folder: str, dst_folder: str, manifest_file: str): + """ + Converts flac to wav and build manifests's json + Args: + data_folder: source with flac files + dst_folder: where wav files will be stored + manifest_file: where to store manifest + Returns: + """ + if not os.path.exists(dst_folder): + os.makedirs(dst_folder) + + real_rir_list = os.path.join(data_folder, "RIRS_NOISES", "real_rirs_isotropic_noises", "rir_list") + rirfiles = [] + with open(real_rir_list, "r") as rir_f: + for line in rir_f: + rirfiles.append(os.path.join(data_folder, line.rstrip().split(" ")[4])) + + real_rir_folder = os.path.join(dst_folder, "real_rirs") + if not os.path.exists(real_rir_folder): + os.makedirs(real_rir_folder) + # split multi-channel rir files to single channel + for rir_f in rirfiles: + n_chans = int(subprocess.check_output("soxi -c {0}".format(rir_f), shell=True)) + if n_chans == 1: + copy(rir_f, real_rir_folder) + else: + for chan in range(1, n_chans + 1): + chan_file_name = os.path.join( + real_rir_folder, os.path.splitext(os.path.basename(rir_f))[0] + "-" + str(chan) + ".wav" + ) + _ = subprocess.check_output(f"sox {rir_f} {chan_file_name} remix {chan}", shell=True) + + # move simulated rirs to processed + if not os.path.exists(os.path.join(dst_folder, "simulated_rirs")): + move(os.path.join(data_folder, "RIRS_NOISES", "simulated_rirs"), dst_folder) + + os.chdir(dst_folder) + all_rirs = glob.glob("**/*.wav", recursive=True) + with open(manifest_file, 'w') as man_f: + entry = {} + for rir in all_rirs: + rir_file = os.path.join(dst_folder, rir) + duration = subprocess.check_output("soxi -D {0}".format(rir_file), shell=True) + entry['audio_filepath'] = rir_file + entry['duration'] = float(duration) + entry['offset'] = 0 + entry['text'] = '_' + man_f.write(json.dumps(entry) + "\n") + + print('Done!') + + +def main(): + data_root = os.path.abspath(args.data_root) + data_set = "slr28" + logging.getLogger().setLevel(logging.INFO) + logging.info("\n\nWorking on: {0}".format(data_set)) + filepath = os.path.join(data_root, data_set + ".zip") + logging.info("Getting {0}".format(data_set)) + __maybe_download_file(filepath, data_set.upper()) + logging.info("Extracting {0}".format(data_set)) + __extract_file(filepath, data_root) + logging.info("Processing {0}".format(data_set)) + __process_data( + data_root, + os.path.join(os.path.join(data_root, "processed")), + os.path.join(os.path.join(data_root, "processed", "rir.json")), + ) + logging.info('Done!') + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/dataset_processing/ljspeech/README b/tts/NeMo/scripts/dataset_processing/ljspeech/README new file mode 100644 index 0000000..d16fdac --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/ljspeech/README @@ -0,0 +1,14 @@ +These scripts are used for extracting features from LJSpeech. + +You will need to run the following scripts (note that these will call the other +scripts as necessary): + +- `create_manifests_and_textfiles.py`: Creates the manifest and text files that + are used by the Montreal Forced Aligner (MFA) library. +- `extract_ljspeech_phonemes_and_durs.sh`: Extracts phonemes and alignments via + MFA and calculates phoneme durations. + Needs to be run with Conda active since it creates a Conda environment. + Also note that you may need to install OpenBlas manually (e.g. sudo apt-get + install libopenblas-dev), sometimes MFA can't find it if installed via Conda. + (This script calls `create_token2idx_dict.py` and `calculate_durs.py`.) +- `extract_ljspeech_energy_pitch.py` diff --git a/tts/NeMo/scripts/dataset_processing/ljspeech/calculate_durs.py b/tts/NeMo/scripts/dataset_processing/ljspeech/calculate_durs.py new file mode 100644 index 0000000..f7a37c2 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/ljspeech/calculate_durs.py @@ -0,0 +1,126 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. +""" +Calculates durations for LJSpeech based on MFA TextGrid alignments. +""" +import argparse +import glob +import json +import os +import pickle +from math import ceil + +import numpy as np +import tgt +import torch +from tqdm import tqdm + +parser = argparse.ArgumentParser(description="Calculates phoneme durations for LJSpeech from TextGrids.") +parser.add_argument('--ljspeech_dir', required=True, default=None, type=str) +parser.add_argument( + '--mappings', + required=False, + default=None, + type=str, + help='JSON file of mappings created with create_token2idx_dict.py', +) +parser.add_argument('--sr', required=False, default=22050, type=int) +parser.add_argument('--hop_length', required=False, default=256, type=int) +args = parser.parse_args() + + +def calculate_durations(textgrid, phone2idx): + tokens = [] + durs = [] + + frames_per_second = args.sr / args.hop_length + tg = tgt.read_textgrid(textgrid, include_empty_intervals=True) + data_tier = tg.get_tier_by_name("phones") + + # Get total frames + total_frames = ceil((data_tier.end_time - data_tier.start_time) * frames_per_second) + + # Find start and end frames of each token + se_in_frames = np.array([(frames_per_second * d.start_time, frames_per_second * d.end_time) for d in data_tier]) + se_in_frames = np.round(se_in_frames) + durs = (se_in_frames[:, 1] - se_in_frames[:, 0]).astype(int) + blank_set = ('sil', 'sp', 'spn', '', '') + blank_token = " " + + # merge repeated blank tokens + tokens, durations = [], [] + for i in range(len(data_tier)): + x = data_tier[i].text + if x == 'spn': + return None, None, None + x = blank_token if x in blank_set else x + + if len(tokens) and tokens[-1] == blank_token and x == blank_token: + durations[-1] += durs[i] + else: + tokens.append(x) + durations.append(durs[i]) + + tokens_enc = [phone2idx[token] for token in tokens] + tokens_enc, durations = torch.LongTensor(tokens_enc), torch.LongTensor(durations) + + # Add rounding error to final token + durations[-1] += total_frames - durations.sum() + + return tokens, tokens_enc, durations + + +def main(): + textgrid_list = glob.glob(os.path.join(args.ljspeech_dir, 'alignments/wavs/*.TextGrid')) + + # Create target_dir if necessary + target_dir = os.path.join(args.ljspeech_dir, 'phoneme_durations/') + print(f"Calculating phoneme durations, files will be in: {target_dir}") + + if not os.path.exists(target_dir): + print(f"Creating {target_dir}") + os.mkdir(target_dir) + + # Read phoneme to idx mappings + phone2idx = None + if args.mappings: + with open(args.mappings, 'r') as f: + mappings = json.load(f) + phone2idx = mappings['phone2idx'] + + oov_samples = [] + + # Iterate through all TextGrid files + for textgrid in tqdm(textgrid_list): + basename = os.path.splitext(os.path.basename(textgrid))[0][5:] # Chop off 'wavs_' prefix + + phones_mfa, tokens_mfa, durs = calculate_durations(textgrid, phone2idx) + + if phones_mfa is None: + oov_samples.append(basename) + continue + + # Save to file + target_path = os.path.join(target_dir, f'{basename}.pt') + torch.save({'text_encoded': tokens_mfa, 'token_duration': durs}, target_path) + + print(f"Getting rid of {len(oov_samples)} samples with OOV words.") + oov_target = os.path.join(args.ljspeech_dir, 'wavs_to_ignore.pkl') + with open(oov_target, 'wb') as f: + pickle.dump(oov_samples, f) + print(f"List of OOV samples written to: {oov_target}") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/ljspeech/create_manifests_and_textfiles.py b/tts/NeMo/scripts/dataset_processing/ljspeech/create_manifests_and_textfiles.py new file mode 100644 index 0000000..aede9f8 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/ljspeech/create_manifests_and_textfiles.py @@ -0,0 +1,71 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. +""" +Creates the manifest and .txt transcript files for an LJSpeech split. +The manifest will be used for training, and the .txt files are for the MFA library to find. +""" + +import argparse +import json +import os + +import sox +import wget + +from nemo.collections.common.parts.preprocessing import parsers + +parser = argparse.ArgumentParser() +parser.add_argument('--ljspeech_base', required=True, default=None, type=str) +args = parser.parse_args() + + +def main(): + filelist_base = 'https://raw.githubusercontent.com/NVIDIA/tacotron2/master/filelists/' + filelists = ['train', 'val', 'test'] + + # NeMo parser for text normalization + text_parser = parsers.make_parser(name='en') + + for split in filelists: + # Download file list if necessary + filelist_path = os.path.join(args.ljspeech_base, f"ljs_audio_text_{split}_filelist.txt") + if not os.path.exists(filelist_path): + wget.download(f"{filelist_base}/ljs_audio_text_{split}_filelist.txt", out=args.ljspeech_base) + + manifest_target = os.path.join(args.ljspeech_base, f"ljspeech_{split}.json") + with open(manifest_target, 'w') as f_out: + with open(filelist_path, 'r') as filelist: + print(f"\nCreating {manifest_target}...") + for line in filelist: + basename = line[6:16] + text = text_parser._normalize(line[21:].strip()) + + # Make sure corresponding wavfile exists and write .txt transcript + wav_path = os.path.join(args.ljspeech_base, 'wavs/', basename + '.wav') + assert os.path.exists(wav_path) + txt_path = os.path.join(args.ljspeech_base, 'wavs/', basename + '.txt') + with open(txt_path, 'w') as f_txt: + f_txt.write(text) + + # Write manifest entry + entry = { + 'audio_filepath': wav_path, + 'duration': sox.file_info.duration(wav_path), + 'text': text, + } + f_out.write(json.dumps(entry) + '\n') + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/ljspeech/create_token2idx_dict.py b/tts/NeMo/scripts/dataset_processing/ljspeech/create_token2idx_dict.py new file mode 100644 index 0000000..2d3e73a --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/ljspeech/create_token2idx_dict.py @@ -0,0 +1,68 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. +""" +Creates a dictionary from token to index based on dictionary .txt given. +""" +import argparse +import json +import os + +parser = argparse.ArgumentParser() +parser.add_argument('--dictionary', required=True, default=None, type=str) +parser.add_argument('--dict_out', required=True, default=None, type=str) +args = parser.parse_args() + + +def main(): + if not os.path.exists(args.dictionary): + raise FileNotFoundError(f"Could not find dictionary file {args.dictionary}") + + phonemes = set() + word2phones = {} + with open(args.dictionary, 'r') as f: + for line in f: + line = line.split() + word = line[0] + tokens = line[1:] + + word2phones[word] = tokens + phonemes.update(tokens) + + # Small list of additional punctuation + word2phones[','] = [' '] + word2phones[';'] = [' '] + word2phones['.'] = [' '] + word2phones['!'] = [' '] + word2phones['?'] = [' '] + word2phones['"'] = [' '] + word2phones['-'] = [' '] + + phone2idx = {k: i for i, k in enumerate(phonemes)} + phone2idx[' '] = len(phone2idx) + phone2idx['sil'] = phone2idx[' '] # Silence + phone2idx['sp'] = phone2idx[' '] # Space + phone2idx['spn'] = phone2idx[' '] # OOV/unk + + dicts = { + 'phone2idx': phone2idx, + 'word2phones': word2phones, + } + with open(args.dict_out, 'w') as f: + json.dump(dicts, f) + + print(f"Total number of phone indices: {len(phone2idx)}") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_energy_pitch.py b/tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_energy_pitch.py new file mode 100644 index 0000000..a76ce6d --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_energy_pitch.py @@ -0,0 +1,88 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. +""" +Extracts energy and pitch data from LJSpeech wav files and writes them to a directory as LJxxx-xxxx.npy files. +Assuming that the wavs are located at `/wavs`, this script will write the +energy files to `/energies/` and the pitch files to `/pitches`, +creating the relevant directories if necessary. + +USAGE: python extract_ljspeech_energy_pitch.py --ljspeech_dir= +""" +import argparse +from pathlib import Path + +import librosa +import numpy as np + +tqdm = None + +try: + from tqdm import tqdm +except ModuleNotFoundError: + pass + +parser = argparse.ArgumentParser( + description="Extracts energies (L2-norm of STFT frame amplitudes) and pitches (F0) from LJSpeech data." +) +parser.add_argument("--ljspeech_dir", required=True, default=None, type=str) +args = parser.parse_args() + + +def main(): + wavfile_dir = Path(args.ljspeech_dir) / "wavs" + wavfile_list = list(wavfile_dir.glob('*.wav')) + + target_dir = Path(args.ljspeech_dir) + # Create target dir /energies and /pitches if necessary + if not Path(target_dir / "energies").exists(): + print(f"Creating target directory: {target_dir/'energies'}") + Path(target_dir / "energies").mkdir() + if not Path(target_dir / "pitches").exists(): + print(f"Creating target directory: {target_dir/'pitches'}") + Path(target_dir / "pitches").mkdir() + + if tqdm is not None: + wavfile_list = tqdm(wavfile_list) + for count, file_ in enumerate(wavfile_list): + basename = Path(file_).stem + pitch_path = target_dir / "pitches" / f"{basename}.npy" + energy_path = target_dir / "energies" / f"{basename}.npy" + if pitch_path.exists() and energy_path.exists(): + continue + audio, sr = librosa.load(file_, sr=22050) + + # Calculate f0 + # Please note that fmin and fmax are good approximates for the speaker in LJSpeech and may not generalize to + # other speakers + f0, _, _ = librosa.pyin(audio, fmin=80, fmax=800, frame_length=1024, sr=sr, fill_na=0.0) + + # Save to new file + np.save(pitch_path, f0) + + # Calculate energy + stft_amplitude = np.abs(librosa.stft(audio, n_fft=1024, hop_length=256, win_length=1024)) + energy = np.linalg.norm(stft_amplitude, axis=0) # axis=0 since librosa.stft -> (freq bins, frames) + + # Save to new file + np.save(energy_path, energy) + + assert energy.shape == f0.shape + if tqdm is None and count % 1000 == 0: + print(f"Finished processing {count} wav files...") + + print(f"Finished energy extraction for a total of {len(wavfile_list)} wav files.") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_phonemes_and_durs.sh b/tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_phonemes_and_durs.sh new file mode 100755 index 0000000..d5ee277 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/ljspeech/extract_ljspeech_phonemes_and_durs.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# Extracts the phonemes and alignments for the LJSpeech dataset via the +# Montreal Forced Aligner (MFA) library, and computes durations per phoneme. +# Assumes you have downloaded and expanded the LJSpeech dataset, and that they +# are located at the directory specified. +# +# This script will create: +# - /mappings.json: Contains word->phone and phone->idx mappings +# - /wavs_to_ignore.pkl: A pickled list of wavs to ignore +# because of OOV words in their transcripts +# - /phoneme_durations/LJ*.npz: Numpy files for each wavfile +# with fields 'tokens' (token indices) and 'durs' (durations per token) +# +# It will also create intermediate files: +# - /alignments/wavs/LJ*.TextGrid: MFA output +# +# Note: This script will create a conda environment to set up MFA, so please +# make sure that conda is active before running this script. +# +# Note: You may need to install OpenBlas yourself if the MFA script can't find +# it. (e.g. sudo apt-get install libopenblas-dev) +# +# Example Usage: +# ./extract_ljspeech_phonemes_and_durs.sh /data/LJSpeech-1.1 + +ENV_NAME='aligner' + +SAMPLE_RATE=22050 +WINDOW_STRIDE=256 + +CMUDICT_URL='https://raw.githubusercontent.com/cmusphinx/cmudict/master/cmudict.dict' +SPLITS_BASE_URL='https://raw.githubusercontent.com/NVIDIA/tacotron2/master/filelists/' + +# Usage info +show_help() { +cat << EOF +Usage: $(basename "$0") [-h] \ + [--skip_env_setup] \ + [--g2p_dict=] \ + +Extracts phonemes and their respective durations for the LJSpeech dataset using +the Montreal Forced Aligner (MFA). + + -h Help message + --skip_env_setup (Optional) Skips setting up the MFA conda environment + "aligner". Use only if you already have this set up. + --g2p_dict (Optional) Path to the grapheme to phoneme dictionary + text file, if already generated. If set, skips the G2P + step. +EOF +} + +SKIP_ENV_SETUP=false +G2P_DICT='' + +while :; do + case $1 in + -h|-\?|--help) + show_help + exit + ;; + --g2p_dict=?*) + G2P_DICT=${1#*=} + ;; + --skip_env_setup) + SKIP_ENV_SETUP=true + ;; + *) + break + esac + shift +done + +if [[ -z $1 ]]; then + echo "Must specify a LJSpeech base directory." + exit 1 +fi +LJSPEECH_BASE=$1 + +# Check for conda +read -r -d '' CONDA_MESSAGE << EOM +This script requires either Anaconda or Miniconda to be active, as it installs the Montreal Forced Aligner via a conda environment. +See their documentation (https://montreal-forced-aligner.readthedocs.io/en/latest/installation.html) for more details. +EOM +if [ -z "$(which conda)" ]; then + echo $CONDA_MESSAGE + exit +fi + +CONDA_PREFIX=$(conda info --base) +source $CONDA_PREFIX/etc/profile.d/conda.sh + +# Set up env for MFA (env name "aligner") and install +if $SKIP_ENV_SETUP; then + echo "Skipping environment setup. Assuming env name "aligner" exists." +else + echo "Setting up conda environment for MFA (env name \"aligner\")..." + conda create -n $ENV_NAME -c conda-forge openblas python=3.8 openfst pynini ngram baumwelch + conda activate $ENV_NAME + pip install montreal-forced-aligner tgt torch + mfa thirdparty download + echo "Conda environment \"$ENV_NAME\" set up." +fi + +if ! conda activate $ENV_NAME; then + echo "Could not activate environment, see Conda output above." + exit +fi + +# Download CMU word-to-phoneme dict and clean out comments so they're not mistaken for tokens +if [ -z $G2P_DICT ]; then + if [ ! -f $LJSPEECH_BASE/cmudict.dict ]; then + echo "Downloading CMU dict." + wget -P $LJSPEECH_BASE $CMUDICT_URL + fi + if [ ! -f $LJSPEECH_BASE/uncommented_cmudict.dict ]; then + echo "Creating uncommented version of CMUdict." + sed 's/\ \#.*//' $LJSPEECH_BASE/cmudict.dict > $LJSPEECH_BASE/uncommented_cmudict.dict + fi + G2P_DICT=$LJSPEECH_BASE/uncommented_cmudict.dict +fi + +# Run alignment +echo "Starting MFA with dictionary at: $G2P_DICT" + +read -r -d '' MFA_ERROR_MSG << EOM +Could not run MFA. If it could not find OpenBlas, you may need to install it manually. +(e.g. sudo apt-get install libopenblas-dev) +EOM + +if ! mfa download acoustic english; then + echo $MFA_ERROR_MSG +fi +mfa align --clean $LJSPEECH_BASE $G2P_DICT english $LJSPEECH_BASE/alignments + +# Create JSON mappings from word to phonemes and phonemes to indices +echo "Creating word->phone and phone->idx mappings at $LJSPEECH_BASE/mappings.json..." +python create_token2idx_dict.py \ + --dictionary=$G2P_DICT \ + --dict_out=$LJSPEECH_BASE/mappings.json + +# Calculate phoneme durations +echo "Calculating phoneme durations..." +python calculate_durs.py \ + --ljspeech_dir=$LJSPEECH_BASE \ + --mappings=$LJSPEECH_BASE/mappings.json \ + --sr=$SAMPLE_RATE \ + --hop_length=$WINDOW_STRIDE +echo "Phoneme durations and tokens written." diff --git a/tts/NeMo/scripts/dataset_processing/process_an4_data.py b/tts/NeMo/scripts/dataset_processing/process_an4_data.py new file mode 100644 index 0000000..5eaace2 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/process_an4_data.py @@ -0,0 +1,88 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import glob +import json +import logging +import os +import subprocess +import tarfile + +import librosa +import wget + +parser = argparse.ArgumentParser(description="AN4 dataset download and processing") +parser.add_argument("--data_root", required=True, default=None, type=str) +args = parser.parse_args() + + +def build_manifest(data_root, transcripts_path, manifest_path, wav_path): + with open(transcripts_path, 'r') as fin: + with open(manifest_path, 'w') as fout: + for line in fin: + # Lines look like this: + # transcript (fileID) + transcript = line[: line.find('(') - 1].lower() + transcript = transcript.replace('', '').replace('', '') + transcript = transcript.strip() + + file_id = line[line.find('(') + 1 : -2] # e.g. "cen4-fash-b" + audio_path = os.path.join( + data_root, wav_path, file_id[file_id.find('-') + 1 : file_id.rfind('-')], file_id + '.wav', + ) + + duration = librosa.core.get_duration(filename=audio_path) + + # Write the metadata to the manifest + metadata = { + "audio_filepath": audio_path, + "duration": duration, + "text": transcript, + } + json.dump(metadata, fout) + fout.write('\n') + + +def main(): + data_root = os.path.abspath(args.data_root) + + # Convert from .sph to .wav + logging.info("Converting audio files to .wav...") + sph_list = glob.glob(os.path.join(data_root, 'an4/**/*.sph'), recursive=True) + for sph_path in sph_list: + wav_path = sph_path[:-4] + '.wav' + cmd = ['sox', sph_path, wav_path] + subprocess.run(cmd) + logging.info("Finished conversion.") + + # Build manifests + logging.info("Building training manifest...") + train_transcripts = os.path.join(data_root, 'an4/etc/an4_train.transcription') + train_manifest = os.path.join(data_root, 'an4/train_manifest.json') + train_wavs = os.path.join(data_root, 'an4/wav/an4_clstk') + build_manifest(data_root, train_transcripts, train_manifest, train_wavs) + logging.info("Training manifests created.") + + logging.info("Building test manifest...") + test_transcripts = os.path.join(data_root, 'an4/etc/an4_test.transcription') + test_manifest = os.path.join(data_root, 'an4/test_manifest.json') + test_wavs = os.path.join(data_root, 'an4/wav/an4test_clstk') + build_manifest(data_root, test_transcripts, test_manifest, test_wavs) + logging.info("Test manifest created.") + + logging.info("Done with AN4 processing!") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/process_degli_data.py b/tts/NeMo/scripts/dataset_processing/process_degli_data.py new file mode 100644 index 0000000..ba1b26a --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/process_degli_data.py @@ -0,0 +1,70 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import sys + +from nemo.collections.tts.data.datalayers import preprocess_linear_specs_dataset + +sys.path.insert(0, '../') + + +def main(): + parser = argparse.ArgumentParser( + description='Create dataset fitted for training and validating deep griffin iteration from wavefiles' + ) + parser.add_argument( + "-v", + "--valid_filelist", + help="Filelist for validation set, with all validation audio files listed", + required=True, + default=None, + type=str, + ) + parser.add_argument( + "-t", + "--train_filelist", + help="Filelist for train set, with all train audio files listed", + required=True, + default=None, + type=str, + ) + parser.add_argument( + "-n", + "--n_fft", + help="Value for the n_fft parameter, and the filter length for the STFT", + default=512, + type=int, + ) + parser.add_argument("--hop_length", help="STFT parameter", default=256, type=int) + parser.add_argument( + "-d", "--destination", help="Destination to save the preprocessed data set to", default="/tmp", type=str + ) + parser.add_argument( + "-s", + "--num_snr", + help="Number of distinctive noisy samples to generate for each clear sample at the file list", + default=1, + type=int, + ) + + args = parser.parse_args() + + preprocess_linear_specs_dataset( + args.valid_filelist, args.train_filelist, args.n_fft, args.hop_length, args.num_snr, args.destination + ) + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/dataset_processing/process_hub5_data.py b/tts/NeMo/scripts/dataset_processing/process_hub5_data.py new file mode 100644 index 0000000..e67a0d0 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/process_hub5_data.py @@ -0,0 +1,256 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +# This script is heavily derived from the Patter HUB5 processing script written +# by Ryan Leary + +import argparse +import glob +import json +import os +import re +import subprocess +import sys +from collections import namedtuple +from math import ceil, floor +from operator import attrgetter + +import numpy as np +import scipy.io.wavfile as wavfile +from tqdm import tqdm + +parser = argparse.ArgumentParser(description="Prepare HUB5 data for training/eval") +parser.add_argument( + "--data_root", default=None, type=str, required=True, help="The path to the root LDC HUB5 dataset directory.", +) +parser.add_argument( + "--dest_root", + default=None, + type=str, + required=True, + help="Path to the destination root directory for processed files.", +) + +# Optional arguments +parser.add_argument( + "--min_slice_duration", default=10.0, type=float, help="Minimum audio slice duration after processing.", +) + +args = parser.parse_args() + +StmUtterance = namedtuple( + 'StmUtterance', ['filename', 'channel', 'speaker_id', 'begin', 'end', 'label', 'transcript',], +) +STM_LINE_FMT = re.compile(r"^(\w+)\s+(\w+)\s+(\w+)\s+([0-9.]+)\s+([0-9.]+)\s+(<.*>)?\s+(.+)$") + +# Transcription errors and their fixes +TRANSCRIPT_BUGS = {"en_4622-B-12079-12187": "KIND OF WEIRD BUT"} + + +def get_utt_id(segment): + """ + Gives utterance IDs in a form like: en_4156-a-36558-37113 + """ + return "{}-{}-{}-{}".format(segment.filename, segment.channel, int(segment.begin * 100), int(segment.end * 100),) + + +def convert_utterances(sph_path, wav_path): + """ + Converts a sphere audio file to wav. + """ + cmd = ["sph2pipe", "-f", "wav", "-p", sph_path, wav_path] + subprocess.run(cmd) + + +def create_wavs(data_root, dest_root): + """ + Converts the English sph files to wav using sph2pipe. + """ + sph_root = os.path.join(data_root, "hub5e_00", "english") + sph_list = glob.glob(os.path.join(sph_root, "*.sph")) + + # Iterate over each sphere file and conver to wav + for sph_path in tqdm(sph_list, desc="Converting to wav", unit="file"): + sph_name, _ = os.path.splitext(os.path.basename(sph_path)) + wav_path = os.path.join(dest_root, 'full_audio_wav', sph_name + ".wav") + cmd = ["sph2pipe", "-f", "wav", "-p", sph_path, wav_path] + subprocess.run(cmd) + + +def process_transcripts(dataset_root): + """ + Reads in transcripts for each audio segment and processes them. + """ + stm_path = os.path.join(dataset_root, "2000_hub5_eng_eval_tr", "reference", "hub5e00.english.000405.stm",) + results = [] + chars = set() + + with open(stm_path, "r") as fh: + for line in fh: + # lines with ';;' are comments + if line.startswith(";;"): + continue + + if "IGNORE_TIME_SEGMENT_" in line: + continue + line = line.replace("", "").replace("", "") + line = line.replace("(%HESITATION)", "UH") + line = line.replace("-", "") + line = line.replace("(%UH)", "UH") + line = line.replace("(%AH)", "UH") + line = line.replace("(", "").replace(")", "") + + line = line.lower() + + m = STM_LINE_FMT.search(line.strip()) + utt = StmUtterance(*m.groups()) + + # Convert begin/end times to float + utt = utt._replace(begin=float(utt.begin)) + utt = utt._replace(end=float(utt.end)) + + # Check for utterance in dict of transcript mistakes + transcript_update = TRANSCRIPT_BUGS.get(get_utt_id(utt)) + if transcript_update is not None: + utt = utt._replace(transcript=transcript_update) + + results.append(utt) + chars.update(list(utt.transcript)) + return results, chars + + +def write_one_segment(dest_root, speaker_id, count, audio, sr, duration, transcript): + """ + Writes out one segment of audio, and writes its corresponding transcript + in the manifest. + + Args: + dest_root: the path to the output directory root + speaker_id: ID of the speaker, used in file naming + count: number of segments from this speaker so far + audio: the segment's audio data + sr: sample rate of the audio + duration: duration of the audio + transcript: the corresponding transcript + """ + audio_path = os.path.join(dest_root, "audio", f"{speaker_id}_{count:03}.wav") + + manifest_path = os.path.join(dest_root, "manifest_hub5.json") + + # Write audio + wavfile.write(audio_path, sr, audio) + + # Write transcript + transcript = { + "audio_filepath": audio_path, + "duration": duration, + "text": transcript, + } + with open(manifest_path, 'a') as f: + json.dump(transcript, f) + f.write('\n') + + +def segment_audio(info_list, dest_root, min_slice_duration): + """ + Combines audio into >= min_slice_duration segments of the same speaker, + and writes the combined transcripts into a manifest. + + Args: + info_list: list of StmUtterance objects with transcript information. + dest_root: path to output destination + min_slice_duration: min number of seconds per output audio slice + """ + info_list = sorted(info_list, key=attrgetter('speaker_id', 'begin')) + + prev_id = None # For checking audio concatenation + id_count = 0 + + sample_rate, audio_data = None, None + transcript_buffer = '' + audio_buffer = [] + buffer_duration = 0.0 + + # Iterate through utterances to build segments + for info in info_list: + if info.speaker_id != prev_id: + # Scrap the remainder in the buffers and start next segment + prev_id = info.speaker_id + id_count = 0 + + sample_rate, audio_data = wavfile.read(os.path.join(dest_root, 'full_audio_wav', info.filename + '.wav')) + transcript_buffer = '' + audio_buffer = [] + buffer_duration = 0.0 + + # Append utterance info to buffers + transcript_buffer += info.transcript + channel = 0 if info.channel.lower() == 'a' else 1 + audio_buffer.append( + audio_data[floor(info.begin * sample_rate) : ceil(info.end * sample_rate), channel,] + ) + buffer_duration += info.end - info.begin + + if buffer_duration < min_slice_duration: + transcript_buffer += ' ' + else: + # Write out segment and transcript + id_count += 1 + write_one_segment( + dest_root, + info.speaker_id, + id_count, + np.concatenate(audio_buffer, axis=0), + sample_rate, + buffer_duration, + transcript_buffer, + ) + + transcript_buffer = '' + audio_buffer = [] + buffer_duration = 0.0 + + +def main(): + data_root = args.data_root + dest_root = args.dest_root + + min_slice_duration = args.min_slice_duration + + if not os.path.exists(os.path.join(dest_root, 'full_audio_wav')): + os.makedirs(os.path.join(dest_root, 'full_audio_wav')) + if not os.path.exists(os.path.join(dest_root, 'audio')): + os.makedirs(os.path.join(dest_root, 'audio')) + + # Create/wipe manifest contents + open(os.path.join(dest_root, "manifest_hub5.json"), 'w').close() + + # Convert full audio files from .sph to .wav + create_wavs(data_root, dest_root) + + # Get each audio transcript from transcript file + info_list, chars = process_transcripts(data_root) + + print("Writing out vocab file", file=sys.stderr) + with open(os.path.join(dest_root, "vocab.txt"), 'w') as fh: + for x in sorted(list(chars)): + fh.write(x + "\n") + + # Segment the audio data + print("Segmenting audio and writing manifest") + segment_audio(info_list, dest_root, min_slice_duration) + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/dataset_processing/process_speech_commands_data.py b/tts/NeMo/scripts/dataset_processing/process_speech_commands_data.py new file mode 100644 index 0000000..9080b33 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/process_speech_commands_data.py @@ -0,0 +1,402 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +Usage: + +python process_speech_commands_data.py \ + --data_root= \ + --data_version= \ + --class_split= \ + --rebalance \ + --log +""" + +import argparse +import glob +import json +import logging +import os +import re +import tarfile +import urllib.request + +import librosa +import numpy as np + +URL_v1 = "http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz" +URL_v2 = "http://download.tensorflow.org/data/speech_commands_v0.02.tar.gz" + + +def __maybe_download_file(destination: str, source: str): + """ + Downloads source to destination if it doesn't exist. + If exists, skips download + Args: + destination: local filepath + source: url of resource + + Returns: + + """ + if not os.path.exists(destination): + logging.info(f"{destination} does not exist. Downloading ...") + urllib.request.urlretrieve(source, filename=destination + '.tmp') + os.rename(destination + '.tmp', destination) + logging.info(f"Downloaded {destination}.") + else: + logging.info(f"Destination {destination} exists. Skipping.") + return destination + + +def __extract_all_files(filepath: str, data_root: str, data_dir: str): + if not os.path.exists(data_dir): + extract_file(filepath, data_dir) + else: + logging.info(f'Skipping extracting. Data already there {data_dir}') + + +def extract_file(filepath: str, data_dir: str): + try: + tar = tarfile.open(filepath) + tar.extractall(data_dir) + tar.close() + except Exception: + logging.info('Not extracting. Maybe already there?') + + +def __process_data( + data_folder: str, dst_folder: str, rebalance: bool = False, class_split: str = "all", skip_duration: bool = False +): + """ + To generate manifest + + Args: + data_folder: source with wav files and validation / test lists + dst_folder: where manifest files will be stored + rebalance: rebalance the classes to have same number of samples. + class_split: whether to use all classes as distinct labels, or to use + 10 classes subset and rest of the classes as noise or background. + skip_duration: Bool whether to skip duration computation. Use this only for + colab notebooks where knowing duration is not necessary for demonstration. + + Returns: + + """ + + if not os.path.exists(dst_folder): + os.makedirs(dst_folder) + + # Used for 10 classes + silence + unknown class setup + class_subset = ["yes", "no", "up", "down", "left", "right", "on", "off", "stop", "go"] + + pattern = re.compile(r"(.+\/)?(\w+)\/([^_]+)_.+wav") + all_files = glob.glob(os.path.join(data_folder, '*/*wav')) + + with open(os.path.join(data_folder, 'validation_list.txt'), 'r') as fin: + validation_files = fin.readlines() + + valset = set() + for entry in validation_files: + r = re.match(pattern, entry) + if r: + valset.add(r.group(3)) + + with open(os.path.join(data_folder, 'testing_list.txt'), 'r') as fin: + testing_files = fin.readlines() + + testset = set() + for entry in testing_files: + r = re.match(pattern, entry) + if r: + testset.add(r.group(3)) + + logging.info("Validation and test set lists extracted") + + label_count = {} + label_filepaths = {} + unknown_val_filepaths = [] + unknown_test_filepaths = [] + + train, val, test = [], [], [] + for entry in all_files: + r = re.match(pattern, entry) + if r: + label, uid = r.group(2), r.group(3) + + if label == '_background_noise_' or label == 'silence': + continue + + if class_split == "sub": + if label not in class_subset: + label = "unknown" # replace label + + if uid in valset: + unknown_val_filepaths.append((label, entry)) + elif uid in testset: + unknown_test_filepaths.append((label, entry)) + + sample = (label, entry) + + if uid not in valset and uid not in testset: + if label in label_count: + label_count[label] += 1 + else: + label_count[label] = 1 + + if label in label_filepaths: + label_filepaths[label] += [sample] + else: + label_filepaths[label] = [sample] + + if label == 'unknown': + continue + + if uid in valset: + val.append(sample) + elif uid in testset: + test.append(sample) + else: + train.append(sample) + + logging.info("Prepared filepaths for dataset") + + # Add silence and unknown class label samples + if class_split == "sub": + logging.info("Perforiming 10+2 class subsplit") + + silence_path = os.path.join(data_folder, "silence") + if not os.path.exists(silence_path): + os.mkdir(silence_path) + + silence_stride = 1000 # 0.0625 second stride + sampling_rate = 16000 + folder = os.path.join(data_folder, "_background_noise_") + + silence_files = [] + rng = np.random.RandomState(0) + + for file in os.listdir(folder): + if ".wav" in file: + load_path = os.path.join(folder, file) + y, sr = librosa.load(load_path, sr=sampling_rate) + + for i in range(0, len(y) - sampling_rate, silence_stride): + file_path = "silence/{}_{}.wav".format(file[:-4], i) + y_slice = y[i : i + sampling_rate] + magnitude = rng.uniform(0.0, 1.0) + y_slice *= magnitude + out_file_path = os.path.join(data_folder, file_path) + librosa.output.write_wav(out_file_path, y_slice, sr) + + silence_files.append(('silence', out_file_path)) + + rng = np.random.RandomState(0) + rng.shuffle(silence_files) + logging.info(f"Constructed silence set of {len(silence_files)}") + + # Create the splits + rng = np.random.RandomState(0) + silence_split = 0.1 + unknown_split = 0.1 + + # train split + num_total_samples = sum([label_count[cls] for cls in class_subset]) + num_silence_samples = int(np.ceil(silence_split * num_total_samples)) + + # initialize sample + label_count['silence'] = 0 + + for silence_id in range(num_silence_samples): + label_count['silence'] += 1 + + if 'silence' in label_filepaths: + label_filepaths['silence'] += [silence_files[silence_id]] + else: + label_filepaths['silence'] = [silence_files[silence_id]] + + train.extend(label_filepaths['silence']) + + # Update train unknown set + unknown_train_samples = label_filepaths['unknown'] + + rng.shuffle(unknown_train_samples) + unknown_size = int(np.ceil(unknown_split * num_total_samples)) + + label_count['unknown'] = unknown_size + label_filepaths['unknown'] = unknown_train_samples[:unknown_size] + + train.extend(label_filepaths['unknown']) + + logging.info("Train set prepared") + + # val set silence + num_val_samples = len(val) + num_silence_samples = int(np.ceil(silence_split * num_val_samples)) + + val_idx = label_count['silence'] + 1 + for silence_id in range(num_silence_samples): + val.append(silence_files[val_idx + silence_id]) + + # Update val unknown set + rng.shuffle(unknown_val_filepaths) + unknown_size = int(np.ceil(unknown_split * num_val_samples)) + + val.extend(unknown_val_filepaths[:unknown_size]) + + logging.info("Validation set prepared") + + # test set silence + num_test_samples = len(test) + num_silence_samples = int(np.ceil(silence_split * num_test_samples)) + + test_idx = val_idx + num_silence_samples + 1 + for silence_id in range(num_silence_samples): + test.append(silence_files[test_idx + silence_id]) + + # Update test unknown set + rng.shuffle(unknown_test_filepaths) + unknown_size = int(np.ceil(unknown_split * num_test_samples)) + + test.extend(unknown_test_filepaths[:unknown_size]) + + logging.info("Test set prepared") + + max_command = None + max_count = -1 + for command, count in label_count.items(): + if command == 'unknown': + continue + + if count > max_count: + max_count = count + max_command = command + + if rebalance: + logging.info(f"Command with maximum number of samples = {max_command} with {max_count} samples") + logging.info(f"Rebalancing dataset by duplicating classes with less than {max_count} samples...") + + for command, samples in label_filepaths.items(): + filepaths = [sample[1] for sample in samples] + + rng = np.random.RandomState(0) + filepaths = np.asarray(filepaths) + num_samples = len(filepaths) + + if num_samples < max_count: + difference = max_count - num_samples + duplication_ids = rng.choice(num_samples, difference, replace=True) + + filepaths = np.append(filepaths, filepaths[duplication_ids], axis=0) + + logging.info(f"Extended class label {command} from {num_samples} samples to {len(filepaths)} samples") + + label_filepaths[command] = [(command, filepath) for filepath in filepaths] + + del train + train = [] + for label, samples in label_filepaths.items(): + train.extend(samples) + + manifests = [ + ('train_manifest.json', train), + ('validation_manifest.json', val), + ('test_manifest.json', test), + ] + + for manifest_filename, dataset in manifests: + with open(os.path.join(dst_folder, manifest_filename), 'w') as fout: + num_files = len(dataset) + pct_file = num_files // 100 + file_count = 0 + + logging.info(f"Preparing manifest : {manifest_filename} with #{num_files} files") + + for label, audio_path in dataset: + if not skip_duration: + duration = librosa.core.get_duration(filename=audio_path) + else: + duration = 0.0 + + # Write the metadata to the manifest + metadata = { + "audio_filepath": audio_path, + "duration": duration, + "command": label, + } + json.dump(metadata, fout) + fout.write('\n') + fout.flush() + + file_count += 1 + if file_count % pct_file == 0: + if not skip_duration: + logging.info(f"Finished serializing {file_count} / {num_files} into {manifest_filename}") + + logging.info(f"Finished construction of manifest : {manifest_filename}") + + if skip_duration: + logging.info( + f"\n<> Duration computation was skipped for demonstration purposes on Colaboratory.\n" + f"In order to replicate paper results and properly perform data augmentation, \n" + f"please recompute the manifest file without the `--skip_duration` flag !\n" + ) + + +def main(): + parser = argparse.ArgumentParser(description='Google Speech Command Data download') + parser.add_argument("--data_root", required=True, default=None, type=str) + parser.add_argument('--data_version', required=True, default=1, type=int, choices=[1, 2]) + parser.add_argument('--class_split', required=False, default='all', type=str, choices=['all', 'sub']) + parser.add_argument('--rebalance', required=False, action='store_true') + parser.add_argument('--skip_duration', required=False, action='store_true') + parser.add_argument('--log', required=False, action='store_true') + parser.set_defaults(log=False, rebalance=False, skip_duration=False) + args = parser.parse_args() + + if args.log: + logging.basicConfig(level=logging.DEBUG) + + data_root = args.data_root + data_set = "google_speech_recognition_v{0}".format(args.data_version) + data_folder = os.path.join(data_root, data_set) + + logging.info(f"Working on: {data_set}") + + if args.data_version == 1: + URL = URL_v1 + else: + URL = URL_v2 + + # Download and extract + if not os.path.exists(data_folder): + file_path = os.path.join(data_root, data_set + ".tar.bz2") + logging.info(f"Getting {data_set}") + __maybe_download_file(file_path, URL) + logging.info(f"Extracting {data_set}") + __extract_all_files(file_path, data_root, data_folder) + + logging.info(f"Processing {data_set}") + __process_data( + data_folder, + data_folder, + rebalance=args.rebalance, + class_split=args.class_split, + skip_duration=args.skip_duration, + ) + logging.info('Done!') + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/dataset_processing/process_vad_data.py b/tts/NeMo/scripts/dataset_processing/process_vad_data.py new file mode 100644 index 0000000..ba98113 --- /dev/null +++ b/tts/NeMo/scripts/dataset_processing/process_vad_data.py @@ -0,0 +1,486 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +""" +Usage: + +python process_vad_data.py \ + --out_dir= \ + --speech_data_root= \ + --background_data_root= \ + --rebalance_method=<'under' or 'over' or 'fixed'> \ + --log + (Optional --demo (for demonstration in tutorial). If you want to use your own background noise data, make sure to delete --demo) +""" +import argparse +import glob +import json +import logging +import os +import tarfile +import urllib.request + +import librosa +import numpy as np +import soundfile as sf +from sklearn.model_selection import train_test_split + +sr = 16000 + +# google speech command v2 +URL = "http://download.tensorflow.org/data/speech_commands_v0.02.tar.gz" + + +def __maybe_download_file(destination: str, source: str): + """ + Downloads source to destination if it doesn't exist. + If exists, skips download + Args: + destination: local filepath + source: url of resource + + Returns: + + """ + if not os.path.exists(destination): + logging.info(f"{destination} does not exist. Downloading ...") + urllib.request.urlretrieve(source, filename=destination + '.tmp') + os.rename(destination + '.tmp', destination) + logging.info(f"Downloaded {destination}.") + else: + logging.info(f"Destination {destination} exists. Skipping.") + return destination + + +def extract_file(filepath: str, data_dir: str): + try: + tar = tarfile.open(filepath) + tar.extractall(data_dir) + tar.close() + except Exception: + logging.info('Not extracting. Maybe already there?') + + +def __extract_all_files(filepath: str, data_root: str, data_dir: str): + if not os.path.exists(data_dir): + extract_file(filepath, data_dir) + else: + logging.info(f'Skipping extracting. Data already there {data_dir}') + + +def split_train_val_test(data_dir, file_type, test_size=0.1, val_size=0.1, demo=False): + X = [] + if file_type == "speech": + for o in os.listdir(data_dir): + if os.path.isdir(os.path.join(data_dir, o)) and o.split("/")[-1] != "_background_noise_": + X.extend(glob.glob(os.path.join(data_dir, o) + '/*.wav')) + + if demo: + logging.info( + f"For Demonstration, we use {int(len(X)/100)}/{len(X)} speech data. Make sure to remove --demo flag when you actually train your model!" + ) + X = np.random.choice(X, int(len(X) / 100), replace=False) + + else: + for o in os.listdir(data_dir): + if os.path.isdir(os.path.join(data_dir, o)): + X.extend(glob.glob(os.path.join(data_dir, o) + '/*.wav')) + else: # for using "_background_noise_" from google speech commands as background data + if o.endswith(".wav"): + X.append(os.path.join(data_dir, o)) + + X_train, X_test = train_test_split(X, test_size=test_size, random_state=1) + val_size_tmp = val_size / (1 - test_size) + X_train, X_val = train_test_split(X_train, test_size=val_size_tmp, random_state=1) + + with open(os.path.join(data_dir, file_type + "_training_list.txt"), "w") as outfile: + outfile.write("\n".join(X_train)) + with open(os.path.join(data_dir, file_type + "_testing_list.txt"), "w") as outfile: + outfile.write("\n".join(X_test)) + with open(os.path.join(data_dir, file_type + "_validation_list.txt"), "w") as outfile: + outfile.write("\n".join(X_val)) + + logging.info(f'Overall: {len(X)}, Train: {len(X_train)}, Validatoin: {len(X_val)}, Test: {len(X_test)}') + logging.info(f"Finish spliting train, val and test for {file_type}. Write to files!") + + +def process_google_speech_train(data_dir): + X = [] + for o in os.listdir(data_dir): + if os.path.isdir(os.path.join(data_dir, o)) and o.split("/")[-1] != "_background_noise_": + X.extend(glob.glob(os.path.join(data_dir, o) + '/*.wav')) + + short_files = [i.split(data_dir)[1] for i in files] + + with open(os.path.join(data_dir, 'testing_list.txt'), 'r') as allfile: + testing_list = allfile.read().splitlines() + + with open(os.path.join(data_dir, 'validation_list.txt'), 'r') as allfile: + validation_list = allfile.read().splitlines() + + exist_set = set(testing_list).copy() + exist_set.update(set(validation_list)) + + training_list = [i for i in short_files if i not in exist_set] + + with open(os.path.join(data_dir, "training_list.txt"), "w") as outfile: + outfile.write("\n".join(training_list)) + + logging.info( + f'Overall: {len(files)}, Train: {len(training_list)}, Validatoin: {len(validation_list)}, Test: {len(testing_list)}' + ) + + +def write_manifest( + out_dir, + files, + prefix, + manifest_name, + start=0.0, + end=None, + duration_stride=1.0, + duration_max=None, + duration_limit=100.0, + filter_long=False, +): + """ + Given a list of files, segment each file and write them to manifest with restrictions. + Args: + out_dir: directory of generated manifest + files: list of files to be processed + prefix: label of samples + manifest_name: name of generated manifest + start: beginning of audio of generating segment + end: end of audio of generating segment + duration_stride: stride for segmenting audio samples + duration_max: duration for each segment + duration_limit: duration threshold for filtering out long audio samples + filter_long: boolean to determine whether to filter out long audio samples + Returns: + """ + seg_num = 0 + skip_num = 0 + if duration_max is None: + duration_max = 1e9 + + if not os.path.exists(out_dir): + logging.info(f'Outdir {out_dir} does not exist. Creat directory.') + os.mkdir(out_dir) + + output_path = os.path.join(out_dir, manifest_name + '.json') + with open(output_path, 'w') as fout: + for file in files: + label = prefix + + try: + x, _sr = librosa.load(file, sr=sr) + duration = librosa.get_duration(x, sr=sr) + + except Exception: + continue + + if filter_long and duration > duration_limit: + skip_num += 1 + continue + + offsets = [] + durations = [] + + if duration > duration_max: + current_offset = start + + while current_offset < duration: + if end is not None and current_offset > end: + break + + difference = duration - current_offset + + if difference < duration_max: + break + + offsets.append(current_offset) + durations.append(duration_max) + + current_offset += duration_stride + + else: + # Duration is not long enough! Skip + skip_num += 1 + + for duration, offset in zip(durations, offsets): + metadata = { + 'audio_filepath': file, + 'duration': duration, + 'label': label, + 'text': '_', # for compatibility with ASRAudioText + 'offset': offset, + } + json.dump(metadata, fout) + fout.write('\n') + fout.flush() + seg_num += 1 + return skip_num, seg_num, output_path + + +def load_list_write_manifest( + data_dir, + out_dir, + filename, + prefix, + start, + end, + duration_stride=1.0, + duration_max=1.0, + duration_limit=100.0, + filter_long=True, +): + + filename = prefix + '_' + filename + file_path = os.path.join(data_dir, filename) + + with open(file_path, 'r') as allfile: + files = allfile.read().splitlines() + + manifest_name = filename.split('_list.txt')[0] + '_manifest' + skip_num, seg_num, output_path = write_manifest( + out_dir, + files, + prefix, + manifest_name, + start, + end, + duration_stride, + duration_max, + duration_limit, + filter_long=True, + ) + return skip_num, seg_num, output_path + + +def rebalance_json(data_dir, data_json, num, prefix): + data = [] + seg = 0 + for line in open(data_json, 'r'): + data.append(json.loads(line)) + filename = data_json.split('/')[-1] + fout_path = os.path.join(data_dir, prefix + "_" + filename) + + if len(data) >= num: + selected_sample = np.random.choice(data, num, replace=False) + else: + selected_sample = np.random.choice(data, num, replace=True) + + with open(fout_path, 'a') as fout: + for i in selected_sample: + seg += 1 + json.dump(i, fout) + fout.write('\n') + fout.flush() + + logging.info(f'Get {seg}/{num} to {fout_path} from {data_json}') + return fout_path + + +def generate_variety_noise(data_dir, filename, prefix): + + curr_dir = data_dir.split("_background_noise_")[0] + silence_path = os.path.join(curr_dir, "_background_noise_more") + + if not os.path.exists(silence_path): + os.mkdir(silence_path) + + silence_stride = 1000 # stride = 1/16 seconds + sampling_rate = 16000 + + silence_files = [] + rng = np.random.RandomState(0) + + filename = prefix + '_' + filename + file_path = os.path.join(data_dir, filename) + + with open(file_path, 'r') as allfile: + files = allfile.read().splitlines() + + for file in files: + y, sr = librosa.load(file, sr=sampling_rate) + + for i in range( + 0, len(y) - sampling_rate, silence_stride * 100 + ): # stride * 100 to generate less samples for demo + file_name = "{}_{}.wav".format(file.split("/")[-1], i) + y_slice = y[i : i + sampling_rate] + magnitude = rng.uniform(0.0, 1.0) + y_slice *= magnitude + out_file_path = os.path.join(silence_path, file_name) + sf.write(out_file_path, y_slice, sr) + + silence_files.append(out_file_path) + + new_list_file = os.path.join(silence_path, filename) + with open(new_list_file, "w") as outfile: + outfile.write("\n".join(silence_files)) + + logging.info(f"Generate {len(out_file_path)} background files for {file_path}. => {new_list_file} !") + return len(silence_files) + + +def main(): + parser = argparse.ArgumentParser(description='Speech and backgound data download and preprocess') + parser.add_argument("--out_dir", required=False, default='./manifest/', type=str) + parser.add_argument("--speech_data_root", required=True, default=None, type=str) + parser.add_argument("--background_data_root", required=True, default=None, type=str) + parser.add_argument('--test_size', required=False, default=0.1, type=float) + parser.add_argument('--val_size', required=False, default=0.1, type=float) + parser.add_argument('--seg_len', required=False, default=0.63, type=float) + parser.add_argument('--log', required=False, action='store_true') + parser.add_argument('--rebalance_method', required=False, default=None, type=str) + parser.add_argument('--demo', required=False, action='store_true') + parser.set_defaults(log=False, generate=False) + args = parser.parse_args() + + if not args.rebalance_method: + rebalance = False + else: + if args.rebalance_method != 'over' and args.rebalance_method != 'under' and args.rebalance_method != 'fixed': + raise NameError("Please select a valid sampling method: over/under/fixed.") + else: + rebalance = True + + if args.log: + logging.basicConfig(level=logging.DEBUG) + + # Download speech data + speech_data_root = args.speech_data_root + data_set = "google_speech_recognition_v2" + speech_data_folder = os.path.join(speech_data_root, data_set) + + background_data_folder = args.background_data_root + logging.info(f"Working on: {data_set}") + + # Download and extract speech data + if not os.path.exists(speech_data_folder): + file_path = os.path.join(speech_data_root, data_set + ".tar.bz2") + logging.info(f"Getting {data_set}") + __maybe_download_file(file_path, URL) + logging.info(f"Extracting {data_set}") + __extract_all_files(file_path, speech_data_root, speech_data_folder) + + logging.info(f"Split speech data!") + # dataset provide testing.txt and validation.txt feel free to split data using that with process_google_speech_train + split_train_val_test(speech_data_folder, "speech", args.test_size, args.val_size, args.demo) + + logging.info(f"Split background data!") + split_train_val_test(background_data_folder, "background", args.test_size, args.val_size) + + out_dir = args.out_dir + + # Process Speech manifest + logging.info(f"=== Write speech data to manifest!") + skip_num_val, speech_seg_num_val, speech_val = load_list_write_manifest( + speech_data_folder, out_dir, 'validation_list.txt', 'speech', 0.2, 0.8, args.seg_len, args.seg_len + ) + skip_num_test, speech_seg_num_test, speech_test = load_list_write_manifest( + speech_data_folder, out_dir, 'testing_list.txt', 'speech', 0.2, 0.8, 0.01, args.seg_len + ) + skip_num_train, speech_seg_num_train, speech_train = load_list_write_manifest( + speech_data_folder, out_dir, 'training_list.txt', 'speech', 0.2, 0.8, args.seg_len, args.seg_len + ) + + logging.info(f'Val: Skip {skip_num_val} samples. Get {speech_seg_num_val} segments! => {speech_val} ') + logging.info(f'Test: Skip {skip_num_test} samples. Get {speech_seg_num_test} segments! => {speech_test}') + logging.info(f'Train: Skip {skip_num_train} samples. Get {speech_seg_num_train} segments!=> {speech_train}') + + # Process background manifest + # if we select to generate more background noise data + if args.demo: + logging.info("Start generating more background noise data") + generate_variety_noise(background_data_folder, 'validation_list.txt', 'background') + generate_variety_noise(background_data_folder, 'training_list.txt', 'background') + generate_variety_noise(background_data_folder, 'testing_list.txt', 'background') + background_data_folder = os.path.join( + background_data_folder.split("_background_noise_")[0], "_background_noise_more" + ) + + logging.info(f"=== Write background data to manifest!") + skip_num_val, background_seg_num_val, background_val = load_list_write_manifest( + background_data_folder, out_dir, 'validation_list.txt', 'background', 0, None, 0.15, args.seg_len + ) + skip_num_test, background_seg_num_test, background_test = load_list_write_manifest( + background_data_folder, out_dir, 'testing_list.txt', 'background', 0, None, 0.01, args.seg_len + ) + skip_num_train, background_seg_num_train, background_train = load_list_write_manifest( + background_data_folder, out_dir, 'training_list.txt', 'background', 0, None, 0.15, args.seg_len + ) + + logging.info(f'Val: Skip {skip_num_val} samples. Get {background_seg_num_val} segments! => {background_val}') + logging.info(f'Test: Skip {skip_num_test} samples. Get {background_seg_num_test} segments! => {background_test}') + logging.info( + f'Train: Skip {skip_num_train} samples. Get {background_seg_num_train} segments! => {background_train}' + ) + min_val, max_val = min(speech_seg_num_val, background_seg_num_val), max(speech_seg_num_val, background_seg_num_val) + min_test, max_test = ( + min(speech_seg_num_test, background_seg_num_test), + max(speech_seg_num_test, background_seg_num_test), + ) + min_train, max_train = ( + min(speech_seg_num_train, background_seg_num_train), + max(speech_seg_num_train, background_seg_num_train), + ) + + logging.info('Finish generating manifest!') + + if rebalance: + # Random Oversampling: Randomly duplicate examples in the minority class. + # Random Undersampling: Randomly delete examples in the majority class. + if args.rebalance_method == 'under': + logging.info(f"Rebalancing number of samples in classes using {args.rebalance_method} sampling.") + logging.info(f'Val: {min_val} Test: {min_test} Train: {min_train}!') + + rebalance_json(out_dir, background_val, min_val, 'balanced') + rebalance_json(out_dir, background_test, min_test, 'balanced') + rebalance_json(out_dir, background_train, min_train, 'balanced') + + rebalance_json(out_dir, speech_val, min_val, 'balanced') + rebalance_json(out_dir, speech_test, min_test, 'balanced') + rebalance_json(out_dir, speech_train, min_train, 'balanced') + + if args.rebalance_method == 'over': + logging.info(f"Rebalancing number of samples in classes using {args.rebalance_method} sampling.") + logging.info(f'Val: {max_val} Test: {max_test} Train: {max_train}!') + + rebalance_json(out_dir, background_val, max_val, 'balanced') + rebalance_json(out_dir, background_test, max_test, 'balanced') + rebalance_json(out_dir, background_train, max_train, 'balanced') + + rebalance_json(out_dir, speech_val, max_val, 'balanced') + rebalance_json(out_dir, speech_test, max_test, 'balanced') + rebalance_json(out_dir, speech_train, max_train, 'balanced') + + if args.rebalance_method == 'fixed': + fixed_test, fixed_val, fixed_train = 200, 100, 500 + logging.info(f"Rebalancing number of samples in classes using {args.rebalance_method} sampling.") + logging.info(f'Val: {fixed_val} Test: {fixed_test} Train: {fixed_train}!') + + rebalance_json(out_dir, background_val, fixed_val, 'balanced') + rebalance_json(out_dir, background_test, fixed_test, 'balanced') + rebalance_json(out_dir, background_train, fixed_train, 'balanced') + + rebalance_json(out_dir, speech_val, fixed_val, 'balanced') + rebalance_json(out_dir, speech_test, fixed_test, 'balanced') + rebalance_json(out_dir, speech_train, fixed_train, 'balanced') + else: + logging.info("Don't rebalance number of samples in classes.") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/scripts/export/convasr_to_enemo.py b/tts/NeMo/scripts/export/convasr_to_enemo.py new file mode 100644 index 0000000..908236f --- /dev/null +++ b/tts/NeMo/scripts/export/convasr_to_enemo.py @@ -0,0 +1,76 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import os +import tarfile +from shutil import copyfile + +from nemo.collections.asr.models import EncDecClassificationModel, EncDecCTCModel, EncDecSpeakerLabelModel +from nemo.utils import logging + + +def get_parser(): + parser = argparse.ArgumentParser(description="Convert .nemo file to onnx file (encoder and decoder fused)") + parser.add_argument( + "--nemo_file", default=None, type=str, required=True, help="Path to .nemo file", + ) + parser.add_argument( + "--onnx_file", default=None, type=str, required=True, help="Path to the onnx output", + ) + parser.add_argument( + "--enemo_file", default=None, type=str, required=True, help="Path to the enemo output, consiting of onnx file", + ) + parser.add_argument( + "--model_type", + default="asr", + type=str, + choices=["asr", "speech_label", "speaker"], + help="Type of decoder used by the model.", + ) + return parser + + +def main( + nemo_file, enemo_file, onnx_file, model_type="asr", +): + if model_type == "asr": + logging.info("Preparing ASR model") + model = EncDecCTCModel.restore_from(nemo_file) + elif model_type == "speech_label": + logging.info("Preparing Speech Label Classification model") + model = EncDecClassificationModel.restore_from(nemo_file) + elif model_type == "speaker": + logging.info("Preparing Speaker Recognition model") + model = EncDecSpeakerLabelModel.restore_from(nemo_file) + else: + raise NameError("Available model names are asr, speech_label and speaker") + + logging.info("Writing onnx file") + model.export(onnx_file, onnx_opset_version=12) + logging.info("succesfully ported onnx file") + + with tarfile.open(nemo_file, "r") as archive: + archive.extract("./model_config.yaml") + with tarfile.open(enemo_file, "w") as enemo_archive: + enemo_archive.add("./model_config.yaml") + copyfile(onnx_file, "model_graph.onnx") + enemo_archive.add("model_graph.onnx") + os.remove("model_graph.onnx") # cleanup extra file + + +if __name__ == "__main__": + args = get_parser().parse_args() + main( + args.nemo_file, args.enemo_file, args.onnx_file, model_type=args.model_type, + ) diff --git a/tts/NeMo/scripts/export/convasr_to_onnx.py b/tts/NeMo/scripts/export/convasr_to_onnx.py new file mode 100644 index 0000000..2b92e98 --- /dev/null +++ b/tts/NeMo/scripts/export/convasr_to_onnx.py @@ -0,0 +1,66 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse + +from nemo.collections.asr.models import EncDecClassificationModel, EncDecCTCModel, EncDecSpeakerLabelModel +from nemo.utils import logging + + +def get_parser(): + parser = argparse.ArgumentParser(description="Convert .nemo file to encoder decoder onnx files") + parser.add_argument( + "--nemo_file", default=None, type=str, required=True, help="Path to .nemo file", + ) + parser.add_argument( + "--onnx_encoder", default=None, type=str, required=True, help="Path to the onnx encoder output.", + ) + parser.add_argument( + "--onnx_decoder", default=None, type=str, required=True, help="Path to the onnx decoder output.", + ) + parser.add_argument( + "--model_type", + default='asr', + type=str, + choices=['asr', 'speech_label', 'speaker'], + help="Type of decoder used by the model.", + ) + return parser + + +def main( + nemo_file, onnx_encoder, onnx_decoder, model_type='asr', +): + if model_type == 'asr': + logging.info("Preparing encoder decoder for ASR model") + model = EncDecCTCModel.restore_from(nemo_file) + elif model_type == 'speech_label': + logging.info("Preparing encoder decoder for Speech Label Classification model") + model = EncDecClassificationModel.restore_from(nemo_file) + elif model_type == 'speaker': + logging.info("Preparing encoder decoder for Speaker Recognition model") + model = EncDecSpeakerLabelModel.restore_from(nemo_file) + else: + raise NameError("Available model names are asr, speech_label and speaker ") + + logging.info("Writing onnx encoder and decoder onnx files") + model.encoder.export(onnx_encoder) + model.decoder.export(onnx_decoder, onnx_opset_version=10) + logging.info("succesfully ported onnx files") + + +if __name__ == "__main__": + args = get_parser().parse_args() + main( + args.nemo_file, args.onnx_encoder, args.onnx_decoder, model_type=args.model_type, + ) diff --git a/tts/NeMo/scripts/export/convasr_to_single_onnx.py b/tts/NeMo/scripts/export/convasr_to_single_onnx.py new file mode 100644 index 0000000..7c7321f --- /dev/null +++ b/tts/NeMo/scripts/export/convasr_to_single_onnx.py @@ -0,0 +1,62 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse + +from nemo.collections.asr.models import EncDecClassificationModel, EncDecCTCModel, EncDecSpeakerLabelModel +from nemo.utils import logging + + +def get_parser(): + parser = argparse.ArgumentParser(description="Convert .nemo file to onnx file (encoder and decoder fused)") + parser.add_argument( + "--nemo_file", default=None, type=str, required=True, help="Path to .nemo file", + ) + parser.add_argument( + "--onnx_file", default=None, type=str, required=True, help="Path to the onnx output", + ) + parser.add_argument( + "--model_type", + default='asr', + type=str, + choices=['asr', 'speech_label', 'speaker'], + help="Type of decoder used by the model.", + ) + return parser + + +def main( + nemo_file, onnx_file, model_type='asr', +): + if model_type == 'asr': + logging.info("Preparing ASR model") + model = EncDecCTCModel.restore_from(nemo_file) + elif model_type == 'speech_label': + logging.info("Preparing Speech Label Classification model") + model = EncDecClassificationModel.restore_from(nemo_file) + elif model_type == 'speaker': + logging.info("Preparing Speaker Recognition model") + model = EncDecSpeakerLabelModel.restore_from(nemo_file) + else: + raise NameError("Available model names are asr, speech_label and speaker") + + logging.info("Writing onnx file") + model.export(onnx_file, onnx_opset_version=12) + logging.info("succesfully ported onnx file") + + +if __name__ == "__main__": + args = get_parser().parse_args() + main( + args.nemo_file, args.onnx_file, model_type=args.model_type, + ) diff --git a/tts/NeMo/scripts/freesound_download_resample/download_resample_freesound.sh b/tts/NeMo/scripts/freesound_download_resample/download_resample_freesound.sh new file mode 100644 index 0000000..af0a07f --- /dev/null +++ b/tts/NeMo/scripts/freesound_download_resample/download_resample_freesound.sh @@ -0,0 +1,115 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +#!/bin/bash + +# This is bash script actually run the downloading and resampling script. +# See instructions in freesound_download.py + +# Change this arguments if you want +page_size=100 # Number of sounds per page +max_samples=200 # Maximum number of sound samples +min_filesize=0 # Minimum filesize allowed (in MB) +max_filesize=100 # Maximum filesize allowed (in MB) + +if [[ $# -ne 3 ]]; then + echo "Require number of all files | data directory | resample data directory as arguments to the script" + exit 2 +fi + + +NUM_ALL_FILES=$1 +DATADIR=$2 +RESAMPLE_DATADIR=$3 + + +if [ ! -d "$DATADIR" ]; then + echo "Creating dir $DATADIR" + mkdir -p "$DATADIR" +fi + +if [ ! -d "$RESAMPLE_DATADIR" ]; then + echo "Creating dir $RESAMPLE_DATADIR" + mkdir -p "$RESAMPLE_DATADIR" +fi + +# we just need background categories for constructing dataset, feel free to include other (speech) categories for testing and training your VAD model +# background +categories=( + "Air brake" + "Static" + "Acoustic environment" + "Distortion" + "Tape hiss" + "Hubbub" + "Vibration" + "Cacophony" + "Throbbing" + "Reverberation" + "Inside, public space" + "Inside, small room" + "Echo" + "Outside, rural" + "Outside, natural" + "Outside, urban" + "Outside, manmade" + "Car" + "Bus" + "Traffic noise" + "Roadway noise" + "Truck" + "Emergency vehicle" + "Motorcycle" + "Aircraft engine" + "Aircraft" + "Helicopter" + "Bicycle" + "Skateboard" + "Subway, metro, underground" + "Railroad car" + "Train wagon" + "Train" + "Sailboat" + "Rowboat" + "Ship" +) + + +WAV_FILECOUNT="$(find $DATADIR -name '*.wav' -type f | wc -l)" +FLAC_FILECOUNT="$(find $DATADIR -name '*.flac' -type f | wc -l)" +FILECOUNT="$((WAV_FILECOUNT + FLAC_FILECOUNT))" +echo "File count: " $FILECOUNT + + +while((FILECOUNT <= NUM_ALL_FILES)) +do + for category in "${categories[@]}" + do + python freesound_download.py --data_dir "${DATADIR}" --category "${category}" --page_size "${page_size}" --max_samples "${max_samples}" --min_filesize "${min_filesize}" --max_filesize "${max_filesize}" + ret=$? + if [ $ret -ne 0 ]; then + exit 1 + fi + done + + WAV_FILECOUNT="$(find $DATADIR -name '*.wav' -type f | wc -l)" + FLAC_FILECOUNT="$(find $DATADIR -name '*.flac' -type f | wc -l)" + FILECOUNT="$((WAV_FILECOUNT + FLAC_FILECOUNT))" + echo "Current file count is: " $FILECOUNT +done + +# RESAMPLE +echo "Got enough data. Start resample!" +python freesound_resample.py --data_dir="${DATADIR}" --resampled_dir="${RESAMPLE_DATADIR}" + +echo "Done resample data!" diff --git a/tts/NeMo/scripts/freesound_download_resample/freesound_download.py b/tts/NeMo/scripts/freesound_download_resample/freesound_download.py new file mode 100644 index 0000000..076c69b --- /dev/null +++ b/tts/NeMo/scripts/freesound_download_resample/freesound_download.py @@ -0,0 +1,585 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import os +import pickle +import time + +try: + import librosa + import requests + import requests_oauthlib + from joblib import Parallel, delayed + from oauthlib.oauth2 import TokenExpiredError +except (ModuleNotFoundError, ImportError) as e: + raise e + +try: + import freesound +except ModuleNotFoundError as e: + raise ModuleNotFoundError( + "freesound is not installed. Execute `pip install --no-cache-dir git+https://github.com/MTG/freesound-python.git` in terminal" + ) + + +""" +Instructions +1. We will need some requirements including freesound, requests, requests_oauthlib, joblib, librosa and sox. If they are not installed, please run `pip install -r freesound_requirements.txt` +2. Create an API key for freesound.org at https://freesound.org/help/developers/ +3. Create a python file called `freesound_private_apikey.py` and add lined `api_key = ` and `client_id = ` +4. Authorize by run `python freesound_download.py --authorize` and visit website, and paste response code +5. Feel free to change any arguments in download_resample_freesound.sh such as max_samples and max_filesize +6. Run `bash download_resample_freesound.sh ` +""" + +# Import the API Key +try: + from freesound_private_apikey import api_key, client_id + + print("API Key found !") +except ImportError: + raise ImportError( + "Create a python file called `freesound_private_apikey.py` and add lined `api_key = ` and `client_id = `" + ) + +auth_url = 'https://freesound.org/apiv2/oauth2/authorize/' +redirect_url = 'https://freesound.org/home/app_permissions/permission_granted/' +token_url = 'https://freesound.org/apiv2/oauth2/access_token/' +scope = ["read", "write"] + +BACKGROUND_CLASSES = [ + "Air brake", + "Static", + "Acoustic environment", + "Distortion", + "Tape hiss", + "Hubbub", + "Vibration", + "Cacophony", + "Throbbing", + "Reverberation", + "Inside, public space", + "Inside, small room", + "Echo", + "Outside, rural", + "Outside, natural", + "Outside, urban", + "Outside, manmade", + "Car", + "Bus", + "Traffic noise", + "Roadway noise", + "Truck", + "Emergency vehicle", + "Motorcycle", + "Aircraft engine", + "Aircraft", + "Helicopter", + "Bicycle", + "Skateboard", + "Subway, metro, underground", + "Railroad car", + "Train wagon", + "Train", + "Sailboat", + "Rowboat", + "Ship", +] + +SPEECH_CLASSES = [ + "Male speech", + "Female speech", + "Speech synthesizer", + "Babbling", + "Conversation", + "Child speech", + "Narration", + "Laughter", + "Yawn", + "Whispering", + "Whimper", + "Baby cry", + "Sigh", + "Groan", + "Humming", + "Male singing", + "Female singing", + "Child singing", + "Children shouting", +] + + +def initialize_oauth(): + # If token already exists, then just load it + if os.path.exists('_token.pkl'): + token = unpickle_object('_token') + oauth = requests_oauthlib.OAuth2Session(client_id, redirect_uri=redirect_url, scope=scope, token=token) + + else: + # Construct a new token after OAuth2 flow + # Initialize a OAuth2 session + oauth = requests_oauthlib.OAuth2Session(client_id, redirect_uri=redirect_url, scope=scope) + + authorization_url, state = oauth.authorization_url(auth_url) + print(f"Visit below website and paste access token below : \n\n{authorization_url}\n") + + authorization_response = input("Paste authorization response code here :\n") + + token = oauth.fetch_token( + token_url, + authorization_response=authorization_response, + code=authorization_response, + client_secret=api_key, + ) + + # Save the token generated + pickle_object(token, '_token') + + return oauth, token + + +def instantiate_session(): + # Reconstruct session in process, and force singular execution thread to reduce session + # connections to server + token = unpickle_object('_token') + session = requests_oauthlib.OAuth2Session(client_id, redirect_uri=redirect_url, scope=scope, token=token) + adapter = requests.adapters.HTTPAdapter(pool_connections=1, pool_maxsize=1) + session.mount('http://', adapter) + return session + + +def refresh_token(session): + print("Refreshing tokens...") + # Token expired, perform token refresh + extras = {'client_id': client_id, 'client_secret': api_key} + token = session.refresh_token(token_url, **extras) + print("Token refresh performed...") + # Save the refreshed token + pickle_object(token, '_token') + return session + + +def pickle_object(token, name): + with open(name + '.pkl', 'wb') as f: + pickle.dump(token, f) + + +def unpickle_object(name): + fp = name + '.pkl' + if os.path.exists(fp): + with open(fp, 'rb') as f: + token = pickle.load(f) + + return token + else: + raise FileNotFoundError('Token not found!') + + +def is_resource_limited(e: freesound.FreesoundException): + """ + Test if the reason for a freesound exception was either rate limit + or daily limit. + + If it was for either reason, sleep for an appropriate delay and return + to try again. + + Args: + e: Freesound Exception object + + Returns: + A boolean which describes whether the error was due to some + api limit issue, or if it was some other reason. + + If false is returned, then the user should carefully check the cause + and log it. + """ + detail = e.detail['detail'] + + if '2000' in detail: + # This is the request limit, hold off for 1 hour and try again + print(f"Hit daily limit, sleeping for 20 minutes.") + time.sleep(60 * 20) + return True + + elif '60' in detail: + # This is the request limit per minute, hold off for 1 minute and try again + print(f"Hit rate limit, sleeping for 1 minute.") + time.sleep(60) + return True + + else: + return False + + +def prepare_client(client: freesound.FreesoundClient, token) -> freesound.FreesoundClient: + # Initialize the client with token auth + client.set_token(token['access_token'], auth_type='oauth') + print("Client ready !") + return client + + +def get_text_query_with_resource_limit_checks(client, query: str, filters: list, fields: str, page_size: int): + """ + Performs a text query, checks for rate / api limits, and retries. + + Args: + client: FreesoundAPI client + query: query string (either exact or inexact) + filters: list of string filters + fields: String of values to recover + page_size: samples per page returned + + Returns: + + """ + pages = None + attempts = 20 + + while pages is None: + try: + pages = client.text_search(query=query, filter=" ".join(filters), fields=fields, page_size=str(page_size),) + + except freesound.FreesoundException as e: + # Most probably a rate limit or a request limit + # Check if that was the case, and wait appropriate ammount of time + # for retry + was_resource_limited = is_resource_limited(e) + + # If result of test False, it means that failure was due to some other reason. + # Log it, then break loop + if not was_resource_limited: + print(e.with_traceback(None)) + break + + attempts -= 1 + + # Attempt to refresh tokens if it fails multiple times + if attempts % 5 == 0 and attempts > 0: + session = instantiate_session() + refresh_token(session) + session.close() + token = unpickle_object('_token') + client = prepare_client(client, token) + + if attempts <= 0: + print(f"Failed to query pages for '{query}' after 10 attempts, skipping query") + break + + if pages is None: + print(f"Query attempts remaining = {attempts}") + + return client, pages + + +def get_resource_with_auto_refresh(session, download_url): + """ + Attempts download of audio with a token refresh if necessary. + """ + try: + result = session.get(download_url) + + except TokenExpiredError as e: + session = refresh_token(session) + result = session.get(download_url) + + except Exception as e: + result = None + + print(f"Skipping file {download_url} due to exception below\n\n") + print(e) + + return result.content + + +def download_song(basepath, id, name, download_url): + # Cleanup name + name = name.replace(":", "-") + name = name.replace(",", "-") + name = name.replace("/", "-") + name = name.replace("\\", "-") + name = name.replace(".", "-") + name = name.replace(" ", "") + + # Correct last `.` for filetype + name = name[:-4] + '.wav' + + # Add file id to filename + name = f"id_{id} " + name + + fp = os.path.join(basepath, name) + + # Check if file, if exists already, can be loaded by librosa + # If it cannot be loaded, possibly corrupted file. + # Delete and then re-download + if os.path.exists(fp): + try: + _ = librosa.load(fp) + except Exception: + # File is currupted, delete and re-download. + os.remove(fp) + + print(f"Pre-existing file {fp} was corrupt and was deleted, will be re-downloaded.") + + if not os.path.exists(fp): + print("Downloading file :", name) + + session = instantiate_session() + + data = None + attempts = 10 + + try: + while data is None: + + try: + # Get the sound data + data = get_resource_with_auto_refresh(session, download_url) + + except freesound.FreesoundException as e: + # Most probably a rate limit or a request limit + # Check if that was the case, and wait appropriate amount of time + # for retry + was_resource_limited = is_resource_limited(e) + + # If result of test False, it means that failure was due to some other reason. + # Log it, then break loop + if not was_resource_limited: + print(e) + break + + attempts -= 1 + + if attempts <= 0: + print(f"Failed to download file {fp} after 10 attempts, skipping file") + break + + if data is None: + print(f"Download attempts remaining = {attempts}") + + finally: + session.close() + + # Write the data to file + if data is not None: + print("Downloaded file :", name) + + with open(fp, 'wb') as f: + f.write(data) + + # If file size is less than 89, then this probably is a text format and not an actual audio file. + if os.path.getsize(fp) > 89: + print(f"File written : {fp}") + + else: + os.remove(fp) + print(f"File corrupted and has been deleted: {fp}") + + else: + print(f"File [{fp}] corrupted or faced some issue when downloading, skipped.") + + # Sleep to avoid hitting rate limits + time.sleep(5) + + else: + print(f"File [{fp}] already exists in dataset, skipping re-download.") + + +def get_songs_by_category( + client: freesound.FreesoundClient, + category: str, + data_dir: str, + max_num_samples=100, + page_size=100, + min_filesize_in_mb=0, + max_filesize_in_mb=10, + n_jobs=None, +): + """ + Download songs of a category with restrictions + + Args: + client: FreesoundAPI client + category: category to be downloaded + data_dir: directory of downloaded songs + max_num_samples: maximum number of samples of this category + page_size: samples per page returned + min_filesize_in_mb: minimum filesize of the song in MB + max_filesize_in_mb: maximum filesize of the song in MB + n_jobs: number of jobs for parallel processing + + Returns: + + """ + # quote string to force exact match + query = f'"{category}"' + print(f"Query : {query}") + + page_size = min(page_size, 150) + max_filesize = int(max_filesize_in_mb * (2 ** 20)) + + if min_filesize_in_mb == 0: + min_filesize_in_mb = 1 + else: + min_filesize_in_mb = int(min_filesize_in_mb * (2 ** 20)) + + if max_num_samples < 0: + max_num_samples = int(1e6) + + filters = [ + 'type:(wav OR flac)', + 'license:("Attribution" OR "Creative Commons 0")', + f'filesize:[{min_filesize_in_mb} TO {max_filesize}]', + ] + + fields = "id,name,download,license" + + client, pages = get_text_query_with_resource_limit_checks( + client, query=query, filters=filters, fields=fields, page_size=page_size + ) + + if pages is None: + print(f"Number of attempts exceeded limit, skipping query {query}") + return + + num_pages = pages.count + + # Check if returned empty result; if so, fallback to inexact category search + if num_pages == 0: + print(f"Found 0 samples of results for query '{query}'") + print(f"Trying less restricted query : {category}") + + client, pages = get_text_query_with_resource_limit_checks( + client, query=category, filters=filters, fields=fields, page_size=page_size + ) + + if pages is None: + print(f"Number of attempts exceeded limit, skipping query {query}") + return + + num_pages = pages.count + + print(f"Found {num_pages} samples of results for query '{query}'") + + category = category.replace(' ', '_') + basepath = os.path.join(data_dir, category) + + if not os.path.exists(basepath): + os.makedirs(basepath) + + sounds = [] + sample_count = 0 + + # Retrieve sound license information + with open(os.path.join(basepath, 'licenses.txt'), 'w') as f: + f.write("ID,LICENSE\n") + f.flush() + + while True: + for sound in pages: + if sample_count >= max_num_samples: + print( + f"Collected {sample_count} samples, which is >= max number of samples requested " + f"{max_num_samples}. Stopping for this category : {category}" + ) + break + + sounds.append(sound) + sample_count += 1 + + f.write(f"{sound.id},{sound.license}\n") + f.flush() + + if sample_count >= max_num_samples: + break + + try: + pages = pages.next_page() + except ValueError: + break + + if n_jobs is None: + n_jobs = max(1, len(sounds)) + + # Parallel download all songs + with Parallel(n_jobs=n_jobs, verbose=10) as parallel: + _ = parallel(delayed(download_song)(basepath, sound.id, sound.name, sound.download) for sound in sounds) + + +if __name__ == '__main__': + + parser = argparse.ArgumentParser(description="Freesound download script") + + parser.add_argument( + '--authorize', action='store_true', dest='auth', help='Flag to only perform OAuth2 authorization step' + ) + + parser.add_argument('-c', '--category', default='', type=str, help='Category required to download') + + parser.add_argument('-d', '--data_dir', default='', type=str, help='Destination folder to store data') + + parser.add_argument('--page_size', default=100, type=int, help='Number of sounds per page') + + parser.add_argument('--max_samples', default=100, type=int, help='Maximum number of sound samples') + + parser.add_argument('--min_filesize', default=0, type=int, help='Maximum filesize allowed (in MB)') + + parser.add_argument('--max_filesize', default=20, type=int, help='Maximum filesize allowed (in MB)') + + parser.set_defaults(auth=False) + + args = parser.parse_args() + + if args.auth: + """ Initialize oauth token to be used by all """ + oauth, token = initialize_oauth() + oauth.close() + + print("Authentication suceeded ! Token stored in `_token.pkl`") + exit(0) + + if not os.path.exists('_token.pkl'): + raise FileNotFoundError( + "Please authorize the application first using " "`python freesound_download.py --authorize`" + ) + if args.data_dir == '': + raise ValueError("Data dir must be passed as an argument using `--data_dir`") + + data_dir = args.data_dir + + page_size = args.page_size + max_num_samples = args.max_samples + min_filesize_in_mb = args.min_filesize + max_filesize_in_mb = args.max_filesize + + # Initialize and authenticate client + token = unpickle_object('_token') + freesound_client = freesound.FreesoundClient() + client = prepare_client(freesound_client, token) + + category = args.category + + if category == '': + raise ValueError("Cannot pass empty string as it will select all of FreeSound data !") + + print(f"Downloading category : {category}") + get_songs_by_category( + client, + category, + data_dir=data_dir, + max_num_samples=max_num_samples, + page_size=page_size, + min_filesize_in_mb=min_filesize_in_mb, + max_filesize_in_mb=max_filesize_in_mb, + n_jobs=30, + ) diff --git a/tts/NeMo/scripts/freesound_download_resample/freesound_requirements.txt b/tts/NeMo/scripts/freesound_download_resample/freesound_requirements.txt new file mode 100644 index 0000000..127e509 --- /dev/null +++ b/tts/NeMo/scripts/freesound_download_resample/freesound_requirements.txt @@ -0,0 +1,6 @@ +git+git://github.com/MTG/freesound-python.git +requests +requests_oauthlib +joblib +librosa +sox \ No newline at end of file diff --git a/tts/NeMo/scripts/freesound_download_resample/freesound_resample.py b/tts/NeMo/scripts/freesound_download_resample/freesound_resample.py new file mode 100644 index 0000000..79a01c0 --- /dev/null +++ b/tts/NeMo/scripts/freesound_download_resample/freesound_resample.py @@ -0,0 +1,119 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import glob +import os +import time + +import librosa +import sox +from joblib import Parallel, delayed + + +def resample_file(resampled_dir, filepath, ext, sample_rate): + """ + Resample an audio file to 16kHZ and transform to monochannel + Remove incompatible files. + + Args: + resampled_dir: Directory of transformed files. + filepath: Filepath of Audio + ext: File type e.g. "wav", "flac" + + Returns: + + """ + head, filename = os.path.split(filepath) + _, clsname = os.path.split(head) + + filename, _ = os.path.splitext(filename) + + new_dir = os.path.join(resampled_dir, clsname) + if not os.path.exists(new_dir): + os.makedirs(new_dir) + + new_path = os.path.join(new_dir, filename + f'.{ext}') + + # check if the resampled data exists. + if os.path.exists(new_path): + print(f"Resampled file {filepath} exists. Skip it.") + return None + + transform = sox.Transformer() + transform.set_output_format(file_type='wav') + transform.convert(samplerate=sample_rate, n_channels=1) + + try: + transform.build(filepath, new_path) + print(f"Finished converting file {filepath}.") + + return None + + except sox.core.SoxError as e: + + try: + # Check if the file is readable + librosa.load(filepath) + + # if it is, force input format and try again + transform.set_input_format(file_type=ext) + transform.build(filepath, new_path) + return None + + except Exception: + return filepath + + +def main(): + start = time.time() + parser = argparse.ArgumentParser(description='Freesound data resample') + parser.add_argument("--data_dir", required=True, default=None, type=str) + parser.add_argument('--resampled_dir', required=True, default=None, type=str) + parser.add_argument('--sample_rate', default=16000, type=int) + args = parser.parse_args() + + data_dir = args.data_dir + resampled_dir = args.resampled_dir + sample_rate = args.sample_rate + + wav_files = sorted(glob.glob(os.path.join(data_dir, '*/*.wav'))) + flac_files = sorted(glob.glob(os.path.join(data_dir, '*/*.flac'))) + + with Parallel(n_jobs=-1, verbose=10) as parallel: + wav_files_failed = parallel( + delayed(resample_file)(resampled_dir, filepath, ext='wav', sample_rate=sample_rate) + for filepath in wav_files + ) + + flac_files_failed = parallel( + delayed(resample_file)(resampled_dir, filepath, ext='flac', sample_rate=sample_rate) + for filepath in flac_files + ) + + with open('dataset_conversion_logs.txt', 'w') as f: + for file in wav_files_failed: + if file is not None: + f.write(f"{file}\n") + + for file in flac_files_failed: + if file is not None: + f.write(f"{file}\n") + + end = time.time() + print(f'Resample data in {data_dir} and save to {resampled_dir} takes {end-start} seconds.') + + +if __name__ == '__main__': + + main() diff --git a/tts/NeMo/scripts/nemo_legacy_import/asr_checkpoint_port.py b/tts/NeMo/scripts/nemo_legacy_import/asr_checkpoint_port.py new file mode 100644 index 0000000..f9b7387 --- /dev/null +++ b/tts/NeMo/scripts/nemo_legacy_import/asr_checkpoint_port.py @@ -0,0 +1,72 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +"""This script converts old Jasper/QuartzNet models from NeMo 0.11.* to NeMo v1.0.0* +""" + +import argparse + +import torch +from omegaconf import DictConfig +from ruamel.yaml import YAML + +import nemo.collections.asr as nemo_asr +from nemo.utils import logging + + +def get_parser(): + parser = argparse.ArgumentParser(description="Converts old Jasper/QuartzNet models to NeMo v1.0beta") + parser.add_argument("--config_path", default=None, required=True, help="Path to model config (NeMo v1.0beta)") + parser.add_argument("--encoder_ckpt", default=None, required=True, help="Encoder checkpoint path") + parser.add_argument("--decoder_ckpt", default=None, required=True, help="Decoder checkpoint path") + parser.add_argument("--output_path", default=None, required=True, help="Output checkpoint path (should be .nemo)") + parser.add_argument( + "--model_type", + default='asr', + type=str, + choices=['asr', 'speech_label', 'speaker'], + help="Type of decoder used by the model.", + ) + + return parser + + +def main(config_path, encoder_ckpt, decoder_ckpt, output_path, model_type): + + yaml = YAML(typ='safe') + with open(config_path) as f: + params = yaml.load(f) + + model = None + if model_type == 'asr': + logging.info("Creating ASR NeMo 1.0 model") + model = nemo_asr.models.EncDecCTCModel(cfg=DictConfig(params['model'])) + elif model_type == 'speech_label': + logging.info("Creating speech label NeMo 1.0 model") + model = nemo_asr.models.EncDecClassificationModel(cfg=DictConfig(params['model'])) + else: + logging.info("Creating Speaker Recognition NeMo 1.0 model") + model = nemo_asr.models.EncDecSpeakerLabelModel(cfg=DictConfig(params['model'])) + + model.encoder.load_state_dict(torch.load(encoder_ckpt)) + model.decoder.load_state_dict(torch.load(decoder_ckpt)) + logging.info("Succesfully ported old checkpoint") + + model.save_to(output_path) + logging.info("new model saved at {}".format(output_path)) + + +if __name__ == "__main__": + args = get_parser().parse_args() + main(args.config_path, args.encoder_ckpt, args.decoder_ckpt, args.output_path, args.model_type) diff --git a/tts/NeMo/scripts/neural_machine_translation/filter_langs_nmt.py b/tts/NeMo/scripts/neural_machine_translation/filter_langs_nmt.py new file mode 100644 index 0000000..7363406 --- /dev/null +++ b/tts/NeMo/scripts/neural_machine_translation/filter_langs_nmt.py @@ -0,0 +1,403 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import logging +import multiprocessing as mp +import re +import shutil +import warnings +from pathlib import Path +from time import sleep + +import fasttext +from tqdm import tqdm + +""" +Usage: +python filter_by_language.py --input-src train.en \ + --input-tgt train.de \ + --output-src train_lang_filtered.en \ + --output-tgt train_lang_filtered.de \ + --source-lang en \ + --target-lang de \ + --removed-src train_garbage.en \ + --removed-tgt train_garbage.de \ + --fasttext-model lid.176.bin +""" + + +logging.basicConfig(level=logging.INFO) + + +def get_args(): + parser = argparse.ArgumentParser( + description="It is a script for verifying language in machine translation data sets. If the script is used on " + "a parallel corpus, it verifies both a source and a target language. If number of jobs `--num-jobs` is bigger " + "than 1 than lines in an input file (or files if parallel corpus is checked) split equally between workers. " + "If `num_jobs > 1` is used, the best performance is achieved if dataset is shuffled and lines with different " + "lengths are distributed evenly in the input file. Filtered data is stored into `output_src`[, `--output-tgt`]" + " and removed lines are put into `removed_src`[, `--removed-tgt`] files. If language cannot be detected " + "(e.g. date), the line is removed. Working time on en-de wikimatrix (6.23M pairs: 700 MB German and 625 MB " + "English) from wmt20 on machine with 20 CPU cores: less than 1 minute." + ) + parser.add_argument( + "--input-src", + "-s", + help="Path to the input file which has to contain text in language `source_lang`.", + required=True, + type=Path, + ) + parser.add_argument( + "--input-tgt", + "-t", + help="Path to the input file which has to contain text in language `target_lang`. If not provided, data is " + "processed as monolingual.", + type=Path, + ) + parser.add_argument( + "--output-src", + "-S", + help="Path to the file where filtered `input_src` will be saved.", + required=True, + type=Path, + ) + parser.add_argument( + "--output-tgt", "-T", help="Path to the output target file", type=Path, + ) + parser.add_argument( + "--source-lang", + "-l", + required=True, + help="Input language. For options see https://fasttext.cc/docs/en/language-identification.html.", + ) + parser.add_argument( + "--target-lang", + "-L", + help="Output language. For options see https://fasttext.cc/docs/en/language-identification.html.", + ) + parser.add_argument( + "--removed-src", "-r", required=True, help="Path to file where removed source lines will be saved", type=Path, + ) + parser.add_argument( + "--removed-tgt", "-R", help="Path to file where removed target lines will be saved", type=Path, + ) + parser.add_argument( + "--num-jobs", + "-j", + type=int, + help="Number of jobs. By default, the number of jobs is equal to the number of CPU cores.", + ) + parser.add_argument( + "--fasttext-model", + "-m", + help="Path to fasttext model. The description and download links are here " + "https://fasttext.cc/docs/en/language-identification.html", + type=Path, + ) + args = parser.parse_args() + if not ( + args.output_tgt is None + and args.input_tgt is None + and args.target_lang is None + and args.removed_tgt is None + or args.output_tgt is not None + and args.input_tgt is not None + and args.target_lang is not None + and args.removed_tgt is not None + ): + raise ValueError( + f"Arguments `input_tgt`, `output_tgt`, `target_lang`, `removed_tgt` have to be either `None` " + f"simultaneously or not `None` simultaneously. Given " + f"input_tgt={args.input_tgt}, output_tgt={args.output_tgt}, target_lang={args.target_lang}, " + f"removed_tgt={args.removed_tgt}" + ) + args.input_src = args.input_src.expanduser() + if args.input_tgt is not None: + args.input_tgt = args.input_tgt.expanduser() + args.output_src = args.output_src.expanduser() + if args.output_tgt is not None: + args.output_tgt = args.output_tgt.expanduser() + args.removed_src = args.removed_src.expanduser() + if args.removed_tgt is not None: + args.removed_tgt = args.removed_tgt.expanduser() + args.fasttext_model = args.fasttext_model.expanduser() + return args + + +def get_lang(line, fasttext_model): + labels, _ = fasttext_model.predict(line, k=1) + lang = labels[0].split('__')[-1] + return lang + + +def get_edges_in_1_file(fn, num_parts): + num_lines = 0 + edges = [0] + with open(fn) as f: + i = 0 + for l in f: + i += len(l.encode('utf-8')) + edges.append(i) + num_lines += 1 + return [edges[int(i * num_lines / num_parts)] for i in range(num_parts)] + [edges[-1]], num_lines + + +def get_edges_and_num_lines(src_fn, tgt_fn, num_parts): + src_edges, src_num_lines = get_edges_in_1_file(src_fn, num_parts) + assert num_parts + 1 == len(src_edges) + src_edges = [(src_edges[i], src_edges[i + 1]) for i in range(len(src_edges) - 1)] + if tgt_fn is not None: + tgt_edges, tgt_num_lines = get_edges_in_1_file(tgt_fn, num_parts) + tgt_edges = [(tgt_edges[i], tgt_edges[i + 1]) for i in range(len(tgt_edges) - 1)] + if tgt_num_lines != src_num_lines: + raise ValueError( + f"Source {repr(src_fn)} and target {repr(tgt_fn)} files have different number of lines " + f"{src_num_lines} and {tgt_num_lines} correspondingly." + ) + + else: + tgt_edges = [None] * num_parts + assert len(src_edges) == num_parts + return src_edges, tgt_edges, src_num_lines + + +def filter_pairs( + src_edges, + tgt_edges, + input_src, + input_tgt, + filtered_dir_src, + filtered_dir_tgt, + removed_dir_src, + removed_dir_tgt, + source_lang, + target_lang, + fasttext_model, + rank, +): + global counter + fasttext_model = fasttext.load_model(str(fasttext_model)) + output_src = filtered_dir_src / Path(f"rank{rank}") + output_src_removed = removed_dir_src / Path(f"rank{rank}") + output_tgt = filtered_dir_tgt / Path(f"rank{rank}") + output_tgt_removed = removed_dir_tgt / Path(f"rank{rank}") + with open(input_src) as in_src, open(input_tgt) as in_tgt, open(output_src, 'w') as out_src, open( + output_tgt, 'w' + ) as out_tgt, open(output_src_removed, 'w') as out_r_src, open(output_tgt_removed, 'w') as out_r_tgt: + in_src.seek(src_edges[0]) + in_tgt.seek(tgt_edges[0]) + src_l, tgt_l, i = in_src.readline(), in_tgt.readline(), 0 + if in_src.tell() > src_edges[1] or in_tgt.tell() > tgt_edges[1]: + return + while src_l and tgt_l: + with counter.get_lock(): + counter.value += 1 + src_l = src_l.strip() + tgt_l = tgt_l.strip() + src_lang = get_lang(src_l, fasttext_model) + if src_lang is not None: + tgt_lang = get_lang(tgt_l, fasttext_model) + if src_lang is None or tgt_lang is None or src_lang != source_lang or tgt_lang != target_lang: + out_r_src.write(src_l + '\n') + out_r_tgt.write(tgt_l + '\n') + else: + out_src.write(src_l + '\n') + out_tgt.write(tgt_l + '\n') + if in_src.tell() >= src_edges[1]: + if in_tgt.tell() < tgt_edges[1]: + raise ValueError( + f"Edges of target and source has to be reached simultaneously, whereas " + f"in_src.tell()={in_src.tell()}, in_tgt.tell()={in_tgt.tell()}, " + f"src_edges[1]={src_edges[1]}, tgt_edges[1]={tgt_edges[1]}." + ) + break + if in_tgt.tell() >= tgt_edges[1]: + raise ValueError( + f"Edges of target and source has to be reached simultaneously, whereas " + f"in_src.tell()={in_src.tell()}, in_tgt.tell()={in_tgt.tell()}, " + f"src_edges[1]={src_edges[1]}, tgt_edges[1]={tgt_edges[1]}." + ) + src_l, tgt_l, i = in_src.readline(), in_tgt.readline(), i + 1 + with counter.get_lock(): + counter.value += 1 + + +def filter_singles( + src_edges, input_src, filtered_dir_src, removed_dir_src, source_lang, fasttext_model, rank, +): + logging.debug("filter singles") + global counter + fasttext_model = fasttext.load_model(str(fasttext_model)) + output_src = filtered_dir_src / Path(f"rank{rank}") + output_src_removed = removed_dir_src / Path(f"rank{rank}") + with open(input_src) as in_f, open(output_src, 'w') as out_f, open(output_src_removed, 'w') as out_r_f: + in_f.seek(src_edges[0]) + i, line = 0, in_f.readline() + if in_f.tell() > src_edges[1]: + return + while line: + with counter.get_lock(): + counter.value += 1 + line = line.strip() + in_lang = get_lang(line, fasttext_model) + if in_lang is None or in_lang != source_lang: + out_r_f.write(line + '\n') + else: + out_f.write(line + '\n') + if in_f.tell() >= src_edges[1]: + break + i, line = i + 1, in_f.readline() + with counter.get_lock(): + counter.value += 1 + + +def filter_by_lang(args): + ( + src_edges, + tgt_edges, + input_src, + input_tgt, + filtered_dir_src, + filtered_dir_tgt, + removed_dir_src, + removed_dir_tgt, + source_lang, + target_lang, + fasttext_model, + rank, + ) = args + logging.debug(f"filter by lang input_tgt: {input_tgt}") + if input_tgt is None: + if tgt_edges is not None: + warnings.warn("If input target is not provided `tgt_edges` argument is expected to be `None`") + filter_singles( + src_edges, input_src, filtered_dir_src, removed_dir_src, source_lang, fasttext_model, rank, + ) + else: + filter_pairs( + src_edges, + tgt_edges, + input_src, + input_tgt, + filtered_dir_src, + filtered_dir_tgt, + removed_dir_src, + removed_dir_tgt, + source_lang, + target_lang, + fasttext_model, + rank, + ) + + +def _cat_results(out_file, tmp_dir): + file_name_pattern = re.compile(r"/rank([1-9][0-9]*)|0$") + with out_file.open('w') as out_f: + for f in sorted(tmp_dir.iterdir()): + if not f.is_file(): + warnings.warn(f"Unexpected not file {f}") + elif not file_name_pattern.search(str(f)): + warnings.warn(f"Unexpected file {f}") + else: + with f.open('r') as in_f: + for l in in_f: + out_f.write(l) + + +def cat_results(out_files, tmp_dirs): + for o_f, t_d in zip(out_files, tmp_dirs): + if o_f is None or t_d is None: + if o_f is not None or t_d is not None: + warnings.warn( + f"Output file and tmp directory are expected to be `None` simultaneously whereas tmp directory " + f"is {t_d} and output file is {o_f}." + ) + else: + _cat_results(o_f, t_d) + + +counter = None + + +def init(args): + global counter + counter = args + + +def main(): + args = get_args() + tmp_dir = Path("tmp") + i = 0 + while tmp_dir.exists(): + tmp_dir = Path("tmp" + str(i)) + i += 1 + tmp_filtered = tmp_dir / Path("filtered") + tmp_filtered_src = tmp_filtered / Path("src") + tmp_filtered_src.mkdir(parents=True, exist_ok=True) + if args.input_tgt is None: + tmp_filtered_tgt = None + else: + tmp_filtered_tgt = tmp_filtered / Path("tgt") + tmp_filtered_tgt.mkdir(parents=True, exist_ok=True) + tmp_removed = tmp_dir / Path("removed") + tmp_removed_src = tmp_removed / Path("src") + tmp_removed_src.mkdir(parents=True, exist_ok=True) + if args.input_tgt is None: + tmp_removed_tgt = None + else: + tmp_removed_tgt = tmp_removed / Path("tgt") + tmp_removed_tgt.mkdir(parents=True, exist_ok=True) + num_jobs = mp.cpu_count() if args.num_jobs is None else args.num_jobs + src_edges, tgt_edges, num_lines = get_edges_and_num_lines(args.input_src, args.input_tgt, num_jobs) + global counter + counter = mp.Value('i', 0) + t = tqdm(total=num_lines, desc="processed lines / total number of lines") + with mp.Pool(num_jobs, initializer=init, initargs=(counter,)) as pool: + async_result = pool.map_async( + filter_by_lang, + [ + ( + se, + te, + args.input_src, + args.input_tgt, + tmp_filtered_src, + tmp_filtered_tgt, + tmp_removed_src, + tmp_removed_tgt, + args.source_lang, + args.target_lang, + args.fasttext_model, + rank, + ) + for rank, (se, te) in enumerate(zip(src_edges, tgt_edges)) + ], + ) + while not async_result.ready(): + t.update(counter.value) + with counter.get_lock(): + counter.value = 0 + sleep(0.1) + t.update(counter.value) + + cat_results( + [args.output_src, args.output_tgt, args.removed_src, args.removed_tgt], + [tmp_filtered_src, tmp_filtered_tgt, tmp_removed_src, tmp_removed_tgt], + ) + shutil.rmtree(tmp_dir) + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/speaker_recognition/rttm_to_manifest.py b/tts/NeMo/scripts/speaker_recognition/rttm_to_manifest.py new file mode 100644 index 0000000..3d7b772 --- /dev/null +++ b/tts/NeMo/scripts/speaker_recognition/rttm_to_manifest.py @@ -0,0 +1,40 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse + +from nemo.collections.asr.parts.utils.speaker_utils import write_rttm2manifest +from nemo.utils import logging + +""" +This file converts vad outputs to manifest file for speaker diarization purposes +present in vad output directory. +every vad line consists of start_time, end_time , speech/non-speech +""" + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "--paths2rttm_files", help="path to vad output rttm-like files. Could be a list or a text file", required=True + ) + parser.add_argument( + "--paths2audio_files", + help="path to audio files that vad was computed. Could be a list or a text file", + required=True, + ) + parser.add_argument("--manifest_file", help="output manifest file name", type=str, required=True) + args = parser.parse_args() + + write_rttm2manifest(args.paths2audio_files, args.paths2rttm_files, args.manifest_file) + logging.info("wrote {} file from vad output files present in {}".format(args.manifest_file, args.paths2rttm_files)) diff --git a/tts/NeMo/scripts/speaker_recognition/scp_to_manifest.py b/tts/NeMo/scripts/speaker_recognition/scp_to_manifest.py new file mode 100644 index 0000000..1261db9 --- /dev/null +++ b/tts/NeMo/scripts/speaker_recognition/scp_to_manifest.py @@ -0,0 +1,96 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import json +import logging +import os + +import librosa as l +from sklearn.model_selection import StratifiedShuffleSplit +from tqdm import tqdm + + +""" +This scipt converts a scp file where each line contains + +to a manifest json file. +Args: +--scp: scp file name +--id: index of speaker label in filename present in scp file that is separated by '/' +--out: output manifest file name +--split: True / False if you would want to split the manifest file for training purposes + you may not need this for test set. output file names is _.json + Defaults to False +""" + + +def write_file(name, lines, idx): + with open(name, 'w') as fout: + for i in idx: + dic = lines[i] + json.dump(dic, fout) + fout.write('\n') + logging.info("wrote", name) + + +def main(scp, id, out, split=False): + if os.path.exists(out): + os.remove(out) + scp_file = open(scp, 'r').readlines() + + lines = [] + speakers = [] + with open(out, 'w') as outfile: + for line in tqdm(scp_file): + line = line.strip() + y, sr = l.load(line, sr=None) + dur = l.get_duration(y=y, sr=sr) + speaker = line.split('/')[id] + speaker = list(speaker) + speaker = ''.join(speaker) + speakers.append(speaker) + meta = {"audio_filepath": line, "offset": 0, "duration": float(dur), "label": speaker} + lines.append(meta) + json.dump(meta, outfile) + outfile.write("\n") + + path = os.path.dirname(out) + if split: + sss = StratifiedShuffleSplit(n_splits=1, test_size=0.1, random_state=42) + for train_idx, test_idx in sss.split(speakers, speakers): + logging.info(len(train_idx)) + + out = os.path.join(path, 'train.json') + write_file(out, lines, train_idx) + out = os.path.join(path, 'dev.json') + write_file(out, lines, test_idx) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--scp", help="scp file name", type=str, required=True) + parser.add_argument( + "--id", help="field num seperated by '/' to be considered as speaker label", type=int, required=True + ) + parser.add_argument("--out", help="manifest_file name", type=str, required=True) + parser.add_argument( + "--split", + help="bool if you would want to split the manifest file for training purposes", + required=False, + action='store_true', + ) + args = parser.parse_args() + + main(args.scp, args.id, args.out, args.split) diff --git a/tts/NeMo/scripts/speech_recognition/convert_to_tarred_audio_dataset.py b/tts/NeMo/scripts/speech_recognition/convert_to_tarred_audio_dataset.py new file mode 100644 index 0000000..4e13c05 --- /dev/null +++ b/tts/NeMo/scripts/speech_recognition/convert_to_tarred_audio_dataset.py @@ -0,0 +1,601 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. +""" +# This script converts an existing audio dataset with a manifest to +# a tarred and sharded audio dataset that can be read by the +# TarredAudioToTextDataLayer. + +# Please make sure your audio_filepath DOES NOT CONTAIN '-sub'! +# Because we will use it to handle files which have duplicate filenames but with different offsets +# (see function create_shard for details) + +# Usage: +1) Creating a new tarfile dataset + +python convert_to_tarred_audio_dataset.py \ + --manifest_path= \ + --target_dir= \ + --num_shards= + --max_duration= \ + --min_duration= \ + --shuffle --shuffle_seed=1 + + +2) Concatenating more tarfiles to a pre-existing tarred dataset + +python convert_to_tarred_audio_dataset.py \ + --manifest_path= \ + --metadata_path= \ + --target_dir= \ + --max_duration= \ + --min_duration= \ + --shuffle --shuffle_seed=1 \ + --concat_manifest_paths \ + + +3) Writing an empty metadata file + +python convert_to_tarred_audio_dataset.py \ + --target_dir= \ + # any other optional argument + --num_shards=8 \ + --max_duration=16.7 \ + --min_duration=0.01 \ + --shuffle \ + --shuffle_seed=1 \ + --write_metadata + +""" +import argparse +import copy +import json +import os +import random +import tarfile +from dataclasses import dataclass, field +from datetime import datetime +from typing import Any, List, Optional + +from joblib import Parallel, delayed +from omegaconf import DictConfig, OmegaConf, open_dict + +parser = argparse.ArgumentParser( + description="Convert an existing ASR dataset to tarballs compatible with TarredAudioToTextDataLayer." +) +parser.add_argument( + "--manifest_path", default=None, type=str, required=False, help="Path to the existing dataset's manifest." +) + +parser.add_argument( + '--concat_manifest_paths', + nargs='+', + default=None, + type=str, + required=False, + help="Path to the additional dataset's manifests that will be concatenated with base dataset.", +) + +# Optional arguments +parser.add_argument( + "--target_dir", + default='./tarred', + type=str, + help="Target directory for resulting tarballs and manifest. Defaults to `./tarred`. Creates the path if necessary.", +) + +parser.add_argument( + "--metadata_path", required=False, default=None, type=str, help="Path to metadata file for the dataset.", +) + +parser.add_argument( + "--num_shards", + default=-1, + type=int, + help="Number of shards (tarballs) to create. Used for partitioning data among workers.", +) +parser.add_argument( + '--max_duration', + default=None, + type=float, + help='Maximum duration of audio clip in the dataset. By default, it is None and will not filter files.', +) +parser.add_argument( + '--min_duration', + default=None, + type=float, + help='Minimum duration of audio clip in the dataset. By default, it is None and will not filter files.', +) +parser.add_argument( + "--shuffle", + action='store_true', + help="Whether or not to randomly shuffle the samples in the manifest before tarring/sharding.", +) +parser.add_argument("--shuffle_seed", type=int, help="Random seed for use if shuffling is enabled.") +parser.add_argument( + '--write_metadata', + action='store_true', + help=( + "Flag to write a blank metadata with the current call config. " + "Note that the metadata will not contain the number of shards, " + "and it must be filled out by the user." + ), +) +parser.add_argument('--workers', type=int, default=1, help='Number of worker processes') +args = parser.parse_args() + + +@dataclass +class ASRTarredDatasetConfig: + num_shards: int = -1 + shuffle: bool = False + max_duration: Optional[float] = None + min_duration: Optional[float] = None + shuffle_seed: Optional[int] = None + + +@dataclass +class ASRTarredDatasetMetadata: + created_datetime: Optional[str] = None + version: int = 0 + num_samples_per_shard: Optional[int] = None + is_concatenated_manifest: bool = False + + dataset_config: Optional[ASRTarredDatasetConfig] = ASRTarredDatasetConfig() + history: Optional[List[Any]] = field(default_factory=lambda: []) + + def __post_init__(self): + self.created_datetime = self.get_current_datetime() + + def get_current_datetime(self): + return datetime.now().strftime("%m-%d-%Y %H-%M-%S") + + @classmethod + def from_config(cls, config: DictConfig): + obj = cls() + obj.__dict__.update(**config) + return obj + + @classmethod + def from_file(cls, filepath: str): + config = OmegaConf.load(filepath) + return ASRTarredDatasetMetadata.from_config(config=config) + + +class ASRTarredDatasetBuilder: + """ + Helper class that constructs a tarred dataset from scratch, or concatenates tarred datasets + together and constructs manifests for them. + """ + + def __init__(self): + self.config = None + + def configure(self, config: ASRTarredDatasetConfig): + """ + Sets the config generated from command line overrides. + + Args: + config: ASRTarredDatasetConfig dataclass object. + """ + self.config = config # type: ASRTarredDatasetConfig + + if self.config.num_shards < 0: + raise ValueError("`num_shards` must be > 0. Please fill in the metadata information correctly.") + + def create_new_dataset(self, manifest_path: str, target_dir: str = "./tarred/", num_workers: int = 0): + """ + Creates a new tarred dataset from a given manifest file. + + Args: + manifest_path: Path to the original ASR manifest. + target_dir: Output directory. + num_workers: Integer denoting number of parallel worker processes which will write tarfiles. + Defaults to 1 - which denotes sequential worker process. + + Output: + Writes tarfiles, along with the tarred dataset compatible manifest file. + Also preserves a record of the metadata used to construct this tarred dataset. + """ + if self.config is None: + raise ValueError("Config has not been set. Please call `configure(config: ASRTarredDatasetConfig)`") + + if manifest_path is None: + raise FileNotFoundError("Manifest filepath cannot be None !") + + config = self.config # type: ASRTarredDatasetConfig + + if not os.path.exists(target_dir): + os.makedirs(target_dir) + + # Read the existing manifest + entries, filtered_entries, filtered_duration = self._read_manifest(manifest_path, config) + + if len(filtered_entries) > 0: + print(f"Filtered {len(filtered_entries)} files which amounts to {filtered_duration} seconds of audio.") + + if config.shuffle: + random.seed(config.shuffle_seed) + print("Shuffling...") + random.shuffle(entries) + + # Create shards and updated manifest entries + print(f"Number of samples added : {len(entries)}") + print(f"Remainder: {len(entries) % config.num_shards}") + + start_indices = [] + end_indices = [] + # Build indices + for i in range(config.num_shards): + start_idx = (len(entries) // config.num_shards) * i + end_idx = start_idx + (len(entries) // config.num_shards) + print(f"Shard {i} has entries {start_idx} ~ {end_idx}") + if i == config.num_shards - 1: + # We discard in order to have the same number of entries per shard. + print(f"Have {len(entries) - end_idx} entries left over that will be discarded.") + + start_indices.append(start_idx) + end_indices.append(end_idx) + + with Parallel(n_jobs=num_workers, verbose=config.num_shards) as parallel: + # Call parallel tarfile construction + new_entries_list = parallel( + delayed(self._create_shard)(entries[start_idx:end_idx], target_dir, i) + for i, (start_idx, end_idx) in enumerate(zip(start_indices, end_indices)) + ) + + # Flatten the list of list of entries to a list of entries + new_entries = [sample for manifest in new_entries_list for sample in manifest] + del new_entries_list + + print("Total number of files in manifest :", len(new_entries)) + + # Write manifest + new_manifest_path = os.path.join(target_dir, 'tarred_audio_manifest.json') + with open(new_manifest_path, 'w') as m2: + for entry in new_entries: + json.dump(entry, m2) + m2.write('\n') + + # Write metadata (default metadata for new datasets) + new_metadata_path = os.path.join(target_dir, 'metadata.yaml') + metadata = ASRTarredDatasetMetadata() + + # Update metadata + metadata.dataset_config = config + metadata.num_samples_per_shard = len(new_entries) // config.num_shards + + # Write metadata + metadata_yaml = OmegaConf.structured(metadata) + OmegaConf.save(metadata_yaml, new_metadata_path, resolve=True) + + def create_concatenated_dataset( + self, + base_manifest_path: str, + manifest_paths: List[str], + metadata: ASRTarredDatasetMetadata, + target_dir: str = "./tarred_concatenated/", + num_workers: int = 1, + ): + """ + Creates new tarfiles in order to create a concatenated dataset, whose manifest contains the data for + both the original dataset as well as the new data submitted in manifest paths. + + Args: + base_manifest_path: Path to the manifest file which contains the information for the original + tarred dataset (with flattened paths). + manifest_paths: List of one or more paths to manifest files that will be concatenated with above + base tarred dataset. + metadata: ASRTarredDatasetMetadata dataclass instance with overrides from command line. + target_dir: Output directory + + Output: + Writes tarfiles which with indices mapping to a "concatenated" tarred dataset, + along with the tarred dataset compatible manifest file which includes information + about all the datasets that comprise the concatenated dataset. + + Also preserves a record of the metadata used to construct this tarred dataset. + """ + if not os.path.exists(target_dir): + os.makedirs(target_dir) + + if base_manifest_path is None: + raise FileNotFoundError("Base manifest filepath cannot be None !") + + if manifest_paths is None or len(manifest_paths) == 0: + raise FileNotFoundError("List of additional manifest filepaths cannot be None !") + + config = ASRTarredDatasetConfig(**(metadata.dataset_config)) + + # Read the existing manifest (no filtering here) + base_entries, _, _ = self._read_manifest(base_manifest_path, config) + print(f"Read base manifest containing {len(base_entries)} samples.") + + # Precompute number of samples per shard + if metadata.num_samples_per_shard is None: + num_samples_per_shard = len(base_entries) // config.num_shards + else: + num_samples_per_shard = metadata.num_samples_per_shard + + print("Number of samples per shard :", num_samples_per_shard) + + # Compute min and max duration and update config (if no metadata passed) + print(f"Selected max duration : {config.max_duration}") + print(f"Selected min duration : {config.min_duration}") + + entries = [] + for new_manifest_idx in range(len(manifest_paths)): + new_entries, filtered_new_entries, filtered_duration = self._read_manifest( + manifest_paths[new_manifest_idx], config + ) + + if len(filtered_new_entries) > 0: + print( + f"Filtered {len(filtered_new_entries)} files which amounts to {filtered_duration:0.2f}" + f" seconds of audio from manifest {manifest_paths[new_manifest_idx]}." + ) + + entries.extend(new_entries) + + if config.shuffle: + random.seed(config.shuffle_seed) + print("Shuffling...") + random.shuffle(entries) + + # Drop last section of samples that cannot be added onto a chunk + drop_count = len(entries) % num_samples_per_shard + total_new_entries = len(entries) + entries = entries[:-drop_count] + + print( + f"Dropping {drop_count} samples from total new samples {total_new_entries} since they cannot " + f"be added into a uniformly sized chunk." + ) + + # Create shards and updated manifest entries + num_added_shards = len(entries) // num_samples_per_shard + + print(f"Number of samples in base dataset : {len(base_entries)}") + print(f"Number of samples in additional datasets : {len(entries)}") + print(f"Number of added shards : {num_added_shards}") + print(f"Remainder: {len(entries) % num_samples_per_shard}") + + start_indices = [] + end_indices = [] + shard_indices = [] + for i in range(num_added_shards): + start_idx = (len(entries) // num_added_shards) * i + end_idx = start_idx + (len(entries) // num_added_shards) + shard_idx = i + config.num_shards + print(f"Shard {shard_idx} has entries {start_idx + len(base_entries)} ~ {end_idx + len(base_entries)}") + + start_indices.append(start_idx) + end_indices.append(end_idx) + shard_indices.append(shard_idx) + + with Parallel(n_jobs=num_workers, verbose=num_added_shards) as parallel: + # Call parallel tarfile construction + new_entries_list = parallel( + delayed(self._create_shard)(entries[start_idx:end_idx], target_dir, shard_idx) + for i, (start_idx, end_idx, shard_idx) in enumerate(zip(start_indices, end_indices, shard_indices)) + ) + + # Flatten the list of list of entries to a list of entries + new_entries = [sample for manifest in new_entries_list for sample in manifest] + del new_entries_list + + # Write manifest + if metadata is None: + new_version = 1 # start with `1`, where `0` indicates the base manifest + dataset + else: + new_version = metadata.version + 1 + + print("Total number of files in manifest :", len(base_entries) + len(new_entries)) + + new_manifest_path = os.path.join(target_dir, f'tarred_audio_manifest_version_{new_version}.json') + with open(new_manifest_path, 'w') as m2: + # First write all the entries of base manifest + for entry in base_entries: + json.dump(entry, m2) + m2.write('\n') + + # Finally write the new entries + for entry in new_entries: + json.dump(entry, m2) + m2.write('\n') + + # Preserve historical metadata + base_metadata = metadata + + # Write metadata (updated metadata for concatenated datasets) + new_metadata_path = os.path.join(target_dir, f'metadata_version_{new_version}.yaml') + metadata = ASRTarredDatasetMetadata() + + # Update config + config.num_shards = config.num_shards + num_added_shards + + # Update metadata + metadata.version = new_version + metadata.dataset_config = config + metadata.num_samples_per_shard = num_samples_per_shard + metadata.is_concatenated_manifest = True + metadata.created_datetime = metadata.get_current_datetime() + + # Attach history + current_metadata = OmegaConf.structured(base_metadata.history) + metadata.history = current_metadata + + # Write metadata + metadata_yaml = OmegaConf.structured(metadata) + OmegaConf.save(metadata_yaml, new_metadata_path, resolve=True) + + def _read_manifest(self, manifest_path: str, config: ASRTarredDatasetConfig): + """Read and filters data from the manifest""" + # Read the existing manifest + entries = [] + filtered_entries = [] + filtered_duration = 0.0 + with open(manifest_path, 'r') as m: + for line in m: + entry = json.loads(line) + if (config.max_duration is None or entry['duration'] < config.max_duration) and ( + config.min_duration is None or entry['duration'] > config.min_duration + ): + entries.append(entry) + else: + filtered_entries.append(entry) + filtered_duration += entry['duration'] + + return entries, filtered_entries, filtered_duration + + def _create_shard(self, entries, target_dir, shard_id): + """Creates a tarball containing the audio files from `entries`. + """ + new_entries = [] + tar = tarfile.open(os.path.join(target_dir, f'audio_{shard_id}.tar'), mode='w', dereference=True) + + count = dict() + for entry in entries: + # We squash the filename since we do not preserve directory structure of audio files in the tarball. + base, ext = os.path.splitext(entry['audio_filepath']) + base = base.replace('/', '_') + # Need the following replacement as long as WebDataset splits on first period + base = base.replace('.', '_') + squashed_filename = f'{base}{ext}' + if squashed_filename not in count: + tar.add(entry['audio_filepath'], arcname=squashed_filename) + + if 'label' in entry: + base, ext = os.path.splitext(squashed_filename) + # no suffix if it's single sample or starting sub parts, -sub1 for the second subpart -sub2 -sub3 ,etc. + if squashed_filename not in count: + to_write = squashed_filename + count[squashed_filename] = 1 + else: + to_write = base + "-sub" + str(count[squashed_filename]) + ext + count[squashed_filename] += 1 + + new_entry = { + 'audio_filepath': to_write, + 'duration': entry['duration'], + 'text': entry['text'], + 'label': entry['label'], + 'offset': entry['offset'], + 'shard_id': shard_id, # Keep shard ID for recordkeeping + } + else: + count[squashed_filename] = 1 + new_entry = { + 'audio_filepath': squashed_filename, + 'duration': entry['duration'], + 'text': entry['text'], + 'shard_id': shard_id, # Keep shard ID for recordkeeping + } + + new_entries.append(new_entry) + + tar.close() + return new_entries + + @classmethod + def setup_history(cls, base_metadata: ASRTarredDatasetMetadata, history: List[Any]): + if 'history' in base_metadata.keys(): + for history_val in base_metadata.history: + cls.setup_history(history_val, history) + + if base_metadata is not None: + metadata_copy = copy.deepcopy(base_metadata) + with open_dict(metadata_copy): + metadata_copy.pop('history', None) + history.append(metadata_copy) + + +def main(): + manifest_path = args.manifest_path + concat_manifest_paths = args.concat_manifest_paths + target_dir = args.target_dir + metadata_path = args.metadata_path + num_shards = args.num_shards + max_duration = args.max_duration + min_duration = args.min_duration + shuffle = args.shuffle + seed = args.shuffle_seed if args.shuffle_seed else None + write_metadata = args.write_metadata + num_workers = args.workers + + builder = ASRTarredDatasetBuilder() + + if write_metadata: + metadata = ASRTarredDatasetMetadata() + dataset_cfg = ASRTarredDatasetConfig( + num_shards=num_shards, + shuffle=shuffle, + max_duration=max_duration, + min_duration=min_duration, + shuffle_seed=seed, + ) + metadata.dataset_config = dataset_cfg + + output_path = os.path.join(target_dir, 'default_metadata.yaml') + OmegaConf.save(metadata, output_path, resolve=True) + print(f"Default metadata written to {output_path}") + exit(0) + + if concat_manifest_paths is None or len(concat_manifest_paths) == 0: + print("Creating new tarred dataset ...") + + # Create a tarred dataset from scratch + config = ASRTarredDatasetConfig( + num_shards=num_shards, + shuffle=shuffle, + max_duration=max_duration, + min_duration=min_duration, + shuffle_seed=seed, + ) + builder.configure(config) + builder.create_new_dataset(manifest_path=manifest_path, target_dir=target_dir, num_workers=num_workers) + + else: + print("Concatenating multiple tarred datasets ...") + + # Implicitly update config from base details + if metadata_path is not None: + metadata = ASRTarredDatasetMetadata.from_file(metadata_path) + else: + raise ValueError("`metadata` yaml file path must be provided!") + + # Preserve history + history = [] + builder.setup_history(OmegaConf.structured(metadata), history) + metadata.history = history + + # Add command line overrides (everything other than num_shards) + metadata.dataset_config.max_duration = max_duration + metadata.dataset_config.min_duration = min_duration + metadata.dataset_config.shuffle = shuffle + metadata.dataset_config.shuffle_seed = seed + + builder.configure(metadata.dataset_config) + + # Concatenate a tarred dataset onto a previous one + builder.create_concatenated_dataset( + base_manifest_path=manifest_path, + manifest_paths=concat_manifest_paths, + metadata=metadata, + target_dir=target_dir, + num_workers=num_workers, + ) + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/tokenizers/process_asr_text_tokenizer.py b/tts/NeMo/scripts/tokenizers/process_asr_text_tokenizer.py new file mode 100644 index 0000000..8c64507 --- /dev/null +++ b/tts/NeMo/scripts/tokenizers/process_asr_text_tokenizer.py @@ -0,0 +1,282 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# USAGE: python process_asr_text_tokenizer.py --manifest= \ +# --data_root="" \ +# --vocab_size= \ +# --tokenizer=<"spe" or "wpe"> \ +# --log +# where can be: train_clean_100, train_clean_360, train_other_500 +# You can also put more than one data_set comma-separated: +# --manifest="train_clean_100,train_clean_360,train_other_500" +# or +# python process_asr_text_tokenizer.py --data_file= \ +# --data_root="" \ +# --vocab_size= \ +# --tokenizer=<"bpe" or "wpe"> \ +# --log +# where can be: train_clean_100, train_clean_360, train_other_500 +# You can also put more than one data_set comma-separated: +# --manifest="train_clean_100,train_clean_360,train_other_500" +# +# Args: +# --manifest or --data_file: If your text data lies inside of an ASR manifest file, +# then use the --manifest path. If instead the text data is inside a file with separate lines +# corresponding to different text lines, then use --data_file. +# In either case, you can add commas to concatenate different manifests or different data files. +# +# --data_root: The output directory (whose subdirectories will be created if not present) where +# the tokenizers will be placed. +# +# --vocab_size: The size of the tokenizer vocabulary. Larger vocabularies can accommodate almost entire, +# words but the decoder size of any model will grow proportionally. +# +# --tokenizer: Can be either spe or wpe . spe refers to the Google sentencepiece library tokenizer. +# wpe refers to the HuggingFace BERT Word Piece tokenizer. +# +# --no_lower_case: When this flag is passed, it will force the tokenizer to create seperate tokens for +# upper and lower case characters. By default, the script will turn all the text to lower case +# before tokenization (and if upper case characters are passed during training/inference, the +# tokenizer will emit a token equivalent to Out-Of-Vocabulary). Used primarily for the +# English language. +# +# --spe_type: The sentencepiece library has a few implementations of the tokenization technique, and +# spe_type refers to these implementations. Currently supported types are unigram, bpe, char, word. +# Defaults to bpe. +# +# --spe_character_coverage: The sentencepiece library considers how much of the original vocabulary it +# should cover in its "base set" of tokens (akin to the lower and upper case characters of the +# English language). For almost all languages with small base token sets (<1000 tokens), this +# should be kept at its default of 1.0. For languages with larger vocabularies (say Japanese, +# Mandarin, Korean etc), the suggested value is 0.9995. +# +# --spe_sample_size: If the dataset is too large, consider using a sampled dataset indicated by a +# positive integer. By default, any negative value (default = -1) will use the entire dataset. +# +# --spe_train_extremely_large_corpus: When training a sentencepiece tokenizer on very large amounts of text, +# sometimes the tokenizer will run out of memory or wont be able to process so much data on RAM. +# At some point you might receive the following error - "Input corpus too large, try with +# train_extremely_large_corpus=true". If your machine has large amounts of RAM, it might still be possible +# to build the tokenizer using the above flag. Will silently fail if it runs out of RAM. +# +# --spe_max_sentencepiece_length: Limits the maximum length that any any SentencePiece subword can be. +# Using this will change the subword tokens generated. +# +# --log: Whether the script should display log messages + + +import argparse +import json +import logging +import os + +import tokenizers + +from nemo.collections.common.tokenizers.sentencepiece_tokenizer import create_spt_model + +parser = argparse.ArgumentParser(description='Create tokenizer') +group = parser.add_mutually_exclusive_group(required=True) +group.add_argument("--manifest", default=None, type=str, help='Comma separated list of manifest files') +group.add_argument("--data_file", default=None, help='data file from which to create tokenizer model') +parser.add_argument("--data_root", required=True, default=None, type=str, help='Output directory') +parser.add_argument("--vocab_size", default=1024, type=int, help='Vocabulary size') +parser.add_argument("--tokenizer", default="wpe", choices=["spe", "wpe"], help='Type of tokenization to perform') +parser.add_argument( + "--spe_type", + default="bpe", + choices=['bpe', 'unigram', 'char', 'word'], + help='Type of the SentencePiece model. Can be `bpe`, `unigram`, `char` or `word`.' + 'Used only if --tokenizer == `spe`', +) +parser.add_argument( + '--spe_character_coverage', + type=float, + default=1.0, + help="Character coverage percentage for SentencePiece tokenization. For languages " + "with large vocabulary, should be close to 0.9995, otherwise kept as 1.0", +) +parser.add_argument( + '--spe_sample_size', + type=int, + default=-1, + help="Samples the dataset by `sample_size` if positive integer, otherwise uses whole dataset", +) +parser.add_argument('--spe_train_extremely_large_corpus', action='store_true', help='') +parser.add_argument( + '--spe_max_sentencepiece_length', + type=int, + default=-1, + help='Limit the maximum number of tokens in each SentencePiece subword. ' + 'Must be a positive integer > 0. By default places no limit on subword length.', +) +parser.add_argument('--no_lower_case', dest='lower_case', action='store_false') +parser.add_argument("--log", action='store_true') +parser.set_defaults(log=False, lower_case=True, spe_train_extremely_large_corpus=False) +args = parser.parse_args() + + +def __build_document_from_manifests( + data_root: str, manifests: str, +): + if ',' in manifests: + manifests = manifests.split(',') + else: + manifests = [manifests] + + document_dir = os.path.join(data_root, 'text_corpus') + if not os.path.exists(document_dir): + os.makedirs(document_dir) + + document_path = os.path.join(document_dir, 'document.txt') + + if os.path.exists(document_path): + logging.info('Corpus already exists at path : %s', document_path) + return document_path + + num_lines = 0 + with open(document_path, 'w') as out_writer: + for manifest in manifests: + with open(manifest, 'r') as in_reader: + for line in in_reader: + item = json.loads(line) + text = item['text'] + + out_writer.write(text + '\n') + out_writer.flush() + + num_lines += 1 + + logging.info(f"Finished extracting manifest : {manifest}") + + logging.info("Finished extracting all manifests ! Number of sentences : {}".format(num_lines)) + return document_path + + +def __process_data( + text_path: str, + dst_folder: str, + vocab_size: int, + tokenizer_type: str, + spe_type: str, + spe_character_coverage: float, + spe_train_extremely_large_corpus: bool, + spe_sample_size: int, + spe_max_sentencepiece_length: int, + lower_case: bool, +): + """ + Converts flac to wav and build manifests's json + Args: + text_path: source with text lines + dst_folder: where wav files will be stored + vocab_size: vocabular size used in encoding the text + tokenizer_type: type of tokenization to perform - wpe or spe + spe_type: type of tokenization model used for spe. + spe_character_coverage: float value between 0 and 1 (as a percentage). For languages with a vast charset, + can be < 1.0, but for all other languages, it should be set as 1.0 + spe_sample_size: int, default of -1. If positive integer is used, samples the dataset + by given sample size. + spe_train_extremely_large_corpus: bool. If dataset is too large, and user has sufficient RAM, + this flag can be set to try to trained the tokenizer. Will silently fail if it runs out of RAM. + spe_max_sentencepiece_length: Limits the maximum length of the SentencePiece subword that can be constructed. + By default, no limit is placed. + lower_case: whether to tokenize with lower case character set only (for english) + + Returns: + """ + if tokenizer_type == 'spe': + if spe_max_sentencepiece_length > 0: + tokenizer_dir = os.path.join(dst_folder, 'tokenizer_{}_{}_v{}_max{}').format( + tokenizer_type, spe_type, vocab_size, spe_max_sentencepiece_length + ) + else: + tokenizer_dir = os.path.join(dst_folder, 'tokenizer_{}_{}_v{}').format( + tokenizer_type, spe_type, vocab_size + ) + + if not os.path.exists(tokenizer_dir): + os.makedirs(tokenizer_dir) + + if os.path.exists(os.path.join(tokenizer_dir, 'tokenizer.model')): + logging.warning("Model file already exists, overriding old model file !") + os.remove(os.path.join(tokenizer_dir, 'tokenizer.model')) + + tokenizer_path, vocab_path = create_spt_model( + data_file=text_path, + vocab_size=vocab_size, + sample_size=spe_sample_size, + do_lower_case=lower_case, + output_dir=tokenizer_dir, + tokenizer_type=spe_type, + character_coverage=spe_character_coverage, + train_extremely_large_corpus=spe_train_extremely_large_corpus, + max_sentencepiece_length=spe_max_sentencepiece_length, + ) + + else: + tokenizer_dir = os.path.join(dst_folder, 'tokenizer_{}_v{}').format(tokenizer_type, vocab_size) + + if not os.path.exists(tokenizer_dir): + os.makedirs(tokenizer_dir) + + tokenizer = tokenizers.BertWordPieceTokenizer(lowercase=lower_case) + + tokenizer.train(text_path, vocab_size=vocab_size) + tokenizer.save_model(tokenizer_dir) + + return tokenizer_dir + + +def main(): + data_root = args.data_root + manifests = args.manifest + data_file = args.data_file + vocab_size = args.vocab_size + tokenizer = args.tokenizer + spe_type = args.spe_type + spe_character_coverage = args.spe_character_coverage + spe_sample_size = args.spe_sample_size + spe_train_extremely_large_corpus = args.spe_train_extremely_large_corpus + spe_max_sentencepiece_length = args.spe_max_sentencepiece_length + lower_case = args.lower_case + + if not os.path.exists(data_root): + os.makedirs(data_root) + + if args.log: + logging.basicConfig(level=logging.INFO) + + if manifests: + text_corpus_path = __build_document_from_manifests(data_root, manifests) + else: + text_corpus_path = data_file + tokenizer_path = __process_data( + text_corpus_path, + data_root, + vocab_size, + tokenizer, + spe_type, + lower_case=lower_case, + spe_character_coverage=spe_character_coverage, + spe_sample_size=spe_sample_size, + spe_train_extremely_large_corpus=spe_train_extremely_large_corpus, + spe_max_sentencepiece_length=spe_max_sentencepiece_length, + ) + + print("Serialized tokenizer at location :", tokenizer_path) + logging.info('Done!') + + +if __name__ == "__main__": + main() diff --git a/tts/NeMo/scripts/voice_activity_detection/vad_overlap_posterior.py b/tts/NeMo/scripts/voice_activity_detection/vad_overlap_posterior.py new file mode 100644 index 0000000..0849a65 --- /dev/null +++ b/tts/NeMo/scripts/voice_activity_detection/vad_overlap_posterior.py @@ -0,0 +1,259 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import glob +import os +import time +from argparse import ArgumentParser +from itertools import repeat +from multiprocessing import Pool + +import numpy as np +import pandas as pd + + +""" +This script serves two purposes: + + 1) gen_overlap_seq: + Generate predictions with overlapping input segments by using the frame level prediction from NeMo/examples/asr/vad_infer.py. + Then a smoothing filter is applied to decide the label for a frame spanned by multiple segments. + + 2)gen_seg_table: + Converting frame level prediction to speech/no-speech segment in start and end times format. + +Usage: + +python vad_overlap_posterior.py --gen_overlap_seq --gen_seg_table --frame_folder= --method='median' --overlap=0.875 --num_workers=20 --threshold=0.8 + +""" + + +def gen_overlap_seq(frame_filepath, per_args): + """ + Given a frame level prediction, generate predictions with overlapping input segments by using it + Args: + frame_filepath : frame prediction file to be processed. + per_args: + method : Median or mean smoothing filter. + overlap : Amounts of overlap. + seg_len : Length of window for generating the frame. + shift_len : Amount of shift of window for generating the frame. + out_dir : Output dir of generated prediction. + """ + + try: + method = per_args['method'] + overlap = per_args['overlap'] + seg_len = per_args['seg_len'] + shift_len = per_args['shift_len'] + out_dir = per_args['out_dir'] + + frame = np.loadtxt(frame_filepath) + name = os.path.basename(frame_filepath).split(".frame")[0] + "." + method + overlap_filepath = os.path.join(out_dir, name) + + shift = int(shift_len / 0.01) # number of units of shift + seg = int((seg_len / 0.01 + 1)) # number of units of each window/segment + + jump_on_target = int(seg * (1 - overlap)) # jump on target generated sequence + jump_on_frame = int(jump_on_target / shift) # jump on input frame sequence + + if jump_on_frame < 1: + raise ValueError( + f"Note we jump over frame sequence to generate overlapping input segments. \n \ + Your input makes jump_on_fram={jump_on_frame} < 1 which is invalid because it cannot jump and will stuck.\n \ + Please try different seg_len, shift_len and overlap choices. \n \ + jump_on_target = int(seg * (1 - overlap)) \n \ + jump_on_frame = int(jump_on_frame/shift) " + ) + + target_len = int(len(frame) * shift) + + if method == 'mean': + preds = np.zeros(target_len) + pred_count = np.zeros(target_len) + + for i, og_pred in enumerate(frame): + if i % jump_on_frame != 0: + continue + start = i * shift + end = start + seg + preds[start:end] = preds[start:end] + og_pred + pred_count[start:end] = pred_count[start:end] + 1 + + preds = preds / pred_count + last_non_zero_pred = preds[pred_count != 0][-1] + preds[pred_count == 0] = last_non_zero_pred + + elif method == 'median': + preds = [[] for _ in range(target_len)] + for i, og_pred in enumerate(frame): + if i % jump_on_frame != 0: + continue + + start = i * shift + end = start + seg + for j in range(start, end): + if j <= target_len - 1: + preds[j].append(og_pred) + + preds = np.array([np.median(l) for l in preds]) + nan_idx = np.isnan(preds) + last_non_nan_pred = preds[~nan_idx][-1] + preds[nan_idx] = last_non_nan_pred + + else: + raise ValueError("method should be either mean or median") + + round_final = np.round(preds, 4) + np.savetxt(overlap_filepath, round_final, delimiter='\n') + print(f"Finished! {overlap_filepath}!") + + except Exception as e: + raise (e) + + +def gen_seg_table(frame_filepath, per_args): + + """ + Convert frame level prediction to speech/no-speech segment in start and end times format. + And save to csv file in rttm-like format + 0, 10, speech + 10,12, no-speech + Args: + frame_filepath : frame prediction file to be processed. + per_args : + threshold : threshold for prediction score (from 0 to 1). + shift_len : Amount of shift of window for generating the frame. + out_dir : Output dir of generated table/csv file. + """ + threshold = per_args['threshold'] + shift_len = per_args['shift_len'] + out_dir = per_args['out_dir'] + + print(f"process {frame_filepath}") + name = frame_filepath.split("/")[-1].rsplit(".", 1)[0] + + sequence = np.loadtxt(frame_filepath) + start = 0 + end = 0 + start_list = [0] + end_list = [] + state_list = [] + + for i in range(len(sequence) - 1): + current_sate = "non-speech" if sequence[i] <= threshold else "speech" + next_state = "non-speech" if sequence[i + 1] <= threshold else "speech" + if next_state != current_sate: + end = i * shift_len + shift_len # shift_len for handling joint + state_list.append(current_sate) + end_list.append(end) + + start = (i + 1) * shift_len + start_list.append(start) + + end_list.append((i + 1) * shift_len + shift_len) + state_list.append(current_sate) + + seg_table = pd.DataFrame({'start': start_list, 'end': end_list, 'vad': state_list}) + + save_name = name + ".txt" + save_path = os.path.join(out_dir, save_name) + seg_table.to_csv(save_path, sep='\t', index=False, header=False) + + +if __name__ == '__main__': + start = time.time() + parser = ArgumentParser() + parser.add_argument("--gen_overlap_seq", default=False, action='store_true') + parser.add_argument("--gen_seg_table", default=False, action='store_true') + parser.add_argument("--frame_folder", type=str, required=True) + parser.add_argument( + "--method", + type=str, + required=True, + help="Use mean/median for overlapped prediction. Use frame for gen_seg_table of frame prediction", + ) + parser.add_argument("--overlap_out_dir", type=str) + parser.add_argument("--table_out_dir", type=str) + parser.add_argument("--overlap", type=float, default=0.875, help="Overlap percentatge. Default is 0.875") + parser.add_argument("--seg_len", type=float, default=0.63) + parser.add_argument("--shift_len", type=float, default=0.01) + parser.add_argument("--threshold", type=float, default=0.5) + parser.add_argument("--num_workers", type=int, default=4) + args = parser.parse_args() + + if args.gen_overlap_seq: + p = Pool(processes=args.num_workers) + print("Generating predictions with overlapping input segments") + frame_filepathlist = glob.glob(args.frame_folder + "/*.frame") + + if not args.overlap_out_dir: + overlap_out_dir = "./overlap_smoothing_output" + "_" + args.method + "_" + str(args.overlap) + else: + overlap_out_dir = args.overlap_out_dir + if not os.path.exists(overlap_out_dir): + print(f"Creating output dir {overlap_out_dir}") + os.mkdir(overlap_out_dir) + + per_args = { + "method": args.method, + "overlap": args.overlap, + "seg_len": args.seg_len, + "shift_len": args.shift_len, + "out_dir": overlap_out_dir, + } + + p.starmap(gen_overlap_seq, zip(frame_filepathlist, repeat(per_args))) + p.close() + p.join() + + end = time.time() + print(f"Generate overlapped prediction takes {end-start} seconds!\n Save to {overlap_out_dir}") + + if args.gen_seg_table: + p = Pool(processes=args.num_workers) + print("Converting frame level prediction to speech/no-speech segment in start and end times format.") + + if args.gen_overlap_seq: + print("Use overlap prediction. Change if you want to use basic frame level prediction") + frame_filepath = overlap_out_dir + shift_len = 0.01 + else: + print("Use basic frame level prediction") + frame_filepath = args.frame_folder + shift_len = args.shift_len + + frame_filepathlist = glob.glob(frame_filepath + "/*." + args.method) + + if not args.table_out_dir: + table_out_dir = "table_output_" + str(args.threshold) + else: + table_out_dir = args.table_out_dir + if not os.path.exists(table_out_dir): + print(f"Creating rttm-like table output dir {table_out_dir}") + os.mkdir(table_out_dir) + + per_args = { + "threshold": args.threshold, + "shift_len": shift_len, + "out_dir": table_out_dir, + } + + p.starmap(gen_seg_table, zip(frame_filepathlist, repeat(per_args))) + p.close() + p.join() + + end = time.time() + print(f"Generate rttm-like table for {frame_filepath} takes {end-start} seconds!\n Save to {table_out_dir}") diff --git a/tts/NeMo/scripts/voice_activity_detection/vad_tune_threshold.py b/tts/NeMo/scripts/voice_activity_detection/vad_tune_threshold.py new file mode 100644 index 0000000..1486ae7 --- /dev/null +++ b/tts/NeMo/scripts/voice_activity_detection/vad_tune_threshold.py @@ -0,0 +1,58 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse + +import numpy as np + +from nemo.collections.asr.parts.utils.vad_utils import vad_tune_threshold_on_dev +from nemo.utils import logging + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "--threshold_range", help="range of threshold in list 'START,END,STEP' to be tuned on", required=True + ) + parser.add_argument( + "--vad_pred", help="Directory of vad predictions or a file contains the paths of them.", required=True + ) + parser.add_argument( + "--groundtruth_RTTM", + help="Directory of groundtruch rttm files or a file contains the paths of them", + type=str, + required=True, + ) + parser.add_argument( + "--vad_pred_method", + help="suffix of prediction file. Should be either in 'frame', 'mean' or 'median'", + required=True, + ) + parser.add_argument( + "--focus_metric", + help="metrics we care most when tuning threshold. Should be either in 'DetER', 'FA', 'MISS' ", + type=str, + default='DetER', + ) + args = parser.parse_args() + + try: + start, stop, step = [float(i) for i in args.threshold_range.split(",")] + thresholds = np.arange(start, stop, step) + except: + raise ValueError("Theshold input is invalid! Please enter it as a 'START,STOP,STEP' ") + + best_threhsold = vad_tune_threshold_on_dev( + thresholds, args.vad_pred, args.groundtruth_RTTM, args.vad_pred_method, args.focus_metric + ) + logging.info(f"Best threshold selected from {thresholds} is {best_threhsold}!") diff --git a/tts/NeMo/scripts/voice_activity_detection/write_long_audio_manifest.py b/tts/NeMo/scripts/voice_activity_detection/write_long_audio_manifest.py new file mode 100644 index 0000000..f450122 --- /dev/null +++ b/tts/NeMo/scripts/voice_activity_detection/write_long_audio_manifest.py @@ -0,0 +1,173 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import json +import logging +import multiprocessing +import os +from argparse import ArgumentParser +from itertools import repeat + +import librosa +import numpy as np + + +""" +This script is designed for inference of frame level Voice Activity Detection (VAD) + +This script serves three goals: + (1) Write audio files to manifest + (2) Split audio file for avoiding CUDA memory issue + (3) Take care of joint of seperate json line for an audio file + +Usage: +python write_long_audio_manifest.py --inp_dir= --manifest_name= --split_duration=300 --time_length=0.63 --num_worker=10 + +""" + + +def write_manifest(file, args_func): + """ + Given a list of files, write them to manifest with restrictions. + Args: + files : file to be processed + label : label for audio snippet. + split_duration : Max duration of each audio clip (each line in json) + time_length : Used for taking care of joint. + Length of window for generating the frame. + Returns: + res : list of generated metadata line of json for file + """ + + label = args_func['label'] + split_duration = args_func['split_duration'] + time_length = args_func['time_length'] + + res = [] + try: + sr = 16000 + x, _sr = librosa.load(file, sr=sr) + duration = librosa.get_duration(x, sr=sr) + + left = duration + current_offset = 0 + status = 'single' + + while left > 0: + if left <= split_duration: + if status == 'single': + write_duration = left + current_offset = 0 + else: + status = 'end' + write_duration = left + time_length + current_offset -= time_length + offset_inc = left + left = 0 + else: + if status == 'start' or status == 'next': + status = 'next' + else: + status = 'start' + + if status == 'start': + write_duration = split_duration + offset_inc = split_duration + else: + write_duration = split_duration + time_length + current_offset -= time_length + offset_inc = split_duration + time_length + + left -= split_duration + + metadata = { + 'audio_filepath': file, + 'duration': write_duration, + 'label': label, + 'text': '_', + 'offset': current_offset, + } + res.append(metadata) + + current_offset += offset_inc + + except Exception as e: + err_file = "error.log" + with open(err_file, 'w') as fout: + fout.write(file + ":" + str(e)) + + return res + + +def main(): + parser = ArgumentParser() + parser.add_argument("--inp_dir", type=str, required=True, help="(full path) folder of files to be processed") + parser.add_argument( + "--inp_list", type=str, help="(full path) a file contains NAME of files inside inp_dir to be processed" + ) + parser.add_argument( + "--out_dir", type=str, default=".", help="[Optional](full path) location to store generated json file" + ) + parser.add_argument("--manifest_name", type=str, required=True, help="name of generated json file") + parser.add_argument("--split_duration", type=int, required=True, help="max duration of each audio clip/line") + parser.add_argument( + "--time_length", type=float, default=0.63, help="[Optional] time length of segment, default is 0.63s" + ) + parser.add_argument("--num_workers", type=int, default=4, help="[Optional] number of workers for multiprocessing") + args = parser.parse_args() + + if not args.inp_list: + input_audios = [] + for root, dirs, files in os.walk(args.inp_dir): + for basename in files: + if basename.endswith('.wav'): + filename = os.path.join(root, basename) + input_audios.append(filename) + else: + name_list = np.loadtxt(args.inp_list, dtype='str') + input_audios = [os.path.join(args.inp_dir, name + ".wav") for name in name_list] + print(f"Number of wav files to be processed: {len(input_audios)}") + + output_path = os.path.join(args.out_dir, args.manifest_name + '.json') + print(f"Save generate manifest to {output_path}!") + if not os.path.exists(args.out_dir): + logging.info(f'Outdir {args.out_dir} does not exist. Creat directory.') + os.mkdir(args.out_dir) + if os.path.exists(output_path): + print(f"Manifest {output_path} exists! Overwriting") + os.remove(output_path) + + p = multiprocessing.Pool(processes=args.num_workers) + + args_func = { + 'label': 'infer', + 'split_duration': args.split_duration, + 'time_length': args.time_length, + } + + results = p.starmap(write_manifest, zip(input_audios, repeat(args_func))) + + with open(output_path, 'a') as fout: + for res in results: + for r in res: + json.dump(r, fout) + fout.write('\n') + fout.flush() + + p.close() + + print(f"Done! Save to {output_path}") + + +if __name__ == '__main__': + main() diff --git a/tts/NeMo/setup.cfg b/tts/NeMo/setup.cfg new file mode 100644 index 0000000..694e915 --- /dev/null +++ b/tts/NeMo/setup.cfg @@ -0,0 +1,36 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +[aliases] +test=pytest + +# durations=0 will display all tests execution time, sorted in ascending order starting from from the slowest one. +# -vv will also display tests with durration = 0.00s +[tool:pytest] +addopts = --verbose --pyargs --durations=0 +markers = + unit: marks unit test, i.e. testing a single, well isolated functionality (deselect with '-m "not unit"') + integration: marks test checking the elements when integrated into subsystems (deselect with '-m "not integration"') + system: marks test working at the highest integration level (deselect with '-m "not system"') + acceptance: marks test checking whether the developed product/model passes the user defined acceptance criteria (deselect with '-m "not acceptance"') + docs: mark tests related to documentation (deselect with '-m "not docs"') + skipduringci: marks tests that are skipped ci as they are addressed by Jenkins jobs but should be run to test user setups + pleasefixme: marks tests that are broken and need fixing + +[isort] +known_localfolder = nemo,tests +sections = FUTURE,STDLIB,THIRDPARTY,LOCALFOLDER +default_section = THIRDPARTY +#TODO tests/unit/core/test_deploy_export.py gets screwed by isort +skip = setup.py, docs/source/conf.py, nemo/utils/__init__.py, tests/unit/core/test_deploy_export.py diff --git a/tts/NeMo/setup.py b/tts/NeMo/setup.py new file mode 100644 index 0000000..77c8a56 --- /dev/null +++ b/tts/NeMo/setup.py @@ -0,0 +1,238 @@ +# ! /usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +"""Setup for pip package.""" + +import codecs +import os +import subprocess +from distutils import cmd as distutils_cmd +from distutils import log as distutils_log +from itertools import chain +import imp + +import setuptools + + +package_info = imp.load_source('package_info', 'nemo/package_info.py') +from package_info import ( + __contact_emails__, + __contact_names__, + __description__, + __download_url__, + __homepage__, + __keywords__, + __license__, + __package_name__, + __repository_url__, + __version__, +) + +if os.path.exists('nemo/README.md'): + with open("nemo/README.md", "r") as fh: + long_description = fh.read() + long_description_content_type = "text/markdown" + +elif os.path.exists('README.rst'): + # codec is used for consistent encoding + long_description = codecs.open( + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'README.rst'), 'r', 'utf-8', + ).read() + long_description_content_type = "text/x-rst" + +else: + long_description = 'See ' + __homepage__ + + +############################################################################### +# Dependency Loading # +# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # + + +def req_file(filename, folder="requirements"): + with open(os.path.join(folder, filename)) as f: + content = f.readlines() + # you may also want to remove whitespace characters + # Example: `\n` at the end of each line + return [x.strip() for x in content] + + +install_requires = req_file("requirements.txt") + +extras_require = { + # User packages + 'test': req_file("requirements_test.txt"), + # Collections Packages + 'asr': req_file("requirements_asr.txt"), + 'cv': req_file("requirements_cv.txt"), + 'nlp': req_file("requirements_nlp.txt"), + 'tts': req_file("requirements_tts.txt"), + 'text_processing': req_file("requirements_text_processing.txt"), +} + +extras_require['all'] = list(chain(extras_require.values())) + +# TTS depends on ASR +extras_require['tts'] = list(chain([extras_require['tts'], extras_require['asr']])) + +tests_requirements = extras_require["test"] + + +############################################################################### +# Code style checkers # +# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # + + +class StyleCommand(distutils_cmd.Command): + __LINE_WIDTH = 119 + __ISORT_BASE = ( + 'isort ' + # These two lines makes isort compatible with black. + '--multi-line=3 --trailing-comma --force-grid-wrap=0 ' + f'--use-parentheses --line-width={__LINE_WIDTH} -rc -ws' + ) + __BLACK_BASE = f'black --skip-string-normalization --line-length={__LINE_WIDTH}' + description = 'Checks overall project code style.' + user_options = [ + ('scope=', None, 'Folder of file to operate within.'), + ('fix', None, 'True if tries to fix issues in-place.'), + ] + + def __call_checker(self, base_command, scope, check): + command = list(base_command) + + command.append(scope) + + if check: + command.extend(['--check', '--diff']) + + self.announce( + msg='Running command: %s' % str(' '.join(command)), level=distutils_log.INFO, + ) + + return_code = subprocess.call(command) + + return return_code + + def _isort(self, scope, check): + return self.__call_checker(base_command=self.__ISORT_BASE.split(), scope=scope, check=check,) + + def _black(self, scope, check): + return self.__call_checker(base_command=self.__BLACK_BASE.split(), scope=scope, check=check,) + + def _pass(self): + self.announce(msg='\033[32mPASS\x1b[0m', level=distutils_log.INFO) + + def _fail(self): + self.announce(msg='\033[31mFAIL\x1b[0m', level=distutils_log.INFO) + + # noinspection PyAttributeOutsideInit + def initialize_options(self): + self.scope = '.' + self.fix = '' + + def run(self): + scope, check = self.scope, not self.fix + isort_return = self._isort(scope=scope, check=check) + black_return = self._black(scope=scope, check=check) + + if isort_return == 0 and black_return == 0: + self._pass() + else: + self._fail() + exit(isort_return if isort_return != 0 else black_return) + + def finalize_options(self): + pass + + +############################################################################### + +setuptools.setup( + name=__package_name__, + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version=__version__, + description=__description__, + long_description=long_description, + long_description_content_type=long_description_content_type, + # The project's main homepage. + url=__repository_url__, + download_url=__download_url__, + # Author details + author=__contact_names__, + author_email=__contact_emails__, + # maintainer Details + maintainer=__contact_names__, + maintainer_email=__contact_emails__, + # The licence under which the project is released + license=__license__, + classifiers=[ + # How mature is this project? Common values are + # 1 - Planning + # 2 - Pre-Alpha + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + # 6 - Mature + # 7 - Inactive + 'Development Status :: 4 - Beta', + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Intended Audience :: Information Technology', + # Indicate what your project relates to + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Mathematics', + 'Topic :: Scientific/Engineering :: Image Recognition', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Utilities', + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: Apache Software License', + # Supported python versions + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + # Additional Setting + 'Environment :: Console', + 'Natural Language :: English', + 'Operating System :: OS Independent', + ], + packages=setuptools.find_packages(), + install_requires=install_requires, + setup_requires=['pytest-runner'], + tests_require=tests_requirements, + # List additional groups of dependencies here (e.g. development + # dependencies). You can install these using the following syntax, + # $ pip install -e ".[all]" + # $ pip install nemo_toolkit[all] + extras_require=extras_require, + # Add in any packaged data. + include_package_data=True, + exclude=['tools', 'tests'], + package_data={'': ['*.tsv', '*.txt', '*.far']}, + zip_safe=False, + # PyPI package information. + keywords=__keywords__, + # Custom commands. + cmdclass={'style': StyleCommand}, +) diff --git a/tts/NeMo/tests/__init__.py b/tts/NeMo/tests/__init__.py new file mode 100644 index 0000000..9e32500 --- /dev/null +++ b/tts/NeMo/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/tests/collections/asr/numba/rnnt_loss/test_rnnt_pytorch.py b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/test_rnnt_pytorch.py new file mode 100644 index 0000000..c8f5502 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/test_rnnt_pytorch.py @@ -0,0 +1,256 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import pytest +import torch + +from nemo.collections.asr.parts.numba.rnnt_loss.rnnt_numpy import RNNTLoss as RNNTLoss_Numpy +from nemo.collections.asr.parts.numba.rnnt_loss.rnnt_pytorch import RNNTLossNumba +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ + +DEVICES = ['cpu'] + +if torch.cuda.is_available(): + DEVICES.append('cuda') + + +def wrap_and_call(fn, acts, labels, device): + acts = torch.FloatTensor(acts) + if 'cuda' in device: + acts = acts.cuda() + acts.requires_grad = True + + lengths = [acts.shape[1]] * acts.shape[0] + label_lengths = [len(l) for l in labels] + labels = torch.IntTensor(labels) + lengths = torch.IntTensor(lengths) + label_lengths = torch.IntTensor(label_lengths) + if 'cuda' in device: + labels = labels.cuda() + lengths = lengths.cuda() + label_lengths = label_lengths.cuda() + + costs = fn(acts, labels, lengths, label_lengths) + cost = torch.sum(costs) + cost.backward() + return costs.data.cpu().numpy(), acts.grad.data.cpu().numpy() + + +class TestRNNTLossPytorch: + @pytest.mark.unit + @pytest.mark.parametrize('device', DEVICES) + def test_case_small(self, device): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + acts = np.array( + [ + [ + [[0.1, 0.6, 0.1, 0.1, 0.1], [0.1, 0.1, 0.6, 0.1, 0.1], [0.1, 0.1, 0.2, 0.8, 0.1]], + [[0.1, 0.6, 0.1, 0.1, 0.1], [0.1, 0.1, 0.2, 0.1, 0.1], [0.7, 0.1, 0.2, 0.1, 0.1]], + ] + ] + ) + labels = [[1, 2]] + + fn_pt = RNNTLossNumba(blank=0, reduction='sum') + pt_cost, pt_grads = wrap_and_call(fn_pt, acts, labels, device) + + fn_np = RNNTLoss_Numpy() + np_cost, np_grads = wrap_and_call(fn_np, acts, labels, device) + + expected_cost = 4.495666 + expected_grads = np.array( + [ + [ + [ + [-0.13116688, -0.3999269, 0.17703125, 0.17703125, 0.17703125], + [-0.18572757, 0.12247056, -0.18168412, 0.12247056, 0.12247056], + [-0.32091254, 0.06269141, 0.06928472, 0.12624499, 0.06269141], + ], + [ + [0.05456069, -0.21824276, 0.05456069, 0.05456069, 0.05456069], + [0.12073959, 0.12073959, -0.48295835, 0.12073959, 0.12073959], + [-0.6925882, 0.16871116, 0.18645467, 0.16871116, 0.16871116], + ], + ] + ] + ) + assert np.allclose(pt_cost, expected_cost, rtol=1e-6), "small_test costs mismatch." + assert np.allclose(pt_grads, expected_grads), "small_test gradient mismatch." + + assert np.allclose(pt_cost, np_cost, rtol=1e-6), "small_test costs mismatch." + assert np.allclose(pt_grads, np_grads), "small_test gradient mismatch." + + @pytest.mark.unit + @pytest.mark.parametrize('device', DEVICES) + def test_case_small_random(self, device): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + rng = np.random.RandomState(0) + acts = rng.randn(1, 4, 3, 3) + labels = [[1, 2]] + + fn_pt = RNNTLossNumba(blank=0, reduction='sum') + pt_cost, pt_grads = wrap_and_call(fn_pt, acts, labels, device) + + fn_np = RNNTLoss_Numpy() + np_cost, np_grads = wrap_and_call(fn_np, acts, labels, device) + + assert np.allclose(pt_cost, np_cost, rtol=1e-6), "small_random_test costs mismatch." + assert np.allclose(pt_grads, np_grads), "small_random_test gradient mismatch." + + @pytest.mark.unit + @pytest.mark.parametrize('device', DEVICES) + def big_test(self, device): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # minibatch x T x U x alphabet_size + activations = [ + [ + [ + [0.06535690384862791, 0.7875301411923206, 0.08159176605666074], + [0.5297155426466327, 0.7506749639230854, 0.7541348379087998], + [0.6097641124736383, 0.8681404965673826, 0.6225318186056529], + ], + [ + [0.6685222872103057, 0.8580392805336061, 0.16453892311765583], + [0.989779515236694, 0.944298460961015, 0.6031678586829663], + [0.9467833543605416, 0.666202507295747, 0.28688179752461884], + ], + [ + [0.09418426230195986, 0.3666735970751962, 0.736168049462793], + [0.1666804425271342, 0.7141542198635192, 0.3993997272216727], + [0.5359823524146038, 0.29182076440286386, 0.6126422611507932], + ], + [ + [0.3242405528768486, 0.8007644367291621, 0.5241057606558068], + [0.779194617063042, 0.18331417220174862, 0.113745182072432], + [0.24022162381327106, 0.3394695622533106, 0.1341595066017014], + ], + ], + [ + [ + [0.5055615569388828, 0.051597282072282646, 0.6402903936686337], + [0.43073311517251, 0.8294731834714112, 0.1774668847323424], + [0.3207001991262245, 0.04288308912457006, 0.30280282975568984], + ], + [ + [0.6751777088333762, 0.569537369330242, 0.5584738347504452], + [0.08313242153985256, 0.06016544344162322, 0.10795752845152584], + [0.7486153608562472, 0.943918041459349, 0.4863558118797222], + ], + [ + [0.4181986264486809, 0.6524078485043804, 0.024242983423721887], + [0.13458171554507403, 0.3663418070512402, 0.2958297395361563], + [0.9236695822497084, 0.6899291482654177, 0.7418981733448822], + ], + [ + [0.25000547599982104, 0.6034295486281007, 0.9872887878887768], + [0.5926057265215715, 0.8846724004467684, 0.5434495396894328], + [0.6607698886038497, 0.3771277082495921, 0.3580209022231813], + ], + ], + ] + + expected_costs = [4.2806528590890736, 3.9384369822503591] + expected_grads = [ + [ + [ + [-1.86843902e-01, -6.25548810e-02, 2.49398798e-01], + [-2.03376666e-01, 2.02399328e-01, 9.77333169e-04], + [-1.41016081e-01, 7.91234672e-02, 6.18926100e-02], + ], + [ + [-1.15517676e-02, -8.12802389e-02, 9.28319991e-02], + [-1.54257029e-01, 2.29432687e-01, -7.51756504e-02], + [-2.46593088e-01, 1.46404594e-01, 1.00188486e-01], + ], + [ + [-1.29182907e-02, -6.15932420e-02, 7.45115355e-02], + [-5.59857301e-02, 2.19830811e-01, -1.63845062e-01], + [-4.97626871e-01, 2.09239945e-01, 2.88386941e-01], + ], + [ + [1.36048580e-02, -3.02196294e-02, 1.66147724e-02], + [1.13924511e-01, 6.27811998e-02, -1.76705718e-01], + [-6.67078257e-01, 3.67658824e-01, 2.99419403e-01], + ], + ], + [ + [ + [-3.56343776e-01, -5.53474613e-02, 4.11691219e-01], + [-9.69219357e-02, 2.94591039e-02, 6.74628317e-02], + [-6.35175705e-02, 2.76544970e-02, 3.58630717e-02], + ], + [ + [-1.54499024e-01, -7.39420280e-02, 2.28441030e-01], + [-1.66789949e-01, -8.78955179e-05, 1.66877866e-01], + [-1.72369644e-01, 1.05565332e-01, 6.68043196e-02], + ], + [ + [2.38748826e-02, -1.18255816e-01, 9.43809375e-02], + [-1.04707085e-01, -1.08934477e-01, 2.13641584e-01], + [-3.69844258e-01, 1.80118099e-01, 1.89726159e-01], + ], + [ + [2.57137045e-02, -7.94617534e-02, 5.37480488e-02], + [1.22328237e-01, -2.38788679e-01, 1.16460443e-01], + [-5.98686993e-01, 3.02203178e-01, 2.96483815e-01], + ], + ], + ] + + activations = np.array(activations) + labels = [[1, 2], [1, 1]] + + fn_pt = RNNTLossNumba(blank=0, reduction='sum') + pt_costs, pt_grads = wrap_and_call(fn_pt, activations, labels, device) + + fn_np = RNNTLoss_Numpy() + np_costs, np_grads = wrap_and_call(fn_np, activations, labels, device) + + assert np.allclose(pt_costs, sum(expected_costs)), "big_test average costs mismatch." + assert np.allclose(pt_grads, expected_grads, rtol=1e-3), "big_test grads for average cost mismatch." + + assert np.allclose(pt_costs, np_costs), "big_test average costs mismatch." + assert np.allclose(pt_grads, np_grads, rtol=1e-3), "big_test grads for average cost mismatch." + + @pytest.mark.unit + @pytest.mark.parametrize('device', DEVICES) + def test_case_large_random(self, device): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + rng = np.random.RandomState(0) + acts = rng.randn(4, 8, 11, 5) + labels = [ + [1, 2, 4, 3, 2, 2, 1, 1, 1, 1], + [3, 2, 2, 3, 4, 1, 1, 1, 1, 1], + [4, 4, 1, 2, 1, 3, 4, 3, 1, 2], + [1, 1, 2, 1, 2, 3, 3, 1, 1, 1], + ] + + fn_pt = RNNTLossNumba(blank=0, reduction='sum') + pt_cost, pt_grads = wrap_and_call(fn_pt, acts, labels, device) + + fn_np = RNNTLoss_Numpy() + np_cost, np_grads = wrap_and_call(fn_np, acts, labels, device) + + assert np.allclose(pt_cost, np_cost, atol=1e-5, rtol=1e-3), "large_random_test costs mismatch." + assert np.allclose(pt_grads, np_grads, atol=1e-5, rtol=1e-3), "large_random_test gradient mismatch." + + +if __name__ == "__main__": + pytest.main([__file__]) diff --git a/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_gpu_rnnt_kernel.py b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_gpu_rnnt_kernel.py new file mode 100644 index 0000000..a0cb84c --- /dev/null +++ b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_gpu_rnnt_kernel.py @@ -0,0 +1,169 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import pytest +import torch +from numba import cuda + +from nemo.collections.asr.parts.numba.rnnt_loss import rnnt_numpy +from nemo.collections.asr.parts.numba.rnnt_loss.rnnt_pytorch import certify_inputs +from nemo.collections.asr.parts.numba.rnnt_loss.utils.cuda_utils import gpu_rnnt_kernel, reduce +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ + + +def log_softmax(x, axis=-1): + x = torch.from_numpy(x) # zero-copy + x = torch.log_softmax(x, axis) + x = x.numpy() + return x + + +class TestRNNTCUDAKernels: + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Reductions can only be run when CUDA is available") + @pytest.mark.unit + def test_compute_alphas_kernel(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + random = np.random.RandomState(0) + original_shape = [1, 5, 11, 3] + B, T, U, V = original_shape + + # Numpy kernel + x = random.randn(*original_shape) + labels = np.array([[1, 1, 1, 2, 2, 2, 1, 2, 2, 1]]) # [1, 10] + label_len = len(labels[0]) + 1 + blank_idx = 0 + + x_np = log_softmax(x, axis=-1) + ground_alphas, ground_log_likelihood = rnnt_numpy.forward_pass( + x_np[0, :, :label_len, :], labels[0, : label_len - 1], blank_idx + ) + + # Pytorch kernel + device = torch.device('cuda') + if hasattr(cuda, 'external_stream'): + stream = cuda.external_stream(torch.cuda.current_stream(device).cuda_stream) + else: + stream = cuda.default_stream() + + x_c = torch.tensor(x, device=device, dtype=torch.float32) + labels_c = torch.tensor(labels, device=device, dtype=torch.int32) + + # Allocate workspace memory + denom = torch.zeros(B * T * U, device=device, dtype=x_c.dtype) + alphas = torch.zeros(B * T * U, device=device, dtype=x_c.dtype) + llForward = torch.zeros(B, device=device, dtype=x_c.dtype) + input_lengths = torch.tensor([T], dtype=torch.int32, device=device) + label_lengths = torch.tensor([len(labels[0])], dtype=torch.int32, device=device) + + # certify input data + certify_inputs(x_c, labels_c, input_lengths, label_lengths) + + # flatten activation tensor (for pointer based indexing) + x_c = x_c.view([-1]) + + # call kernel + # log softmax reduction + reduce.reduce_max(x_c, denom, rows=V, cols=B * T * U, minus=False, stream=stream) + reduce.reduce_exp(x_c, denom, rows=V, cols=B * T * U, minus=True, stream=stream) + + # alpha kernel + gpu_rnnt_kernel.compute_alphas_kernel[B, U, stream, 0]( + x_c, denom, alphas, llForward, input_lengths, label_lengths, labels_c, B, T, U, V, blank_idx, + ) + + # sync kernel + stream.synchronize() + + # reshape alphas + alphas = alphas.view([B, T, U]) + diff = ground_alphas - alphas[0].cpu().numpy() + + assert np.abs(diff).mean() <= 1e-5 + assert np.square(diff).mean() <= 1e-10 + + ll_diff = ground_log_likelihood - llForward[0].cpu().numpy() + + assert np.abs(ll_diff).mean() <= 1e-5 + assert np.square(ll_diff).mean() <= 1e-10 + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Reductions can only be run when CUDA is available") + @pytest.mark.unit + def test_compute_betas_kernel(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + random = np.random.RandomState(0) + original_shape = [1, 5, 11, 3] + B, T, U, V = original_shape + + # Numpy kernel + x = random.randn(*original_shape) + labels = np.array([[1, 1, 1, 2, 2, 2, 1, 2, 2, 1]]) # [1, 10] + label_len = len(labels[0]) + 1 + blank_idx = 0 + + x_np = log_softmax(x, axis=-1) + ground_alphas, ground_log_likelihood = rnnt_numpy.backward_pass( + x_np[0, :, :label_len, :], labels[0, : label_len - 1], blank_idx + ) + + # Pytorch kernel + device = torch.device('cuda') + if hasattr(cuda, 'external_stream'): + stream = cuda.external_stream(torch.cuda.current_stream(device).cuda_stream) + else: + stream = cuda.default_stream() + + x_c = torch.tensor(x, device=device, dtype=torch.float32) + labels_c = torch.tensor(labels, device=device, dtype=torch.int32) + + # Allocate workspace memory + denom = torch.zeros(B * T * U, device=device, dtype=x_c.dtype) + betas = torch.zeros(B * T * U, device=device, dtype=x_c.dtype) + llBackward = torch.zeros(B, device=device, dtype=x_c.dtype) + input_lengths = torch.tensor([T], dtype=torch.int32, device=device) + label_lengths = torch.tensor([len(labels[0])], dtype=torch.int32, device=device) + + # certify input data + certify_inputs(x_c, labels_c, input_lengths, label_lengths) + + # flatten activation tensor (for pointer based indexing) + x_c = x_c.view([-1]) + + # call kernel + # log softmax reduction + reduce.reduce_max(x_c, denom, rows=V, cols=B * T * U, minus=False, stream=stream) + reduce.reduce_exp(x_c, denom, rows=V, cols=B * T * U, minus=True, stream=stream) + + # beta kernel + gpu_rnnt_kernel.compute_betas_kernel[B, U, stream, 0]( + x_c, denom, betas, llBackward, input_lengths, label_lengths, labels_c, B, T, U, V, blank_idx, + ) + + # sync kernel + stream.synchronize() + + # reshape alphas + betas = betas.view([B, T, U]) + diff = ground_alphas - betas[0].cpu().numpy() + + assert np.abs(diff).mean() <= 1e-5 + assert np.square(diff).mean() <= 1e-10 + + ll_diff = ground_log_likelihood - llBackward[0].cpu().numpy() + + assert np.abs(ll_diff).mean() <= 1e-5 + assert np.square(ll_diff).mean() <= 1e-10 diff --git a/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_reduce.py b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_reduce.py new file mode 100644 index 0000000..7c2ba6a --- /dev/null +++ b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_reduce.py @@ -0,0 +1,86 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import pytest +from numba import cuda + +from nemo.collections.asr.parts.numba.rnnt_loss.utils.cuda_utils import reduce +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ + + +class TestRNNTCUDAReductions: + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Reductions can only be run when CUDA is available") + @pytest.mark.unit + def test_reduce_max(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + random = np.random.RandomState(0) + original_shape = [1, 5, 4, 3] + x = random.randn(*original_shape).reshape([-1]) + dx = random.randn(*x.shape) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + dx_c = cuda.to_device(dx, stream=stream) + + # call kernel + cols = np.prod(original_shape[:3]) + reduce.reduce_max(x_c, dx_c, rows=original_shape[-1], cols=cols, minus=False, stream=stream) + + # sync kernel + stream.synchronize() + + dx_result = dx_c.copy_to_host(stream=stream) + del x_c, dx_c + + # collect results in first [B * T * U] values; for all V + assert np.abs(dx_result[cols:] - dx[cols:]).sum() <= 1e-7 + # make sure dx_result updates the [B * T * U] values + assert np.abs(dx_result[:cols] - dx[:cols]).sum() > 0 + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Reductions can only be run when CUDA is available") + @pytest.mark.unit + def test_reduce_exp(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + random = np.random.RandomState(0) + original_shape = [1, 5, 4, 2] + x = random.randn(*original_shape).reshape([-1]) + dx = np.zeros_like(x) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + dx_c = cuda.to_device(dx, stream=stream) + + # call kernel + cols = np.prod(original_shape[:3]) + reduce.reduce_exp(x_c, dx_c, rows=original_shape[-1], cols=cols, minus=False, stream=stream) + + # sync kernel + stream.synchronize() + + dx_result = dx_c.copy_to_host(stream=stream) + del x_c, dx_c + + # collect results in first [B * T * U] values; for all V + assert (dx_result[cols:] - dx[cols:]).sum() <= 1e-7 + + # make sure dx_result updates the [B * T * U] values + assert np.abs(dx_result[:cols] - dx[:cols]).sum() > 0 + + +if __name__ == '__main__': + pytest.main([__file__]) diff --git a/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_rnnt_helper.py b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_rnnt_helper.py new file mode 100644 index 0000000..d054bae --- /dev/null +++ b/tts/NeMo/tests/collections/asr/numba/rnnt_loss/utils/test_rnnt_helper.py @@ -0,0 +1,319 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import pytest +from numba import cuda + +from nemo.collections.asr.parts.numba.rnnt_loss.utils import global_constants, rnnt_helper +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ + + +class TestRNNTHelper: + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_log_sum_exp(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x, y): + x_pos = cuda.grid(1) + if x_pos < x.shape[0] and x_pos < y.shape[0]: + x[x_pos] = rnnt_helper.log_sum_exp(x[x_pos], y[x_pos]) + + x = np.zeros([8]) # np.random.rand(8192) + y = np.ones([8]) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + y_c = cuda.to_device(y, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c, y_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c, y_c + + assert (x_new.sum() - 10.506093500145782) <= 1e-5 + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_log_sum_exp_neg_inf(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x, y): + x_pos = cuda.grid(1) + if x_pos < x.shape[0] and x_pos < y.shape[0]: + x[x_pos] = rnnt_helper.log_sum_exp(x[x_pos], y[x_pos]) + + x = np.asarray([global_constants.FP32_NEG_INF] * 8) + y = np.ones([len(x)]) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + y_c = cuda.to_device(y, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c, y_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c, y_c + + assert np.allclose(x_new, np.ones_like(x_new), atol=1e-5) + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_div_up(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x, y): + x_pos = cuda.grid(1) + if x_pos < x.shape[0] and x_pos < y.shape[0]: + x[x_pos] = rnnt_helper.div_up(x[x_pos], y[x_pos]) + + x = np.full([8], fill_value=10) # np.random.rand(8192) + y = np.full([8], fill_value=2) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + y_c = cuda.to_device(y, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c, y_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c, y_c + + for i in range(len(x_new)): + assert x_new[i] == ((10 + 2 - 1) // 2) + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_add(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x, y): + x_pos = cuda.grid(1) + if x_pos < x.shape[0] and x_pos < y.shape[0]: + x[x_pos] = rnnt_helper.add(x[x_pos], y[x_pos]) + + x = np.full([8], fill_value=10) # np.random.rand(8192) + y = np.full([8], fill_value=2) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + y_c = cuda.to_device(y, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c, y_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c, y_c + + for i in range(len(x_new)): + assert x_new[i] == 12 + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_maximum(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x, y): + x_pos = cuda.grid(1) + if x_pos < x.shape[0] and x_pos < y.shape[0]: + x[x_pos] = rnnt_helper.maximum(x[x_pos], y[x_pos]) + + x = np.full([8], fill_value=10) # np.random.rand(8192) + y = np.full([8], fill_value=2) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + y_c = cuda.to_device(y, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c, y_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c, y_c + + for i in range(len(x_new)): + assert x_new[i] == 10 + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_identity(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x): + x_pos = cuda.grid(1) + if x_pos < x.shape[0]: + x[x_pos] = rnnt_helper.identity(x[x_pos]) + + x = np.full([8], fill_value=10) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c + + for i in range(len(x_new)): + assert x_new[i] == x[i] + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_negate(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x): + x_pos = cuda.grid(1) + if x_pos < x.shape[0]: + x[x_pos] = rnnt_helper.negate(x[x_pos]) + + x = np.full([8], fill_value=10) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c + + for i in range(len(x_new)): + assert x_new[i] == -x[i] + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_exponential(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x): + x_pos = cuda.grid(1) + if x_pos < x.shape[0]: + x[x_pos] = rnnt_helper.exponential(x[x_pos]) + + x = np.random.rand(8) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c + + y = np.exp(x) + for i in range(len(x_new)): + assert (x_new[i] - y[i]) < 1e-4 + + @pytest.mark.skipif(not cuda.is_available(), reason="CUDA Helpers can only be run when CUDA is available") + @pytest.mark.unit + def test_log_plus(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + # wrapper kernel for device function that is tested + @cuda.jit + def _kernel(x, y): + x_pos = cuda.grid(1) + if x_pos < x.shape[0] and x_pos < y.shape[0]: + x[x_pos] = rnnt_helper.log_plus(x[x_pos], y[x_pos]) + + x = np.full([8], fill_value=10.0) # np.random.rand(8192) + y = np.full([8], fill_value=2.0) # np.random.rand(8192) + + stream = cuda.stream() + x_c = cuda.to_device(x, stream=stream) + y_c = cuda.to_device(y, stream=stream) + + # call kernel + threads_per_block = global_constants.threads_per_block() + blocks_per_grid = (x.shape[0] + threads_per_block - 1) // threads_per_block + _kernel[blocks_per_grid, threads_per_block, stream](x_c, y_c) + + # sync kernel + stream.synchronize() + + x_new = x_c.copy_to_host(stream=stream) + del x_c, y_c + + z = np.log1p(np.exp(-np.fabs(x - y))) + np.maximum(x, y) + + for i in range(len(x_new)): + assert x_new[i] == z[i] + + +if __name__ == '__main__': + pytest.main([__file__]) diff --git a/tts/NeMo/tests/collections/asr/numba/spec_augment/test_spec_aug_numba.py b/tts/NeMo/tests/collections/asr/numba/spec_augment/test_spec_aug_numba.py new file mode 100644 index 0000000..17b6d6c --- /dev/null +++ b/tts/NeMo/tests/collections/asr/numba/spec_augment/test_spec_aug_numba.py @@ -0,0 +1,252 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import torch +from omegaconf import OmegaConf + +from nemo.collections.asr.parts.numba.spec_augment import spec_aug_numba +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ + + +def get_cfg(seed=0, dtype='float32'): + # fmt: off + cfg = OmegaConf.create( + dict(b=2, f=80, t=20, device='cuda', + freq_masks=2, time_masks=2, freq_width=27, time_width=0.05, mask_value=0.0, + seed=seed, dtype=dtype) + ) + # fmt: on + return cfg + + +# fmt: off +def prepare_data(b, f, t, device='cuda', freq_masks=0, time_masks=0, freq_width=10, time_width=0.1, + seed=0, dtype='float32', + **kwargs): + torch.manual_seed(seed) + + if dtype == 'float16': + dtype = torch.float16 + else: + dtype = torch.float + + x = torch.randn([b, f, t], dtype=dtype, device=device) + x_len = torch.randint(t, size=[b], device=x.device) + + sh = x.shape + bs = sh[0] + + if isinstance(time_width, int): + adaptive_temporal_width = False + else: + if time_width > 1.0 or time_width < 0.0: + raise ValueError('If `time_width` is a float value, must be in range [0, 1]') + + adaptive_temporal_width = True + + if adaptive_temporal_width: + time_width = max(1, int(sh[2] * time_width)) + else: + time_width = time_width + + # Construct the freq and time masks as well as start positions + if freq_masks > 0: + freq_starts = torch.randint(0, sh[1] - freq_width + 1, size=[bs, freq_masks], device=x.device) + freq_lengths = torch.randint(0, freq_width + 1, size=[bs, freq_masks], device=x.device) + else: + freq_starts = torch.zeros([bs, 1], dtype=torch.int64, device=x.device) + freq_lengths = torch.zeros([bs, 1], dtype=torch.int64, device=x.device) + + if time_masks > 0: + time_starts = torch.randint(0, sh[2] - time_width + 1, size=[bs, time_masks], device=x.device) + time_lengths = torch.randint(0, time_width + 1, size=[bs, time_masks], device=x.device) + else: + time_starts = torch.zeros([bs, 1], dtype=torch.int64, device=x.device) + time_lengths = torch.zeros([bs, 1], dtype=torch.int64, device=x.device) + + output = dict( + x=x, + x_len=x_len, + freq_starts=freq_starts, + freq_lengths=freq_lengths, + time_starts=time_starts, + time_lengths=time_lengths, + sh=sh, + ) + return output +# fmt: on + + +def launch_kernel(data, cfg): + # Launch CUDA kernel + # fmt: off + data['x'] = spec_aug_numba.launch_spec_augment_kernel( + x=data['x'], x_len=data['x_len'], + freq_starts=data['freq_starts'], freq_lengths=data['freq_lengths'], + time_starts=data['time_starts'], time_lengths=data['time_lengths'], + freq_masks=cfg.freq_masks, time_masks=cfg.time_masks, mask_value=cfg.mask_value + ) + # fmt: on + + +def freq_mask_check(x, x_len, f_start, f_len, mask_value, bidx): + check_result = True + for fidx in range(f_start, f_start + f_len): + if not (x[bidx, fidx, :] == mask_value).all(): + check_result = False + break + assert check_result + + +def time_mask_check(x, x_len, t_start, t_len, mask_value, bidx): + check_result = True + for tidx in range(t_start, t_start + t_len): + if tidx >= x_len[bidx]: + # this sample has smaller length than the time index of mask, ignore + continue + + if not (x[bidx, :, tidx] == mask_value).all(): + check_result = False + break + assert check_result + + +class TestSpecAugmentNumba: + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + @pytest.mark.parametrize('dtype', ['float16', 'float32']) + def test_spec_aug_kernel(self, dtype): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + cfg = get_cfg(seed=0, dtype=dtype) + cfg.freq_masks = 2 + cfg.time_masks = 10 + + data = prepare_data(**cfg) + + launch_kernel(data, cfg) + x, x_len, sh = data['x'], data['x_len'], data['sh'] + + # Assert freq masks are correct + for bidx in range(sh[0]): + for f_start, f_len in zip(data['freq_starts'][bidx], data['freq_lengths'][bidx]): + freq_mask_check(x, x_len, f_start, f_len, mask_value=cfg.mask_value, bidx=bidx) + + # Assert time masks are correct + for bidx in range(sh[0]): + for t_start, t_len in zip(data['time_starts'][bidx], data['time_lengths'][bidx]): + time_mask_check(x, x_len, t_start, t_len, mask_value=cfg.mask_value, bidx=bidx) + + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + def test_spec_aug_kernel_mask_value(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + cfg = get_cfg(seed=0) + cfg.freq_masks = 2 + cfg.time_masks = 10 + cfg.mask_value = -1.0 + + data = prepare_data(**cfg) + + launch_kernel(data, cfg) + x, x_len, sh = data['x'], data['x_len'], data['sh'] + + # Assert freq masks are correct + for bidx in range(sh[0]): + for f_start, f_len in zip(data['freq_starts'][bidx], data['freq_lengths'][bidx]): + freq_mask_check(x, x_len, f_start, f_len, mask_value=cfg.mask_value, bidx=bidx) + + # Assert time masks are correct + for bidx in range(sh[0]): + for t_start, t_len in zip(data['time_starts'][bidx], data['time_lengths'][bidx]): + time_mask_check(x, x_len, t_start, t_len, mask_value=cfg.mask_value, bidx=bidx) + + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + def test_spec_aug_kernel_grad(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + cfg = get_cfg(seed=0) + cfg.freq_masks = 2 + cfg.time_masks = 10 + + data = prepare_data(**cfg) + + launch_kernel(data, cfg) + + result = data['x'] # inplace modification via kernel + y = torch.ones_like(result, requires_grad=True) + z = y + result + z.mean().backward() + + assert y.grad is not None + + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + def test_spec_aug_kernel_no_freq_mask(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + cfg = get_cfg(seed=0) + cfg.freq_masks = 0 + cfg.time_masks = 10 + + data = prepare_data(**cfg) + + launch_kernel(data, cfg) + x, x_len, sh = data['x'], data['x_len'], data['sh'] + + # Assert time masks are correct + for bidx in range(sh[0]): + for t_start, t_len in zip(data['time_starts'][bidx], data['time_lengths'][bidx]): + time_mask_check(x, x_len, t_start, t_len, mask_value=cfg.mask_value, bidx=bidx) + + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + def test_spec_aug_kernel_no_time_mask(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + cfg = get_cfg(seed=0) + cfg.freq_masks = 2 + cfg.time_masks = 0 + + data = prepare_data(**cfg) + + launch_kernel(data, cfg) + x, x_len, sh = data['x'], data['x_len'], data['sh'] + + # Assert freq masks are correct + for bidx in range(sh[0]): + for f_start, f_len in zip(data['freq_starts'][bidx], data['freq_lengths'][bidx]): + freq_mask_check(x, x_len, f_start, f_len, mask_value=cfg.mask_value, bidx=bidx) + + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + def test_spec_aug_kernel_no_freq_time_mask(self): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + cfg = get_cfg(seed=0) + cfg.freq_masks = 0 + cfg.time_masks = 0 + + data = prepare_data(**cfg) + + x, x_len, sh = data['x'], data['x_len'], data['sh'] + x_copy = x.clone() + launch_kernel(data, cfg) + + # Assert no data edits occured + assert (data['x'] - x_copy).abs().mean() <= 1e-9 diff --git a/tts/NeMo/tests/collections/asr/test_asr_classification_model.py b/tts/NeMo/tests/collections/asr/test_asr_classification_model.py new file mode 100644 index 0000000..24c88d9 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_classification_model.py @@ -0,0 +1,208 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import os + +import pytest +import torch +from omegaconf import DictConfig, ListConfig + +from nemo.collections.asr.data import audio_to_label +from nemo.collections.asr.models import EncDecClassificationModel, configs +from nemo.utils.config_utils import assert_dataclass_signature_match + + +@pytest.fixture() +def speech_classification_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 32, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.ConvASRDecoderClassification', + 'params': {'feat_in': 32, 'num_classes': 30,}, + } + + modelConfig = DictConfig( + { + 'preprocessor': DictConfig(preprocessor), + 'encoder': DictConfig(encoder), + 'decoder': DictConfig(decoder), + 'labels': ListConfig(["dummy_cls_{}".format(i + 1) for i in range(30)]), + } + ) + model = EncDecClassificationModel(cfg=modelConfig) + return model + + +class TestEncDecClassificationModel: + @pytest.mark.unit + def test_constructor(self, speech_classification_model): + asr_model = speech_classification_model.train() + + conv_cnt = (64 * 32 * 1 + 32) + (64 * 1 * 1 + 32) # separable kernel + bias + pointwise kernel + bias + bn_cnt = (4 * 32) * 2 # 2 * moving averages + dec_cnt = 32 * 30 + 30 # fc + bias + + param_count = conv_cnt + bn_cnt + dec_cnt + assert asr_model.num_weights == param_count + + # Check to/from config_dict: + confdict = asr_model.to_config_dict() + instance2 = EncDecClassificationModel.from_config_dict(confdict) + + assert isinstance(instance2, EncDecClassificationModel) + + @pytest.mark.unit + def test_forward(self, speech_classification_model): + asr_model = speech_classification_model.eval() + + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + + with torch.no_grad(): + # batch size 1 + logprobs_instance = [] + for i in range(input_signal.size(0)): + logprobs_ins = asr_model.forward( + input_signal=input_signal[i : i + 1], input_signal_length=length[i : i + 1] + ) + logprobs_instance.append(logprobs_ins) + logprobs_instance = torch.cat(logprobs_instance, 0) + + # batch size 4 + logprobs_batch = asr_model.forward(input_signal=input_signal, input_signal_length=length) + + assert logprobs_instance.shape == logprobs_batch.shape + diff = torch.mean(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + diff = torch.max(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + + @pytest.mark.unit + def test_vocab_change(self, speech_classification_model): + asr_model = speech_classification_model.train() + + old_labels = copy.deepcopy(asr_model._cfg.labels) + nw1 = asr_model.num_weights + asr_model.change_labels(new_labels=old_labels) + # No change + assert nw1 == asr_model.num_weights + new_labels = copy.deepcopy(old_labels) + new_labels.append('dummy_cls_31') + new_labels.append('dummy_cls_32') + new_labels.append('dummy_cls_33') + asr_model.change_labels(new_labels=new_labels) + # fully connected + bias + assert asr_model.num_weights == nw1 + 3 * (asr_model.decoder._feat_in + 1) + + @pytest.mark.unit + def test_transcription(self, speech_classification_model, test_data_dir): + # Ground truth labels = ["yes", "no"] + audio_filenames = ['an22-flrp-b.wav', 'an90-fbbh-b.wav'] + audio_paths = [os.path.join(test_data_dir, "asr", "train", "an4", "wav", fp) for fp in audio_filenames] + + model = speech_classification_model.eval() + + # Test Top 1 classification transcription + results = model.transcribe(audio_paths, batch_size=2) + assert len(results) == 2 + assert results[0].shape == torch.Size([1]) + + # Test Top 5 classification transcription + model._accuracy.top_k = [5] # set top k to 5 for accuracy calculation + results = model.transcribe(audio_paths, batch_size=2) + assert len(results) == 2 + assert results[0].shape == torch.Size([5]) + + # Test Top 1 and Top 5 classification transcription + model._accuracy.top_k = [1, 5] + results = model.transcribe(audio_paths, batch_size=2) + assert len(results) == 2 + assert results[0].shape == torch.Size([2, 1]) + assert results[1].shape == torch.Size([2, 5]) + assert model._accuracy.top_k == [1, 5] + + # Test log probs extraction + model._accuracy.top_k = [1] + results = model.transcribe(audio_paths, batch_size=2, logprobs=True) + assert len(results) == 2 + assert results[0].shape == torch.Size([len(model.cfg.labels)]) + + # Test log probs extraction remains same for any top_k + model._accuracy.top_k = [5] + results = model.transcribe(audio_paths, batch_size=2, logprobs=True) + assert len(results) == 2 + assert results[0].shape == torch.Size([len(model.cfg.labels)]) + + @pytest.mark.unit + def test_EncDecClassificationDatasetConfig_for_AudioToSpeechLabelDataset(self): + # ignore some additional arguments as dataclass is generic + IGNORE_ARGS = [ + 'is_tarred', + 'num_workers', + 'batch_size', + 'tarred_audio_filepaths', + 'shuffle', + 'pin_memory', + 'drop_last', + 'tarred_shard_strategy', + 'shuffle_n', + # `featurizer` is supplied at runtime + 'featurizer', + # additional ignored arguments + 'vad_stream', + 'int_values', + 'sample_rate', + 'normalize_audio', + 'augmentor', + ] + + REMAP_ARGS = {'trim_silence': 'trim'} + + result = assert_dataclass_signature_match( + audio_to_label.AudioToSpeechLabelDataset, + configs.EncDecClassificationDatasetConfig, + ignore_args=IGNORE_ARGS, + remap_args=REMAP_ARGS, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None diff --git a/tts/NeMo/tests/collections/asr/test_asr_ctc_encoder_model_bpe.py b/tts/NeMo/tests/collections/asr/test_asr_ctc_encoder_model_bpe.py new file mode 100644 index 0000000..b42a06d --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_ctc_encoder_model_bpe.py @@ -0,0 +1,313 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import os +import shutil +import tempfile + +import pytest +import torch +from omegaconf import DictConfig + +from nemo.collections.asr.data import audio_to_text +from nemo.collections.asr.models import configs +from nemo.collections.asr.models.ctc_bpe_models import EncDecCTCModelBPE +from nemo.collections.common import tokenizers +from nemo.utils.config_utils import assert_dataclass_signature_match + + +@pytest.fixture() +def asr_model(test_data_dir): + preprocessor = {'_target_': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor'} + encoder = { + '_target_': 'nemo.collections.asr.modules.ConvASREncoder', + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 1024, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + } + + decoder = { + '_target_': 'nemo.collections.asr.modules.ConvASRDecoder', + 'feat_in': 1024, + 'num_classes': -1, + 'vocabulary': None, + } + + tokenizer = {'dir': os.path.join(test_data_dir, "asr", "tokenizers", "an4_wpe_128"), 'type': 'wpe'} + + modelConfig = DictConfig( + { + 'preprocessor': DictConfig(preprocessor), + 'encoder': DictConfig(encoder), + 'decoder': DictConfig(decoder), + 'tokenizer': DictConfig(tokenizer), + } + ) + + model_instance = EncDecCTCModelBPE(cfg=modelConfig) + return model_instance + + +class TestEncDecCTCModel: + @pytest.mark.unit + def test_constructor(self, asr_model): + asr_model.train() + # TODO: make proper config and assert correct number of weights + # Check to/from config_dict: + confdict = asr_model.to_config_dict() + instance2 = EncDecCTCModelBPE.from_config_dict(confdict) + assert isinstance(instance2, EncDecCTCModelBPE) + + @pytest.mark.unit + def test_forward(self, asr_model): + asr_model = asr_model.eval() + + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + + with torch.no_grad(): + # batch size 1 + logprobs_instance = [] + for i in range(input_signal.size(0)): + logprobs_ins, _, _ = asr_model.forward( + input_signal=input_signal[i : i + 1], input_signal_length=length[i : i + 1] + ) + logprobs_instance.append(logprobs_ins) + print(len(logprobs_ins)) + logprobs_instance = torch.cat(logprobs_instance, 0) + + # batch size 4 + logprobs_batch, _, _ = asr_model.forward(input_signal=input_signal, input_signal_length=length) + + assert logprobs_instance.shape == logprobs_batch.shape + diff = torch.mean(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + diff = torch.max(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + + @pytest.mark.unit + def test_save_restore_artifact(self, asr_model): + with tempfile.TemporaryDirectory() as tmpdir: + save_path = os.path.join(tmpdir, 'ctc_bpe.nemo') + asr_model.train() + asr_model.save_to(save_path) + + new_model = EncDecCTCModelBPE.restore_from(save_path) + assert isinstance(new_model, type(asr_model)) + assert new_model.vocab_path.endswith('_vocab.txt') + + assert len(new_model.tokenizer.tokenizer.get_vocab()) == 128 + + @pytest.mark.unit + def test_save_restore_artifact_spe(self, asr_model, test_data_dir): + with tempfile.TemporaryDirectory() as tmpdir: + tokenizer_dir = os.path.join(test_data_dir, "asr", "tokenizers", "an4_spe_128") + asr_model.change_vocabulary(new_tokenizer_dir=tokenizer_dir, new_tokenizer_type='bpe') + + save_path = os.path.join(tmpdir, 'ctc_bpe.nemo') + asr_model.train() + asr_model.save_to(save_path) + + new_model = EncDecCTCModelBPE.restore_from(save_path) + assert isinstance(new_model, type(asr_model)) + assert isinstance(new_model.tokenizer, tokenizers.SentencePieceTokenizer) + assert new_model.model_path.endswith('_tokenizer.model') + assert new_model.vocab_path.endswith('_vocab.txt') + assert new_model.spe_vocab_path.endswith('_tokenizer.vocab') + + assert len(new_model.tokenizer.tokenizer.get_vocab()) == 128 + + @pytest.mark.unit + def test_vocab_change(self, test_data_dir, asr_model): + old_vocab = copy.deepcopy(asr_model.decoder.vocabulary) + + with tempfile.TemporaryDirectory() as save_dir: + save_path = os.path.join(save_dir, 'temp.nemo') + + with tempfile.TemporaryDirectory() as tmpdir: + old_tmpdir_path = tmpdir + + old_tokenizer_dir = os.path.join(test_data_dir, "asr", "tokenizers", "an4_wpe_128", 'vocab.txt') + new_tokenizer_dir = os.path.join(tmpdir, 'tokenizer') + + os.makedirs(new_tokenizer_dir, exist_ok=True) + shutil.copy2(old_tokenizer_dir, new_tokenizer_dir) + + nw1 = asr_model.num_weights + asr_model.change_vocabulary(new_tokenizer_dir=new_tokenizer_dir, new_tokenizer_type='wpe') + # No change + assert nw1 == asr_model.num_weights + + with open(os.path.join(new_tokenizer_dir, 'vocab.txt'), 'a+') as f: + f.write("!\n") + f.write('$\n') + f.write('@\n') + + asr_model.change_vocabulary(new_tokenizer_dir=new_tokenizer_dir, new_tokenizer_type='wpe') + # fully connected + bias + assert asr_model.num_weights == nw1 + 3 * (asr_model.decoder._feat_in + 1) + + new_vocab = copy.deepcopy(asr_model.decoder.vocabulary) + assert len(old_vocab) != len(new_vocab) + + # save the model (after change of vocabulary) + asr_model.save_to(save_path) + assert os.path.exists(save_path) + # delete copied version of the vocabulary from nested tmpdir (by scope) + + # assert copied vocab no longer exists + assert not os.path.exists(os.path.join(old_tmpdir_path, 'tokenizer', 'vocab.txt')) + + # make a copy of the tokenizer before renaming + try: + os.rename(old_tokenizer_dir, old_tokenizer_dir + '.bkp') + assert not os.path.exists(old_tokenizer_dir) + + # restore model from .nemo + asr_model2 = EncDecCTCModelBPE.restore_from(save_path) + assert isinstance(asr_model2, EncDecCTCModelBPE) + + # Check if vocabulary size is same + assert asr_model.tokenizer.tokenizer.vocab_size == asr_model2.tokenizer.tokenizer.vocab_size + + # Make a copy of the tokenizer + new_tokenizer_dir = os.path.join(save_dir, 'tokenizer') + + os.makedirs(new_tokenizer_dir, exist_ok=True) + new_tokenizer_path = os.path.join(new_tokenizer_dir, 'vocab.txt') + with open(new_tokenizer_path, 'w') as f: + for v in asr_model2.tokenizer.tokenizer.get_vocab(): + f.write(f"{v}\n") + + # Add some new tokens too + f.write("^\n") + f.write("^^\n") + f.write("^^^\n") + + assert os.path.exists(new_tokenizer_path) + + # change vocabulary + asr_model2.change_vocabulary(new_tokenizer_dir, new_tokenizer_type='wpe') + assert asr_model.tokenizer.vocab_size != asr_model2.tokenizer.vocab_size + + new_save_path = os.path.join(save_dir, 'temp2.nemo') + asr_model2.save_to(new_save_path) + + asr_model3 = EncDecCTCModelBPE.restore_from(new_save_path) + assert isinstance(asr_model3, EncDecCTCModelBPE) + + # Check if vocabulary size is same + assert asr_model2.tokenizer.tokenizer.vocab_size == asr_model3.tokenizer.tokenizer.vocab_size + assert asr_model2.vocab_path != asr_model3.vocab_path + + # Model PT level checks + assert len(asr_model2.artifacts) == 1 + + finally: + os.rename(old_tokenizer_dir + '.bkp', old_tokenizer_dir) + + @pytest.mark.unit + def test_EncDecCTCDatasetConfig_for_AudioToBPEDataset(self): + # ignore some additional arguments as dataclass is generic + IGNORE_ARGS = [ + 'is_tarred', + 'num_workers', + 'batch_size', + 'tarred_audio_filepaths', + 'shuffle', + 'pin_memory', + 'drop_last', + 'tarred_shard_strategy', + 'shuffle_n', + 'parser', + 'normalize', + 'unk_index', + 'pad_id', + 'bos_id', + 'eos_id', + 'blank_index', + ] + + REMAP_ARGS = {'trim_silence': 'trim', 'labels': 'tokenizer'} + + result = assert_dataclass_signature_match( + audio_to_text.AudioToBPEDataset, + configs.EncDecCTCDatasetConfig, + ignore_args=IGNORE_ARGS, + remap_args=REMAP_ARGS, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_EncDecCTCDatasetConfig_for_TarredAudioToBPEDataset(self): + # ignore some additional arguments as dataclass is generic + IGNORE_ARGS = [ + 'is_tarred', + 'num_workers', + 'batch_size', + 'shuffle', + 'pin_memory', + 'drop_last', + 'parser', + 'normalize', + 'unk_index', + 'pad_id', + 'bos_id', + 'eos_id', + 'blank_index', + 'global_rank', + 'world_size', + ] + + REMAP_ARGS = { + 'trim_silence': 'trim', + 'tarred_audio_filepaths': 'audio_tar_filepaths', + 'tarred_shard_strategy': 'shard_strategy', + 'shuffle_n': 'shuffle', + 'labels': 'tokenizer', + } + + result = assert_dataclass_signature_match( + audio_to_text.TarredAudioToBPEDataset, + configs.EncDecCTCDatasetConfig, + ignore_args=IGNORE_ARGS, + remap_args=REMAP_ARGS, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None diff --git a/tts/NeMo/tests/collections/asr/test_asr_ctcencdec_model.py b/tts/NeMo/tests/collections/asr/test_asr_ctcencdec_model.py new file mode 100644 index 0000000..be9c502 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_ctcencdec_model.py @@ -0,0 +1,305 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import copy + +import pytest +import torch +from omegaconf import DictConfig, OmegaConf, open_dict + +import nemo.collections.asr as nemo_asr +from nemo.collections.asr.data import audio_to_text +from nemo.collections.asr.models import EncDecCTCModel, configs +from nemo.utils.config_utils import assert_dataclass_signature_match, update_model_config + + +@pytest.fixture() +def asr_model(): + preprocessor = {'_target_': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor'} + encoder = { + '_target_': 'nemo.collections.asr.modules.ConvASREncoder', + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 1024, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + } + + decoder = { + '_target_': 'nemo.collections.asr.modules.ConvASRDecoder', + 'feat_in': 1024, + 'num_classes': 28, + 'vocabulary': [ + ' ', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + "'", + ], + } + modelConfig = DictConfig( + {'preprocessor': DictConfig(preprocessor), 'encoder': DictConfig(encoder), 'decoder': DictConfig(decoder)} + ) + + model_instance = EncDecCTCModel(cfg=modelConfig) + return model_instance + + +class TestEncDecCTCModel: + @pytest.mark.unit + def test_constructor(self, asr_model): + asr_model.train() + # TODO: make proper config and assert correct number of weights + # Check to/from config_dict: + confdict = asr_model.to_config_dict() + instance2 = EncDecCTCModel.from_config_dict(confdict) + assert isinstance(instance2, EncDecCTCModel) + + @pytest.mark.unit + def test_forward(self, asr_model): + asr_model = asr_model.eval() + + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + + with torch.no_grad(): + # batch size 1 + logprobs_instance = [] + for i in range(input_signal.size(0)): + logprobs_ins, _, _ = asr_model.forward( + input_signal=input_signal[i : i + 1], input_signal_length=length[i : i + 1] + ) + logprobs_instance.append(logprobs_ins) + print(len(logprobs_ins)) + logprobs_instance = torch.cat(logprobs_instance, 0) + + # batch size 4 + logprobs_batch, _, _ = asr_model.forward(input_signal=input_signal, input_signal_length=length) + + assert logprobs_instance.shape == logprobs_batch.shape + diff = torch.mean(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + diff = torch.max(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + + @pytest.mark.unit + def test_vocab_change(self, asr_model): + old_vocab = copy.deepcopy(asr_model.decoder.vocabulary) + nw1 = asr_model.num_weights + asr_model.change_vocabulary(new_vocabulary=old_vocab) + # No change + assert nw1 == asr_model.num_weights + new_vocab = copy.deepcopy(old_vocab) + new_vocab.append('!') + new_vocab.append('$') + new_vocab.append('@') + asr_model.change_vocabulary(new_vocabulary=new_vocab) + # fully connected + bias + assert asr_model.num_weights == nw1 + 3 * (asr_model.decoder._feat_in + 1) + + @pytest.mark.unit + def test_change_conv_asr_se_context_window(self, asr_model): + old_cfg = copy.deepcopy(asr_model.cfg) + asr_model.change_conv_asr_se_context_window(context_window=32) # 32 * 0.01s context + new_config = asr_model.cfg + + assert old_cfg.encoder.jasper[0].se_context_size == -1 + assert new_config.encoder.jasper[0].se_context_size == 32 + + for name, m in asr_model.encoder.named_modules(): + if type(m).__class__.__name__ == 'SqueezeExcite': + assert m.context_window == 32 + + @pytest.mark.unit + def test_change_conv_asr_se_context_window_no_config_update(self, asr_model): + old_cfg = copy.deepcopy(asr_model.cfg) + asr_model.change_conv_asr_se_context_window(context_window=32, update_config=False) # 32 * 0.01s context + new_config = asr_model.cfg + + assert old_cfg.encoder.jasper[0].se_context_size == -1 + assert new_config.encoder.jasper[0].se_context_size == -1 # no change + + for name, m in asr_model.encoder.named_modules(): + if type(m).__class__.__name__ == 'SqueezeExcite': + assert m.context_window == 32 + + @pytest.mark.unit + def test_dataclass_instantiation(self, asr_model): + model_cfg = configs.EncDecCTCModelConfig() + + # Update mandatory values + vocabulary = asr_model.decoder.vocabulary + model_cfg.model.labels = vocabulary + + # Update encoder + model_cfg.model.encoder.activation = 'relu' + model_cfg.model.encoder.feat_in = 64 + model_cfg.model.encoder.jasper = [ + nemo_asr.modules.conv_asr.JasperEncoderConfig( + filters=1024, + repeat=1, + kernel=[1], + stride=[1], + dilation=[1], + dropout=0.0, + residual=False, + se=True, + se_context_size=-1, + ) + ] + + # Update decoder + model_cfg.model.decoder.feat_in = 1024 + model_cfg.model.decoder.num_classes = 28 + model_cfg.model.decoder.vocabulary = vocabulary + + # Construct the model + asr_cfg = OmegaConf.create({'model': asr_model.cfg}) + model_cfg_v1 = update_model_config(model_cfg, asr_cfg) + new_model = EncDecCTCModel(cfg=model_cfg_v1.model) + + assert new_model.num_weights == asr_model.num_weights + # trainer and exp manager should be there + # assert 'trainer' in model_cfg_v1 + # assert 'exp_manager' in model_cfg_v1 + # datasets and optim/sched should not be there after ModelPT.update_model_dataclass() + assert 'train_ds' not in model_cfg_v1.model + assert 'validation_ds' not in model_cfg_v1.model + assert 'test_ds' not in model_cfg_v1.model + assert 'optim' not in model_cfg_v1.model + + # Construct the model, without dropping additional keys + asr_cfg = OmegaConf.create({'model': asr_model.cfg}) + model_cfg_v2 = update_model_config(model_cfg, asr_cfg, drop_missing_subconfigs=False) + + # Assert all components are in config + # assert 'trainer' in model_cfg_v2 + # assert 'exp_manager' in model_cfg_v2 + assert 'train_ds' in model_cfg_v2.model + assert 'validation_ds' in model_cfg_v2.model + assert 'test_ds' in model_cfg_v2.model + assert 'optim' in model_cfg_v2.model + + # Remove extra components (optim and sched can be kept without issue) + with open_dict(model_cfg_v2.model): + model_cfg_v2.model.pop('train_ds') + model_cfg_v2.model.pop('validation_ds') + model_cfg_v2.model.pop('test_ds') + + new_model = EncDecCTCModel(cfg=model_cfg_v2.model) + + assert new_model.num_weights == asr_model.num_weights + # trainer and exp manager should be there + + @pytest.mark.unit + def test_EncDecCTCDatasetConfig_for_AudioToCharDataset(self): + # ignore some additional arguments as dataclass is generic + IGNORE_ARGS = [ + 'is_tarred', + 'num_workers', + 'batch_size', + 'tarred_audio_filepaths', + 'shuffle', + 'pin_memory', + 'drop_last', + 'tarred_shard_strategy', + 'shuffle_n', + 'use_start_end_token', + 'use_start_end_token', + ] + + REMAP_ARGS = {'trim_silence': 'trim'} + + result = assert_dataclass_signature_match( + audio_to_text.AudioToCharDataset, + configs.EncDecCTCDatasetConfig, + ignore_args=IGNORE_ARGS, + remap_args=REMAP_ARGS, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_EncDecCTCDatasetConfig_for_TarredAudioToCharDataset(self): + # ignore some additional arguments as dataclass is generic + IGNORE_ARGS = [ + 'is_tarred', + 'num_workers', + 'batch_size', + 'shuffle', + 'pin_memory', + 'drop_last', + 'global_rank', + 'world_size', + 'use_start_end_token', + ] + + REMAP_ARGS = { + 'trim_silence': 'trim', + 'tarred_audio_filepaths': 'audio_tar_filepaths', + 'tarred_shard_strategy': 'shard_strategy', + 'shuffle_n': 'shuffle', + } + + result = assert_dataclass_signature_match( + audio_to_text.TarredAudioToCharDataset, + configs.EncDecCTCDatasetConfig, + ignore_args=IGNORE_ARGS, + remap_args=REMAP_ARGS, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None diff --git a/tts/NeMo/tests/collections/asr/test_asr_datasets.py b/tts/NeMo/tests/collections/asr/test_asr_datasets.py new file mode 100644 index 0000000..b2a3ccf --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_datasets.py @@ -0,0 +1,127 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import os + +import pytest +from omegaconf import OmegaConf + +from nemo.collections.asr.data.audio_to_text import TarredAudioToBPEDataset, TarredAudioToCharDataset +from nemo.collections.asr.data.audio_to_text_dataset import inject_dataloader_value_from_model_config +from nemo.collections.common import tokenizers +from nemo.utils import logging + + +class TestASRDatasets: + labels = [ + " ", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "'", + ] + + @pytest.mark.unit + def test_tarred_dataset(self, test_data_dir): + manifest_path = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/tarred_audio_manifest.json')) + + # Test braceexpand loading + tarpath = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/audio_{0..1}.tar')) + ds_braceexpand = TarredAudioToCharDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, labels=self.labels, sample_rate=16000 + ) + assert len(ds_braceexpand) == 32 + count = 0 + for _ in ds_braceexpand: + count += 1 + assert count == 32 + + # Test loading via list + tarpath = [os.path.abspath(os.path.join(test_data_dir, f'asr/tarred_an4/audio_{i}.tar')) for i in range(2)] + ds_list_load = TarredAudioToCharDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, labels=self.labels, sample_rate=16000 + ) + count = 0 + for _ in ds_list_load: + count += 1 + assert count == 32 + + @pytest.mark.unit + def test_mismatch_in_model_dataloader_config(self, caplog): + logging._logger.propagate = True + caplog.set_level(logging.WARNING) + + model_cfg = OmegaConf.create(dict(labels=OmegaConf.create(["a", "b", "c"]))) + dataloader_cfg = OmegaConf.create(dict(labels=copy.deepcopy(self.labels))) + + inject_dataloader_value_from_model_config(model_cfg, dataloader_cfg, key='labels') + + assert ( + """`labels` is explicitly provided to the data loader, and is different from the `labels` provided at the model level config.""" + in caplog.text + ) + + logging._logger.propagate = False + + @pytest.mark.unit + def test_tarred_bpe_dataset(self, test_data_dir): + manifest_path = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/tarred_audio_manifest.json')) + + tokenizer_path = os.path.join(test_data_dir, "asr", "tokenizers", "an4_wpe_128", 'vocab.txt') + tokenizer = tokenizers.AutoTokenizer(pretrained_model_name='bert-base-cased', vocab_file=tokenizer_path) + + # Test braceexpand loading + tarpath = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/audio_{0..1}.tar')) + ds_braceexpand = TarredAudioToBPEDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, tokenizer=tokenizer, sample_rate=16000 + ) + assert len(ds_braceexpand) == 32 + count = 0 + for _ in ds_braceexpand: + count += 1 + assert count == 32 + + # Test loading via list + tarpath = [os.path.abspath(os.path.join(test_data_dir, f'asr/tarred_an4/audio_{i}.tar')) for i in range(2)] + ds_list_load = TarredAudioToBPEDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, tokenizer=tokenizer, sample_rate=16000 + ) + count = 0 + for _ in ds_list_load: + count += 1 + assert count == 32 diff --git a/tts/NeMo/tests/collections/asr/test_asr_exportables.py b/tts/NeMo/tests/collections/asr/test_asr_exportables.py new file mode 100644 index 0000000..0ebd233 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_exportables.py @@ -0,0 +1,301 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import tempfile + +import onnx +import pytest +from omegaconf import DictConfig, ListConfig + +from nemo.collections.asr.models import EncDecClassificationModel, EncDecCTCModel, EncDecSpeakerLabelModel +from nemo.collections.asr.modules import ConvASRDecoder, ConvASREncoder + + +class TestExportable: + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_EncDecCTCModel_export_to_onnx(self): + model_config = DictConfig( + { + 'preprocessor': DictConfig(self.preprocessor), + 'encoder': DictConfig(self.encoder_dict), + 'decoder': DictConfig(self.decoder_dict), + } + ) + model = EncDecCTCModel(cfg=model_config) + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'qn.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'audio_signal' + assert onnx_model.graph.output[0].name == 'logprobs' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_EncDecClassificationModel_export_to_onnx(self, speech_classification_model): + model = speech_classification_model.train() + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'edc.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'audio_signal' + assert onnx_model.graph.output[0].name == 'logits' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_EncDecSpeakerLabelModel_export_to_onnx(self, speaker_label_model): + model = speaker_label_model.train() + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'sl.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'audio_signal' + assert onnx_model.graph.output[0].name == 'logits' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_EncDecCitrinetModel_export_to_onnx(self, citrinet_model): + model = citrinet_model.train() + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join('.', 'citri.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'audio_signal' + assert onnx_model.graph.output[0].name == 'logprobs' + + def setup_method(self): + self.preprocessor = { + 'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', + 'params': dict({}), + } + + self.encoder_dict = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 1024, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + self.decoder_dict = { + 'cls': 'nemo.collections.asr.modules.ConvASRDecoder', + 'params': { + 'feat_in': 1024, + 'num_classes': 28, + 'vocabulary': [ + ' ', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + "'", + ], + }, + } + + +@pytest.fixture() +def speech_classification_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 32, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.ConvASRDecoderClassification', + 'params': {'feat_in': 32, 'num_classes': 30,}, + } + + modelConfig = DictConfig( + { + 'preprocessor': DictConfig(preprocessor), + 'encoder': DictConfig(encoder), + 'decoder': DictConfig(decoder), + 'labels': ListConfig(["dummy_cls_{}".format(i + 1) for i in range(30)]), + } + ) + model = EncDecClassificationModel(cfg=modelConfig) + return model + + +@pytest.fixture() +def speaker_label_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 512, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': False, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.SpeakerDecoder', + 'params': {'feat_in': 512, 'num_classes': 2, 'pool_mode': 'xvector', 'emb_sizes': [1024]}, + } + + modelConfig = DictConfig( + {'preprocessor': DictConfig(preprocessor), 'encoder': DictConfig(encoder), 'decoder': DictConfig(decoder)} + ) + speaker_model = EncDecSpeakerLabelModel(cfg=modelConfig) + return speaker_model + + +@pytest.fixture() +def citrinet_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 80, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 512, + 'repeat': 1, + 'kernel': [5], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + }, + { + 'filters': 512, + 'repeat': 5, + 'kernel': [11], + 'stride': [2], + 'dilation': [1], + 'dropout': 0.1, + 'residual': True, + 'separable': True, + 'se': True, + 'se_context_size': -1, + 'stride_last': True, + 'residual_mode': 'stride_add', + }, + { + 'filters': 512, + 'repeat': 5, + 'kernel': [13], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.1, + 'residual': True, + 'separable': True, + 'se': True, + 'se_context_size': -1, + }, + { + 'filters': 640, + 'repeat': 1, + 'kernel': [41], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': True, + 'separable': True, + 'se': True, + 'se_context_size': -1, + }, + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.ConvASRDecoder', + 'params': {'feat_in': 640, 'num_classes': 1024, 'vocabulary': list(chr(i % 28) for i in range(0, 1024))}, + } + + modelConfig = DictConfig( + {'preprocessor': DictConfig(preprocessor), 'encoder': DictConfig(encoder), 'decoder': DictConfig(decoder)} + ) + citri_model = EncDecSpeakerLabelModel(cfg=modelConfig) + return citri_model diff --git a/tts/NeMo/tests/collections/asr/test_asr_filterbankfeatures_seq_len.py b/tts/NeMo/tests/collections/asr/test_asr_filterbankfeatures_seq_len.py new file mode 100644 index 0000000..24ba584 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_filterbankfeatures_seq_len.py @@ -0,0 +1,99 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import librosa +import numpy as np +import pytest +import torch + +from nemo.collections.asr.parts.preprocessing.features import FilterbankFeatures + + +class TestFilterbankFeatures: + @pytest.mark.unit + def test_seq_len(self): + fb_module = FilterbankFeatures(exact_pad=False, pad_to=1) + test_1 = torch.randn(1, 800) + test_1_len = torch.tensor([800]) + fb_spec, fb_len = fb_module(test_1, test_1_len) + assert fb_spec.shape[2] == fb_len[0], f"{fb_spec.shape} != {fb_len}" + librosa_spec = librosa.stft(test_1.cpu().detach().numpy().squeeze(), n_fft=512, hop_length=160, win_length=320) + + assert librosa_spec.shape[1] == fb_spec.shape[2], f"{librosa_spec.shape} != {fb_spec.shape}" + + @pytest.mark.unit + def test_random_stft_sizes(self): + for _ in range(5): + nfft = 2 ** np.random.randint(7, 12) + window_size = np.random.randint(100, nfft) + hop_size = np.random.randint(64, window_size) + fb_module = FilterbankFeatures( + exact_pad=False, + pad_to=1, + n_fft=nfft, + n_window_size=window_size, + n_window_stride=hop_size, + normalize=False, + ) + audio_length = np.random.randint(nfft, 2 ** 16) + test_1 = torch.randn(1, audio_length) + test_1_len = torch.tensor([audio_length]) + fb_spec, fb_len = fb_module(test_1, test_1_len) + assert ( + fb_spec.shape[2] == fb_len[0] + ), f"{fb_spec.shape} != {fb_len}: {nfft}, {window_size}, {hop_size}, {audio_length}" + + librosa_spec = librosa.stft( + test_1.cpu().detach().numpy().squeeze(), n_fft=nfft, hop_length=hop_size, win_length=window_size + ) + + assert ( + librosa_spec.shape[1] == fb_spec.shape[2] + ), f"{librosa_spec.shape} != {fb_spec.shape}: {nfft}, {window_size}, {hop_size}, {audio_length}" + + @pytest.mark.unit + def test_random_stft_sizes_exact_pad(self): + for _ in range(5): + nfft = 2 ** np.random.randint(7, 12) + window_size = np.random.randint(100, nfft) + hop_size = np.random.randint(64, window_size) + if hop_size % 2 == 1: + hop_size = hop_size - 1 + fb_module = FilterbankFeatures( + exact_pad=True, + pad_to=1, + n_fft=nfft, + n_window_size=window_size, + n_window_stride=hop_size, + normalize=False, + ) + audio_length = np.random.randint(nfft, 2 ** 16) + test_1 = torch.randn(1, audio_length) + test_1_len = torch.tensor([audio_length]) + fb_spec, fb_len = fb_module(test_1, test_1_len) + assert ( + fb_spec.shape[2] == fb_len[0] + ), f"{fb_spec.shape} != {fb_len}: {nfft}, {window_size}, {hop_size}, {audio_length}" + + test_2 = test_1.cpu().detach().numpy().squeeze() + test_2 = np.pad(test_2, int((nfft - hop_size) // 2), mode="reflect") + librosa_spec = librosa.stft(test_2, n_fft=nfft, hop_length=hop_size, win_length=window_size, center=False,) + + assert ( + fb_spec.shape[2] == librosa_spec.shape[1] + ), f"{fb_spec.shape} != {librosa_spec.shape}: {nfft}, {window_size}, {hop_size}, {audio_length}" + + assert ( + fb_spec.shape[2] == audio_length // hop_size + ), f"{fb_spec.shape}, {nfft}, {window_size}, {hop_size}, {audio_length}, {audio_length // hop_size}" diff --git a/tts/NeMo/tests/collections/asr/test_asr_metrics.py b/tts/NeMo/tests/collections/asr/test_asr_metrics.py new file mode 100644 index 0000000..7f78c1d --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_metrics.py @@ -0,0 +1,172 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import random + +import pytest +import torch + +from nemo.collections.asr.metrics.wer import WER, word_error_rate +from nemo.collections.asr.parts.utils.rnnt_utils import Hypothesis + + +class TestWordErrorRate: + + vocabulary = [ + " ", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "'", + ] + + def __string_to_ctc_tensor(self, txt: str) -> torch.Tensor: + # This function emulates how CTC output could like for txt + blank_id = len(self.vocabulary) + char_to_ind = dict([(self.vocabulary[i], i) for i in range(len(self.vocabulary))]) + string_in_id_form = [char_to_ind[c] for c in txt] + ctc_list = [] + prev_id = -1 + for c in string_in_id_form: + # when character is repeated we need to insert CTC blank symbol + if c != prev_id: + ctc_list.append(c) + else: + ctc_list.append(blank_id) + ctc_list.append(c) + prev_id = c + return torch.Tensor(ctc_list).unsqueeze(0) + + def __reference_string_to_tensor(self, txt: str) -> torch.Tensor: + # Reference tensors aren't produced by CTC logic + char_to_ind = dict([(self.vocabulary[i], i) for i in range(len(self.vocabulary))]) + string_in_id_form = [char_to_ind[c] for c in txt] + return torch.Tensor(string_in_id_form).unsqueeze(0) + + def get_wer(self, wer, prediction: str, reference: str): + wer( + predictions=self.__string_to_ctc_tensor(prediction), + targets=self.__reference_string_to_tensor(reference), + target_lengths=torch.tensor([len(reference)]), + ) + res, _, _ = wer.compute() + res = res.detach().cpu() + # return res[0] / res[1] + return res.item() + + @pytest.mark.unit + def test_wer_function(self): + assert word_error_rate(hypotheses=['cat'], references=['cot']) == 1.0 + assert word_error_rate(hypotheses=['GPU'], references=['G P U']) == 1.0 + assert word_error_rate(hypotheses=['G P U'], references=['GPU']) == 3.0 + assert word_error_rate(hypotheses=['ducati motorcycle'], references=['motorcycle']) == 1.0 + assert word_error_rate(hypotheses=['ducati motorcycle'], references=['ducuti motorcycle']) == 0.5 + assert word_error_rate(hypotheses=['a B c'], references=['a b c']) == 1.0 / 3.0 + + @pytest.mark.unit + def test_wer_metric_simple(self): + wer = WER(vocabulary=self.vocabulary, batch_dim_index=0, use_cer=False, ctc_decode=True) + + assert self.get_wer(wer, 'cat', 'cot') == 1.0 + assert self.get_wer(wer, 'gpu', 'g p u') == 1.0 + assert self.get_wer(wer, 'g p u', 'gpu') == 3.0 + assert self.get_wer(wer, 'ducati motorcycle', 'motorcycle') == 1.0 + assert self.get_wer(wer, 'ducati motorcycle', 'ducuti motorcycle') == 0.5 + assert abs(self.get_wer(wer, 'a f c', 'a b c') - 1.0 / 3.0) < 1e-6 + + @pytest.mark.unit + def test_wer_metric_randomized(self): + """This test relies on correctness of word_error_rate function.""" + + def __randomString(N): + return ''.join(random.choice(''.join(self.vocabulary)) for i in range(N)) + + wer = WER(vocabulary=self.vocabulary, batch_dim_index=0, use_cer=False, ctc_decode=True) + + for test_id in range(256): + n1 = random.randint(1, 512) + n2 = random.randint(1, 512) + s1 = __randomString(n1) + s2 = __randomString(n2) + # skip empty strings as reference + if s2.strip(): + assert ( + abs( + self.get_wer(wer, prediction=s1, reference=s2) + - word_error_rate(hypotheses=[s1], references=[s2]) + ) + < 1e-6 + ) + + @pytest.mark.unit + def test_wer_metric_decode(self): + wer = WER(vocabulary=self.vocabulary, batch_dim_index=0, use_cer=False, ctc_decode=True) + + tokens = self.__string_to_ctc_tensor('cat')[0].int().numpy().tolist() + assert tokens == [3, 1, 20] + + tokens_decoded = wer.decode_ids_to_tokens(tokens) + assert tokens_decoded == ['c', 'a', 't'] + + str_decoded = wer.decode_tokens_to_str(tokens) + assert str_decoded == 'cat' + + @pytest.mark.unit + def test_wer_metric_return_hypothesis(self): + wer = WER(vocabulary=self.vocabulary, batch_dim_index=0, use_cer=False, ctc_decode=True) + + tensor = self.__string_to_ctc_tensor('cat').int() + + # pass batchsize 1 tensor, get back list of length 1 Hypothesis + hyp = wer.ctc_decoder_predictions_tensor(tensor, return_hypotheses=True) + hyp = hyp[0] + assert isinstance(hyp, Hypothesis) + + assert hyp.y_sequence is None + assert hyp.score == -1.0 + assert hyp.text == 'cat' + assert hyp.alignments == [3, 1, 20] + assert hyp.length == 0 + + length = torch.tensor([tensor.shape[-1]], dtype=torch.long) + + # pass batchsize 1 tensor, get back list of length 1 Hypothesis [add length info] + hyp = wer.ctc_decoder_predictions_tensor(tensor, predictions_len=length, return_hypotheses=True) + hyp = hyp[0] + assert isinstance(hyp, Hypothesis) + assert hyp.length == 3 diff --git a/tts/NeMo/tests/collections/asr/test_asr_modules.py b/tts/NeMo/tests/collections/asr/test_asr_modules.py new file mode 100644 index 0000000..b4dd12b --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_modules.py @@ -0,0 +1,325 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import torch +from omegaconf import OmegaConf + +from nemo.collections.asr import modules +from nemo.collections.asr.parts.utils.rnnt_utils import Hypothesis +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ +from nemo.utils import config_utils, logging + + +class TestASRModulesBasicTests: + @pytest.mark.unit + def test_AudioToMelSpectrogramPreprocessor1(self): + # Test 1 that should test the pure stft implementation as much as possible + instance1 = modules.AudioToMelSpectrogramPreprocessor( + dither=0, stft_conv=False, mag_power=1.0, normalize=False, preemph=0.0, log=False, pad_to=0 + ) + instance2 = modules.AudioToMelSpectrogramPreprocessor( + dither=0, stft_conv=True, mag_power=1.0, normalize=False, preemph=0.0, log=False, pad_to=0 + ) + + # Ensure that the two functions behave similarily + for _ in range(10): + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + res1, length1 = instance1(input_signal=input_signal, length=length) + res2, length2 = instance2(input_signal=input_signal, length=length) + for len1, len2 in zip(length1, length2): + assert len1 == len2 + assert res1.shape == res2.shape + diff = torch.mean(torch.abs(res1 - res2)) + assert diff <= 1e-3 + diff = torch.max(torch.abs(res1 - res2)) + assert diff <= 1e-2 + + @pytest.mark.unit + def test_AudioToMelSpectrogramPreprocessor_config(self): + # Test that dataclass matches signature of module + result = config_utils.assert_dataclass_signature_match( + modules.AudioToMelSpectrogramPreprocessor, + modules.audio_preprocessing.AudioToMelSpectrogramPreprocessorConfig, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_AudioToMelSpectrogramPreprocessor_batch(self): + # Test 1 that should test the pure stft implementation as much as possible + instance1 = modules.AudioToMelSpectrogramPreprocessor(normalize="per_feature", dither=0, pad_to=0) + + # Ensure that the two functions behave similarily + for _ in range(10): + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + + with torch.no_grad(): + # batch size 1 + res_instance, length_instance = [], [] + for i in range(input_signal.size(0)): + res_ins, length_ins = instance1(input_signal=input_signal[i : i + 1], length=length[i : i + 1]) + res_instance.append(res_ins) + length_instance.append(length_ins) + + res_instance = torch.cat(res_instance, 0) + length_instance = torch.cat(length_instance, 0) + + # batch size 4 + res_batch, length_batch = instance1(input_signal=input_signal, length=length) + + assert res_instance.shape == res_batch.shape + assert length_instance.shape == length_batch.shape + diff = torch.mean(torch.abs(res_instance - res_batch)) + assert diff <= 1e-3 + diff = torch.max(torch.abs(res_instance - res_batch)) + assert diff <= 1e-3 + + @pytest.mark.unit + def test_AudioToMelSpectrogramPreprocessor2(self): + # Test 2 that should test the stft implementation as used in ASR models + instance1 = modules.AudioToMelSpectrogramPreprocessor(dither=0, stft_conv=False) + instance2 = modules.AudioToMelSpectrogramPreprocessor(dither=0, stft_conv=True) + + # Ensure that the two functions behave similarily + for _ in range(5): + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + res1, length1 = instance1(input_signal=input_signal, length=length) + res2, length2 = instance2(input_signal=input_signal, length=length) + for len1, len2 in zip(length1, length2): + assert len1 == len2 + assert res1.shape == res2.shape + diff = torch.mean(torch.abs(res1 - res2)) + assert diff <= 3e-3 + diff = torch.max(torch.abs(res1 - res2)) + assert diff <= 3 + + @pytest.mark.unit + def test_SpectrogramAugmentationr(self): + # Make sure constructor works + instance1 = modules.SpectrogramAugmentation( + freq_masks=10, time_masks=3, rect_masks=3, use_numba_spec_augment=False + ) + assert isinstance(instance1, modules.SpectrogramAugmentation) + + # Make sure forward doesn't throw with expected input + instance0 = modules.AudioToMelSpectrogramPreprocessor(dither=0) + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + res0 = instance0(input_signal=input_signal, length=length) + res = instance1(input_spec=res0[0]) + + assert res.shape == res0[0].shape + + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + def test_SpectrogramAugmentationr_numba_kernel(self, caplog): + numba_utils.skip_numba_cuda_test_if_unsupported(__NUMBA_MINIMUM_VERSION__) + + logging._logger.propagate = True + original_verbosity = logging.get_verbosity() + logging.set_verbosity(logging.DEBUG) + caplog.set_level(logging.DEBUG) + + # Make sure constructor works + instance1 = modules.SpectrogramAugmentation( + freq_masks=10, time_masks=3, rect_masks=3, use_numba_spec_augment=True + ) + assert isinstance(instance1, modules.SpectrogramAugmentation) + + # Make sure forward doesn't throw with expected input + instance0 = modules.AudioToMelSpectrogramPreprocessor(dither=0) + input_signal = torch.randn(size=(8, 512)) + length = torch.randint(low=161, high=500, size=[8]) + res0 = instance0(input_signal=input_signal, length=length) + res = instance1(input_spec=res0[0], length=length) + + assert res.shape == res0[0].shape + + # check tha numba kernel debug message indicates that it is available for use + assert """Numba SpecAugment kernel is available""" in caplog.text + + logging._logger.propagate = False + logging.set_verbosity(original_verbosity) + + @pytest.mark.unit + def test_SpectrogramAugmentationr_config(self): + # Test that dataclass matches signature of module + result = config_utils.assert_dataclass_signature_match( + modules.SpectrogramAugmentation, modules.audio_preprocessing.SpectrogramAugmentationConfig, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_CropOrPadSpectrogramAugmentation(self): + # Make sure constructor works + audio_length = 128 + instance1 = modules.CropOrPadSpectrogramAugmentation(audio_length=audio_length) + assert isinstance(instance1, modules.CropOrPadSpectrogramAugmentation) + + # Make sure forward doesn't throw with expected input + instance0 = modules.AudioToMelSpectrogramPreprocessor(dither=0) + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + res0 = instance0(input_signal=input_signal, length=length) + res, new_length = instance1(input_signal=res0[0], length=length) + + assert res.shape == torch.Size([4, 64, audio_length]) + assert all(new_length == torch.tensor([128] * 4)) + + @pytest.mark.unit + def test_CropOrPadSpectrogramAugmentation_config(self): + # Test that dataclass matches signature of module + result = config_utils.assert_dataclass_signature_match( + modules.CropOrPadSpectrogramAugmentation, + modules.audio_preprocessing.CropOrPadSpectrogramAugmentationConfig, + ) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_RNNTDecoder(self): + vocab = list(range(10)) + vocab = [str(x) for x in vocab] + vocab_size = len(vocab) + + pred_config = OmegaConf.create( + { + '_target_': 'nemo.collections.asr.modules.RNNTDecoder', + 'prednet': {'pred_hidden': 32, 'pred_rnn_layers': 1,}, + 'vocab_size': vocab_size, + 'blank_as_pad': True, + } + ) + + prednet = modules.RNNTDecoder.from_config_dict(pred_config) + + # num params + pred_hidden = pred_config.prednet.pred_hidden + embed = (vocab_size + 1) * pred_hidden # embedding with blank + rnn = ( + 2 * 4 * (pred_hidden * pred_hidden + pred_hidden) + ) # (ih + hh) * (ifco gates) * (indim * hiddendim + bias) + assert prednet.num_weights == (embed + rnn) + + # State initialization + x_ = torch.zeros(4, dtype=torch.float32) + states = prednet.initialize_state(x_) + + for state_i in states: + assert state_i.dtype == x_.dtype + assert state_i.device == x_.device + assert state_i.shape[1] == len(x_) + + # Blank hypotheses test + blank = vocab_size + hyp = Hypothesis(score=0.0, y_sequence=[blank]) + cache = {} + pred, states, _ = prednet.score_hypothesis(hyp, cache) + + assert pred.shape == torch.Size([1, 1, pred_hidden]) + assert len(states) == 2 + for state_i in states: + assert state_i.dtype == pred.dtype + assert state_i.device == pred.device + assert state_i.shape[1] == len(pred) + + # Blank stateless predict + g, states = prednet.predict(y=None, state=None, add_sos=False, batch_size=1) + + assert g.shape == torch.Size([1, 1, pred_hidden]) + assert len(states) == 2 + for state_i in states: + assert state_i.dtype == g.dtype + assert state_i.device == g.device + assert state_i.shape[1] == len(g) + + # Blank stateful predict + g, states2 = prednet.predict(y=None, state=states, add_sos=False, batch_size=1) + + assert g.shape == torch.Size([1, 1, pred_hidden]) + assert len(states2) == 2 + for state_i, state_j in zip(states, states2): + assert (state_i - state_j).square().sum().sqrt() > 0.0 + + # Predict with token and state + token = torch.full([1, 1], fill_value=0, dtype=torch.long) + g, states = prednet.predict(y=token, state=states2, add_sos=False, batch_size=None) + + assert g.shape == torch.Size([1, 1, pred_hidden]) + assert len(states) == 2 + + # Predict with blank token and no state + token = torch.full([1, 1], fill_value=blank, dtype=torch.long) + g, states = prednet.predict(y=token, state=None, add_sos=False, batch_size=None) + + assert g.shape == torch.Size([1, 1, pred_hidden]) + assert len(states) == 2 + + @pytest.mark.unit + def test_RNNTJoint(self): + vocab = list(range(10)) + vocab = [str(x) for x in vocab] + vocab_size = len(vocab) + + batchsize = 4 + encoder_hidden = 64 + pred_hidden = 32 + joint_hidden = 16 + + joint_cfg = OmegaConf.create( + { + '_target_': 'nemo.collections.asr.modules.RNNTJoint', + 'num_classes': vocab_size, + 'vocabulary': vocab, + 'jointnet': { + 'encoder_hidden': encoder_hidden, + 'pred_hidden': pred_hidden, + 'joint_hidden': joint_hidden, + 'activation': 'relu', + }, + } + ) + + jointnet = modules.RNNTJoint.from_config_dict(joint_cfg) + + enc = torch.zeros(batchsize, encoder_hidden, 48) # [B, D1, T] + dec = torch.zeros(batchsize, pred_hidden, 24) # [B, D2, U] + + # forward call test + out = jointnet(encoder_outputs=enc, decoder_outputs=dec) + assert out.shape == torch.Size([batchsize, 48, 24, vocab_size + 1]) # [B, T, U, V + 1] + + # joint() step test + enc2 = enc.transpose(1, 2) # [B, T, D1] + dec2 = dec.transpose(1, 2) # [B, U, D2] + out2 = jointnet.joint(enc2, dec2) # [B, T, U, V + 1] + assert (out - out2).abs().sum() <= 1e-5 + + # assert vocab size + assert jointnet.num_classes_with_blank == vocab_size + 1 diff --git a/tts/NeMo/tests/collections/asr/test_asr_regression_model.py b/tts/NeMo/tests/collections/asr/test_asr_regression_model.py new file mode 100644 index 0000000..eacce0f --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_regression_model.py @@ -0,0 +1,95 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest +from omegaconf import DictConfig + +from nemo.collections.asr.models.classification_models import EncDecRegressionModel + + +@pytest.fixture() +def speech_regression_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 32, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.conv_asr.ConvASRDecoderClassification', + 'params': {'feat_in': 32, 'return_logits': True, 'num_classes': 1}, + } + + modelConfig = DictConfig( + { + 'preprocessor': DictConfig(preprocessor), + 'encoder': DictConfig(encoder), + 'decoder': DictConfig(decoder), + 'labels': None, + 'is_regression_task': True, + } + ) + model = EncDecRegressionModel(cfg=modelConfig) + return model + + +class TestEncDecRegressionModel: + @pytest.mark.unit + def test_constructor(self, speech_regression_model): + asr_model = speech_regression_model.train() + + conv_cnt = (64 * 32 * 1 + 32) + (64 * 1 * 1 + 32) # separable kernel + bias + pointwise kernel + bias + bn_cnt = (4 * 32) * 2 # 2 * moving averages + dec_cnt = 32 * 1 + 1 # fc + bias + + param_count = conv_cnt + bn_cnt + dec_cnt + assert asr_model.num_weights == param_count + + # Check to/from config_dict: + confdict = asr_model.to_config_dict() + instance2 = EncDecRegressionModel.from_config_dict(confdict) + + assert isinstance(instance2, EncDecRegressionModel) + + @pytest.mark.unit + def test_transcription(self, speech_regression_model, test_data_dir): + + audio_filenames = ['an22-flrp-b.wav', 'an90-fbbh-b.wav'] + audio_paths = [os.path.join(test_data_dir, "asr", "train", "an4", "wav", fp) for fp in audio_filenames] + + model = speech_regression_model.eval() + + # Test Top 1 classification transcription + results = model.transcribe(audio_paths, batch_size=2) + assert len(results) == 2 diff --git a/tts/NeMo/tests/collections/asr/test_asr_rnnt_encdec_model.py b/tts/NeMo/tests/collections/asr/test_asr_rnnt_encdec_model.py new file mode 100644 index 0000000..1512415 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_rnnt_encdec_model.py @@ -0,0 +1,276 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import copy + +import pytest +import torch +from omegaconf import DictConfig, ListConfig + +from nemo.collections.asr.models import EncDecRNNTModel +from nemo.collections.asr.parts.submodules import rnnt_beam_decoding as beam_decode +from nemo.collections.asr.parts.submodules import rnnt_greedy_decoding as greedy_decode +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ +from nemo.utils.config_utils import assert_dataclass_signature_match + +NUMBA_RNNT_LOSS_AVAILABLE = numba_utils.numba_cuda_is_supported(__NUMBA_MINIMUM_VERSION__) + + +@pytest.fixture() +def asr_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + + # fmt: off + labels = [' ', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', "'", + ] + # fmt: on + + model_defaults = {'enc_hidden': 1024, 'pred_hidden': 64} + + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': model_defaults['enc_hidden'], + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + '_target_': 'nemo.collections.asr.modules.RNNTDecoder', + 'prednet': {'pred_hidden': model_defaults['pred_hidden'], 'pred_rnn_layers': 1}, + } + + joint = { + '_target_': 'nemo.collections.asr.modules.RNNTJoint', + 'jointnet': {'joint_hidden': 32, 'activation': 'relu'}, + } + + decoding = {'strategy': 'greedy_batch', 'greedy': {'max_symbols': 30}} + + modelConfig = DictConfig( + { + 'labels': ListConfig(labels), + 'preprocessor': DictConfig(preprocessor), + 'model_defaults': DictConfig(model_defaults), + 'encoder': DictConfig(encoder), + 'decoder': DictConfig(decoder), + 'joint': DictConfig(joint), + 'decoding': DictConfig(decoding), + } + ) + + model_instance = EncDecRNNTModel(cfg=modelConfig) + return model_instance + + +class TestEncDecRNNTModel: + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_constructor(self, asr_model): + asr_model.train() + # TODO: make proper config and assert correct number of weights + # Check to/from config_dict: + confdict = asr_model.to_config_dict() + instance2 = EncDecRNNTModel.from_config_dict(confdict) + assert isinstance(instance2, EncDecRNNTModel) + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_forward(self, asr_model): + asr_model = asr_model.eval() + + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + + asr_model.compute_eval_loss = False + + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + + with torch.no_grad(): + # batch size 1 + logprobs_instance = [] + for i in range(input_signal.size(0)): + logprobs_ins, _ = asr_model.forward( + input_signal=input_signal[i : i + 1], input_signal_length=length[i : i + 1] + ) + logprobs_instance.append(logprobs_ins) + logprobs_instance = torch.cat(logprobs_instance, 0) + + # batch size 4 + logprobs_batch, _ = asr_model.forward(input_signal=input_signal, input_signal_length=length) + + assert logprobs_instance.shape == logprobs_batch.shape + diff = torch.mean(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + diff = torch.max(torch.abs(logprobs_instance - logprobs_batch)) + assert diff <= 1e-6 + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_vocab_change(self, asr_model): + old_vocab = copy.deepcopy(asr_model.joint.vocabulary) + nw1 = asr_model.num_weights + asr_model.change_vocabulary(new_vocabulary=old_vocab) + # No change + assert nw1 == asr_model.num_weights + new_vocab = copy.deepcopy(old_vocab) + new_vocab.append('!') + new_vocab.append('$') + new_vocab.append('@') + asr_model.change_vocabulary(new_vocabulary=new_vocab) + # fully connected + bias + # rnn embedding + joint + bias + pred_embedding = 3 * (asr_model.decoder.pred_hidden) + joint_joint = 3 * (asr_model.joint.joint_hidden + 1) + assert asr_model.num_weights == (nw1 + (pred_embedding + joint_joint)) + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_change_conv_asr_se_context_window(self, asr_model): + old_cfg = copy.deepcopy(asr_model.cfg) + asr_model.change_conv_asr_se_context_window(context_window=32) # 32 * 0.01s context + new_config = asr_model.cfg + + assert old_cfg.encoder.jasper[0].se_context_size == -1 + assert new_config.encoder.jasper[0].se_context_size == 32 + + for name, m in asr_model.encoder.named_modules(): + if type(m).__class__.__name__ == 'SqueezeExcite': + assert m.context_window == 32 + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_change_conv_asr_se_context_window_no_config_update(self, asr_model): + old_cfg = copy.deepcopy(asr_model.cfg) + asr_model.change_conv_asr_se_context_window(context_window=32, update_config=False) # 32 * 0.01s context + new_config = asr_model.cfg + + assert old_cfg.encoder.jasper[0].se_context_size == -1 + assert new_config.encoder.jasper[0].se_context_size == -1 # no change + + for name, m in asr_model.encoder.named_modules(): + if type(m).__class__.__name__ == 'SqueezeExcite': + assert m.context_window == 32 + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_decoding_change(self, asr_model): + assert isinstance(asr_model.decoding.decoding, greedy_decode.GreedyBatchedRNNTInfer) + + new_strategy = DictConfig({}) + new_strategy.strategy = 'greedy' + new_strategy.greedy = DictConfig({'max_symbols': 10}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, greedy_decode.GreedyRNNTInfer) + + new_strategy = DictConfig({}) + new_strategy.strategy = 'beam' + new_strategy.beam = DictConfig({'beam_size': 1}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "default" + + new_strategy = DictConfig({}) + new_strategy.strategy = 'beam' + new_strategy.beam = DictConfig({'beam_size': 2}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "default" + + new_strategy = DictConfig({}) + new_strategy.strategy = 'tsd' + new_strategy.beam = DictConfig({'beam_size': 2}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "tsd" + + new_strategy = DictConfig({}) + new_strategy.strategy = 'alsd' + new_strategy.beam = DictConfig({'beam_size': 2}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "alsd" + + @pytest.mark.unit + def test_GreedyRNNTInferConfig(self): + IGNORE_ARGS = ['decoder_model', 'joint_model', 'blank_index'] + + result = assert_dataclass_signature_match( + greedy_decode.GreedyRNNTInfer, greedy_decode.GreedyRNNTInferConfig, ignore_args=IGNORE_ARGS + ) + + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_GreedyBatchedRNNTInferConfig(self): + IGNORE_ARGS = ['decoder_model', 'joint_model', 'blank_index'] + + result = assert_dataclass_signature_match( + greedy_decode.GreedyBatchedRNNTInfer, greedy_decode.GreedyBatchedRNNTInferConfig, ignore_args=IGNORE_ARGS + ) + + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_BeamRNNTInferConfig(self): + IGNORE_ARGS = ['decoder_model', 'joint_model', 'blank_index'] + + result = assert_dataclass_signature_match( + beam_decode.BeamRNNTInfer, beam_decode.BeamRNNTInferConfig, ignore_args=IGNORE_ARGS + ) + + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None diff --git a/tts/NeMo/tests/collections/asr/test_asr_rnnt_encoder_model_bpe.py b/tts/NeMo/tests/collections/asr/test_asr_rnnt_encoder_model_bpe.py new file mode 100644 index 0000000..294b03d --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_asr_rnnt_encoder_model_bpe.py @@ -0,0 +1,246 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import shutil +import tempfile + +import pytest +import torch +from omegaconf import DictConfig + +from nemo.collections.asr.models.rnnt_bpe_models import EncDecRNNTBPEModel +from nemo.collections.asr.parts.submodules import rnnt_beam_decoding as beam_decode +from nemo.collections.asr.parts.submodules import rnnt_greedy_decoding as greedy_decode +from nemo.collections.common import tokenizers +from nemo.core.utils import numba_utils +from nemo.core.utils.numba_utils import __NUMBA_MINIMUM_VERSION__ + +NUMBA_RNNT_LOSS_AVAILABLE = numba_utils.numba_cuda_is_supported(__NUMBA_MINIMUM_VERSION__) + + +@pytest.fixture() +def asr_model(test_data_dir): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + + model_defaults = {'enc_hidden': 1024, 'pred_hidden': 64} + + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': model_defaults['enc_hidden'], + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + '_target_': 'nemo.collections.asr.modules.RNNTDecoder', + 'prednet': {'pred_hidden': model_defaults['pred_hidden'], 'pred_rnn_layers': 1,}, + } + + joint = { + '_target_': 'nemo.collections.asr.modules.RNNTJoint', + 'jointnet': {'joint_hidden': 32, 'activation': 'relu',}, + } + + decoding = {'strategy': 'greedy_batch', 'greedy': {'max_symbols': 30}} + + tokenizer = {'dir': os.path.join(test_data_dir, "asr", "tokenizers", "an4_wpe_128"), 'type': 'wpe'} + + modelConfig = DictConfig( + { + 'preprocessor': DictConfig(preprocessor), + 'model_defaults': DictConfig(model_defaults), + 'encoder': DictConfig(encoder), + 'decoder': DictConfig(decoder), + 'joint': DictConfig(joint), + 'tokenizer': DictConfig(tokenizer), + 'decoding': DictConfig(decoding), + } + ) + + model_instance = EncDecRNNTBPEModel(cfg=modelConfig) + return model_instance + + +class TestEncDecRNNTBPEModel: + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_constructor(self, asr_model): + asr_model.train() + # TODO: make proper config and assert correct number of weights + # Check to/from config_dict: + confdict = asr_model.to_config_dict() + instance2 = EncDecRNNTBPEModel.from_config_dict(confdict) + assert isinstance(instance2, EncDecRNNTBPEModel) + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_forward(self, asr_model): + asr_model = asr_model.eval() + + asr_model.preprocessor.featurizer.dither = 0.0 + asr_model.preprocessor.featurizer.pad_to = 0 + + asr_model.compute_eval_loss = False + + input_signal = torch.randn(size=(4, 512)) + length = torch.randint(low=161, high=500, size=[4]) + + with torch.no_grad(): + # batch size 1 + logprobs_instance = [] + for i in range(input_signal.size(0)): + logprobs_ins, _ = asr_model.forward( + input_signal=input_signal[i : i + 1], input_signal_length=length[i : i + 1] + ) + logprobs_instance.append(logprobs_ins) + logits_instance = torch.cat(logprobs_instance, 0) + + # batch size 4 + logprobs_batch, _ = asr_model.forward(input_signal=input_signal, input_signal_length=length) + + assert logits_instance.shape == logprobs_batch.shape + diff = torch.mean(torch.abs(logits_instance - logprobs_batch)) + assert diff <= 1e-6 + diff = torch.max(torch.abs(logits_instance - logprobs_batch)) + assert diff <= 1e-6 + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_save_restore_artifact(self, asr_model): + asr_model.train() + + with tempfile.TemporaryDirectory() as tmp_dir: + path = os.path.join(tmp_dir, 'rnnt_bpe.nemo') + asr_model.save_to(path) + + new_model = EncDecRNNTBPEModel.restore_from(path) + assert isinstance(new_model, type(asr_model)) + assert new_model.vocab_path.endswith('_vocab.txt') + + assert len(new_model.tokenizer.tokenizer.get_vocab()) == 128 + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_save_restore_artifact_spe(self, asr_model, test_data_dir): + asr_model.train() + + with tempfile.TemporaryDirectory() as tmpdir: + tokenizer_dir = os.path.join(test_data_dir, "asr", "tokenizers", "an4_spe_128") + asr_model.change_vocabulary(new_tokenizer_dir=tokenizer_dir, new_tokenizer_type='bpe') + + save_path = os.path.join(tmpdir, 'ctc_bpe.nemo') + asr_model.train() + asr_model.save_to(save_path) + + new_model = EncDecRNNTBPEModel.restore_from(save_path) + assert isinstance(new_model, type(asr_model)) + assert isinstance(new_model.tokenizer, tokenizers.SentencePieceTokenizer) + assert new_model.model_path.endswith('_tokenizer.model') + assert new_model.vocab_path.endswith('_vocab.txt') + assert new_model.spe_vocab_path.endswith('_tokenizer.vocab') + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_vocab_change(self, test_data_dir, asr_model): + with tempfile.TemporaryDirectory() as tmpdir: + old_tokenizer_dir = os.path.join(test_data_dir, "asr", "tokenizers", "an4_wpe_128", 'vocab.txt') + new_tokenizer_dir = os.path.join(tmpdir, 'tokenizer') + + os.makedirs(new_tokenizer_dir, exist_ok=True) + shutil.copy2(old_tokenizer_dir, new_tokenizer_dir) + + nw1 = asr_model.num_weights + asr_model.change_vocabulary(new_tokenizer_dir=new_tokenizer_dir, new_tokenizer_type='wpe') + # No change + assert nw1 == asr_model.num_weights + + with open(os.path.join(new_tokenizer_dir, 'vocab.txt'), 'a+') as f: + f.write("!\n") + f.write('$\n') + f.write('@\n') + + asr_model.change_vocabulary(new_tokenizer_dir=new_tokenizer_dir, new_tokenizer_type='wpe') + + # rnn embedding + joint + bias + pred_embedding = 3 * (asr_model.decoder.pred_hidden) + joint_joint = 3 * (asr_model.joint.joint_hidden + 1) + assert asr_model.num_weights == (nw1 + (pred_embedding + joint_joint)) + + @pytest.mark.skipif( + not NUMBA_RNNT_LOSS_AVAILABLE, reason='RNNTLoss has not been compiled with appropriate numba version.', + ) + @pytest.mark.unit + def test_decoding_change(self, asr_model): + assert isinstance(asr_model.decoding.decoding, greedy_decode.GreedyBatchedRNNTInfer) + + new_strategy = DictConfig({}) + new_strategy.strategy = 'greedy' + new_strategy.greedy = DictConfig({'max_symbols': 10}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, greedy_decode.GreedyRNNTInfer) + + new_strategy = DictConfig({}) + new_strategy.strategy = 'beam' + new_strategy.beam = DictConfig({'beam_size': 1}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "default" + + new_strategy = DictConfig({}) + new_strategy.strategy = 'beam' + new_strategy.beam = DictConfig({'beam_size': 2}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "default" + + new_strategy = DictConfig({}) + new_strategy.strategy = 'tsd' + new_strategy.beam = DictConfig({'beam_size': 2}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "tsd" + + new_strategy = DictConfig({}) + new_strategy.strategy = 'alsd' + new_strategy.beam = DictConfig({'beam_size': 2}) + asr_model.change_decoding_strategy(decoding_cfg=new_strategy) + assert isinstance(asr_model.decoding.decoding, beam_decode.BeamRNNTInfer) + assert asr_model.decoding.decoding.search_type == "alsd" diff --git a/tts/NeMo/tests/collections/asr/test_jasper_block.py b/tts/NeMo/tests/collections/asr/test_jasper_block.py new file mode 100644 index 0000000..2b6cfb4 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_jasper_block.py @@ -0,0 +1,295 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import torch + +from nemo.collections.asr.parts.submodules import jasper + + +class TestJasperBlock: + def jasper_base_config(self, **kwargs): + base = dict( + inplanes=16, + planes=8, + kernel_size=[11], + repeat=1, + stride=[1], + dilation=[1], + activation="relu", + conv_mask=True, + separable=False, + se=False, + ) + base.update(kwargs) + return base + + def check_module_exists(self, module, cls): + global _MODULE_EXISTS + _MODULE_EXISTS = 0 + + def _traverse(m): + if isinstance(m, cls): + global _MODULE_EXISTS + _MODULE_EXISTS += 1 + + module.apply(_traverse) + assert _MODULE_EXISTS > 0 + + @pytest.mark.unit + def test_basic_block(self): + config = self.jasper_base_config(residual=False) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + + @pytest.mark.unit + def test_residual_block(self): + config = self.jasper_base_config(residual=True) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + + @pytest.mark.unit + def test_basic_block_repeat(self): + config = self.jasper_base_config(residual=False, repeat=3) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + assert len(block.mconv) == 3 * 3 + 1 # (3 repeats x {1 conv + 1 norm + 1 dropout} + final conv) + + @pytest.mark.unit + def test_basic_block_repeat_stride(self): + config = self.jasper_base_config(residual=False, repeat=3, stride=[2]) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 17]) # 131 // (stride ^ repeats) + assert ylen[0] == 17 # 131 // (stride ^ repeats) + assert len(block.mconv) == 3 * 3 + 1 # (3 repeats x {1 conv + 1 norm + 1 dropout} + final conv) + + @pytest.mark.unit + def test_basic_block_repeat_stride_last(self): + config = self.jasper_base_config(residual=False, repeat=3, stride=[2], stride_last=True) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 66]) # 131 // stride + assert ylen[0] == 66 # 131 // stride + assert len(block.mconv) == 3 * 3 + 1 # (3 repeats x {1 conv + 1 norm + 1 dropout} + final conv) + + @pytest.mark.unit + def test_basic_block_repeat_separable(self): + config = self.jasper_base_config(residual=False, repeat=3, separable=True) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + assert len(block.mconv) == 3 * 4 + 1 # (3 repeats x {1 dconv + 1 pconv + 1 norm + 1 dropout} + final conv) + + @pytest.mark.unit + def test_basic_block_stride(self): + config = self.jasper_base_config(stride=[2], residual=False) + act = jasper.jasper_activations.get(config.pop('activation'))() + + print(config) + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 66]) + assert ylen[0] == 66 + + @pytest.mark.unit + def test_residual_block_stride(self): + config = self.jasper_base_config(stride=[2], residual=True, residual_mode='stride_add') + act = jasper.jasper_activations.get(config.pop('activation'))() + + print(config) + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 66]) + assert ylen[0] == 66 + + @pytest.mark.unit + def test_residual_block_activations(self): + for activation in jasper.jasper_activations.keys(): + config = self.jasper_base_config(activation=activation) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + self.check_module_exists(block, act.__class__) + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + + @pytest.mark.unit + def test_residual_block_normalizations(self): + NORMALIZATIONS = ["batch", "layer", "group"] + for normalization in NORMALIZATIONS: + config = self.jasper_base_config(normalization=normalization) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + + @pytest.mark.unit + def test_residual_block_se(self): + config = self.jasper_base_config(se=True, se_reduction_ratio=8) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + self.check_module_exists(block, jasper.SqueezeExcite) + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + + @pytest.mark.unit + def test_residual_block_asymmetric_pad_future_contexts(self): + # test future contexts at various values + # 0 = no future context + # 2 = limited future context + # 5 = symmetric context + # 8 = excess future context (more future context than present or past context) + future_contexts = [0, 2, 5, 8] + for future_context in future_contexts: + print(future_context) + config = self.jasper_base_config(future_context=future_context) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + self.check_module_exists(block, torch.nn.ConstantPad1d) + self.check_module_exists(block, jasper.MaskedConv1d) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + assert block.mconv[0].pad_layer is not None + assert block.mconv[0]._padding == (config['kernel_size'][0] - 1 - future_context, future_context) + + @pytest.mark.unit + def test_residual_block_asymmetric_pad_future_context_fallback(self): + # test future contexts at various values + # 15 = K < FC; fall back to symmetric context + future_context = 15 + print(future_context) + config = self.jasper_base_config(future_context=future_context) + act = jasper.jasper_activations.get(config.pop('activation'))() + + block = jasper.JasperBlock(**config, activation=act) + + x = torch.randn(1, 16, 131) + xlen = torch.tensor([131]) + y, ylen = block(([x], xlen)) + + self.check_module_exists(block, jasper.MaskedConv1d) + + assert isinstance(block, jasper.JasperBlock) + assert y[0].shape == torch.Size([1, config['planes'], 131]) + assert ylen[0] == 131 + assert block.mconv[0].pad_layer is None + assert block.mconv[0]._padding == config['kernel_size'][0] // 2 + + @pytest.mark.unit + def test_padding_size_conv1d(self): + input_channels = 1 + output_channels = 1 + kernel_sizes = [3, 7, 11] + dilation_sizes = [2, 3, 4] + stride = 1 + inp = torch.rand(2, 1, 40) + + for kernel_size in kernel_sizes: + for dilation_size in dilation_sizes: + padding = jasper.get_same_padding(kernel_size, stride, dilation_size) + + conv = torch.nn.Conv1d( + input_channels, output_channels, kernel_size=kernel_size, dilation=dilation_size, padding=padding + ) + + out = conv(inp) + assert out.shape == inp.shape diff --git a/tts/NeMo/tests/collections/asr/test_label_datasets.py b/tts/NeMo/tests/collections/asr/test_label_datasets.py new file mode 100644 index 0000000..fbe9025 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_label_datasets.py @@ -0,0 +1,106 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os + +import pytest +import torch + +from nemo.collections.asr.data.audio_to_label import TarredAudioToClassificationLabelDataset +from nemo.collections.asr.data.feature_to_label import FeatureToSeqSpeakerLabelDataset +from nemo.collections.asr.parts.preprocessing.feature_loader import ExternalFeatureLoader +from nemo.collections.asr.parts.preprocessing.features import WaveformFeaturizer + + +class TestASRDatasets: + labels = ["fash", "fbbh", "fclc"] + unique_labels_in_seq = ['0', '1', '2', '3', "zero", "one", "two", "three"] + + @pytest.mark.unit + def test_tarred_dataset(self, test_data_dir): + manifest_path = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/tarred_audio_manifest.json')) + + # Test braceexpand loading + tarpath = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/audio_{0..1}.tar')) + featurizer = WaveformFeaturizer(sample_rate=16000, int_values=False, augmentor=None) + ds_braceexpand = TarredAudioToClassificationLabelDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, labels=self.labels, featurizer=featurizer + ) + + assert len(ds_braceexpand) == 32 + count = 0 + for _ in ds_braceexpand: + count += 1 + assert count == 32 + + # Test loading via list + tarpath = [os.path.abspath(os.path.join(test_data_dir, f'asr/tarred_an4/audio_{i}.tar')) for i in range(2)] + ds_list_load = TarredAudioToClassificationLabelDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, labels=self.labels, featurizer=featurizer + ) + count = 0 + for _ in ds_list_load: + count += 1 + assert count == 32 + + @pytest.mark.unit + def test_tarred_dataset_duplicate_name(self, test_data_dir): + manifest_path = os.path.abspath( + os.path.join(test_data_dir, 'asr/tarred_an4/tarred_duplicate_audio_manifest.json') + ) + + # Test braceexpand loading + tarpath = os.path.abspath(os.path.join(test_data_dir, 'asr/tarred_an4/audio_{0..1}.tar')) + featurizer = WaveformFeaturizer(sample_rate=16000, int_values=False, augmentor=None) + ds_braceexpand = TarredAudioToClassificationLabelDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, labels=self.labels, featurizer=featurizer + ) + + assert len(ds_braceexpand) == 6 + count = 0 + for _ in ds_braceexpand: + count += 1 + assert count == 6 + + # Test loading via list + tarpath = [os.path.abspath(os.path.join(test_data_dir, f'asr/tarred_an4/audio_{i}.tar')) for i in range(2)] + ds_list_load = TarredAudioToClassificationLabelDataset( + audio_tar_filepaths=tarpath, manifest_filepath=manifest_path, labels=self.labels, featurizer=featurizer + ) + count = 0 + for _ in ds_list_load: + count += 1 + assert count == 6 + + @pytest.mark.unit + def test_feat_seqlabel_dataset(self, test_data_dir): + manifest_path = os.path.abspath(os.path.join(test_data_dir, 'asr/feat/emb.json')) + feature_loader = ExternalFeatureLoader(file_path=manifest_path, sample_rate=16000, augmentor=None) + ds_braceexpand = FeatureToSeqSpeakerLabelDataset( + manifest_filepath=manifest_path, labels=self.unique_labels_in_seq, feature_loader=feature_loader + ) + # fmt: off + correct_label = torch.tensor( + [0.0, 1.0, 2.0, 2.0, 1.0, 2.0, 1.0, 2.0, 2.0, 1.0, 2.0, 2.0, 3.0, 1.0, 2.0, 2.0, 2.0, 0.0, 2.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, 2.0, 2.0, 1.0, 2.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 2.0, 1.0, 2.0, 1.0,] + ) + # fmt: on + correct_label_length = torch.tensor(50) + + assert ds_braceexpand[0][0].shape == (50, 32) + assert torch.equal(ds_braceexpand[0][2], correct_label) + assert torch.equal(ds_braceexpand[0][3], correct_label_length) + + count = 0 + for _ in ds_braceexpand: + count += 1 + assert count == 2 diff --git a/tts/NeMo/tests/collections/asr/test_speaker_label_models.py b/tts/NeMo/tests/collections/asr/test_speaker_label_models.py new file mode 100644 index 0000000..f11f880 --- /dev/null +++ b/tts/NeMo/tests/collections/asr/test_speaker_label_models.py @@ -0,0 +1,63 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from unittest import TestCase + +import pytest +from omegaconf import DictConfig + +from nemo.collections.asr.models import EncDecSpeakerLabelModel + + +class EncDecSpeechLabelModelTest(TestCase): + @pytest.mark.unit + def test_constructor(self): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 512, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': False, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.SpeakerDecoder', + 'params': {'feat_in': 512, 'num_classes': 2, 'pool_mode': 'xvector', 'emb_sizes': [1024]}, + } + + modelConfig = DictConfig( + {'preprocessor': DictConfig(preprocessor), 'encoder': DictConfig(encoder), 'decoder': DictConfig(decoder)} + ) + speaker_model = EncDecSpeakerLabelModel(cfg=modelConfig) + speaker_model.train() + # TODO: make proper config and assert correct number of weights + + # Check to/from config_dict: + confdict = speaker_model.to_config_dict() + instance2 = EncDecSpeakerLabelModel.from_config_dict(confdict) + self.assertTrue(isinstance(instance2, EncDecSpeakerLabelModel)) diff --git a/tts/NeMo/tests/collections/common/__init__.py b/tts/NeMo/tests/collections/common/__init__.py new file mode 100644 index 0000000..9e32500 --- /dev/null +++ b/tts/NeMo/tests/collections/common/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. diff --git a/tts/NeMo/tests/collections/common/loss_inputs.py b/tts/NeMo/tests/collections/common/loss_inputs.py new file mode 100644 index 0000000..cc3c384 --- /dev/null +++ b/tts/NeMo/tests/collections/common/loss_inputs.py @@ -0,0 +1,69 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# Copyright 2018-2020 William Falcon +# +# 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. + +from dataclasses import dataclass + +import torch + +from .pl_utils import BATCH_SIZE, NUM_BATCHES, NUM_CLASSES + + +@dataclass(frozen=True) +class LossInput: + """ + The input for ``nemo.collections.common.metrics.GlobalAverageLossMetric`` metric tests. + + Args: + loss_sum_or_avg: a one dimensional float tensor which contains losses for averaging. Each element is either a + sum or mean of several losses depending on the parameter ``take_avg_loss`` of the + ``nemo.collections.common.metrics.GlobalAverageLossMetric`` class. + num_measurements: a one dimensional integer tensor which contains number of measurements which sums or average + values are in ``loss_sum_or_avg``. + """ + + loss_sum_or_avg: torch.Tensor + num_measurements: torch.Tensor + + +NO_ZERO_NUM_MEASUREMENTS = LossInput( + loss_sum_or_avg=torch.rand(NUM_BATCHES) * 2.0 - 1.0, num_measurements=torch.randint(1, 100, (NUM_BATCHES,)), +) + +SOME_NUM_MEASUREMENTS_ARE_ZERO = LossInput( + loss_sum_or_avg=torch.rand(NUM_BATCHES) * 2.0 - 1.0, + num_measurements=torch.cat( + ( + torch.randint(1, 100, (NUM_BATCHES // 2,), dtype=torch.int32), + torch.zeros(NUM_BATCHES - NUM_BATCHES // 2, dtype=torch.int32), + ) + ), +) + +ALL_NUM_MEASUREMENTS_ARE_ZERO = LossInput( + loss_sum_or_avg=torch.rand(NUM_BATCHES) * 2.0 - 1.0, num_measurements=torch.zeros(NUM_BATCHES, dtype=torch.int32), +) diff --git a/tts/NeMo/tests/collections/common/perplexity_inputs.py b/tts/NeMo/tests/collections/common/perplexity_inputs.py new file mode 100644 index 0000000..6e785ba --- /dev/null +++ b/tts/NeMo/tests/collections/common/perplexity_inputs.py @@ -0,0 +1,49 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# Copyright 2018-2020 William Falcon +# +# 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. + +from collections import namedtuple + +import torch + +from .pl_utils import BATCH_SIZE, NUM_BATCHES, NUM_CLASSES + +Input = namedtuple('Input', ["probs", "logits"]) + + +ONLY_PROBS = Input(probs=torch.rand(NUM_BATCHES, BATCH_SIZE, NUM_CLASSES), logits=None) + +ONLY_LOGITS1 = Input(probs=None, logits=torch.rand(NUM_BATCHES, BATCH_SIZE, NUM_CLASSES)) + +ONLY_LOGITS100 = Input(probs=None, logits=torch.rand(NUM_BATCHES, BATCH_SIZE, NUM_CLASSES) * 200 - 100) + +PROBS_AND_LOGITS = Input( + probs=torch.rand(NUM_BATCHES, BATCH_SIZE, NUM_CLASSES), + logits=torch.rand(NUM_BATCHES, BATCH_SIZE, NUM_CLASSES) * 200 - 100, +) + +NO_PROBS_NO_LOGITS = Input(probs=None, logits=None) diff --git a/tts/NeMo/tests/collections/common/pl_utils.py b/tts/NeMo/tests/collections/common/pl_utils.py new file mode 100644 index 0000000..b902e40 --- /dev/null +++ b/tts/NeMo/tests/collections/common/pl_utils.py @@ -0,0 +1,557 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +# Copyright 2018-2020 William Falcon +# +# 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 os +import pickle +import sys +from functools import partial +from typing import Callable, Optional + +import numpy as np +import pytest +import torch +from scipy.stats import entropy +from torch.distributions.utils import logits_to_probs +from torch.multiprocessing import Pool, set_start_method +from torchmetrics import Metric + +from nemo.collections.common.metrics import GlobalAverageLossMetric, Perplexity + +NUM_PROCESSES = 2 +NUM_BATCHES = 10 +BATCH_SIZE = 16 +NUM_CLASSES = 5 +EXTRA_DIM = 3 +THRESHOLD = 0.5 + + +def setup_ddp(rank, world_size): + """ Setup ddp enviroment """ + os.environ["MASTER_ADDR"] = 'localhost' + os.environ['MASTER_PORT'] = '8088' + + if torch.distributed.is_available() and sys.platform not in ['win32', 'cygwin']: + torch.distributed.init_process_group("gloo", rank=rank, world_size=world_size) + + +def _class_test( + rank: int, + worldsize: int, + preds: torch.Tensor, + target: torch.Tensor, + metric_class: Metric, + sk_metric: Callable, + dist_sync_on_step: bool, + metric_args: dict = {}, + check_dist_sync_on_step: bool = True, + check_batch: bool = True, + atol: float = 1e-8, +): + """ Utility function doing the actual comparison between lightning class metric + and reference metric. + Args: + rank: rank of current process + worldsize: number of processes + preds: torch tensor with predictions + target: torch tensor with targets + metric_class: lightning metric class that should be tested + sk_metric: callable function that is used for comparison + dist_sync_on_step: bool, if true will synchronize metric state across + processes at each ``forward()`` + metric_args: dict with additional arguments used for class initialization + check_dist_sync_on_step: bool, if true will check if the metric is also correctly + calculated per batch per device (and not just at the end) + check_batch: bool, if true will check if the metric is also correctly + calculated across devices for each batch (and not just at the end) + """ + # Instanciate lightning metric + metric = metric_class(compute_on_step=True, dist_sync_on_step=dist_sync_on_step, **metric_args) + + # verify metrics work after being loaded from pickled state + pickled_metric = pickle.dumps(metric) + metric = pickle.loads(pickled_metric) + + for i in range(rank, NUM_BATCHES, worldsize): + batch_result = metric(preds[i], target[i]) + + if metric.dist_sync_on_step: + if rank == 0: + ddp_preds = torch.stack([preds[i + r] for r in range(worldsize)]) + ddp_target = torch.stack([target[i + r] for r in range(worldsize)]) + sk_batch_result = sk_metric(ddp_preds, ddp_target) + # assert for dist_sync_on_step + if check_dist_sync_on_step: + assert np.allclose(batch_result.numpy(), sk_batch_result, atol=atol) + else: + sk_batch_result = sk_metric(preds[i], target[i]) + # assert for batch + if check_batch: + assert np.allclose(batch_result.numpy(), sk_batch_result, atol=atol) + + # check on all batches on all ranks + result = metric.compute() + assert isinstance(result, torch.Tensor) + + total_preds = torch.stack([preds[i] for i in range(NUM_BATCHES)]) + total_target = torch.stack([target[i] for i in range(NUM_BATCHES)]) + sk_result = sk_metric(total_preds, total_target) + + # assert after aggregation + assert np.allclose(result.numpy(), sk_result, atol=atol) + + +def _functional_test( + preds: torch.Tensor, + target: torch.Tensor, + metric_functional: Callable, + sk_metric: Callable, + metric_args: dict = {}, + atol: float = 1e-8, +): + """ Utility function doing the actual comparison between lightning functional metric + and reference metric. + Args: + preds: torch tensor with predictions + target: torch tensor with targets + metric_functional: lightning metric functional that should be tested + sk_metric: callable function that is used for comparison + metric_args: dict with additional arguments used for class initialization + """ + metric = partial(metric_functional, **metric_args) + + for i in range(NUM_BATCHES): + lightning_result = metric(preds[i], target[i]) + sk_result = sk_metric(preds[i], target[i]) + + # assert its the same + assert np.allclose(lightning_result.numpy(), sk_result, atol=atol) + + +class MetricTester: + """ Class used for efficiently run alot of parametrized tests in ddp mode. + Makes sure that ddp is only setup once and that pool of processes are + used for all tests. + All tests should subclass from this and implement a new method called + `test_metric_name` + where the method `self.run_metric_test` is called inside. + """ + + atol = 1e-8 + + def setup_class(self): + """ Setup the metric class. This will spawn the pool of workers that are + used for metric testing and setup_ddp + """ + try: + set_start_method('spawn') + except RuntimeError: + pass + self.poolSize = NUM_PROCESSES + self.pool = Pool(processes=self.poolSize) + self.pool.starmap(setup_ddp, [(rank, self.poolSize) for rank in range(self.poolSize)]) + + def teardown_class(self): + """ Close pool of workers """ + self.pool.close() + self.pool.join() + + def run_functional_metric_test( + self, + preds: torch.Tensor, + target: torch.Tensor, + metric_functional: Callable, + sk_metric: Callable, + metric_args: dict = {}, + ): + """ Main method that should be used for testing functions. Call this inside + testing method + Args: + preds: torch tensor with predictions + target: torch tensor with targets + metric_functional: lightning metric class that should be tested + sk_metric: callable function that is used for comparison + metric_args: dict with additional arguments used for class initialization + """ + _functional_test( + preds=preds, + target=target, + metric_functional=metric_functional, + sk_metric=sk_metric, + metric_args=metric_args, + atol=self.atol, + ) + + def run_class_metric_test( + self, + ddp: bool, + preds: torch.Tensor, + target: torch.Tensor, + metric_class: Metric, + sk_metric: Callable, + dist_sync_on_step: bool, + metric_args: dict = {}, + check_dist_sync_on_step: bool = True, + check_batch: bool = True, + ): + """ Main method that should be used for testing class. Call this inside testing + methods. + Args: + ddp: bool, if running in ddp mode or not + preds: torch tensor with predictions + target: torch tensor with targets + metric_class: lightning metric class that should be tested + sk_metric: callable function that is used for comparison + dist_sync_on_step: bool, if true will synchronize metric state across + processes at each ``forward()`` + metric_args: dict with additional arguments used for class initialization + check_dist_sync_on_step: bool, if true will check if the metric is also correctly + calculated per batch per device (and not just at the end) + check_batch: bool, if true will check if the metric is also correctly + calculated across devices for each batch (and not just at the end) + """ + if ddp: + if sys.platform == "win32": + pytest.skip("DDP not supported on windows") + + self.pool.starmap( + partial( + _class_test, + preds=preds, + target=target, + metric_class=metric_class, + sk_metric=sk_metric, + dist_sync_on_step=dist_sync_on_step, + metric_args=metric_args, + check_dist_sync_on_step=check_dist_sync_on_step, + check_batch=check_batch, + atol=self.atol, + ), + [(rank, self.poolSize) for rank in range(self.poolSize)], + ) + else: + _class_test( + 0, + 1, + preds=preds, + target=target, + metric_class=metric_class, + sk_metric=sk_metric, + dist_sync_on_step=dist_sync_on_step, + metric_args=metric_args, + check_dist_sync_on_step=check_dist_sync_on_step, + check_batch=check_batch, + atol=self.atol, + ) + + +def reference_perplexity_func(probs): + ent = entropy(probs, axis=-1) + ppl = np.exp(ent) + return ppl.mean() + + +def _perplexity_class_test( + rank: int, + worldsize: int, + probs: Optional[torch.Tensor], + logits: Optional[torch.Tensor], + dist_sync_on_step: bool, + metric_args: dict = {}, + check_dist_sync_on_step: bool = True, + check_batch: bool = True, + atol: float = 1e-8, +): + """ Utility function doing the actual comparison between lightning class metric + and reference metric. + Args: + rank: rank of current process + worldsize: number of processes + probs: torch tensor with probabilities + logits: torch tensor with logits. The function checks ``probs`` and ``logits are mutually exclusive for + ``Perplexity`` metric. + dist_sync_on_step: bool, if true will synchronize metric state across + processes at each ``forward()`` + metric_args: dict with additional arguments used for class initialization + check_dist_sync_on_step: bool, if true will check if the metric is also correctly + calculated per batch per device (and not just at the end) + check_batch: bool, if true will check if the metric is also correctly + calculated across devices for each batch (and not just at the end) + """ + # Instanciate lightning metric + perplexity = Perplexity(compute_on_step=True, dist_sync_on_step=dist_sync_on_step, **metric_args) + if (probs is None) == (logits is None): + with pytest.raises(ValueError): + perplexity(probs, logits) + return + + # verify perplexity works after being loaded from pickled state + pickled_metric = pickle.dumps(perplexity) + perplexity = pickle.loads(pickled_metric) + + for i in range(rank, NUM_BATCHES, worldsize): + batch_result = perplexity(None if probs is None else probs[i], None if logits is None else logits[i]) + + if perplexity.dist_sync_on_step: + if rank == 0: + if probs is not None: + ddp_probs = torch.stack([probs[i + r] for r in range(worldsize)]) + else: + ddp_logits = torch.stack([logits[i + r] for r in range(worldsize)]) + ddp_probs = logits_to_probs(ddp_logits, is_binary=False) + sk_batch_result = reference_perplexity_func(ddp_probs) + # assert for dist_sync_on_step + if check_dist_sync_on_step: + assert np.allclose(batch_result.numpy(), sk_batch_result, atol=atol) + else: + if probs is None: + p = logits_to_probs(logits[i], is_binary=False) + else: + p = probs[i] + sk_batch_result = reference_perplexity_func(p) + # assert for batch + if check_batch: + assert np.allclose(batch_result.numpy(), sk_batch_result, atol=atol) + + assert (probs is None) != (logits is None) + # check on all batches on all ranks + result = perplexity.compute() + assert isinstance(result, torch.Tensor) + + if probs is None: + probs = logits_to_probs(logits, is_binary=False) + sk_result = reference_perplexity_func(probs) + + # assert after aggregation + assert np.allclose(result.numpy(), sk_result, atol=atol) + + +class PerplexityTester(MetricTester): + def run_class_perplexity_test( + self, + ddp: bool, + probs: Optional[torch.Tensor], + logits: Optional[torch.Tensor], + dist_sync_on_step: bool, + metric_args: dict = {}, + check_dist_sync_on_step: bool = True, + check_batch: bool = True, + ): + """ Main method that should be used for testing class. Call this inside testing + methods. + Args: + ddp: bool, if running in ddp mode or not + probs: torch tensor with probabilities. + logits: torch tensor with logits. This test checks that probs and logits are mutually exclusive for + ``Perplexity`` metric. + dist_sync_on_step: bool, if true will synchronize metric state across + processes at each ``forward()`` + metric_args: dict with additional arguments used for class initialization + check_dist_sync_on_step: bool, if true will check if the metric is also correctly + calculated per batch per device (and not just at the end) + check_batch: bool, if true will check if the metric is also correctly + calculated across devices for each batch (and not just at the end) + """ + if ddp: + if sys.platform == "win32": + pytest.skip("DDP not supported on windows") + + self.pool.starmap( + partial( + _perplexity_class_test, + probs=probs, + logits=logits, + dist_sync_on_step=dist_sync_on_step, + metric_args=metric_args, + check_dist_sync_on_step=check_dist_sync_on_step, + check_batch=check_batch, + atol=self.atol, + ), + [(rank, self.poolSize) for rank in range(self.poolSize)], + ) + else: + _perplexity_class_test( + 0, + 1, + probs=probs, + logits=logits, + dist_sync_on_step=dist_sync_on_step, + metric_args=metric_args, + check_dist_sync_on_step=check_dist_sync_on_step, + check_batch=check_batch, + atol=self.atol, + ) + + +def reference_loss_func(loss_sum_or_avg: torch.Tensor, num_measurements: torch.Tensor, take_avg_loss: bool): + """ + Returns average loss for data from``loss_sum_or_avg``. This function sums all losses from ``loss_sum_or_avg`` and + divides the sum by the sum of ``num_measurements`` elements. + + If ``take_avg_loss`` is ``True`` then ``loss_sum_or_avg[i]`` elements are mean values of ``num_measurements[i]`` + losses. In that case before computing sum of losses each element of ``loss_sum_or_avg`` is multiplied by + corresponding element of ``num_measurements``. + + If ``num_measurements`` sum is zero then the function returns NaN tensor. + + The function is used for testing ``nemo.collections.common.metrics.GlobalAverageLossMetric`` class. + + Args: + loss_sum_or_avg: a one dimensional float ``torch.Tensor``. Sums or mean values of loss. + num_measurements: a one dimensional integer ``torch.Tensor``. Number of values on which sums of means in + ``loss_sum_or_avg`` are calculated. + take_avg_loss: if ``True`` then ``loss_sum_or_avg`` contains mean losses else ``loss_sum_or_avg`` contains + sums of losses. + """ + if take_avg_loss: + for i in range(loss_sum_or_avg.shape[0]): + loss_sum_or_avg[i] *= num_measurements[i] + nm_sum = num_measurements.sum() + if nm_sum.eq(0): + return torch.tensor(float('nan')) + return loss_sum_or_avg.sum() / nm_sum + + +def _loss_class_test( + rank: int, + worldsize: int, + loss_sum_or_avg: Optional[torch.Tensor], + num_measurements: Optional[torch.Tensor], + dist_sync_on_step: bool, + take_avg_loss: bool, + check_dist_sync_on_step: bool = True, + check_batch: bool = True, + atol: float = 1e-8, +): + """ Utility function doing the actual comparison between lightning class metric + and reference metric. + Args: + rank: rank of current process + worldsize: number of processes + loss_sum_or_avg: a one dimensional float torch tensor with loss sums or means. + num_measurements: a one dimensional integer torch tensor with number of values on which sums or means from + ``loss_sum_or_avg`` were computed. + dist_sync_on_step: bool, if true will synchronize metric state across + processes at each ``forward()`` + take_avg_loss: dict with additional arguments used for class initialization + check_dist_sync_on_step: bool, if true will check if the metric is also correctly + calculated per batch per device (and not just at the end) + check_batch: bool, if true will check if the metric is also correctly + calculated across devices for each batch (and not just at the end) + """ + # Instantiate lightning metric + loss_metric = GlobalAverageLossMetric( + compute_on_step=True, dist_sync_on_step=dist_sync_on_step, take_avg_loss=take_avg_loss + ) + + # verify perplexity works after being loaded from pickled state + pickled_metric = pickle.dumps(loss_metric) + loss_metric = pickle.loads(pickled_metric) + + for i in range(rank, NUM_BATCHES, worldsize): + batch_result = loss_metric(loss_sum_or_avg[i], num_measurements[i]) + if loss_metric.dist_sync_on_step: + if rank == 0: + ddp_loss_sum_or_avg = torch.stack([loss_sum_or_avg[i + r] for r in range(worldsize)]) + ddp_num_measurements = torch.stack([num_measurements[i + r] for r in range(worldsize)]) + sk_batch_result = reference_loss_func(ddp_loss_sum_or_avg, ddp_num_measurements, take_avg_loss) + # assert for dist_sync_on_step + if check_dist_sync_on_step: + if sk_batch_result.isnan(): + assert batch_result.isnan() + else: + assert ( + np.allclose(batch_result.numpy(), sk_batch_result, atol=atol), + f"batch_result = {batch_result.numpy()}, sk_batch_result = {sk_batch_result}", + ) + else: + ls = loss_sum_or_avg[i : i + 1] + nm = num_measurements[i : i + 1] + sk_batch_result = reference_loss_func(ls, nm, take_avg_loss) + # assert for batch + if check_batch: + if sk_batch_result.isnan(): + assert batch_result.isnan() + else: + assert ( + np.allclose(batch_result.numpy(), sk_batch_result, atol=atol), + f"batch_result = {batch_result.numpy()}, sk_batch_result = {sk_batch_result}", + ) + # check on all batches on all ranks + result = loss_metric.compute() + assert isinstance(result, torch.Tensor) + sk_result = reference_loss_func(loss_sum_or_avg, num_measurements, take_avg_loss) + + # assert after aggregation + if sk_result.isnan(): + assert result.isnan() + else: + assert ( + np.allclose(result.numpy(), sk_result, atol=atol), + f"result = {result.numpy()}, sk_result = {sk_result}", + ) + + +class LossTester(MetricTester): + def run_class_loss_test( + self, + ddp: bool, + loss_sum_or_avg: torch.Tensor, + num_measurements: torch.Tensor, + dist_sync_on_step: bool, + take_avg_loss: bool, + check_dist_sync_on_step: bool = True, + check_batch: bool = True, + ): + if ddp: + if sys.platform == "win32": + pytest.skip("DDP not supported on windows") + self.pool.starmap( + partial( + _loss_class_test, + loss_sum_or_avg=loss_sum_or_avg, + num_measurements=num_measurements, + dist_sync_on_step=dist_sync_on_step, + take_avg_loss=take_avg_loss, + check_dist_sync_on_step=check_dist_sync_on_step, + check_batch=check_batch, + atol=self.atol, + ), + [(rank, self.poolSize) for rank in range(self.poolSize)], + ) + else: + _loss_class_test( + 0, + 1, + loss_sum_or_avg=loss_sum_or_avg, + num_measurements=num_measurements, + dist_sync_on_step=dist_sync_on_step, + take_avg_loss=take_avg_loss, + check_dist_sync_on_step=check_dist_sync_on_step, + check_batch=check_batch, + atol=self.atol, + ) diff --git a/tts/NeMo/tests/collections/common/test_metrics.py b/tts/NeMo/tests/collections/common/test_metrics.py new file mode 100644 index 0000000..6729ae3 --- /dev/null +++ b/tts/NeMo/tests/collections/common/test_metrics.py @@ -0,0 +1,150 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import torch + +from .loss_inputs import ALL_NUM_MEASUREMENTS_ARE_ZERO, NO_ZERO_NUM_MEASUREMENTS, SOME_NUM_MEASUREMENTS_ARE_ZERO +from .perplexity_inputs import NO_PROBS_NO_LOGITS, ONLY_LOGITS1, ONLY_LOGITS100, ONLY_PROBS, PROBS_AND_LOGITS +from .pl_utils import LossTester, PerplexityTester +from nemo.collections.common.metrics.classification_accuracy import TopKClassificationAccuracy + + +class TestCommonMetrics: + top_k_logits = torch.tensor([[0.1, 0.3, 0.2, 0.0], [0.9, 0.6, 0.2, 0.3], [0.2, 0.1, 0.4, 0.3]],) # 1 # 0 # 2 + + @pytest.mark.unit + def test_top_1_accuracy(self): + labels = torch.tensor([0, 0, 2], dtype=torch.long) + + accuracy = TopKClassificationAccuracy(top_k=None) + acc = accuracy(logits=self.top_k_logits, labels=labels) + + assert accuracy.correct_counts_k.shape == torch.Size([1]) + assert accuracy.total_counts_k.shape == torch.Size([1]) + assert abs(acc[0] - 0.667) < 1e-3 + + @pytest.mark.unit + def test_top_1_2_accuracy(self): + labels = torch.tensor([0, 1, 0], dtype=torch.long) + + accuracy = TopKClassificationAccuracy(top_k=[1, 2]) + top1_acc, top2_acc = accuracy(logits=self.top_k_logits, labels=labels) + + assert accuracy.correct_counts_k.shape == torch.Size([2]) + assert accuracy.total_counts_k.shape == torch.Size([2]) + + assert abs(top1_acc - 0.0) < 1e-3 + assert abs(top2_acc - 0.333) < 1e-3 + + @pytest.mark.unit + def test_top_1_accuracy_distributed(self): + # Simulate test on 2 process DDP execution + labels = torch.tensor([[0, 0, 2], [2, 0, 0]], dtype=torch.long) + + accuracy = TopKClassificationAccuracy(top_k=None) + proc1_acc = accuracy(logits=self.top_k_logits, labels=labels[0]) + correct1, total1 = accuracy.correct_counts_k, accuracy.total_counts_k + + accuracy.reset() + proc2_acc = accuracy(logits=torch.flip(self.top_k_logits, dims=[1]), labels=labels[1]) # reverse logits + correct2, total2 = accuracy.correct_counts_k, accuracy.total_counts_k + + correct = torch.stack([correct1, correct2]) + total = torch.stack([total1, total2]) + + assert correct.shape == torch.Size([2, 1]) + assert total.shape == torch.Size([2, 1]) + + assert abs(proc1_acc[0] - 0.667) < 1e-3 # 2/3 + assert abs(proc2_acc[0] - 0.333) < 1e-3 # 1/3 + + accuracy.reset() + accuracy.correct_counts_k = torch.tensor([correct.sum()]) + accuracy.total_counts_k = torch.tensor([total.sum()]) + acc_topk = accuracy.compute() + acc_top1 = acc_topk[0] + + assert abs(acc_top1 - 0.5) < 1e-3 # 3/6 + + @pytest.mark.unit + def test_top_1_accuracy_distributed_uneven_batch(self): + # Simulate test on 2 process DDP execution + accuracy = TopKClassificationAccuracy(top_k=None) + + proc1_acc = accuracy(logits=self.top_k_logits, labels=torch.tensor([0, 0, 2])) + correct1, total1 = accuracy.correct_counts_k, accuracy.total_counts_k + + proc2_acc = accuracy( + logits=torch.flip(self.top_k_logits, dims=[1])[:2, :], # reverse logits, select first 2 samples + labels=torch.tensor([2, 0]), + ) # reduce number of labels + correct2, total2 = accuracy.correct_counts_k, accuracy.total_counts_k + + correct = torch.stack([correct1, correct2]) + total = torch.stack([total1, total2]) + + assert correct.shape == torch.Size([2, 1]) + assert total.shape == torch.Size([2, 1]) + + assert abs(proc1_acc[0] - 0.667) < 1e-3 # 2/3 + assert abs(proc2_acc[0] - 0.500) < 1e-3 # 1/2 + + accuracy.correct_counts_k = torch.tensor([correct.sum()]) + accuracy.total_counts_k = torch.tensor([total.sum()]) + acc_topk = accuracy.compute() + acc_top1 = acc_topk[0] + + assert abs(acc_top1 - 0.6) < 1e-3 # 3/5 + + +@pytest.mark.parametrize("ddp", [True, False]) +@pytest.mark.parametrize("dist_sync_on_step", [True, False]) +@pytest.mark.parametrize( + "probs, logits", + [ + (ONLY_PROBS.probs, ONLY_PROBS.logits), + (ONLY_LOGITS1.probs, ONLY_LOGITS1.logits), + (ONLY_LOGITS100.probs, ONLY_LOGITS100.logits), + (PROBS_AND_LOGITS.probs, PROBS_AND_LOGITS.logits), + (NO_PROBS_NO_LOGITS.probs, NO_PROBS_NO_LOGITS.logits), + ], +) +class TestPerplexity(PerplexityTester): + def test_perplexity(self, ddp, dist_sync_on_step, probs, logits): + self.run_class_perplexity_test( + ddp=ddp, probs=probs, logits=logits, dist_sync_on_step=dist_sync_on_step, + ) + + +@pytest.mark.parametrize("ddp", [True, False]) +@pytest.mark.parametrize("dist_sync_on_step", [True, False]) +@pytest.mark.parametrize("take_avg_loss", [True, False]) +@pytest.mark.parametrize( + "loss_sum_or_avg, num_measurements", + [ + (NO_ZERO_NUM_MEASUREMENTS.loss_sum_or_avg, NO_ZERO_NUM_MEASUREMENTS.num_measurements), + (SOME_NUM_MEASUREMENTS_ARE_ZERO.loss_sum_or_avg, SOME_NUM_MEASUREMENTS_ARE_ZERO.num_measurements), + (ALL_NUM_MEASUREMENTS_ARE_ZERO.loss_sum_or_avg, ALL_NUM_MEASUREMENTS_ARE_ZERO.num_measurements), + ], +) +class TestLoss(LossTester): + def test_loss(self, ddp, dist_sync_on_step, loss_sum_or_avg, num_measurements, take_avg_loss): + self.run_class_loss_test( + ddp=ddp, + loss_sum_or_avg=loss_sum_or_avg, + num_measurements=num_measurements, + dist_sync_on_step=dist_sync_on_step, + take_avg_loss=take_avg_loss, + ) diff --git a/tts/NeMo/tests/collections/common/test_spc_tokenizer.py b/tts/NeMo/tests/collections/common/test_spc_tokenizer.py new file mode 100644 index 0000000..da7b079 --- /dev/null +++ b/tts/NeMo/tests/collections/common/test_spc_tokenizer.py @@ -0,0 +1,267 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from nemo.collections.common.tokenizers.sentencepiece_tokenizer import SentencePieceTokenizer +from nemo.collections.common.tokenizers.youtokentome_tokenizer import YouTokenToMeTokenizer + +MODEL_SPECIAL_TOKENS = { + 'unk_token': '[UNK]', + 'sep_token': '[SEP]', + 'pad_token': '[PAD]', + 'bos_token': '[CLS]', + 'mask_token': '[MASK]', + 'eos_token': '[SEP]', + 'cls_token': '[CLS]', +} + + +class TestSentencePieceTokenizerLegacy: + model_name = "/m_common.model" + + @pytest.mark.unit + def test_add_special_tokens(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + special_tokens = MODEL_SPECIAL_TOKENS + tokenizer.add_special_tokens(special_tokens) + assert tokenizer.vocab_size == tokenizer.original_vocab_size + len(set(special_tokens.values())) + + @pytest.mark.unit + def test_text_to_tokens(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + special_tokens = MODEL_SPECIAL_TOKENS + tokenizer.add_special_tokens(special_tokens) + + text = "[CLS] a b c [MASK] e f [SEP] g h i [SEP]" + tokens = tokenizer.text_to_tokens(text) + + assert len(tokens) == len(text.split()) + assert tokens.count("[CLS]") == 1 + assert tokens.count("[MASK]") == 1 + assert tokens.count("[SEP]") == 2 + + @pytest.mark.unit + def test_tokens_to_text(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + + text = "[CLS] a b c [MASK] e f [SEP] g h i [SEP]" + tokens = tokenizer.text_to_tokens(text) + result = tokenizer.tokens_to_text(tokens) + + assert text == result + + @pytest.mark.unit + def test_text_to_ids(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + special_tokens = MODEL_SPECIAL_TOKENS + tokenizer.add_special_tokens(special_tokens) + + text = "[CLS] a b c [MASK] e f [SEP] g h i [SEP]" + ids = tokenizer.text_to_ids(text) + + assert len(ids) == len(text.split()) + assert ids.count(tokenizer.token_to_id("[CLS]")) == 1 + assert ids.count(tokenizer.token_to_id("[MASK]")) == 1 + assert ids.count(tokenizer.token_to_id("[SEP]")) == 2 + + @pytest.mark.unit + def test_ids_to_text(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + special_tokens = MODEL_SPECIAL_TOKENS + tokenizer.add_special_tokens(special_tokens) + + text = "[CLS] a b c [MASK] e f [SEP] g h i [SEP]" + ids = tokenizer.text_to_ids(text) + result = tokenizer.ids_to_text(ids) + + assert text == result + + @pytest.mark.unit + def test_tokens_to_ids(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + special_tokens = MODEL_SPECIAL_TOKENS + tokenizer.add_special_tokens(special_tokens) + + text = "[CLS] a b c [MASK] e f [SEP] g h i [SEP]" + tokens = tokenizer.text_to_tokens(text) + ids = tokenizer.tokens_to_ids(tokens) + + assert len(ids) == len(tokens) + assert ids.count(tokenizer.token_to_id("[CLS]")) == 1 + assert ids.count(tokenizer.token_to_id("[MASK]")) == 1 + assert ids.count(tokenizer.token_to_id("[SEP]")) == 2 + + @pytest.mark.unit + def test_ids_to_tokens(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name, legacy=True) + special_tokens = MODEL_SPECIAL_TOKENS + tokenizer.add_special_tokens(special_tokens) + + text = "[CLS] a b c [MASK] e f [SEP] g h i [SEP]" + tokens = tokenizer.text_to_tokens(text) + ids = tokenizer.tokens_to_ids(tokens) + result = tokenizer.ids_to_tokens(ids) + + assert len(result) == len(tokens) + + for i in range(len(result)): + assert result[i] == tokens[i] + + +class TestSentencePieceTokenizer: + model_name = "/m_new.model" + + @pytest.mark.unit + def test_text_to_tokens(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name) + + # is user_defined_symbol in the test tokenizer model + # , , , and are control symbols + text = " a b c e f g h i
+
+ +
+
+ ASR Transcription + +
+
+
+ + +
+ +
+ +
Model Name : + + +
+ +
+ + + + + + + +  
+ NeMo File : + + + + +
+ + + + +
+ +
+
+ + +
+ + + + + +
+
+
+ + + + +
+ + + + +
+
+ +
+ +
+
+
" + tokens = tokenizer.text_to_tokens(text) + + assert tokens.count("") == 1 + assert tokens.count("") == 0 + assert tokens.count("
") == 0 + + @pytest.mark.unit + def test_tokens_to_text(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name) + + # is user_defined_symbol in the test tokenizer model + text = " a b c e f g h i" + tokens = tokenizer.text_to_tokens(text) + result = tokenizer.tokens_to_text(tokens) + + assert text == result + + @pytest.mark.unit + def test_text_to_ids(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name) + + # is user_defined_symbol in the test tokenizer model + # , , , and are control symbols + text = " a b c e f g h i
" + tokens = tokenizer.text_to_ids(text) + + assert tokens.count(tokenizer.token_to_id("")) == 1 + assert tokens.count(tokenizer.token_to_id("")) == 0 + assert tokens.count(tokenizer.token_to_id("
")) == 0 + + @pytest.mark.unit + def test_ids_to_text(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name) + + text = " a b c e f g h i
" + ids = tokenizer.text_to_ids(text) + result = tokenizer.ids_to_text(ids) + + assert text == result + + @pytest.mark.unit + def test_tokens_to_ids(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name) + + tokens = ["", "a", "b", "c", "", "e", "f", "", "g", "h", "i", "
"] + ids = tokenizer.tokens_to_ids(tokens) + + assert len(ids) == len(tokens) + assert ids.count(tokenizer.token_to_id("")) == 1 + assert ids.count(tokenizer.token_to_id("
")) == 1 + assert ids.count(tokenizer.token_to_id("")) == 2 + + @pytest.mark.unit + def test_ids_to_tokens(self, test_data_dir): + tokenizer = SentencePieceTokenizer(test_data_dir + self.model_name) + + tokens = ["", "a", "b", "c", "", "e", "f", "", "g", "h", "i", "
"] + ids = tokenizer.tokens_to_ids(tokens) + result = tokenizer.ids_to_tokens(ids) + + assert len(result) == len(tokens) + + for i in range(len(result)): + assert result[i] == tokens[i] + + +class TestYouTokenToMeTokenizer: + model_name = "/yttm.4096.en-de.model" + + @pytest.mark.unit + def test_text_to_tokens(self, test_data_dir): + tokenizer = YouTokenToMeTokenizer(test_data_dir + self.model_name) + + text = " a b c e f g h i " + tokens = tokenizer.text_to_tokens(text) + + assert tokens.count("") == 0 + assert tokens.count("") == 0 + assert tokens.count("") == 0 + + @pytest.mark.unit + def test_tokens_to_text(self, test_data_dir): + tokenizer = YouTokenToMeTokenizer(test_data_dir + self.model_name) + + text = "a b c e f g h i" + tokens = tokenizer.text_to_tokens(text) + result = tokenizer.tokens_to_text(tokens) + + assert text == result + + @pytest.mark.unit + def test_text_to_ids(self, test_data_dir): + tokenizer = YouTokenToMeTokenizer(test_data_dir + self.model_name) + + text = " a b c e f g h i " + tokens = tokenizer.text_to_ids(text) + + assert tokens.count(tokenizer.bos_id) == 0 + assert tokens.count(tokenizer.unk_id) == 0 + assert tokens.count(tokenizer.eos_id) == 0 + + @pytest.mark.unit + def test_ids_to_text(self, test_data_dir): + tokenizer = YouTokenToMeTokenizer(test_data_dir + self.model_name) + + text = "a b c e f g h i" + ids = tokenizer.text_to_ids(text) + result = tokenizer.ids_to_text(ids) + + assert text == result + + @pytest.mark.unit + def test_tokens_to_ids(self, test_data_dir): + tokenizer = YouTokenToMeTokenizer(test_data_dir + self.model_name) + + tokens = ["", "a", "b", "c", "", "e", "f", "", "g", "h", "i", ""] + ids = tokenizer.tokens_to_ids(tokens) + + assert len(ids) == len(tokens) + assert ids.count(tokenizer.bos_id) == 1 + assert ids.count(tokenizer.eos_id) == 1 + assert ids.count(tokenizer.unk_id) == 2 + + @pytest.mark.unit + def test_ids_to_tokens(self, test_data_dir): + tokenizer = YouTokenToMeTokenizer(test_data_dir + self.model_name) + + tokens = ["", "a", "b", "c", "", "e", "f", "", "g", "h", "i", ""] + ids = tokenizer.tokens_to_ids(tokens) + result = tokenizer.ids_to_tokens(ids) + + assert len(result) == len(tokens) + + for i in range(len(result)): + assert result[i] == tokens[i] diff --git a/tts/NeMo/tests/collections/nlp/test_classification_report.py b/tts/NeMo/tests/collections/nlp/test_classification_report.py new file mode 100644 index 0000000..de2c4f7 --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_classification_report.py @@ -0,0 +1,48 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +import torch +from sklearn.metrics import precision_recall_fscore_support + +from nemo.collections.nlp.metrics.classification_report import ClassificationReport + + +class ClassificationReportTests: + num_classes = 3 + label_ids = {'a': 0, 'b': 1, 'c': 2} + + @pytest.mark.unit + def test_classification_report(self): + + preds = torch.Tensor([0, 1, 1, 1, 2, 2, 0]) + labels = torch.Tensor([1, 0, 0, 1, 2, 1, 0]) + + def __convert_to_tensor(sklearn_metric): + return torch.Tensor([round(sklearn_metric * 100)])[0] + + for mode in ['macro', 'micro', 'weighted']: + + classification_report_nemo = ClassificationReport( + num_classes=self.num_classes, label_ids=self.label_ids, mode=mode + ) + # pytest.set_trace() + precision, recall, f1, _ = classification_report_nemo(preds, labels) + tp, fp, fn = classification_report_nemo.tp, classification_report_nemo.fp, classification_report_nemo.fn + pr_sklearn, recall_sklearn, f1_sklearn, _ = precision_recall_fscore_support(labels, preds, average=mode) + + self.assertEqual(torch.round(precision), __convert_to_tensor(pr_sklearn), f'wrong precision for {mode}') + self.assertEqual(torch.round(recall), __convert_to_tensor(recall_sklearn), f'wrong recall for {mode}') + self.assertEqual(torch.round(f1), __convert_to_tensor(f1_sklearn), f'wrong f1 for {mode}') diff --git a/tts/NeMo/tests/collections/nlp/test_entity_linking_model.py b/tts/NeMo/tests/collections/nlp/test_entity_linking_model.py new file mode 100644 index 0000000..0e96b33 --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_entity_linking_model.py @@ -0,0 +1,83 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import shutil +import tempfile + +import pytest +import wget +from omegaconf import OmegaConf + +from nemo.collections.nlp.models import EntityLinkingModel + + +def get_cfg(): + + language_model = OmegaConf.create( + {"pretrained_model_name": "bert-base-uncased", "config_file": None, "config": None, "lm_checkpoint": None} + ) + + tokenizer = OmegaConf.create( + {"tokenizer_name": "bert-base-uncased", "vocab_file": None, "tokenizer_model": None, "do_lower_case": True} + ) + + model = OmegaConf.create( + { + "nemo_path": "sap_entity_linking.nemo", + "max_seq_length": 128, + "language_model": language_model, + "tokenizer": tokenizer, + "train_ds": None, + "validation_ds": None, + } + ) + + cfg = OmegaConf.create({"model": model}) + + return cfg + + +class TestEntityLinkingModel: + @pytest.mark.unit + def test_creation_saving_restoring(self): + # Create a new temporary directory + with tempfile.TemporaryDirectory() as restore_dir: + with tempfile.TemporaryDirectory() as save_dir: + model = EntityLinkingModel(cfg=get_cfg().model) + assert isinstance(model, EntityLinkingModel) + + save_dir_path = save_dir + + # Where model will be saved + model_save_path = os.path.join(save_dir, f"{model.__class__.__name__}.nemo") + model.save_to(save_path=model_save_path) + + # Where model will be restored from + model_restore_path = os.path.join(restore_dir, f"{model.__class__.__name__}.nemo") + shutil.copy(model_save_path, model_restore_path) + + # at this point save_dir should not exist + assert save_dir_path is not None and not os.path.exists(save_dir_path) + assert not os.path.exists(model_save_path) + assert os.path.exists(model_restore_path) + + # attempt to restore + model_copy = model.__class__.restore_from(restore_path=model_restore_path) + assert model.num_weights == model_copy.num_weights + + +if __name__ == "__main__": + t = TestEntityLinkingModel() + t.test_creation_saving_restoring() diff --git a/tts/NeMo/tests/collections/nlp/test_huggingface.py b/tts/NeMo/tests/collections/nlp/test_huggingface.py new file mode 100644 index 0000000..a179c6d --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_huggingface.py @@ -0,0 +1,86 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import tempfile + +import pytest +import torch + +import nemo.collections.nlp as nemo_nlp +from nemo.collections.common.tokenizers.huggingface.auto_tokenizer import AutoTokenizer +from nemo.collections.nlp.modules.common.tokenizer_utils import get_tokenizer + + +def do_export(model, name: str): + with tempfile.TemporaryDirectory() as tmpdir: + # Generate filename in the temporary directory. + tmp_file_name = os.path.join(tmpdir, name + '.onnx') + # Test export. + if torch.cuda.is_available(): + model = model.cuda() + model.export(tmp_file_name) + + +class TestHuggingFace: + @pytest.mark.unit + def test_list_pretrained_models(self): + pretrained_lm_models = nemo_nlp.modules.get_pretrained_lm_models_list() + assert len(pretrained_lm_models) > 0 + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_get_pretrained_bert_model(self): + model = nemo_nlp.modules.get_lm_model(pretrained_model_name='bert-base-uncased') + assert isinstance(model, nemo_nlp.modules.BertEncoder) + do_export(model, "bert-base-uncased") + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_get_pretrained_distilbert_model(self): + model = nemo_nlp.modules.get_lm_model(pretrained_model_name='distilbert-base-uncased') + assert isinstance(model, nemo_nlp.modules.DistilBertEncoder) + do_export(model, "distilbert-base-uncased") + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_get_pretrained_roberta_model(self): + model = nemo_nlp.modules.get_lm_model(pretrained_model_name='roberta-base') + assert isinstance(model, nemo_nlp.modules.RobertaEncoder) + do_export(model, "roberta-base-uncased") + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_get_pretrained_albert_model(self): + model = nemo_nlp.modules.get_lm_model(pretrained_model_name='albert-base-v1') + assert isinstance(model, nemo_nlp.modules.AlbertEncoder) + do_export(model, "albert-base-v1") + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_get_pretrained_chinese_bert_wwm_model(self): + model_name = 'hfl/chinese-bert-wwm' + model = nemo_nlp.modules.get_lm_model(pretrained_model_name=model_name) + assert isinstance(model, nemo_nlp.modules.BertModule) + tokenizer = get_tokenizer(tokenizer_name=model_name) + assert isinstance(tokenizer, AutoTokenizer) + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_get_pretrained_arabic_model(self): + model_name = 'asafaya/bert-base-arabic' + model = nemo_nlp.modules.get_lm_model(pretrained_model_name=model_name) + assert isinstance(model, nemo_nlp.modules.BertModule) + tokenizer = get_tokenizer(tokenizer_name=model_name) + assert isinstance(tokenizer, AutoTokenizer) diff --git a/tts/NeMo/tests/collections/nlp/test_megatron.py b/tts/NeMo/tests/collections/nlp/test_megatron.py new file mode 100644 index 0000000..4e7d448 --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_megatron.py @@ -0,0 +1,76 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +try: + import apex + + apex_available = True +except Exception: + apex_available = False + +import os +import tempfile + +import onnx +import pytest +import torch + +import nemo.collections.nlp as nemo_nlp +from nemo.core.classes import typecheck + + +def get_pretrained_bert_345m_uncased_model(): + model_name = "megatron-bert-345m-uncased" + model = nemo_nlp.modules.get_lm_model(pretrained_model_name=model_name) + if torch.cuda.is_available(): + model = model.cuda() + return model + + +class TestMegatron: + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_list_pretrained_models(self): + pretrained_lm_models = nemo_nlp.modules.get_pretrained_lm_models_list() + assert len(pretrained_lm_models) > 0 + + @pytest.mark.with_downloads() + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + @pytest.mark.skip("Only one Megatron model is allowed") + def test_get_model(self): + model = get_pretrained_bert_345m_uncased_model() + assert isinstance(model, nemo_nlp.modules.MegatronBertEncoder) + + typecheck.set_typecheck_enabled(enabled=False) + inp = model.input_example() + out = model.forward(*inp) + typecheck.set_typecheck_enabled(enabled=True) + + @pytest.mark.skipif(not os.path.exists('/home/TestData/nlp'), reason='Not a Jenkins machine') + @pytest.mark.with_downloads() + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_onnx_export(self): + model = get_pretrained_bert_345m_uncased_model() + assert model + with tempfile.TemporaryDirectory() as tmpdir: + # Generate filename in the temporary directory. + # Test export. + model.export(os.path.join(".", "megatron.onnx")) + + +if __name__ == "__main__": + t = TestMegatron() + t.test_onnx_export() diff --git a/tts/NeMo/tests/collections/nlp/test_nlp_exportables.py b/tts/NeMo/tests/collections/nlp/test_nlp_exportables.py new file mode 100644 index 0000000..ac5d860 --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_nlp_exportables.py @@ -0,0 +1,176 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import tempfile + +import onnx +import pytest +import pytorch_lightning as pl +import torch +import wget +from omegaconf import OmegaConf + +from nemo.collections import nlp as nemo_nlp +from nemo.collections.nlp.models import IntentSlotClassificationModel +from nemo.collections.nlp.modules.common import ( + SequenceClassifier, + SequenceRegression, + SequenceTokenClassifier, + TokenClassifier, +) + + +def classifier_export(obj): + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, obj.__class__.__name__ + '.onnx') + obj = obj.cuda() + obj.export(output=filename) + + +class TestExportableClassifiers: + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_token_classifier_export_to_onnx(self): + for num_layers in [1, 2, 4]: + classifier_export(TokenClassifier(hidden_size=256, num_layers=num_layers, num_classes=16)) + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_bert_pretraining_export_to_onnx(self): + for num_layers in [1, 2, 4]: + classifier_export(TokenClassifier(hidden_size=256, num_layers=num_layers, num_classes=16)) + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_sequence_token_classifier_export_to_onnx(self): + for num_layers in [1, 2, 4]: + classifier_export( + SequenceTokenClassifier(hidden_size=256, num_slots=8, num_intents=8, num_layers=num_layers) + ) + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_sequence_classifier_export_to_onnx(self): + for num_layers in [1, 2, 4]: + classifier_export(SequenceClassifier(hidden_size=256, num_classes=16, num_layers=num_layers)) + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_sequence_regression_export_to_onnx(self): + for num_layers in [1, 2, 4]: + classifier_export(SequenceRegression(hidden_size=256, num_layers=num_layers)) + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_IntentSlotClassificationModel_export_to_onnx(self, dummy_data): + with tempfile.TemporaryDirectory() as tmpdir: + wget.download( + 'https://raw.githubusercontent.com/NVIDIA/NeMo/main/examples/' + 'nlp/intent_slot_classification/conf/intent_slot_classification_config.yaml', + tmpdir, + ) + config_file = os.path.join(tmpdir, 'intent_slot_classification_config.yaml') + config = OmegaConf.load(config_file) + config = OmegaConf.create(OmegaConf.to_container(config, resolve=True)) + config.model.data_dir = dummy_data + config.trainer.gpus = 1 + config.trainer.precision = 32 + config.trainer.accelerator = None + trainer = pl.Trainer(**config.trainer) + model = IntentSlotClassificationModel(config.model, trainer=trainer) + filename = os.path.join(tmpdir, 'isc.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'input_ids' + assert onnx_model.graph.input[1].name == 'attention_mask' + assert onnx_model.graph.input[2].name == 'token_type_ids' + assert onnx_model.graph.output[0].name == 'intent_logits' + assert onnx_model.graph.output[1].name == 'slot_logits' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + @pytest.mark.skip('Are we exporting to torchscript?') + def test_IntentSlotClassificationModel_export_to_torchscript(self, dummy_data): + with tempfile.TemporaryDirectory() as tmpdir: + wget.download( + 'https://raw.githubusercontent.com/NVIDIA/NeMo/main/examples/' + 'nlp/intent_slot_classification/conf/intent_slot_classification_config.yaml', + tmpdir, + ) + config_file = os.path.join(tmpdir, 'intent_slot_classification_config.yaml') + config = OmegaConf.load(config_file) + config = OmegaConf.create(OmegaConf.to_container(config, resolve=True)) + config.model.data_dir = dummy_data + config.trainer.gpus = 1 + config.trainer.precision = 32 + config.trainer.accelerator = None + trainer = pl.Trainer(**config.trainer) + model = IntentSlotClassificationModel(config.model, trainer=trainer) + filename = os.path.join(tmpdir, 'isc.pt') + model.export(output=filename, check_trace=True) + torchscript_model = torch.jit.load(filename) + inputs = list(torchscript_model.graph.inputs()) + assert inputs[1].debugName() == 'input_ids.1' + assert inputs[2].debugName() == 'input.1' + assert inputs[3].debugName() == 'attention_mask.1' + modules = list(torchscript_model.modules()) + assert modules[2].original_name == 'BertEmbeddings' + assert modules[46].original_name == 'BertSelfAttention' + assert modules[217].original_name == 'SequenceTokenClassifier' + assert modules[219].original_name == 'MultiLayerPerceptron' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_TokenClassificationModel_export_to_onnx(self): + model = nemo_nlp.models.TokenClassificationModel.from_pretrained(model_name="ner_en_bert") + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'ner.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'input_ids' + assert onnx_model.graph.output[0].name == 'logits' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_PunctuationCapitalizationModel_export_to_onnx(self): + model = nemo_nlp.models.PunctuationCapitalizationModel.from_pretrained(model_name="punctuation_en_distilbert") + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'puncap.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'input_ids' + # assert onnx_model.graph.input[2].name == 'token_type_ids' + assert onnx_model.graph.output[0].name == 'punct_logits' + assert onnx_model.graph.output[1].name == 'capit_logits' + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_QAModel_export_to_onnx(self): + model = nemo_nlp.models.QAModel.from_pretrained(model_name="qa_squadv2.0_bertbase") + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'qa.onnx') + model.export(output=filename) + onnx_model = onnx.load(filename) + onnx.checker.check_model(onnx_model, full_check=True) # throws when failed + assert onnx_model.graph.input[0].name == 'input_ids' + assert onnx_model.graph.input[2].name == 'token_type_ids' + assert onnx_model.graph.output[0].name == 'logits' + + +@pytest.fixture() +def dummy_data(test_data_dir): + return os.path.join(test_data_dir, 'nlp', 'dummy_data') diff --git a/tts/NeMo/tests/collections/nlp/test_nmt_model.py b/tts/NeMo/tests/collections/nlp/test_nmt_model.py new file mode 100644 index 0000000..9f0277f --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_nmt_model.py @@ -0,0 +1,144 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import shutil +import tempfile + +import pytest +import torch +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.nlp.models import MTEncDecModel +from nemo.collections.nlp.models.machine_translation.mt_enc_dec_config import AAYNBaseConfig + + +def export_test(model, suffix, try_script=False): + with tempfile.TemporaryDirectory() as restore_folder: + enc_filename = os.path.join(restore_folder, 'nmt_e' + suffix) + dec_filename = os.path.join(restore_folder, 'nmt_d' + suffix) + model.encoder.export(output=enc_filename, try_script=try_script) + model.decoder.export(output=dec_filename, try_script=try_script) + assert os.path.exists(enc_filename) + assert os.path.exists(dec_filename) + + +def get_cfg(): + cfg = AAYNBaseConfig() + cfg.encoder_tokenizer.tokenizer_name = 'yttm' + cfg.encoder_tokenizer.tokenizer_model = 'tests/.data/yttm.4096.en-de.model' + cfg.decoder_tokenizer.tokenizer_name = 'yttm' + cfg.decoder_tokenizer.tokenizer_model = 'tests/.data/yttm.4096.en-de.model' + cfg.train_ds = None + cfg.validation_ds = None + cfg.test_ds = None + return cfg + + +class TestMTEncDecModel: + @pytest.mark.unit + def test_creation_saving_restoring(self): + model = MTEncDecModel(cfg=get_cfg()) + assert isinstance(model, MTEncDecModel) + # Create a new temporary directory + with tempfile.TemporaryDirectory() as restore_folder: + with tempfile.TemporaryDirectory() as save_folder: + save_folder_path = save_folder + # Where model will be saved + model_save_path = os.path.join(save_folder, f"{model.__class__.__name__}.nemo") + model.save_to(save_path=model_save_path) + # Where model will be restored from + model_restore_path = os.path.join(restore_folder, f"{model.__class__.__name__}.nemo") + shutil.copy(model_save_path, model_restore_path) + # at this point save_folder should not exist + assert save_folder_path is not None and not os.path.exists(save_folder_path) + assert not os.path.exists(model_save_path) + assert os.path.exists(model_restore_path) + # attempt to restore + model_copy = model.__class__.restore_from(restore_path=model_restore_path) + assert model.num_weights == model_copy.num_weights + + @pytest.mark.unit + def test_no_artifact_name_collision(self): + model = MTEncDecModel(cfg=get_cfg()) + assert isinstance(model, MTEncDecModel) + with tempfile.TemporaryDirectory() as tmpdir1: + model.save_to("nmt_model.nemo") + with tempfile.TemporaryDirectory() as tmpdir: + model._unpack_nemo_file(path2file="nmt_model.nemo", out_folder=tmpdir) + conf = OmegaConf.load(os.path.join(tmpdir, "model_config.yaml")) + # Make sure names now differ in saved config + assert conf.encoder_tokenizer.tokenizer_model != conf.decoder_tokenizer.tokenizer_model + # Make sure names in config start with "nemo:" prefix + assert conf.encoder_tokenizer.tokenizer_model.startswith("nemo:") + assert conf.decoder_tokenizer.tokenizer_model.startswith("nemo:") + # Check if both tokenizers were included + assert os.path.exists(os.path.join(tmpdir, conf.encoder_tokenizer.tokenizer_model[5:])) + assert os.path.exists(os.path.join(tmpdir, conf.decoder_tokenizer.tokenizer_model[5:])) + + @pytest.mark.unit + def test_train_eval_loss(self): + cfg = get_cfg() + cfg.label_smoothing = 0.5 + model = MTEncDecModel(cfg=cfg) + assert isinstance(model, MTEncDecModel) + batch_size = 10 + time = 32 + vocab_size = 32000 + torch.manual_seed(42) + tgt_ids = torch.LongTensor(batch_size, time).random_(1, model.decoder_tokenizer.vocab_size) + logits = torch.FloatTensor(batch_size, time, vocab_size).random_(-1, 1) + log_probs = torch.nn.functional.log_softmax(logits, dim=-1) + train_loss = model.loss_fn(log_probs=log_probs, labels=tgt_ids) + eval_loss = model.eval_loss_fn(log_probs=log_probs, labels=tgt_ids) + assert not torch.allclose(train_loss, eval_loss) # , (train_loss, eval_loss) + + cfg.label_smoothing = 0 + model = MTEncDecModel(cfg=cfg) + # Train loss == val loss when label smoothing = 0 + train_loss = model.loss_fn(log_probs=log_probs, labels=tgt_ids) + eval_loss = model.eval_loss_fn(log_probs=log_probs, labels=tgt_ids) + assert torch.allclose(train_loss, eval_loss) + + @pytest.mark.unit + def test_cpu_export_onnx(self): + model = MTEncDecModel(cfg=get_cfg()) + assert isinstance(model, MTEncDecModel) + export_test(model, ".ts") + + @pytest.mark.unit + def test_cpu_export_ts(self): + model = MTEncDecModel(cfg=get_cfg()) + assert isinstance(model, MTEncDecModel) + export_test(model, ".onnx") + + @pytest.mark.skipif(not os.path.exists('/home/TestData/nlp'), reason='Not a Jenkins machine') + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_gpu_export_ts(self): + model = MTEncDecModel(cfg=get_cfg()).cuda() + assert isinstance(model, MTEncDecModel) + export_test(model, ".ts") + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_gpu_export_onnx(self): + model = MTEncDecModel(cfg=get_cfg()).cuda() + assert isinstance(model, MTEncDecModel) + export_test(model, ".onnx") + + +if __name__ == "__main__": + t = TestMTEncDecModel() + # t.test_gpu_export_ts() + t.test_train_eval_loss() diff --git a/tts/NeMo/tests/collections/nlp/test_pretrained_models_performance.py b/tts/NeMo/tests/collections/nlp/test_pretrained_models_performance.py new file mode 100644 index 0000000..47f4f76 --- /dev/null +++ b/tts/NeMo/tests/collections/nlp/test_pretrained_models_performance.py @@ -0,0 +1,110 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from pathlib import Path +from shutil import rmtree +from unittest import TestCase + +import pytest +import pytorch_lightning as pl +from omegaconf import OmegaConf + +import nemo.collections.nlp.models as models + + +def get_metrics(data_dir, model): + trainer = pl.Trainer(gpus=[0]) + + model.set_trainer(trainer) + model.update_data_dir(data_dir) + + test_ds = OmegaConf.create( + { + 'text_file': 'text_dev.txt', + 'labels_file': 'labels_dev.txt', + 'shuffle': False, + 'num_samples': -1, + 'batch_size': 8, + } + ) + + model._cfg.dataset.use_cache = False + trainer.test(model) + model.setup_test_data(test_data_config=test_ds) + metrics = trainer.test(model)[0] + + return metrics + + +def data_exists(data_dir): + return os.path.exists(data_dir) + + +class TestPretrainedModelPerformance: + @pytest.mark.with_downloads() + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + @pytest.mark.skipif( + not data_exists('/home/TestData/nlp/token_classification_punctuation/fisher'), reason='Not a Jenkins machine' + ) + def test_punct_capit_with_bert(self): + data_dir = '/home/TestData/nlp/token_classification_punctuation/fisher' + model = models.PunctuationCapitalizationModel.from_pretrained("punctuation_en_bert") + metrics = get_metrics(data_dir, model) + + assert abs(metrics['punct_precision'] - 52.3024) < 0.001 + assert abs(metrics['punct_recall'] - 58.9220) < 0.001 + assert abs(metrics['punct_f1'] - 53.2976) < 0.001 + assert abs(metrics['capit_precision'] - 87.0707) < 0.001 + assert abs(metrics['capit_recall'] - 87.0707) < 0.001 + assert abs(metrics['capit_f1'] - 87.0707) < 0.001 + assert int(model.punct_class_report.total_examples) == 128 + + preds_512 = model.add_punctuation_capitalization(['what can i do for you today'], max_seq_length=512)[0] + assert preds_512 == 'What can I do for you today?' + preds_5 = model.add_punctuation_capitalization(['what can i do for you today'], max_seq_length=5)[0] + assert preds_5 == 'What can i' + + @pytest.mark.with_downloads() + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + @pytest.mark.skipif( + not data_exists('/home/TestData/nlp/token_classification_punctuation/fisher'), reason='Not a Jenkins machine' + ) + def test_punct_capit_with_distilbert(self): + data_dir = '/home/TestData/nlp/token_classification_punctuation/fisher' + model = models.PunctuationCapitalizationModel.from_pretrained("punctuation_en_distilbert") + metrics = get_metrics(data_dir, model) + + assert abs(metrics['punct_precision'] - 53.0826) < 0.001 + assert abs(metrics['punct_recall'] - 56.2905) < 0.001 + assert abs(metrics['punct_f1'] - 52.4225) < 0.001 + assert int(model.punct_class_report.total_examples) == 128 + + @pytest.mark.with_downloads() + @pytest.mark.unit + @pytest.mark.run_only_on('GPU') + @pytest.mark.skipif( + not data_exists('/home/TestData/nlp/token_classification_punctuation/gmb'), reason='Not a Jenkins machine' + ) + def test_ner_model(self): + data_dir = '/home/TestData/nlp/token_classification_punctuation/gmb' + model = models.TokenClassificationModel.from_pretrained("ner_en_bert") + metrics = get_metrics(data_dir, model) + + assert abs(metrics['precision'] - 96.0937) < 0.001 + assert abs(metrics['recall'] - 96.0146) < 0.001 + assert abs(metrics['f1'] - 95.6076) < 0.001 + assert int(model.classification_report.total_examples) == 202 diff --git a/tts/NeMo/tests/collections/tts/test_tts_datasets.py b/tts/NeMo/tests/collections/tts/test_tts_datasets.py new file mode 100644 index 0000000..04d557e --- /dev/null +++ b/tts/NeMo/tests/collections/tts/test_tts_datasets.py @@ -0,0 +1,43 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest +import torch + +from nemo.collections.tts.data.datalayers import FastSpeech2Dataset + + +class TestTTSDatasets: + @pytest.mark.unit + def test_fs2_dataset(self, test_data_dir): + manifest_path = os.path.join(test_data_dir, 'tts/mini_ljspeech/manifest.json') + mappings_file = os.path.join(test_data_dir, 'tts/mini_ljspeech/mappings.json') + ignore_file = os.path.join(test_data_dir, 'tts/mini_ljspeech/wavs_to_ignore.pkl') + + # Test loading data (including supplementary data) with ignore file + ds = FastSpeech2Dataset( + manifest_filepath=manifest_path, + mappings_filepath=mappings_file, + sample_rate=22050, + ignore_file=ignore_file, + load_supplementary_values=True, + ) + + assert len(ds) == 4 + count = 0 + for _ in ds: + count += 1 + assert count == 4 diff --git a/tts/NeMo/tests/collections/tts/test_tts_exportables.py b/tts/NeMo/tests/collections/tts/test_tts_exportables.py new file mode 100644 index 0000000..59075d9 --- /dev/null +++ b/tts/NeMo/tests/collections/tts/test_tts_exportables.py @@ -0,0 +1,62 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import tempfile + +import onnx +import pytest +from omegaconf import DictConfig, ListConfig, OmegaConf + +from nemo.collections.tts.models import FastPitchModel, HifiGanModel, TalkNetSpectModel, WaveGlowModel + + +@pytest.fixture() +def fastpitch_model(): + test_root = os.path.dirname(os.path.abspath(__file__)) + conf = OmegaConf.load(os.path.join(test_root, '../../../examples/tts/conf/fastpitch.yaml')) + conf.train_dataset = conf.validation_datasets = '.' + conf.model.train_ds = conf.model.test_ds = conf.model.validation_ds = None + model = FastPitchModel(cfg=conf.model) + return model + + +@pytest.fixture() +def hifigan_model(): + test_root = os.path.dirname(os.path.abspath(__file__)) + model = HifiGanModel.from_pretrained(model_name="tts_hifigan") + return model + + +class TestExportable: + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_FastPitchModel_export_to_onnx(self, fastpitch_model): + model = fastpitch_model.cuda() + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'fp.onnx') + model.export(output=filename, verbose=True, check_trace=True) + + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_HifiGanModel_export_to_onnx(self, hifigan_model): + model = hifigan_model.cuda() + assert hifigan_model.generator is not None + with tempfile.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'hfg.pt') + model.export(output=filename, verbose=True, check_trace=True) + + +if __name__ == "__main__": + t = TestExportable() + t.test_FastPitchModel_export_to_onnx(fastpitch_model()) diff --git a/tts/NeMo/tests/collections/tts/test_waveglow.py b/tts/NeMo/tests/collections/tts/test_waveglow.py new file mode 100644 index 0000000..7bfd3e5 --- /dev/null +++ b/tts/NeMo/tests/collections/tts/test_waveglow.py @@ -0,0 +1,110 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import tempfile +from unittest import TestCase + +import onnx +import pytest +import torch +from omegaconf import DictConfig + +from nemo.collections.tts.models import WaveGlowModel +from nemo.collections.tts.modules import WaveGlowModule +from nemo.core.classes import typecheck + +mcfg = DictConfig( + { + "_target_": "nemo.collections.tts.modules.waveglow.WaveGlowModule", + "n_flows": 12, + "n_group": 8, + "n_mel_channels": 80, + "n_early_every": 4, + "n_early_size": 2, + "n_wn_channels": 512, + "n_wn_layers": 8, + "wn_kernel_size": 3, + } +) + +pcfg = DictConfig( + { + "_target_": "nemo.collections.asr.parts.preprocessing.features.FilterbankFeatures", + "dither": 0.0, + "nfilt": 80, + "stft_conv": True, + } +) + +wcfg = DictConfig({"waveglow": mcfg, "sigma": 1.0, "preprocessor": pcfg,}) + + +def input_example(sz): + mel = torch.randn(1, 1, 80, sz).cuda().half() + z = torch.randn(1, 8, sz * 256 // 8, 1).cuda().half() + return ( + mel, + z, + ) + + +def taco2wg(spec, z): + spec = spec.permute(0, 3, 2, 1).contiguous() + return spec.view(spec.size(0), spec.size(1), -1), z.view(z.size(0), z.size(1), -1) + + +# Wrapper method to convert Jasper's Taco2 output to WG input and call inference +def forward_wrapper(self, spec, z=None): + spec, z = taco2wg(spec, z) + audio = self.waveglow.norm_dist_to_audio(spec=spec, sigma=1.0, z=z) + return audio + + +class TestWaveGlow: + @pytest.mark.run_only_on('GPU') + @pytest.mark.unit + def test_export_to_onnx(self): + model = WaveGlowModel(wcfg) + model = model.cuda().half() + typecheck.set_typecheck_enabled(enabled=False) + with tempfile.TemporaryDirectory() as tmpdir, model.nemo_infer(): + # Generate filename in the temporary directory. + # TODO: Change `waveglow.ts` to `waveglow.onnx` for > 21.05 + tmp_file_name = os.path.join("waveglow.ts") + + n_mels = 80 + # Test export. + inp = input_example(n_mels) + inp1 = taco2wg(*inp) + inp2 = inp1 + res1 = model.waveglow(*inp1) + res2 = model.waveglow(*inp2) + assert torch.allclose(res1, res2, rtol=0.01, atol=0.1) + WaveGlowModel.forward_for_export = forward_wrapper + model.export( + tmp_file_name, + verbose=True, + input_example=inp, + output_example=res1, + try_script=False, + check_trace=False, + do_constant_folding=True, + dynamic_axes={"spec": [0], "z": [0], "audio": [0]}, + ) + + +if __name__ == "__main__": + t = TestWaveGlow() + t.test_export_to_onnx() diff --git a/tts/NeMo/tests/conftest.py b/tts/NeMo/tests/conftest.py new file mode 100644 index 0000000..4a947a2 --- /dev/null +++ b/tts/NeMo/tests/conftest.py @@ -0,0 +1,188 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import tarfile +import urllib.request +from os import mkdir +from os.path import dirname, exists, getsize, join +from pathlib import Path +from shutil import rmtree + +import pytest + +# Those variables probably should go to main NeMo configuration file (config.yaml). +__TEST_DATA_FILENAME = "test_data.tar.gz" +__TEST_DATA_URL = "https://github.com/NVIDIA/NeMo/releases/download/v1.0.0rc1/" +__TEST_DATA_SUBDIR = ".data" + + +def pytest_addoption(parser): + """ + Additional command-line arguments passed to pytest. + For now: + --cpu: use CPU during testing (DEFAULT: GPU) + --use_local_test_data: use local test data/skip downloading from URL/GitHub (DEFAULT: False) + """ + parser.addoption( + '--cpu', action='store_true', help="pass that argument to use CPU during testing (DEFAULT: False = GPU)" + ) + parser.addoption( + '--use_local_test_data', + action='store_true', + help="pass that argument to use local test data/skip downloading from URL/GitHub (DEFAULT: False)", + ) + parser.addoption( + '--with_downloads', + action='store_true', + help="pass this argument to active tests which download models from the cloud.", + ) + parser.addoption( + '--relax_numba_compat', + action='store_false', + help="numba compatibility checks will be relaxed to just availability of cuda, " + "without cuda compatibility matrix check", + ) + + +@pytest.fixture +def device(request): + """ Simple fixture returning string denoting the device [CPU | GPU] """ + if request.config.getoption("--cpu"): + return "CPU" + else: + return "GPU" + + +@pytest.fixture(autouse=True) +def run_only_on_device_fixture(request, device): + if request.node.get_closest_marker('run_only_on'): + if request.node.get_closest_marker('run_only_on').args[0] != device: + pytest.skip('skipped on this device: {}'.format(device)) + + +@pytest.fixture(autouse=True) +def downloads_weights(request, device): + if request.node.get_closest_marker('with_downloads'): + if not request.config.getoption("--with_downloads"): + pytest.skip( + 'To run this test, pass --with_downloads option. It will download (and cache) models from cloud.' + ) + + +@pytest.fixture(autouse=True) +def cleanup_local_folder(): + # Asserts in fixture are not recommended, but I'd rather stop users from deleting expensive training runs + assert not Path("./lightning_logs").exists() + assert not Path("./NeMo_experiments").exists() + assert not Path("./nemo_experiments").exists() + + yield + + if Path("./lightning_logs").exists(): + rmtree('./lightning_logs', ignore_errors=True) + if Path("./NeMo_experiments").exists(): + rmtree('./NeMo_experiments', ignore_errors=True) + if Path("./nemo_experiments").exists(): + rmtree('./nemo_experiments', ignore_errors=True) + + +@pytest.fixture +def test_data_dir(): + """ Fixture returns test_data_dir. """ + # Test dir. + test_data_dir_ = join(dirname(__file__), __TEST_DATA_SUBDIR) + return test_data_dir_ + + +def pytest_configure(config): + """ + Initial configuration of conftest. + The function checks if test_data.tar.gz is present in tests/.data. + If so, compares its size with github's test_data.tar.gz. + If file absent or sizes not equal, function downloads the archive from github and unpacks it. + """ + config.addinivalue_line( + "markers", "run_only_on(device): runs the test only on a given device [CPU | GPU]", + ) + # Test dir and archive filepath. + test_dir = join(dirname(__file__), __TEST_DATA_SUBDIR) + test_data_archive = join(dirname(__file__), __TEST_DATA_SUBDIR, __TEST_DATA_FILENAME) + + # Get size of local test_data archive. + try: + test_data_local_size = getsize(test_data_archive) + except: + # File does not exist. + test_data_local_size = -1 + + if config.option.use_local_test_data: + if test_data_local_size == -1: + pytest.exit("Test data `{}` is not present in the system".format(test_data_archive)) + else: + print( + "Using the local `{}` test archive ({}B) found in the `{}` folder.".format( + __TEST_DATA_FILENAME, test_data_local_size, test_dir + ) + ) + return + + # Get size of remote test_data archive. + try: + url = __TEST_DATA_URL + __TEST_DATA_FILENAME + u = urllib.request.urlopen(url) + except: + # Couldn't access remote archive. + if test_data_local_size == -1: + pytest.exit("Test data not present in the system and cannot access the '{}' URL".format(url)) + else: + print( + "Cannot access the '{}' URL, using the test data ({}B) found in the `{}` folder.".format( + url, test_data_local_size, test_dir + ) + ) + return + + # Get metadata. + meta = u.info() + test_data_remote_size = int(meta["Content-Length"]) + + # Compare sizes. + if test_data_local_size != test_data_remote_size: + print( + "Downloading the `{}` test archive from `{}`, please wait...".format(__TEST_DATA_FILENAME, __TEST_DATA_URL) + ) + # Remove .data folder. + if exists(test_dir): + rmtree(test_dir) + # Create one .data folder. + mkdir(test_dir) + # Download + urllib.request.urlretrieve(url, test_data_archive) + # Extract tar + print("Extracting the `{}` test archive, please wait...".format(test_data_archive)) + tar = tarfile.open(test_data_archive) + tar.extractall(path=test_dir) + tar.close() + else: + print( + "A valid `{}` test archive ({}B) found in the `{}` folder.".format( + __TEST_DATA_FILENAME, test_data_local_size, test_dir + ) + ) + + if config.option.relax_numba_compat is not None: + from nemo.core.utils import numba_utils + + print("Setting numba compat :", config.option.relax_numba_compat) + numba_utils.set_numba_compat_strictness(strict=config.option.relax_numba_compat) diff --git a/tts/NeMo/tests/core/test_config_utils.py b/tts/NeMo/tests/core/test_config_utils.py new file mode 100644 index 0000000..4b0d8bb --- /dev/null +++ b/tts/NeMo/tests/core/test_config_utils.py @@ -0,0 +1,125 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +from dataclasses import dataclass +from typing import Any + +import pytest +import pytorch_lightning as ptl + +from nemo.core.config.pytorch_lightning import TrainerConfig +from nemo.utils import config_utils + + +@pytest.fixture() +def cls(): + class DummyClass: + def __init__(self, a, b=5, c: int = 0, d: 'ABC' = None): + pass + + return DummyClass + + +class TestConfigUtils: + @pytest.mark.unit + def test_all_args_exist(self, cls): + @dataclass + class DummyDataClass: + a: int = -1 + b: int = 5 + c: int = 0 + d: Any = None + + result = config_utils.assert_dataclass_signature_match(cls, DummyDataClass) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_all_args_dont_exist(self, cls): + @dataclass + class DummyDataClass: + a: int = -1 + b: int = 5 + c: int = 0 + + result = config_utils.assert_dataclass_signature_match(cls, DummyDataClass) + signatures_match, cls_subset, dataclass_subset = result + + assert not signatures_match + assert len(cls_subset) > 0 + assert len(dataclass_subset) == 0 + + @pytest.mark.unit + def test_extra_args_exist(self, cls): + @dataclass + class DummyDataClass: + a: int = -1 + b: int = 5 + c: int = 0 + d: Any = None + e: float = 0.0 + + result = config_utils.assert_dataclass_signature_match(cls, DummyDataClass) + signatures_match, cls_subset, dataclass_subset = result + + assert not signatures_match + assert len(cls_subset) == 0 + assert len(dataclass_subset) > 0 + + @pytest.mark.unit + def test_extra_args_exist_but_is_ignored(self, cls): + @dataclass + class DummyDataClass: + a: int = -1 + b: int = 5 + c: int = 0 + d: Any = None + e: float = 0.0 # Assume ignored + + result = config_utils.assert_dataclass_signature_match(cls, DummyDataClass, ignore_args=['e']) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_args_exist_but_is_remapped(self, cls): + @dataclass + class DummyDataClass: + a: int = -1 + b: int = 5 + c: int = 0 + e: Any = None # Assume remapped + + result = config_utils.assert_dataclass_signature_match(cls, DummyDataClass, remap_args={'e': 'd'}) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None + + @pytest.mark.unit + def test_ptl_config(self): + PTL_DEPRECATED = ['distributed_backend', 'automatic_optimization'] + + result = config_utils.assert_dataclass_signature_match(ptl.Trainer, TrainerConfig, ignore_args=PTL_DEPRECATED) + signatures_match, cls_subset, dataclass_subset = result + + assert signatures_match + assert cls_subset is None + assert dataclass_subset is None diff --git a/tts/NeMo/tests/core/test_exp_manager.py b/tts/NeMo/tests/core/test_exp_manager.py new file mode 100644 index 0000000..e1fa6da --- /dev/null +++ b/tts/NeMo/tests/core/test_exp_manager.py @@ -0,0 +1,357 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import math +import re +from pathlib import Path + +import pytest +import pytorch_lightning as pl +import torch +from omegaconf import OmegaConf +from omegaconf.errors import OmegaConfBaseException + +from nemo.constants import NEMO_ENV_VARNAME_VERSION +from nemo.core.classes import ModelPT +from nemo.utils.exp_manager import ( + CheckpointMisconfigurationError, + LoggerMisconfigurationError, + NotFoundError, + exp_manager, +) + + +class MyTestOptimizer(torch.optim.Optimizer): + def __init__(self, params): + self._step = 0 + super().__init__(params, {}) + + def step(self, *args, **kwargs): + for group in self.param_groups: + for p in group['params']: + if self._step == 0: + p.data = 0.1 * torch.ones(p.shape) + elif self._step == 1: + p.data = 0.0 * torch.ones(p.shape) + else: + p.data = 0.01 * torch.ones(p.shape) + self._step += 1 + return None + + +class OnesDataset(torch.utils.data.Dataset): + def __init__(self, dataset_len): + super().__init__() + self.__dataset_len = dataset_len + + def __getitem__(self, *args): + return torch.ones(2) + + def __len__(self): + return self.__dataset_len + + +class ExampleModel(ModelPT): + def __init__(self, *args, **kwargs): + cfg = OmegaConf.structured({}) + super().__init__(cfg) + self.l1 = torch.nn.modules.Linear(in_features=2, out_features=1) + + def train_dataloader(self): + dataset = OnesDataset(2) + return torch.utils.data.DataLoader(dataset, batch_size=2) + + def val_dataloader(self): + dataset = OnesDataset(10) + return torch.utils.data.DataLoader(dataset, batch_size=2) + + def forward(self, batch): + output = self.l1(batch) + output = torch.nn.functional.l1_loss(output, torch.zeros(output.size()).to(output.device)) + return output + + def validation_step(self, batch, batch_idx): + return self(batch) + + def training_step(self, batch, batch_idx): + return self(batch) + + def configure_optimizers(self): + return MyTestOptimizer(self.parameters()) + # return torch.optim.Adam(self.parameters(), lr=0.1) + + def list_available_models(self): + pass + + def setup_training_data(self): + pass + + def setup_validation_data(self): + pass + + def validation_epoch_end(self, loss): + self.log("val_loss", torch.stack(loss).mean()) + + +class TestExpManager: + @pytest.mark.unit + def test_omegaconf(self): + """Ensure omegaconf raises an error when an unexcepted argument is passed""" + with pytest.raises(OmegaConfBaseException): + exp_manager(pl.Trainer(), {"unused": 1}) + + @pytest.mark.unit + def test_trainer_loggers(self, tmp_path): + """ Test that a trainer with logger errors out with a number of arguments. Test that it works with + create_tensorboard_logger set to False + """ + test_trainer = pl.Trainer() # Should create logger and modelcheckpoint + + with pytest.raises(LoggerMisconfigurationError): # Fails because exp_manager defaults to trainer + exp_manager(test_trainer, {"exp_dir": str(tmp_path)}) + with pytest.raises(LoggerMisconfigurationError): # Fails because exp_manager defaults to trainer + exp_manager(test_trainer, {"explicit_log_dir": str(tmp_path)}) + with pytest.raises(LoggerMisconfigurationError): # Fails because exp_manager defaults to trainer + exp_manager(test_trainer, {"resume_if_exists": True}) + + # Check that exp_manager uses trainer.logger, it's exp_dir, name, and version + log_dir = exp_manager(test_trainer, {"create_tensorboard_logger": False, "create_checkpoint_callback": False}) + assert log_dir.resolve() == Path("./lightning_logs/version_0").resolve() + assert Path("./lightning_logs").exists() + assert Path("./lightning_logs/version_0").exists() + + # Check that a trainer without a logger gets a logger attached to it + test_trainer = pl.Trainer(logger=False) + log_dir = exp_manager( + test_trainer, + {"create_tensorboard_logger": True, "create_checkpoint_callback": False, "exp_dir": str(tmp_path)}, + ) + assert isinstance(test_trainer.logger, pl.loggers.TensorBoardLogger) + + test_trainer = pl.Trainer(logger=False) + # Check that a create_wandb_logger=True errors out unless wandb_logger_kwargs is passed. + with pytest.raises(ValueError): + log_dir = exp_manager( + test_trainer, + { + "create_tensorboard_logger": False, + "create_checkpoint_callback": False, + "exp_dir": str(tmp_path), + "create_wandb_logger": True, + }, + ) + # Check that a WandbLogger is attached to logger if create_wandb_logger=True and wandb_logger_kwargs has name + # and project + log_dir = exp_manager( + test_trainer, + { + "create_tensorboard_logger": False, + "create_checkpoint_callback": False, + "exp_dir": str(tmp_path), + "create_wandb_logger": True, + "wandb_logger_kwargs": {"name": "", "project": ""}, + }, + ) + assert isinstance(test_trainer.logger, pl.loggers.WandbLogger) + + @pytest.mark.unit + def test_checkpoint_configurations(self): + """ Test that trainer creating modelcheckpoint and asking exp_manager to do it too results in errors, but + is error free if only one is asked to do so. + """ + disable_tb_logger = {"create_tensorboard_logger": False} + test_trainer = pl.Trainer() # Should create logger and modelcheckpoint + with pytest.raises(CheckpointMisconfigurationError): # Fails because both try to create modelcheckpoint + exp_manager(test_trainer, disable_tb_logger) + + # Should succeed without error + exp_manager(test_trainer, {"create_checkpoint_callback": False, "create_tensorboard_logger": False}) + + test_trainer_2 = pl.Trainer(checkpoint_callback=False) + exp_manager(test_trainer_2, disable_tb_logger) # Should succeed without error + + @pytest.mark.unit + def test_default_log_dir(self): + """Check the default of ./nemo_experiments/default/datetime works as intended""" + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + + log_dir = exp_manager(test_trainer, {"create_tensorboard_logger": False, "create_checkpoint_callback": False}) + assert (log_dir / "..").resolve() == Path("./nemo_experiments/default/").resolve() + assert Path("./nemo_experiments").exists() + assert Path("./nemo_experiments/default/").exists() + sub_dirs = [x for x in Path("./nemo_experiments/default/").iterdir() if x.is_dir()] + assert len(sub_dirs) == 1 + assert re.match(r"[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}", sub_dirs[0].name) + + @pytest.mark.unit + def test_log_dir_overrides(self, monkeypatch, tmp_path): + """Check a variety of trainer options with exp_manager""" + # Checks that explicit_log_dir ignores exp_dir, name, and version + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + log_dir = exp_manager(test_trainer, {"explicit_log_dir": str(tmp_path / "test_log_dir_overrides")}) + assert log_dir.resolve() == (tmp_path / "test_log_dir_overrides").resolve() + assert Path(tmp_path).exists() + assert Path(tmp_path / "test_log_dir_overrides").exists() + + # Checks that exp_manager uses exp_dir, default name, and explicit version + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + log_dir = exp_manager(test_trainer, {"exp_dir": str(tmp_path / "test_no_name"), "version": 957}) + assert log_dir.resolve() == (tmp_path / "test_no_name" / "default" / "957").resolve() + assert Path(tmp_path).exists() + assert Path(tmp_path / "test_no_name" / "default" / "957").exists() + + monkeypatch.delenv(NEMO_ENV_VARNAME_VERSION) + # Checks that use_datetime_version False toggle works + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + log_dir = exp_manager(test_trainer, {"exp_dir": str(tmp_path / "test_no_name"), "use_datetime_version": False}) + assert log_dir.resolve() == (tmp_path / "test_no_name" / "default" / "version_0").resolve() + assert Path(tmp_path).exists() + assert Path(tmp_path / "test_no_name" / "default" / "version_0").exists() + + monkeypatch.delenv(NEMO_ENV_VARNAME_VERSION) + # Checks that use_datetime_version False toggle works and version increments + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + log_dir = exp_manager(test_trainer, {"exp_dir": str(tmp_path / "test_no_name"), "use_datetime_version": False}) + assert log_dir.resolve() == (tmp_path / "test_no_name" / "default" / "version_1").resolve() + assert Path(tmp_path).exists() + assert Path(tmp_path / "test_no_name" / "default" / "version_1").exists() + + @pytest.mark.unit + def test_resume(self, tmp_path): + """ Tests the resume capabilities of exp_manager""" + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + + # Error because explicit_log_dir does not exist + with pytest.raises(NotFoundError): + exp_manager( + test_trainer, + { + "exp_dir": str(tmp_path / "test_resume"), + "resume_if_exists": True, + "explicit_log_dir": "Does_not_exist", + }, + ) + + # Error because checkpoints folder does not exist + with pytest.raises(NotFoundError): + exp_manager(test_trainer, {"resume_if_exists": True, "exp_dir": str(tmp_path / "test_resume")}) + + # No error because we tell exp_manager to ignore notfounderror + exp_manager( + test_trainer, + { + "resume_if_exists": True, + "exp_dir": str(tmp_path / "test_resume_2"), + "resume_ignore_no_checkpoint": True, + }, + ) + + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints").mkdir(parents=True) + # Error because checkpoints do not exist in folder + with pytest.raises(NotFoundError): + exp_manager( + test_trainer, + { + "resume_if_exists": True, + "explicit_log_dir": str(tmp_path / "test_resume" / "default" / "version_0"), + }, + ) + + Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel--end.ckpt").touch() + # Error because *end.ckpt is in folder indicating that training has already finished + with pytest.raises(ValueError): + exp_manager( + test_trainer, + { + "resume_if_exists": True, + "explicit_log_dir": str(tmp_path / "test_resume" / "default" / "version_0"), + }, + ) + + Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel--end.ckpt").unlink() + Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel--last.ckpt").touch() + Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel2--last.ckpt").touch() + # Error because multiple *last.ckpt is in folder. If more than one, don't know which to restore + with pytest.raises(ValueError): + exp_manager( + test_trainer, + { + "resume_if_exists": True, + "explicit_log_dir": str(tmp_path / "test_resume" / "default" / "version_0"), + }, + ) + + # Finally succeed + Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel2--last.ckpt").unlink() + log_dir = exp_manager( + test_trainer, + {"resume_if_exists": True, "explicit_log_dir": str(tmp_path / "test_resume" / "default" / "version_0")}, + ) + checkpoint = Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel--last.ckpt") + assert Path(test_trainer.resume_from_checkpoint).resolve() == checkpoint.resolve() + + # Succeed again and make sure that run_0 exists and previous log files were moved + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False) + exp_manager(test_trainer, {"resume_if_exists": True, "explicit_log_dir": str(log_dir)}) + checkpoint = Path(tmp_path / "test_resume" / "default" / "version_0" / "checkpoints" / "mymodel--last.ckpt") + assert Path(test_trainer.resume_from_checkpoint).resolve() == checkpoint.resolve() + prev_run_dir = Path(tmp_path / "test_resume" / "default" / "version_0" / "run_0") + assert prev_run_dir.exists() + prev_log = Path(tmp_path / "test_resume" / "default" / "version_0" / "run_0" / "lightning_logs.txt") + assert prev_log.exists() + + @pytest.mark.unit + def test_nemo_checkpoint_save_best_model_1(self, tmp_path): + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False, max_epochs=4) + log_dir = exp_manager( + test_trainer, + {"checkpoint_callback_params": {"save_best_model": True}, "explicit_log_dir": str(tmp_path / "test")}, + ) + model = ExampleModel() + test_trainer.fit(model) + + assert Path(str(tmp_path / "test" / "checkpoints" / "default.nemo")).exists() + + model = ExampleModel.restore_from(str(tmp_path / "test" / "checkpoints" / "default.nemo")) + assert float(model(torch.tensor([1.0, 1.0], device=model.device))) == 0.0 + + @pytest.mark.unit + def test_nemo_checkpoint_save_best_model_2(self, tmp_path): + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False, max_epochs=4) + log_dir = exp_manager(test_trainer, {"explicit_log_dir": str(tmp_path / "test")},) + model = ExampleModel() + test_trainer.fit(model) + + assert Path(str(tmp_path / "test" / "checkpoints" / "default.nemo")).exists() + + model = ExampleModel.restore_from(str(tmp_path / "test" / "checkpoints" / "default.nemo")) + assert math.fabs(float(model(torch.tensor([1.0, 1.0], device=model.device))) - 0.03) < 1e-5 + + @pytest.mark.unit + def test_nemo_checkpoint_always_save_nemo(self, tmp_path): + test_trainer = pl.Trainer(checkpoint_callback=False, logger=False, max_epochs=4) + log_dir = exp_manager( + test_trainer, + { + "checkpoint_callback_params": {"save_best_model": True, "always_save_nemo": True}, + "explicit_log_dir": str(tmp_path / "test"), + }, + ) + model = ExampleModel() + test_trainer.fit(model) + + assert Path(str(tmp_path / "test" / "checkpoints" / "default.nemo")).exists() + + model = ExampleModel.restore_from(str(tmp_path / "test" / "checkpoints" / "default.nemo")) + assert float(model(torch.tensor([1.0, 1.0], device=model.device))) == 0.0 diff --git a/tts/NeMo/tests/core/test_fileio.py b/tts/NeMo/tests/core/test_fileio.py new file mode 100644 index 0000000..f737b23 --- /dev/null +++ b/tts/NeMo/tests/core/test_fileio.py @@ -0,0 +1,299 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import tempfile + +import numpy as np +import pytest +import torch +from omegaconf import DictConfig, OmegaConf + +from nemo.collections.asr.models import EncDecCTCModel + +try: + from eff.cookbooks import NeMoCookbook + + _EFF_PRESENT_ = True +except ImportError: + _EFF_PRESENT_ = False + +# A decorator marking the EFF requirement. +requires_eff = pytest.mark.skipif(not _EFF_PRESENT_, reason="Export File Format library required to run test") + + +@pytest.fixture() +def asr_model(): + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 1024, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.ConvASRDecoder', + 'params': { + 'feat_in': 1024, + 'num_classes': 28, + 'vocabulary': [ + ' ', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + "'", + ], + }, + } + modelConfig = DictConfig( + {'preprocessor': DictConfig(preprocessor), 'encoder': DictConfig(encoder), 'decoder': DictConfig(decoder)} + ) + + model_instance = EncDecCTCModel(cfg=modelConfig) + return model_instance + + +class TestFileIO: + @pytest.mark.unit + def test_to_from_config_file(self, asr_model): + """" Test makes sure that the second instance created with the same configuration (BUT NOT checkpoint) + has different weights. """ + + with tempfile.NamedTemporaryFile() as fp: + yaml_filename = fp.name + asr_model.to_config_file(path2yaml_file=yaml_filename) + next_instance = EncDecCTCModel.from_config_file(path2yaml_file=yaml_filename) + + assert isinstance(next_instance, EncDecCTCModel) + + assert len(next_instance.decoder.vocabulary) == 28 + assert asr_model.num_weights == next_instance.num_weights + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = next_instance.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert not np.array_equal(w1, w2) + + @pytest.mark.unit + def test_save_restore_from_nemo_file(self, asr_model): + """" Test makes sure that the second instance created from the same configuration AND checkpoint + has the same weights. """ + + with tempfile.NamedTemporaryFile() as fp: + filename = fp.name + + # Save model (with random artifact). + with tempfile.NamedTemporaryFile() as artifact: + asr_model.register_artifact(config_path="abc", src=artifact.name) + asr_model.save_to(save_path=filename) + + # Restore the model. + asr_model2 = EncDecCTCModel.restore_from(restore_path=filename) + + assert len(asr_model.decoder.vocabulary) == len(asr_model2.decoder.vocabulary) + assert asr_model.num_weights == asr_model2.num_weights + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = asr_model2.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert np.array_equal(w1, w2) + + @requires_eff + @pytest.mark.unit + def test_eff_save_restore_from_nemo_file_encrypted(self, asr_model): + """" Test makes sure that after encrypted save-restore the model has the same weights. """ + + with tempfile.NamedTemporaryFile() as fp: + filename = fp.name + + # Set key - use checkpoint encryption. + NeMoCookbook.set_encryption_key("test_key") + + # Save model (with random artifact). + with tempfile.NamedTemporaryFile() as artifact: + asr_model.register_artifact(config_path="abc", src=artifact.name) + asr_model.save_to(save_path=filename) + + # Try to restore the encrypted archive (weights) without the encryption key. + NeMoCookbook.set_encryption_key(None) + with pytest.raises(PermissionError): + # Restore the model. + asr_model2 = EncDecCTCModel.restore_from(restore_path=filename) + + # Restore the model. + NeMoCookbook.set_encryption_key("test_key") + asr_model3 = EncDecCTCModel.restore_from(restore_path=filename) + # Reset encryption so it won't mess up with other save/restore. + NeMoCookbook.set_encryption_key(None) + + assert asr_model.num_weights == asr_model3.num_weights + + @pytest.mark.unit + def test_save_restore_from_nemo_file_with_override(self, asr_model, tmpdir): + """" Test makes sure that the second instance created from the same configuration AND checkpoint + has the same weights. + + Args: + tmpdir: fixture providing a temporary directory unique to the test invocation. + """ + # Name of the archive in tmp folder. + filename = os.path.join(tmpdir, "eff.nemo") + + # Get path where the command is executed - the artifacts will be "retrieved" there. + # (original .nemo behavior) + cwd = os.getcwd() + + with tempfile.NamedTemporaryFile(mode='a+') as conf_fp: + + # Create a "random artifact". + with tempfile.NamedTemporaryFile(mode="w", delete=False) as artifact: + artifact.write("magic content 42") + # Remember the filename of the artifact. + _, artifact_filename = os.path.split(artifact.name) + # Add artifact to model. + asr_model.register_artifact(config_path="abc", src=artifact.name) + # Save model (with "random artifact"). + asr_model.save_to(save_path=filename) + + # Modify config slightly + cfg = asr_model.cfg + cfg.encoder.activation = 'swish' + yaml_cfg = OmegaConf.to_yaml(cfg) + conf_fp.write(yaml_cfg) + conf_fp.seek(0) + + # Restore the model. + asr_model2 = EncDecCTCModel.restore_from(restore_path=filename, override_config_path=conf_fp.name) + + assert len(asr_model.decoder.vocabulary) == len(asr_model2.decoder.vocabulary) + assert asr_model.num_weights == asr_model2.num_weights + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = asr_model2.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert np.array_equal(w1, w2) + + assert asr_model2.cfg.encoder.activation == 'swish' + + @pytest.mark.unit + def test_save_model_level_pt_ckpt(self, asr_model): + with tempfile.TemporaryDirectory() as ckpt_dir: + nemo_file = os.path.join(ckpt_dir, 'asr.nemo') + asr_model.save_to(nemo_file) + + # Save model level PT checkpoint + asr_model.extract_state_dict_from(nemo_file, ckpt_dir) + ckpt_path = os.path.join(ckpt_dir, 'model_weights.ckpt') + + assert os.path.exists(ckpt_path) + + # Restore the model. + asr_model2 = EncDecCTCModel.restore_from(restore_path=nemo_file) + + assert len(asr_model.decoder.vocabulary) == len(asr_model2.decoder.vocabulary) + assert asr_model.num_weights == asr_model2.num_weights + + # Change weights values + asr_model2.encoder.encoder[0].mconv[0].conv.weight.data += 1.0 + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = asr_model2.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert not np.array_equal(w1, w2) + + # Restore from checkpoint + asr_model2.load_state_dict(torch.load(ckpt_path)) + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = asr_model2.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert np.array_equal(w1, w2) + + @pytest.mark.unit + def test_save_module_level_pt_ckpt(self, asr_model): + with tempfile.TemporaryDirectory() as ckpt_dir: + nemo_file = os.path.join(ckpt_dir, 'asr.nemo') + asr_model.save_to(nemo_file) + + # Save model level PT checkpoint + asr_model.extract_state_dict_from(nemo_file, ckpt_dir, split_by_module=True) + encoder_path = os.path.join(ckpt_dir, 'encoder.ckpt') + decoder_path = os.path.join(ckpt_dir, 'decoder.ckpt') + preprocessor_path = os.path.join(ckpt_dir, 'preprocessor.ckpt') + + assert os.path.exists(encoder_path) + assert os.path.exists(decoder_path) + assert os.path.exists(preprocessor_path) + + # Restore the model. + asr_model2 = EncDecCTCModel.restore_from(restore_path=nemo_file) + + assert len(asr_model.decoder.vocabulary) == len(asr_model2.decoder.vocabulary) + assert asr_model.num_weights == asr_model2.num_weights + + # Change weights values + asr_model2.encoder.encoder[0].mconv[0].conv.weight.data += 1.0 + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = asr_model2.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert not np.array_equal(w1, w2) + + # Restore from checkpoint + asr_model2.encoder.load_state_dict(torch.load(encoder_path)) + + w1 = asr_model.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + w2 = asr_model2.encoder.encoder[0].mconv[0].conv.weight.data.detach().cpu().numpy() + + assert np.array_equal(w1, w2) diff --git a/tts/NeMo/tests/core/test_neural_types.py b/tts/NeMo/tests/core/test_neural_types.py new file mode 100644 index 0000000..e40ddd9 --- /dev/null +++ b/tts/NeMo/tests/core/test_neural_types.py @@ -0,0 +1,224 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest + +from nemo.core.neural_types import ( + AcousticEncodedRepresentation, + AudioSignal, + AxisKind, + AxisKindAbstract, + AxisType, + ChannelType, + ElementType, + MelSpectrogramType, + MFCCSpectrogramType, + NeuralType, + NeuralTypeComparisonResult, + SpectrogramType, + VoidType, +) + + +class TestNeuralTypeSystem: + @pytest.mark.unit + def test_short_vs_long_version(self): + long_version = NeuralType( + axes=(AxisType(AxisKind.Batch, None), AxisType(AxisKind.Dimension, None), AxisType(AxisKind.Time, None)), + elements_type=AcousticEncodedRepresentation(), + ) + short_version = NeuralType(('B', 'D', 'T'), AcousticEncodedRepresentation()) + assert long_version.compare(short_version) == NeuralTypeComparisonResult.SAME + assert short_version.compare(long_version) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_parameterized_type_audio_sampling_frequency(self): + audio16K = NeuralType(axes=('B', 'T'), elements_type=AudioSignal(16000)) + audio8K = NeuralType(axes=('B', 'T'), elements_type=AudioSignal(8000)) + another16K = NeuralType(axes=('B', 'T'), elements_type=AudioSignal(16000)) + + assert audio8K.compare(audio16K) == NeuralTypeComparisonResult.SAME_TYPE_INCOMPATIBLE_PARAMS + assert audio16K.compare(audio8K) == NeuralTypeComparisonResult.SAME_TYPE_INCOMPATIBLE_PARAMS + assert another16K.compare(audio16K) == NeuralTypeComparisonResult.SAME + assert audio16K.compare(another16K) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_transpose_same_1(self): + type1 = NeuralType(axes=('B', 'T', 'C')) + type2 = NeuralType(axes=('T', 'B', 'C')) + + assert type1.compare(type2) == NeuralTypeComparisonResult.TRANSPOSE_SAME + assert type2.compare(type1) == NeuralTypeComparisonResult.TRANSPOSE_SAME + + @pytest.mark.unit + def test_transpose_same_2(self): + audio16K = NeuralType(axes=('B', 'T'), elements_type=AudioSignal(16000)) + audio16K_t = NeuralType(axes=('T', 'B'), elements_type=AudioSignal(16000)) + + assert audio16K.compare(audio16K_t) == NeuralTypeComparisonResult.TRANSPOSE_SAME + + @pytest.mark.unit + def test_inheritance_spec_augment_example(self): + input = NeuralType(('B', 'D', 'T'), SpectrogramType()) + out1 = NeuralType(('B', 'D', 'T'), MelSpectrogramType()) + out2 = NeuralType(('B', 'D', 'T'), MFCCSpectrogramType()) + + assert out1.compare(out2) == NeuralTypeComparisonResult.INCOMPATIBLE + assert out2.compare(out1) == NeuralTypeComparisonResult.INCOMPATIBLE + assert input.compare(out1) == NeuralTypeComparisonResult.GREATER + assert input.compare(out2) == NeuralTypeComparisonResult.GREATER + assert out1.compare(input) == NeuralTypeComparisonResult.LESS + assert out2.compare(input) == NeuralTypeComparisonResult.LESS + + @pytest.mark.unit + def test_singletone(self): + loss_output1 = NeuralType(axes=None) + loss_output2 = NeuralType(axes=None) + + assert loss_output1.compare(loss_output2) == NeuralTypeComparisonResult.SAME + assert loss_output2.compare(loss_output1) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_list_of_lists(self): + T1 = NeuralType( + axes=( + AxisType(kind=AxisKind.Batch, size=None, is_list=True), + AxisType(kind=AxisKind.Time, size=None, is_list=True), + AxisType(kind=AxisKind.Dimension, size=32, is_list=False), + AxisType(kind=AxisKind.Dimension, size=128, is_list=False), + AxisType(kind=AxisKind.Dimension, size=256, is_list=False), + ), + elements_type=ChannelType(), + ) + T2 = NeuralType( + axes=( + AxisType(kind=AxisKind.Batch, size=None, is_list=False), + AxisType(kind=AxisKind.Time, size=None, is_list=False), + AxisType(kind=AxisKind.Dimension, size=32, is_list=False), + AxisType(kind=AxisKind.Dimension, size=128, is_list=False), + AxisType(kind=AxisKind.Dimension, size=256, is_list=False), + ), + elements_type=ChannelType(), + ) + # TODO: should this be incompatible instead??? + assert T1.compare(T2), NeuralTypeComparisonResult.TRANSPOSE_SAME + + @pytest.mark.unit + def test_void(self): + btc_spctr = NeuralType(('B', 'T', 'C'), SpectrogramType()) + btc_spct_bad = NeuralType(('B', 'T'), SpectrogramType()) + btc_void = NeuralType(('B', 'T', 'C'), VoidType()) + + assert btc_void.compare(btc_spctr) == NeuralTypeComparisonResult.SAME + assert btc_spctr.compare(btc_void) == NeuralTypeComparisonResult.INCOMPATIBLE + assert btc_void.compare(btc_spct_bad) == NeuralTypeComparisonResult.INCOMPATIBLE + + @pytest.mark.unit + def test_big_void(self): + big_void_1 = NeuralType(elements_type=VoidType()) + big_void_2 = NeuralType() + + btc_spctr = NeuralType(('B', 'T', 'C'), SpectrogramType()) + btc_spct_bad = NeuralType(('B', 'T'), SpectrogramType()) + t1 = NeuralType( + axes=( + AxisType(kind=AxisKind.Batch, size=None, is_list=True), + AxisType(kind=AxisKind.Time, size=None, is_list=True), + AxisType(kind=AxisKind.Dimension, size=32, is_list=False), + AxisType(kind=AxisKind.Dimension, size=128, is_list=False), + AxisType(kind=AxisKind.Dimension, size=256, is_list=False), + ), + elements_type=ChannelType(), + ) + t2 = NeuralType( + axes=( + AxisType(kind=AxisKind.Batch, size=None, is_list=False), + AxisType(kind=AxisKind.Time, size=None, is_list=False), + AxisType(kind=AxisKind.Dimension, size=32, is_list=False), + AxisType(kind=AxisKind.Dimension, size=128, is_list=False), + AxisType(kind=AxisKind.Dimension, size=256, is_list=False), + ), + elements_type=ChannelType(), + ) + + assert big_void_1.compare(btc_spctr) == NeuralTypeComparisonResult.SAME + assert big_void_1.compare(btc_spct_bad) == NeuralTypeComparisonResult.SAME + assert big_void_1.compare(t1) == NeuralTypeComparisonResult.SAME + assert big_void_1.compare(t2) == NeuralTypeComparisonResult.SAME + + assert big_void_2.compare(btc_spctr) == NeuralTypeComparisonResult.SAME + assert big_void_2.compare(btc_spct_bad) == NeuralTypeComparisonResult.SAME + assert big_void_2.compare(t1) == NeuralTypeComparisonResult.SAME + assert big_void_2.compare(t2) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_unspecified_dimensions(self): + t0 = NeuralType( + (AxisType(AxisKind.Batch, 64), AxisType(AxisKind.Time, 10), AxisType(AxisKind.Dimension, 128)), + SpectrogramType(), + ) + t1 = NeuralType(('B', 'T', 'C'), SpectrogramType()) + + assert t1.compare(t0), NeuralTypeComparisonResult.SAME + assert t0.compare(t1), NeuralTypeComparisonResult.DIM_INCOMPATIBLE + + @pytest.mark.unit + def test_any_axis(self): + t0 = NeuralType(('B', 'Any', 'Any'), VoidType()) + t1 = NeuralType(('B', 'Any', 'Any'), SpectrogramType()) + t2 = NeuralType(('B', 'T', 'C'), SpectrogramType()) + + assert t0.compare(t1) == NeuralTypeComparisonResult.SAME + assert t0.compare(t2) == NeuralTypeComparisonResult.SAME + assert t1.compare(t2) == NeuralTypeComparisonResult.SAME + assert t2.compare(t1) == NeuralTypeComparisonResult.INCOMPATIBLE + assert t1.compare(t0) == NeuralTypeComparisonResult.INCOMPATIBLE + + @pytest.mark.unit + def test_struct(self): + class BoundingBox(ElementType): + def __str__(self): + return "bounding box from detection model" + + def fields(self): + return ("X", "Y", "W", "H") + + # ALSO ADD new, user-defined, axis kind + class AxisKind2(AxisKindAbstract): + Image = 0 + + T1 = NeuralType( + elements_type=BoundingBox(), + axes=( + AxisType(kind=AxisKind.Batch, size=None, is_list=True), + AxisType(kind=AxisKind2.Image, size=None, is_list=True), + ), + ) + + class BadBoundingBox(ElementType): + def __str__(self): + return "bad bounding box from detection model" + + def fields(self): + return ("X", "Y", "H") + + T2 = NeuralType( + elements_type=BadBoundingBox(), + axes=( + AxisType(kind=AxisKind.Batch, size=None, is_list=True), + AxisType(kind=AxisKind2.Image, size=None, is_list=True), + ), + ) + assert T2.compare(T1) == NeuralTypeComparisonResult.INCOMPATIBLE diff --git a/tts/NeMo/tests/core/test_optimizers_schedulers.py b/tts/NeMo/tests/core/test_optimizers_schedulers.py new file mode 100644 index 0000000..84f7d14 --- /dev/null +++ b/tts/NeMo/tests/core/test_optimizers_schedulers.py @@ -0,0 +1,809 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import math +import random + +import omegaconf +import pytest +import pytorch_lightning as pl +import torch +import torch.optim + +from nemo.core import config, optim +from nemo.core.optim.lr_scheduler import AVAILABLE_SCHEDULERS +from nemo.core.optim.optimizers import AVAILABLE_OPTIMIZERS +from nemo.utils import logging + + +class TempModel(torch.nn.Module): + def __init__(self): + super(TempModel, self).__init__() + self.layer = torch.nn.Linear(5, 1) + + def forward(self, x): + x = self.layer(x) + return x + + +class OptCounter(torch.optim.SGD): + def __init__(self, *args, **kwargs): + self.count = 0 + super().__init__(*args, **kwargs) + + def step(self, closure=None): + try: + self.count += 1 + except AttributeError: + self.count = 1 + super().step(closure) + + +class RandomDataset(torch.utils.data.Dataset): + def __init__(self, dataset_len): + super().__init__() + self.__dataset_len = dataset_len + + def __getitem__(self, *args): + return torch.randn(2) + + def __len__(self): + return self.__dataset_len + + +class ExampleModel(pl.LightningModule): + def __init__(self, batch_size, dataset_len, drop_last, max_steps): + super().__init__() + self.l1 = torch.nn.modules.Linear(in_features=2, out_features=1) + self.batch_size = batch_size + self.dataset_len = dataset_len + self.drop_last = drop_last + self.max_steps = max_steps + + def train_dataloader(self): + dataset = RandomDataset(self.dataset_len) + return torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, drop_last=self.drop_last) + + def training_step(self, batch, batch_idx): + output = self.l1(batch) + output = torch.nn.functional.l1_loss(output, torch.ones(output.size()).to(output.device)) + return {"loss": output} + + def configure_optimizers(self): + self.my_opt = OptCounter(self.parameters(), lr=0.02) + return self.my_opt + + +class Callback(pl.callbacks.Callback): + @pl.utilities.distributed.rank_zero_only + def on_train_end(self, trainer, module): + if trainer.global_step != module.my_opt.count or trainer.global_step != module.max_steps: + logging.debug(f"max_epochs: {trainer.max_epochs}") + logging.debug(f"accumulate_grad_batches: {trainer.accumulate_grad_batches}") + logging.debug(f"limit_train_batches: {trainer.limit_train_batches}") + logging.debug(f"num_processes: {trainer.num_processes}") + logging.debug(f"batch_size: {module.batch_size}") + logging.debug(f"dataset_len: {module.dataset_len}") + logging.debug(f"drop_last: {module.drop_last}") + logging.debug(f"{len(trainer.train_dataloader)}") + logging.debug(f"{trainer.num_training_batches }") + assert ( + trainer.global_step == module.my_opt.count + ), f"{trainer.global_step} != {module.my_opt.count} != {module.max_steps}" + assert ( + trainer.global_step == module.max_steps + ), f"{trainer.global_step} != {module.my_opt.count} != {module.max_steps}" + + +class TestOptimizersSchedulers: + INITIAL_LR = 0.1 + MIN_LR = 1e-3 + MAX_STEPS = 10 + + @pytest.mark.unit + def test_get_optimizer(self): + model = TempModel() + + for opt_name in AVAILABLE_OPTIMIZERS.keys(): + opt_cls = optim.get_optimizer(opt_name) + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + assert isinstance(opt, AVAILABLE_OPTIMIZERS[opt_name]) + + @pytest.mark.unit + def test_register_optimizer(self): + class TempOpt(torch.optim.SGD): + pass + + class TempOptParams(config.optimizers.SGDParams): + pass + + optim.register_optimizer('TempOpt', TempOpt, TempOptParams) + + model = TempModel() + opt_cls = optim.get_optimizer('TempOpt') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + assert isinstance(opt, TempOpt) + + @pytest.mark.unit + def test_optim_config_parse_bypass(self): + basic_optim_config = {'weight_decay': 0.001, 'betas': [0.8, 0.5]} + parsed_params = optim.parse_optimizer_args('novograd', basic_optim_config) + assert parsed_params['weight_decay'] == basic_optim_config['weight_decay'] + assert parsed_params['betas'][0] == basic_optim_config['betas'][0] + assert parsed_params['betas'][1] == basic_optim_config['betas'][1] + + dict_config = omegaconf.OmegaConf.create(basic_optim_config) + parsed_params = optim.parse_optimizer_args('novograd', dict_config) + assert parsed_params['weight_decay'] == dict_config['weight_decay'] + assert parsed_params['betas'][0] == dict_config['betas'][0] + assert parsed_params['betas'][1] == dict_config['betas'][1] + + @pytest.mark.unit + def test_optim_config_parse_arg_by_name(self): + basic_optim_config = {'name': 'auto', 'weight_decay': 0.001, 'betas': [0.8, 0.5]} + parsed_params = optim.parse_optimizer_args('novograd', basic_optim_config) + assert parsed_params['weight_decay'] == basic_optim_config['weight_decay'] + assert parsed_params['betas'][0] == basic_optim_config['betas'][0] + assert parsed_params['betas'][1] == basic_optim_config['betas'][1] + + dict_config = omegaconf.OmegaConf.create(basic_optim_config) + parsed_params = optim.parse_optimizer_args('novograd', dict_config) + assert parsed_params['weight_decay'] == dict_config['weight_decay'] + assert parsed_params['betas'][0] == dict_config['betas'][0] + assert parsed_params['betas'][1] == dict_config['betas'][1] + + with pytest.raises(omegaconf.errors.ConfigKeyError): + optim.parse_optimizer_args('sgd', dict_config) + + @pytest.mark.unit + def test_optim_config_parse_arg_by_target(self): + basic_optim_config = { + '_target_': 'nemo.core.config.NovogradParams', + 'params': {'weight_decay': 0.001, 'betas': [0.8, 0.5]}, + } + basic_optim_config = omegaconf.OmegaConf.create(basic_optim_config) + parsed_params = optim.parse_optimizer_args('novograd', basic_optim_config) + assert parsed_params['weight_decay'] == basic_optim_config['params']['weight_decay'] + assert parsed_params['betas'][0] == basic_optim_config['params']['betas'][0] + assert parsed_params['betas'][1] == basic_optim_config['params']['betas'][1] + + dict_config = omegaconf.OmegaConf.create(basic_optim_config) + parsed_params = optim.parse_optimizer_args('novograd', dict_config) + assert parsed_params['weight_decay'] == dict_config['params']['weight_decay'] + assert parsed_params['betas'][0] == dict_config['params']['betas'][0] + assert parsed_params['betas'][1] == dict_config['params']['betas'][1] + + # Names are ignored when passing class path + # This will be captured during optimizer instantiation + output_config = optim.parse_optimizer_args('sgd', dict_config) + sgd_config = vars(config.SGDParams()) + novograd_config = vars(config.NovogradParams()) + + assert set(output_config.keys()) != set(sgd_config.keys()) + assert set(output_config.keys()) == set(novograd_config) + + @pytest.mark.unit + def test_get_scheduler(self): + model = TempModel() + optimizer = optim.Novograd(model.parameters(), lr=self.INITIAL_LR) + + for sched_name in AVAILABLE_SCHEDULERS.keys(): + sched_cls = optim.lr_scheduler.get_scheduler(sched_name) + + try: + sched = sched_cls(optimizer) + assert isinstance(sched, AVAILABLE_SCHEDULERS[sched_name]) + continue + except Exception: + pass + + try: + sched = sched_cls(optimizer, max_steps=self.MAX_STEPS) + assert isinstance(sched, AVAILABLE_SCHEDULERS[sched_name]) + continue + except Exception: + pass + + @pytest.mark.unit + def test_register_scheduler(self): + class TempSched(optim.lr_scheduler.CosineAnnealing): + pass + + class TempSchedParams(config.schedulers.CosineAnnealingParams): + pass + + optim.lr_scheduler.register_scheduler('TempSched', TempSched, TempSchedParams) + + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + sched_cls = optim.lr_scheduler.get_scheduler('TempSched') + sched = sched_cls(opt, max_steps=self.MAX_STEPS) + + assert isinstance(sched, TempSched) + + @pytest.mark.unit + def test_sched_config_parse_simple(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + basic_sched_config = {'name': 'CosineAnnealing', 'max_steps': 10} + scheduler_setup = optim.lr_scheduler.prepare_lr_scheduler(opt, basic_sched_config) + assert isinstance(scheduler_setup['scheduler'], optim.lr_scheduler.CosineAnnealing) + + dict_config = omegaconf.OmegaConf.create(basic_sched_config) + scheduler_setup = optim.lr_scheduler.prepare_lr_scheduler(opt, dict_config) + assert isinstance(scheduler_setup['scheduler'], optim.lr_scheduler.CosineAnnealing) + + @pytest.mark.unit + def test_sched_config_parse_from_cls(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + basic_sched_config = { + '_target_': 'nemo.core.config.CosineAnnealingParams', + 'params': {'min_lr': 0.1}, + 'max_steps': self.MAX_STEPS, + } + scheduler_setup = optim.lr_scheduler.prepare_lr_scheduler(opt, basic_sched_config) + assert isinstance(scheduler_setup['scheduler'], optim.lr_scheduler.CosineAnnealing) + + dict_config = omegaconf.OmegaConf.create(basic_sched_config) + scheduler_setup = optim.lr_scheduler.prepare_lr_scheduler(opt, dict_config) + assert isinstance(scheduler_setup['scheduler'], optim.lr_scheduler.CosineAnnealing) + + @pytest.mark.unit + def test_WarmupPolicy(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.WarmupPolicy(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] == self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.WarmupPolicy(opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 4: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] == self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_WarmupHoldPolicy(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.WarmupHoldPolicy(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] == self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.WarmupHoldPolicy(opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 4: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] == self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup + Hold steps available + policy = optim.lr_scheduler.WarmupHoldPolicy( + opt, warmup_steps=5, hold_steps=3, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 4: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] == self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_WarmupAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.WarmupAnnealing(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.WarmupAnnealing(opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup + Hold steps available + policy = optim.lr_scheduler.WarmupHoldPolicy( + opt, warmup_steps=5, hold_steps=3, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 4: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] == self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_SquareAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.SquareAnnealing(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.SquareAnnealing(opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_SquareRootAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.SquareRootAnnealing(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.SquareRootAnnealing( + opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_CosineAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.CosineAnnealing(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.CosineAnnealing(opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_PolynomialDecayAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.PolynomialDecayAnnealing( + opt, power=2, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.PolynomialDecayAnnealing( + opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_PolynomialHoldDecayAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.PolynomialHoldDecayAnnealing( + opt, power=2, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.PolynomialHoldDecayAnnealing( + opt, power=2, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup + Hold steps available + policy = optim.lr_scheduler.PolynomialHoldDecayAnnealing( + opt, warmup_steps=5, hold_steps=3, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR, power=2 + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 4: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + elif i <= 8: + assert policy.get_last_lr()[0] == self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + def test_InverseSquareRootAnnealing(self): + model = TempModel() + opt_cls = optim.get_optimizer('novograd') + opt = opt_cls(model.parameters(), lr=self.INITIAL_LR) + + # No warmup case + policy = optim.lr_scheduler.InverseSquareRootAnnealing(opt, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr == self.INITIAL_LR + + for i in range(self.MAX_STEPS): + assert policy.get_last_lr()[0] <= self.INITIAL_LR + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + # Warmup steps available + policy = optim.lr_scheduler.InverseSquareRootAnnealing( + opt, warmup_steps=5, max_steps=self.MAX_STEPS, min_lr=self.MIN_LR + ) + initial_lr = policy.get_last_lr()[0] + + assert initial_lr < self.INITIAL_LR + + for i in range(self.MAX_STEPS): + if i <= 5: + assert policy.get_last_lr()[0] <= self.INITIAL_LR + else: + assert policy.get_last_lr()[0] < self.INITIAL_LR + + opt.step() + policy.step() + + policy.step() + final_lr = policy.get_last_lr()[0] + + assert final_lr == self.MIN_LR + + @pytest.mark.unit + @pytest.mark.run_only_on('CPU') + def test_max_step_computation(self): + def train( + max_epochs, accumulate_grad_batches, limit_train_batches, num_processes, batch_size, dataset_len, drop_last + ): + trainer = pl.Trainer( + max_epochs=max_epochs, + accelerator="ddp_cpu", + num_processes=num_processes, + accumulate_grad_batches=accumulate_grad_batches, + limit_train_batches=limit_train_batches, + checkpoint_callback=False, + progress_bar_refresh_rate=0, + weights_summary=None, + ) + max_steps = optim.lr_scheduler.compute_max_steps( + max_epochs, + accumulate_grad_batches, + limit_train_batches, + num_processes, + dataset_len, + batch_size, + drop_last, + ) + model = ExampleModel(batch_size, dataset_len, drop_last, max_steps) + trainer.callbacks.append(Callback()) + trainer.fit(model) + + # This test will break once we and lightning upgrade to pytorch 1.7.0 due to a bug fix in pytorch 1.7.0 + train( + 31, + accumulate_grad_batches=1, + limit_train_batches=1.0, + num_processes=9, + batch_size=60, + dataset_len=1613, + drop_last=True, + ) + train( + 5, + accumulate_grad_batches=1, + limit_train_batches=0.17382691901706027, + num_processes=4, + batch_size=97, + dataset_len=498, + drop_last=False, + ) + train( + 5, + accumulate_grad_batches=8, + limit_train_batches=0.1663306588594945, + num_processes=4, + batch_size=54, + dataset_len=629, + drop_last=True, + ) + train( + 5, + accumulate_grad_batches=1, + limit_train_batches=0.2121376533631948, + num_processes=1, + batch_size=68, + dataset_len=488, + drop_last=False, + ) + for _ in range(5): + drop_last = bool(random.randint(0, 1)) + accumulate_grad_batches = random.randint(1, 10) + + limit_train_batches_int = random.randint(1, 10) + limit_train_batches_float = random.uniform(0, 1) + limit_train_batches = random.choice([limit_train_batches_int, limit_train_batches_float]) + max_epochs = random.randint(4, 20) + num_processes = random.randint(1, 5) + dataset_len = random.randint(20, num_processes * 500) + batch_size = random.randint(math.ceil(5.0 / num_processes), min(dataset_len // num_processes, 128)) + train( + max_epochs, + accumulate_grad_batches, + limit_train_batches, + num_processes, + batch_size, + dataset_len, + drop_last, + ) diff --git a/tts/NeMo/tests/core/test_save_restore.py b/tts/NeMo/tests/core/test_save_restore.py new file mode 100644 index 0000000..4c59fa0 --- /dev/null +++ b/tts/NeMo/tests/core/test_save_restore.py @@ -0,0 +1,443 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import filecmp +import os +import shutil +import tempfile +from typing import Dict, Optional, Set, Union + +import pytest +import torch +from omegaconf import DictConfig, OmegaConf, open_dict + +from nemo.collections.asr.models import EncDecCTCModel, EncDecCTCModelBPE +from nemo.collections.nlp.models import PunctuationCapitalizationModel, TransformerLMModel +from nemo.core.classes import ModelPT +from nemo.utils.app_state import AppState + + +def getattr2(object, attr): + if not '.' in attr: + return getattr(object, attr) + else: + arr = attr.split('.') + return getattr2(getattr(object, arr[0]), '.'.join(arr[1:])) + + +class MockModel(ModelPT): + def __init__(self, cfg, trainer=None): + super(MockModel, self).__init__(cfg=cfg, trainer=trainer) + self.w = torch.nn.Linear(10, 1) + # mock temp file + if 'temp_file' in self.cfg and self.cfg.temp_file is not None: + self.temp_file = self.register_artifact('temp_file', self.cfg.temp_file) + with open(self.temp_file, 'r') as f: + self.temp_data = f.readlines() + else: + self.temp_file = None + self.temp_data = None + + def forward(self, x): + y = self.w(x) + return y, self.cfg.temp_file + + def setup_training_data(self, train_data_config: Union[DictConfig, Dict]): + self._train_dl = None + + def setup_validation_data(self, val_data_config: Union[DictConfig, Dict]): + self._validation_dl = None + + def setup_test_data(self, test_data_config: Union[DictConfig, Dict]): + self._test_dl = None + + def list_available_models(cls): + return [] + + +def _mock_model_config(): + conf = {'temp_file': None} + conf = OmegaConf.create({'model': conf}) + OmegaConf.set_struct(conf, True) + return conf + + +class TestSaveRestore: + def __test_restore_elsewhere( + self, + model: ModelPT, + attr_for_eq_check: Set[str] = None, + override_config_path: Optional[Union[str, DictConfig]] = None, + map_location: Optional[torch.device] = None, + strict: bool = False, + return_config: bool = False, + ): + """Test's logic: + 1. Save model into temporary folder (save_folder) + 2. Copy .nemo file from save_folder to restore_folder + 3. Delete save_folder + 4. Attempt to restore from .nemo file in restore_folder and compare to original instance + """ + # Create a new temporary directory + with tempfile.TemporaryDirectory() as restore_folder: + with tempfile.TemporaryDirectory() as save_folder: + save_folder_path = save_folder + # Where model will be saved + model_save_path = os.path.join(save_folder, f"{model.__class__.__name__}.nemo") + model.save_to(save_path=model_save_path) + # Where model will be restored from + model_restore_path = os.path.join(restore_folder, f"{model.__class__.__name__}.nemo") + shutil.copy(model_save_path, model_restore_path) + # at this point save_folder should not exist + assert save_folder_path is not None and not os.path.exists(save_folder_path) + assert not os.path.exists(model_save_path) + assert os.path.exists(model_restore_path) + # attempt to restore + model_copy = model.__class__.restore_from( + restore_path=model_restore_path, + map_location=map_location, + strict=strict, + return_config=return_config, + override_config_path=override_config_path, + ) + + if return_config: + return model_copy + + assert model.num_weights == model_copy.num_weights + if attr_for_eq_check is not None and len(attr_for_eq_check) > 0: + for attr in attr_for_eq_check: + assert getattr2(model, attr) == getattr2(model_copy, attr) + + return model_copy + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_EncDecCTCModel(self): + # TODO: Switch to using named configs because here we don't really care about weights + qn = EncDecCTCModel.from_pretrained(model_name="QuartzNet15x5Base-En") + self.__test_restore_elsewhere(model=qn, attr_for_eq_check=set(["decoder._feat_in", "decoder._num_classes"])) + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_EncDecCTCModelBPE(self): + # TODO: Switch to using named configs because here we don't really care about weights + cn = EncDecCTCModelBPE.from_pretrained(model_name="stt_en_citrinet_256") + self.__test_restore_elsewhere(model=cn, attr_for_eq_check=set(["decoder._feat_in", "decoder._num_classes"])) + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_EncDecCTCModelBPE_v2(self): + # TODO: Switch to using named configs because here we don't really care about weights + cn = EncDecCTCModelBPE.from_pretrained(model_name="stt_en_conformer_ctc_small") + self.__test_restore_elsewhere(model=cn, attr_for_eq_check=set(["decoder._feat_in", "decoder._num_classes"])) + + @pytest.mark.with_downloads() + @pytest.mark.unit + def test_PunctuationCapitalization(self): + # TODO: Switch to using named configs because here we don't really care about weights + pn = PunctuationCapitalizationModel.from_pretrained(model_name='punctuation_en_distilbert') + self.__test_restore_elsewhere( + model=pn, attr_for_eq_check=set(["punct_classifier.log_softmax", "punct_classifier.log_softmax"]) + ) + + @pytest.mark.unit + def test_mock_save_to_restore_from(self): + with tempfile.NamedTemporaryFile('w') as empty_file: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + + # Create model + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + + assert model.temp_file == empty_file.name + + # Save test + model_copy = self.__test_restore_elsewhere(model, map_location='cpu') + + # Restore test + diff = model.w.weight - model_copy.w.weight + # because of caching - cache gets prepended + assert os.path.basename(model_copy.temp_file).endswith(os.path.basename(model.temp_file)) + assert diff.mean() <= 1e-9 + # assert os.path.basename(model.temp_file) == model_copy.temp_file + assert model_copy.temp_data == ["*****\n"] + + @pytest.mark.unit + def test_mock_restore_from_config_only(self): + with tempfile.NamedTemporaryFile('w') as empty_file: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + cfg = _mock_model_config() + cfg.model.temp_file = os.path.abspath(empty_file.name) + + # Inject arbitrary config arguments (after creating model) + with open_dict(cfg.model): + cfg.model.xyz = "abc" + + # Create model + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + + assert model.temp_file == empty_file.name + model_copy = self.__test_restore_elsewhere(model, map_location='cpu', return_config=False) + # because of caching - cache gets prepended + assert os.path.basename(model_copy.temp_file).endswith(os.path.basename(model.temp_file)) + # assert filecmp.cmp(model.temp_file, model_copy._cfg.temp_file) + assert model.cfg.xyz == model_copy.cfg.xyz + + @pytest.mark.unit + def test_mock_restore_from_config_override_with_OmegaConf(self): + with tempfile.NamedTemporaryFile('w') as empty_file: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + + # Create model + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + + assert model.temp_file == empty_file.name + + # Inject arbitrary config arguments (after creating model) + with open_dict(cfg.model): + cfg.model.xyz = "abc" + + # Save test (with overriden config as OmegaConf object) + model_copy = self.__test_restore_elsewhere(model, map_location='cpu', override_config_path=cfg) + + # Restore test + diff = model.w.weight - model_copy.w.weight + assert diff.mean() <= 1e-9 + assert model_copy.temp_data == ["*****\n"] + + # Test that new config has arbitrary content + assert model_copy.cfg.xyz == "abc" + + @pytest.mark.unit + def test_mock_restore_from_config_override_with_yaml(self): + with tempfile.NamedTemporaryFile('w') as empty_file, tempfile.NamedTemporaryFile('w') as config_file: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + + # Create model + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + + assert model.temp_file == empty_file.name + + # Inject arbitrary config arguments (after creating model) + with open_dict(cfg.model): + cfg.model.xyz = "abc" + + # Write new config into file + OmegaConf.save(cfg, config_file) + + # Save test (with overriden config as OmegaConf object) + model_copy = self.__test_restore_elsewhere( + model, map_location='cpu', override_config_path=config_file.name + ) + + # Restore test + diff = model.w.weight - model_copy.w.weight + assert diff.mean() <= 1e-9 + assert filecmp.cmp(model.temp_file, model_copy.temp_file) + assert model_copy.temp_data == ["*****\n"] + + # Test that new config has arbitrary content + assert model_copy.cfg.xyz == "abc" + + @pytest.mark.unit + def test_mock_save_to_restore_from_with_target_class(self): + with tempfile.NamedTemporaryFile('w') as empty_file: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + + # Create model + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') # type: MockModel + + assert model.temp_file == empty_file.name + + # Save file using MockModel + with tempfile.TemporaryDirectory() as save_folder: + save_path = os.path.join(save_folder, "temp.nemo") + model.save_to(save_path) + + # Restore test (using ModelPT as restorer) + # This forces the target class = MockModel to be used as resolver + model_copy = ModelPT.restore_from(save_path, map_location='cpu') + # because of caching - cache gets prepended + assert os.path.basename(model_copy.temp_file).endswith(os.path.basename(model.temp_file)) + # assert filecmp.cmp(model.temp_file, model_copy.temp_file) + # Restore test + diff = model.w.weight - model_copy.w.weight + assert diff.mean() <= 1e-9 + assert isinstance(model_copy, MockModel) + assert model_copy.temp_data == ["*****\n"] + + @pytest.mark.unit + def test_mock_save_to_restore_from_multiple_models(self): + with tempfile.NamedTemporaryFile('w') as empty_file, tempfile.NamedTemporaryFile('w') as empty_file2: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + empty_file2.writelines(["+++++\n"]) + empty_file2.flush() + + # Update config + create ,pde;s + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + cfg2 = _mock_model_config() + cfg2.model.temp_file = empty_file2.name + + # Create models + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + model2 = MockModel(cfg=cfg2.model, trainer=None) + model2 = model2.to('cpu') + + assert model.temp_file == empty_file.name + assert model2.temp_file == empty_file2.name + + # Save test + model_copy = self.__test_restore_elsewhere(model, map_location='cpu') + model2_copy = self.__test_restore_elsewhere(model2, map_location='cpu') + + # Restore test + assert model_copy.temp_data == ["*****\n"] + assert model2_copy.temp_data == ["+++++\n"] + + @pytest.mark.unit + def test_mock_save_to_restore_from_multiple_models_inverted_order(self): + with tempfile.NamedTemporaryFile('w') as empty_file, tempfile.NamedTemporaryFile('w') as empty_file2: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + empty_file2.writelines(["+++++\n"]) + empty_file2.flush() + + # Update config + create ,pde;s + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + cfg2 = _mock_model_config() + cfg2.model.temp_file = empty_file2.name + + # Create models + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + model2 = MockModel(cfg=cfg2.model, trainer=None) + model2 = model2.to('cpu') + + assert model.temp_file == empty_file.name + assert model2.temp_file == empty_file2.name + + # Save test (inverted order) + model2_copy = self.__test_restore_elsewhere(model2, map_location='cpu') + model_copy = self.__test_restore_elsewhere(model, map_location='cpu') + + # Restore test + assert model_copy.temp_data == ["*****\n"] + assert model2_copy.temp_data == ["+++++\n"] + + @pytest.mark.unit + def test_mock_save_to_restore_chained(self): + with tempfile.NamedTemporaryFile('w') as empty_file, tempfile.NamedTemporaryFile('w') as empty_file2: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + create ,pde;s + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + + # Create models + model = MockModel(cfg=cfg.model, trainer=None) + model = model.to('cpu') + + assert model.temp_file == empty_file.name + + def save_copy(model, save_folder, restore_folder): + # Where model will be saved + model_save_path = os.path.join(save_folder, f"{model.__class__.__name__}.nemo") + model.save_to(save_path=model_save_path) + # Where model will be restored from + model_restore_path = os.path.join(restore_folder, f"{model.__class__.__name__}.nemo") + shutil.copy(model_save_path, model_restore_path) + return model_restore_path + + # Save test + with tempfile.TemporaryDirectory() as level4: + with tempfile.TemporaryDirectory() as level3: + with tempfile.TemporaryDirectory() as level2: + with tempfile.TemporaryDirectory() as level1: + path = save_copy(model, level1, level2) + model_copy2 = model.__class__.restore_from(path) + path = save_copy(model_copy2, level2, level3) + model_copy3 = model.__class__.restore_from(path) + path = save_copy(model_copy3, level3, level4) + model_copy = model.__class__.restore_from(path) + + # Restore test + assert model_copy.temp_data == ["*****\n"] + + # AppState test + appstate = AppState() + metadata = appstate.get_model_metadata_from_guid(model_copy.model_guid) + assert metadata.guid != model.model_guid + assert metadata.restoration_path == path + + @pytest.mark.unit + def test_mock_save_to_multiple_times(self): + with tempfile.NamedTemporaryFile('w') as empty_file, tempfile.TemporaryDirectory() as tmpdir: + # Write some data + empty_file.writelines(["*****\n"]) + empty_file.flush() + + # Update config + cfg = _mock_model_config() + cfg.model.temp_file = empty_file.name + + # Create model + model = MockModel(cfg=cfg.model, trainer=None) # type: MockModel + model = model.to('cpu') + + assert model.temp_file == empty_file.name + + # Save test + model.save_to(os.path.join(tmpdir, 'save_0.nemo')) + model.save_to(os.path.join(tmpdir, 'save_1.nemo')) + model.save_to(os.path.join(tmpdir, 'save_2.nemo')) diff --git a/tts/NeMo/tests/core/test_serialization.py b/tts/NeMo/tests/core/test_serialization.py new file mode 100644 index 0000000..42b1e22 --- /dev/null +++ b/tts/NeMo/tests/core/test_serialization.py @@ -0,0 +1,165 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from omegaconf import DictConfig + +from nemo.collections.asr.models import EncDecCTCModel +from nemo.collections.asr.modules import SpectrogramAugmentation +from nemo.core.classes.common import Serialization + + +def get_class_path(cls): + return f"{cls.__module__}.{cls.__name__}" + + +class MockSerializationImpl(Serialization): + def __init__(self, cfg: DictConfig): + self.cfg = cfg + self.value = self.__class__.__name__ + + +class MockSerializationImplV2(MockSerializationImpl): + pass + + +class TestSerialization: + @pytest.mark.unit + def test_from_config_dict_with_cls(self): + """Here we test that instantiation works for configs with cls class path in them. + Note that just Serialization.from_config_dict can be used to create an object""" + config = DictConfig( + { + 'cls': 'nemo.collections.asr.modules.SpectrogramAugmentation', + 'params': {'rect_freq': 50, 'rect_masks': 5, 'rect_time': 120,}, + } + ) + obj = Serialization.from_config_dict(config=config) + assert isinstance(obj, SpectrogramAugmentation) + + @pytest.mark.unit + def test_from_config_dict_without_cls(self): + """Here we test that instantiation works for configs without cls class path in them. + IMPORTANT: in this case, correct class type should call from_config_dict. This should work for Models.""" + preprocessor = {'cls': 'nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor', 'params': dict({})} + encoder = { + 'cls': 'nemo.collections.asr.modules.ConvASREncoder', + 'params': { + 'feat_in': 64, + 'activation': 'relu', + 'conv_mask': True, + 'jasper': [ + { + 'filters': 1024, + 'repeat': 1, + 'kernel': [1], + 'stride': [1], + 'dilation': [1], + 'dropout': 0.0, + 'residual': False, + 'separable': True, + 'se': True, + 'se_context_size': -1, + } + ], + }, + } + + decoder = { + 'cls': 'nemo.collections.asr.modules.ConvASRDecoder', + 'params': { + 'feat_in': 1024, + 'num_classes': 28, + 'vocabulary': [ + ' ', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + "'", + ], + }, + } + modelConfig = DictConfig( + {'preprocessor': DictConfig(preprocessor), 'encoder': DictConfig(encoder), 'decoder': DictConfig(decoder)} + ) + obj = EncDecCTCModel.from_config_dict(config=modelConfig) + assert isinstance(obj, EncDecCTCModel) + + @pytest.mark.unit + def test_config_updated(self): + config = DictConfig( + { + 'cls': 'nemo.collections.asr.modules.SpectrogramAugmentation', + 'params': {'rect_freq': 50, 'rect_masks': 5, 'rect_time': 120,}, + } + ) + obj = Serialization.from_config_dict(config=config) + new_config = obj.to_config_dict() + assert config != new_config + assert 'params' not in new_config + assert 'cls' not in new_config + assert '_target_' in new_config + + @pytest.mark.unit + def test_base_class_instantiation(self): + # Target class is V2 impl, calling class is Serialization (base class) + config = DictConfig({'target': get_class_path(MockSerializationImplV2)}) + obj = Serialization.from_config_dict(config=config) + new_config = obj.to_config_dict() + assert config == new_config + assert isinstance(obj, MockSerializationImplV2) + assert obj.value == "MockSerializationImplV2" + + @pytest.mark.unit + def test_self_class_instantiation(self): + # Target class is V1 impl, calling class is V1 (same class) + config = DictConfig({'target': get_class_path(MockSerializationImpl)}) + obj = MockSerializationImpl.from_config_dict(config=config) # Serialization is base class + new_config = obj.to_config_dict() + assert config == new_config + assert isinstance(obj, MockSerializationImpl) + assert obj.value == "MockSerializationImpl" + + @pytest.mark.unit + def test_sub_class_instantiation(self): + # Target class is V1 impl, calling class is V2 (sub class) + config = DictConfig({'target': get_class_path(MockSerializationImpl)}) + obj = MockSerializationImplV2.from_config_dict(config=config) # Serialization is base class + new_config = obj.to_config_dict() + assert config == new_config + assert isinstance(obj, MockSerializationImplV2) + assert obj.value == "MockSerializationImplV2" diff --git a/tts/NeMo/tests/core/test_typecheck.py b/tts/NeMo/tests/core/test_typecheck.py new file mode 100644 index 0000000..c547ab3 --- /dev/null +++ b/tts/NeMo/tests/core/test_typecheck.py @@ -0,0 +1,1075 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import torch + +from nemo.core import Typing, typecheck +from nemo.core.neural_types import * + + +# Perform recursive shape assert +def recursive_assert_shape(x, shape): + if isinstance(x, list) or isinstance(x, tuple): + for xi in x: + recursive_assert_shape(xi, shape) + return + + assert x.shape == shape + + +# Perform recursive type assert +def recursive_assert_homogeneous_type(x, type_val): + if isinstance(x, list) or isinstance(x, tuple): + for xi in x: + recursive_assert_homogeneous_type(xi, type_val) + return + + assert x.neural_type.compare(type_val) == NeuralTypeComparisonResult.SAME + + +class TestNeuralTypeCheckSystem: + @pytest.mark.unit + def test_no_types_passthrough(self): + class NoTypes(Typing): + @typecheck() + def __call__(self, x): + return torch.tensor(1.0) + + obj = NoTypes() + result = obj(torch.tensor(1.0)) + + assert result == torch.tensor(1.0) + assert not hasattr(result, 'neural_type') + + @pytest.mark.unit + def test_input_output_types(self): + class InputOutputTypes(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + obj = InputOutputTypes() + result = obj(x=torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert result.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + # Test passing wrong key for input + with pytest.raises(TypeError): + _ = obj(a=torch.zeros(10)) + + # Test using positional args + with pytest.raises(TypeError): + _ = obj(torch.zeros(10)) + + @pytest.mark.unit + def test_input_types_only(self): + class InputTypes(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + obj = InputTypes() + result = obj(x=torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert hasattr(result, 'neural_type') is False + + @pytest.mark.unit + def test_multiple_input_types_only(self): + class InputTypes(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType()), "y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x, y): + x += y + return x + + obj = InputTypes() + result = obj(x=torch.zeros(10), y=torch.ones(10)) + + assert result.sum() == torch.tensor(10.0) + assert hasattr(result, 'neural_type') is False + + @pytest.mark.unit + def test_output_types_only(self): + class OutputTypes(Typing): + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + obj = OutputTypes() + result = obj(x=torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert result.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + # Test passing positional args + # Positional args allowed if input types is not set ! + result = obj(torch.zeros(10)) + assert result.sum() == torch.tensor(10.0) + + @pytest.mark.unit + def test_multiple_output_types_only(self): + class MultipleOutputTypes(Typing): + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType()), "z": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + y = x + 1 + z = x + 2 + return y, z + + obj = MultipleOutputTypes() + result_y, result_z = obj(x=torch.zeros(10)) + + assert result_y.sum() == torch.tensor(10.0) + assert result_y.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + assert result_z.sum() == torch.tensor(20.0) + assert result_z.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_multiple_mixed_output_types_only(self): + class MultipleMixedOutputTypes(Typing): + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType()), "z": [NeuralType(('B',), ElementType())]} + + @typecheck() + def __call__(self, x): + y = x + 1 + z = x + 2 + return y, [z, z] + + obj = MultipleMixedOutputTypes() + result_y, result_z = obj(x=torch.zeros(10)) + + assert result_y.sum() == torch.tensor(10.0) + assert result_y.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + assert result_z[0].sum() == torch.tensor(20.0) + assert result_z[0].neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + assert result_z[1].sum() == torch.tensor(20.0) + assert result_z[1].neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_multiple_mixed_output_types_only_mismatched(self): + class MultipleMixedOutputTypes(Typing): + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType()), "z": [NeuralType(('B',), ElementType())]} + + @typecheck() + def __call__(self, x): + # Use list of y, single z, contrary to signature + y = x + 1 + z = x + 2 + return [y, y], z + + obj = MultipleMixedOutputTypes() + with pytest.raises(TypeError): + result_y, result_z = obj(x=torch.zeros(10)) + + @pytest.mark.unit + def test_incorrect_inheritance(self): + class IncorrectInheritance(object): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + obj = IncorrectInheritance() + + with pytest.raises(RuntimeError): + _ = obj(x=torch.zeros(10)) + + @pytest.mark.unit + def test_port_definition_rejection(self): + class InputPortDefinitionRejection(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"w": NeuralType(('B',), ElementType()), "u": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x, y): + x += 1 + y -= 1 + return x, y + + # Test input port mismatch + obj = InputPortDefinitionRejection() + + with pytest.raises(TypeError): + _ = obj(x=torch.zeros(10), y=torch.zeros(10)) + + class OutputPortDefinitionRejection(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return { + "w": NeuralType(('B',), ElementType()), + } + + @typecheck() + def __call__(self, x): + return x + 1, x - 1 + + obj = OutputPortDefinitionRejection() + + with pytest.raises(TypeError): + _ = obj(x=torch.zeros(10)) + + @pytest.mark.unit + def test_port_shape_rejection(self): + class InputPortShapeRejection(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B', 'T'), ElementType())} # expect rank 2 matrix + + @property + def output_types(self): + return {"w": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + # Test input port mismatch + obj = InputPortShapeRejection() + + with pytest.raises(TypeError): + _ = obj(x=torch.zeros(10)) + + class OutputPortShapeRejection(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return { + "w": NeuralType(('B', 'T', 'D'), ElementType()), # expect rank 3 matrix + } + + @typecheck() + def __call__(self, x): + return x + 1 + + obj = OutputPortShapeRejection() + + with pytest.raises(TypeError): + _ = obj(x=torch.zeros(10)) + + @pytest.mark.unit + def test_positional_args(self): + # Test positional check on input type + class InputPositional(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + obj = InputPositional() + + with pytest.raises(TypeError): + _ = obj(torch.zeros(10)) + + # Test positional pass-through for only output ports defined + # NOTE: This is required behaviour to support type checking of NeMo Dataset class + # during collate_fn() call. + class OutputPositionalPassthrough(Typing): + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + obj = OutputPositionalPassthrough() + result = obj(torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + + @pytest.mark.unit + def test_optional_types(self): + class InputOptionalTypes(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType()), "y": NeuralType(('B',), ElementType(), optional=True)} + + @typecheck() + def __call__(self, x, y=None): + if y is None: + x += 1 + else: + x += y + return x + + obj = InputOptionalTypes() + result = obj(x=torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert hasattr(result, 'neural_type') is False + + result2 = obj(x=torch.zeros(10), y=torch.full([10], fill_value=5, dtype=torch.int32)) + + assert result2.sum() == torch.tensor(10 * 5) + assert hasattr(result, 'neural_type') is False + + @pytest.mark.unit + def test_input_output_neural_types(self): + class NodeA(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": NeuralType(('B', 'D'), LogitsType())} + + @typecheck() + def __call__(self, x): + y = torch.randn(x.shape[0], 4) + return y + + class NodeB(Typing): + @property + def input_types(self): + return {"w": NeuralType(('B', 'D'), LogitsType())} + + @property + def output_types(self): + return {"u": NeuralType(('B',), LabelsType())} + + @typecheck() + def __call__(self, w): + _, u = w.max(-1) + return u + + nodeA = NodeA() + nodeB = NodeB() + + outA = nodeA(x=torch.zeros(10)) + outB = nodeB(w=outA) + + assert outB.shape == torch.Size([10]) + assert outB.neural_type.compare(NeuralType(('B',), LabelsType())) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_nested_input_output_neural_types(self): + class NestedNodeA(Typing): + @property + def input_types(self): + return {"x": [[NeuralType(('B',), ElementType())]]} + + @property + def output_types(self): + return { + "y0": [NeuralType(('B', 'D'), LogitsType())], + "y1": [NeuralType(('B', 'D'), LogitsType())], + } + + @typecheck(ignore_collections=False) + def __call__(self, x): + # input x = [[x1, x2], [x3]] + x0 = x[0][0] + y = torch.randn(x0.shape[0], 4) + # Output is same as + # 1) return ([y, y], [y]) + # 2) return [y, y], [y] + return [[y, y], [y]] + + # Non-homogeneous output types + class NestedNodeB(Typing): + @property + def input_types(self): + return {"w": [[NeuralType(('B', 'D'), LogitsType())]]} + + @property + def output_types(self): + return { + "u0": [NeuralType(('B',), LogprobsType())], # check non homogeneous type + "u1": [NeuralType(('B',), LabelsType())], + } + + @typecheck(ignore_collections=False) + def __call__(self, w): + # input x = [[x1, x2], [x3]] + _, u00 = w[0][0].max(-1) + _, u01 = w[0][1].max(-1) + _, u10 = w[1][0].max(-1) + # Output is same as + # 1) return ([u00, u01], [u10]) + # 2) return [u00, u01], [u10] + return [[u00, u01], [u10]] + + nodeA = NestedNodeA() + nodeB = NestedNodeB() + + input_nest = [[torch.zeros(10), torch.zeros(10)], [torch.zeros(10)]] + outA = nodeA(x=input_nest) + outB = nodeB(w=outA) + + # Perform recursive shape assert + recursive_assert_shape(outB, torch.Size([10])) + + # Assert non-homogeneous type assertions + assert outB[0][0].neural_type.compare(NeuralType(('B',), LogprobsType())) == NeuralTypeComparisonResult.SAME + assert outB[0][1].neural_type.compare(NeuralType(('B',), LogprobsType())) == NeuralTypeComparisonResult.SAME + assert outB[1][0].neural_type.compare(NeuralType(('B',), LabelsType())) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_nested_input_output_neural_types_ignore_collections(self): + class NestedNodeA(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return { + "y0": NeuralType(('B', 'D'), LogitsType()), + "y1": NeuralType(('B', 'D'), LogitsType()), + } + + @typecheck(ignore_collections=True) + def __call__(self, x): + # input x = [[x1, x2], [x3]] + x0 = x[0][0] + y = torch.randn(x0.shape[0], 4) + return [[y, y], [y]] + + # Non-homogeneous output types + class NestedNodeB(Typing): + @property + def input_types(self): + return {"w": NeuralType(('B', 'D'), LogitsType())} + + @property + def output_types(self): + return { + "u0": NeuralType(('B',), LogprobsType()), # check non homogeneous type + "u1": NeuralType(('B',), LabelsType()), + } + + @typecheck(ignore_collections=True) + def __call__(self, w): + # input x = [[x1, x2], [x3]] + _, u00 = w[0][0].max(-1) + _, u01 = w[0][1].max(-1) + _, u10 = w[1][0].max(-1) + return [[u00, u01], [u10]] + + nodeA = NestedNodeA() + nodeB = NestedNodeB() + + input_nest = [[torch.zeros(10), torch.zeros(10)], [torch.zeros(10)]] + outA = nodeA(x=input_nest) + outB = nodeB(w=outA) + + # Perform recursive shape assert + recursive_assert_shape(outB, torch.Size([10])) + + # Assert non-homogeneous type assertions + assert outB[0][0].neural_type.compare(NeuralType(('B',), LogprobsType())) == NeuralTypeComparisonResult.SAME + assert outB[0][1].neural_type.compare(NeuralType(('B',), LogprobsType())) == NeuralTypeComparisonResult.SAME + assert outB[1][0].neural_type.compare(NeuralType(('B',), LabelsType())) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_nested_mixed_input_output_neural_types(self): + class NestedMixedNodeA(Typing): + @property + def input_types(self): + return {"x1": NeuralType(('B',), ElementType()), "x2": [[NeuralType(('B',), ElementType())]]} + + @property + def output_types(self): + return { + "y0": NeuralType(('B', 'D'), LogprobsType()), + "y1": [[NeuralType(('B', 'D'), LogitsType())]], + } + + @typecheck(ignore_collections=False) + def __call__(self, x1, x2): + # input x = [[x1, x2], [x3]] + x0 = x2[0][0] + y = torch.randn(x0.shape[0], 4) + return y, [[y, y], [y]] + + # Non-homogeneous output types + class NestedMixedNodeB(Typing): + @property + def input_types(self): + return {"w": [[NeuralType(('B', 'D'), LogitsType())]]} + + @property + def output_types(self): + return { + "u0": [NeuralType(('B',), LogprobsType())], # check non homogeneous type + "u1": NeuralType(('B',), LabelsType()), + } + + @typecheck(ignore_collections=False) + def __call__(self, w): + # input x = [[x1, x2], [x3]] + _, u00 = w[0][0].max(-1) + _, u01 = w[0][1].max(-1) + _, u10 = w[1][0].max(-1) + return [u00, u01], u10 + + nodeA = NestedMixedNodeA() + nodeB = NestedMixedNodeB() + + input_nest = [[torch.zeros(10), torch.zeros(10)], [torch.zeros(10)]] + out_y, outA = nodeA(x1=torch.zeros(10), x2=input_nest) + outB, out_u = nodeB(w=outA) + + # Perform recursive shape assert + assert out_y.neural_type.compare(NeuralType(('B', 'D'), LogprobsType())) + recursive_assert_shape(outB, torch.Size([10])) + + # Assert non-homogeneous type assertions + assert outB[0].neural_type.compare(NeuralType(('B',), LogprobsType())) == NeuralTypeComparisonResult.SAME + assert outB[1].neural_type.compare(NeuralType(('B',), LogprobsType())) == NeuralTypeComparisonResult.SAME + assert out_u.neural_type.compare(NeuralType(('B',), LabelsType())) == NeuralTypeComparisonResult.SAME + + @pytest.mark.unit + def test_multi_forward_type(self): + class AdaptiveTypeCheck(Typing): + @property + def input_types(self): + if self.mode == 'train': + return {"x": NeuralType(('B',), ElementType())} + + elif self.mode == 'infer': + return {"y": NeuralType(('B',), ChannelType())} + + elif self.mode == 'eval': + return {"x": NeuralType(('B',), ElementType()), "y": NeuralType(('B',), ChannelType())} + else: + raise ValueError("Wrong mode of operation") + + @property + def output_types(self): + if self.mode == 'train': + return {"u": NeuralType(('B',), ElementType())} + + elif self.mode == 'infer': + return {"v": NeuralType(('B',), ChannelType())} + + elif self.mode == 'eval': + return {"u": NeuralType(('B',), ElementType()), "v": NeuralType(('B',), ChannelType())} + else: + raise ValueError("Wrong mode of operation") + + def __init__(self): + self.mode = 'train' + + def __call__(self, **kwargs): + # Call should call and forward appropriate method in its own mode + if self.mode == 'train': + return self.train_forward(x=kwargs['x']) + + elif self.mode == 'eval': + return self.eval_forward(x=kwargs['x'], y=kwargs['y']) + + elif self.mode == 'infer': + return self.infer_forward(y=kwargs['y']) + + @typecheck() + def train_forward(self, x): + return x + 10 + + @typecheck() + def eval_forward(self, x, y): + return x - 1, y - 1 + + @typecheck() + def infer_forward(self, y): + return y - 10 + + @property + def mode(self): + return self._mode + + @mode.setter + def mode(self, val): + if val not in ['train', 'infer', 'eval']: + raise ValueError('mode must be either train infer or eval') + self._mode = val + + obj = AdaptiveTypeCheck() + + x = torch.zeros(10) + y = torch.full([10], fill_value=5, dtype=torch.int32) + + obj.mode = 'train' + x = obj(x=x) + + assert torch.all(x == 10) + assert x.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + obj.mode = 'eval' + x, y = obj(x=x, y=y) + + assert torch.all(x == 9) + assert torch.all(y == 4) + assert x.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + assert y.neural_type.compare(NeuralType(('B',), ChannelType())) == NeuralTypeComparisonResult.SAME + + obj.mode = 'infer' + y = obj(y=y) + + assert torch.all(y == -6) + assert y.neural_type.compare(NeuralType(('B',), ChannelType())) == NeuralTypeComparisonResult.SAME + + # Now perform assertions of wrong mode with wrong input combinations + obj.mode = 'train' + + # In train mode, call infer + with pytest.raises(TypeError): + _ = obj.eval_forward(x=x, y=y) + + with pytest.raises(TypeError): + # wrong input + wrong mode + _ = obj.infer_forward(y=x) + + @pytest.mark.unit + def test_input_type_override(self): + class InputTypesOverride(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + @typecheck(input_types={"y": NeuralType(('B',), CategoricalValuesType())}) + def forward(self, y): + y -= 1 + return y + + obj = InputTypesOverride() + result = obj(x=torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert hasattr(result, 'neural_type') is False + + # Test override + result2 = obj.forward(y=torch.zeros(10)) + + assert result2.sum() == torch.tensor(-10.0) + assert hasattr(result2, 'neural_type') is False + + @pytest.mark.unit + def test_output_type_override(self): + class OutputTypes(Typing): + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x): + x += 1 + return x + + @typecheck(output_types={"z": NeuralType(('B',), CategoricalValuesType())}) + def forward(self, z): + z -= 1 + return z + + obj = OutputTypes() + result = obj(x=torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert result.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + # Test passing positional args + # Positional args allowed if input types is not set ! + result = obj(torch.zeros(10)) + assert result.sum() == torch.tensor(10.0) + + # Test override + result2 = obj.forward(z=torch.zeros(10)) + + assert result2.sum() == torch.tensor(-10.0) + assert hasattr(result2, 'neural_type') + assert ( + result2.neural_type.compare(NeuralType(('B',), CategoricalValuesType())) == NeuralTypeComparisonResult.SAME + ) + + @pytest.mark.unit + def test_multi_type_override(self): + class AdaptiveTypeCheck(Typing): + @property + def input_types(self): + # __call__ assumed to be for inference only, + # therefore infer types checked at class scope + return {"y": NeuralType(('B',), ChannelType())} + + @property + def output_types(self): + # __call__ assumed to be for inference only, + # therefore infer types checked at class scope + return {"v": NeuralType(('B',), ChannelType())} + + def __call__(self, **kwargs): + # Call should call and forward appropriate method in its own mode + # Let default "forward" call be the infer mode (this is upto developer) + # Therefore default class level types == infer types + return self.infer_forward(y=kwargs['y']) + + @typecheck( + input_types={"x": NeuralType(('B',), ElementType())}, + output_types={"u": NeuralType(('B',), ElementType())}, + ) + def train_forward(self, x): + return x + 10 + + @typecheck( + input_types={"x": NeuralType(('B',), ElementType()), "y": NeuralType(('B',), ChannelType())}, + output_types={"u": NeuralType(('B',), ElementType()), "v": NeuralType(('B',), ChannelType())}, + ) + def eval_forward(self, x, y): + return x - 1, y - 1 + + @typecheck( + input_types={"y": NeuralType(('B',), ChannelType())}, + output_types={"v": NeuralType(('B',), ChannelType())}, + ) + def infer_forward(self, y): + return y - 10 + + obj = AdaptiveTypeCheck() + + x = torch.zeros(10) + y = torch.full([10], fill_value=5, dtype=torch.int32) + + # infer mode + y = obj(y=y) + + assert torch.all(y == -5) + assert y.neural_type.compare(NeuralType(('B',), ChannelType())) == NeuralTypeComparisonResult.SAME + + x, y = obj.eval_forward(x=x, y=y) + + assert torch.all(x == -1) + assert torch.all(y == -6) + assert x.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + assert y.neural_type.compare(NeuralType(('B',), ChannelType())) == NeuralTypeComparisonResult.SAME + + x = obj.train_forward(x=x) + + assert torch.all(x == 9) + assert x.neural_type.compare(NeuralType(('B',), ElementType())) == NeuralTypeComparisonResult.SAME + + # In train func, call eval signature + with pytest.raises(TypeError): + _ = obj.train_forward(x=x, y=y) + + with pytest.raises(TypeError): + # wrong input + wrong mode + _ = obj.infer_forward(x=x) + + @pytest.mark.unit + def test_disable_typecheck(self): + class InputOutputTypes(Typing): + @property + def input_types(self): + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": NeuralType(('B',), ElementType())} + + @typecheck() + def __call__(self, x, **kwargs): + x += 1 + return x + + # Disable typecheck tests + with typecheck.disable_checks(): + obj = InputOutputTypes() + + # Execute function without kwarg + result = obj(torch.zeros(10)) + + assert result.sum() == torch.tensor(10.0) + assert hasattr(result, 'neural_type') is False + + # Test passing wrong key for input + _ = obj(a=torch.zeros(10), x=torch.zeros(5)) + + @pytest.mark.unit + def test_nested_shape_mismatch(self): + class NestedShapeMismatch(Typing): + @property + def input_types(self): + return {"x": [[NeuralType(('D',), ElementType())]]} # Each element of nest will have 4 values + + @property + def output_types(self): + return {"y": [[NeuralType(('D',), ElementType())]]} # Each element of nest will have 4 values + + @typecheck() + def __call__(self, x): + # v-- this is to satisfy 1 output constraint, python will otherwise interpret x as a 3 output value + return x + + def bb(dim=4): + return torch.zeros(dim) + + obj = NestedShapeMismatch() + + # Arbitrary nest 1 (should pass) + data = [[bb(), bb(), bb()], [bb()], [bb(), bb()]] + result = obj(x=data) + + recursive_assert_shape(result, torch.Size([4])) + recursive_assert_homogeneous_type(result, NeuralType(('D',), ElementType())) + + # Arbitrary nest 2 (should pass) + def bb(dim=4): + return torch.zeros(dim, dim) + + data = [[bb(), bb(), bb()], [bb()], [bb(), bb()]] + # Fails since input shape is incorrect + with pytest.raises(TypeError): + _ = obj(x=data) + + # Arbitrary nest 3 + def bb(dim=4): + return torch.zeros(dim) + + data = [[[bb(), bb(), bb()]], [[bb()], [bb(), bb()]]] + # Check should fail since nest level is 3! + with pytest.raises(TypeError): + result = obj(x=data) + + @pytest.mark.unit + def test_nested_mixed_shape_mismatch(self): + class NestedMixedShapeMismatch(Typing): + @property + def input_types(self): + return {"x": [[NeuralType(('D',), ElementType())]]} # Each element of nest will have 4 values + + @property + def output_types(self): + return {"y": [NeuralType(('D',), ElementType())]} # Each element of nest will have 4 values + + @typecheck() + def __call__(self, x): + # v-- this is to satisfy 1 output constraint, python will otherwise interpret x as a 3 output value + x = x[0] + return x + + def bb(dim=4): + return torch.zeros(dim) + + obj = NestedMixedShapeMismatch() + + # Arbitrary nest 1 (should pass) + data = [[bb(), bb(), bb()], [bb()], [bb(), bb()]] + result = obj(x=data) + + recursive_assert_shape(result, torch.Size([4])) + recursive_assert_homogeneous_type(result, NeuralType(('D',), ElementType())) + + # Arbitrary nest 2 (should pass) + def bb(dim=4): + return torch.zeros(dim, dim) + + data = [[bb(), bb(), bb()], [bb()], [bb(), bb()]] + # Fails since input shape is incorrect + with pytest.raises(TypeError): + _ = obj(x=data) + + # Arbitrary nest 3 + def bb(dim=4): + return torch.zeros(dim) + + data = [[[bb(), bb(), bb()]], [[bb()], [bb(), bb()]]] + # Check should fail since nest level is 3! + with pytest.raises(TypeError): + result = obj(x=data) + + @pytest.mark.unit + def test_input_container_neural_types(self): + class NodeA(Typing): + @property + def input_types(self): + return {"x": [NeuralType(('B',), ElementType())]} + + @property + def output_types(self): + return {"y": NeuralType(('B', 'D'), LogitsType())} + + @typecheck() + def __call__(self, x: list()): + x1, x2, x3 = x # unpack x + y = torch.randn(x1.shape[0], 4) + return y + + nodeA = NodeA() + outA = nodeA(x=[torch.zeros(10), torch.zeros(10), torch.zeros(10)]) + + assert outA.neural_type.compare(NeuralType(('B', 'D'), LogitsType())) + + @pytest.mark.unit + def test_input_container_neural_types_incorrect(self): + class NodeA(Typing): + @property + def input_types(self): + # Nest depth level of 2 + return {"x": [[NeuralType(('B',), ElementType())]]} + + @property + def output_types(self): + return {"y": NeuralType(('B', 'D'), LogitsType())} + + @typecheck() + def __call__(self, x: list()): + x1, x2, x3 = x # unpack x + y = torch.randn(x1.shape[0], 4) + return y + + nodeA = NodeA() + # Input nest level of 1 + with pytest.raises(TypeError): + outA = nodeA(x=[torch.zeros(10), torch.zeros(10), torch.zeros(10)]) + + @pytest.mark.unit + def test_output_container_neural_types_incorrect(self): + class NodeA(Typing): + @property + def input_types(self): + # Nest depth level of 2 + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": [[NeuralType(('B', 'D'), LogitsType())]]} + + @typecheck() + def __call__(self, x): + y = torch.randn(x.shape[0], 4) + return y, y, y + + nodeA = NodeA() + # Input nest level of 1 + with pytest.raises(TypeError): + outA = nodeA(x=torch.zeros(10)) + + @pytest.mark.unit + def test_output_container_neural_types_no_tuple_wrap(self): + class NodeA(Typing): + @property + def input_types(self): + # Nest depth level of 2 + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": [NeuralType(('B', 'D'), LogitsType())]} + + @typecheck() + def __call__(self, x): + y = torch.randn(x.shape[0], 4) + y = [y, y, y] + return y + + nodeA = NodeA() + # Input nest level of 1 + outA = nodeA(x=torch.zeros(10)) + + assert len(outA) == 3 + for i in range(len(outA)): + assert outA[i].neural_type.compare(NeuralType(('B', 'D'), LogitsType())) + + @pytest.mark.unit + def test_output_container_neural_types_explicit_tuple_wrap(self): + class NodeA(Typing): + @property + def input_types(self): + # Nest depth level of 2 + return {"x": NeuralType(('B',), ElementType())} + + @property + def output_types(self): + return {"y": [NeuralType(('B', 'D'), LogitsType())]} + + @typecheck() + def __call__(self, x): + y = torch.randn(x.shape[0], 4) + y = [y, y, y] + return (y,) + + nodeA = NodeA() + # Input nest level of 1 + outA = nodeA(x=torch.zeros(10)) + + assert len(outA) == 1 + assert len(outA[0]) == 3 + for i in range(len(outA)): + assert outA[0][i].neural_type.compare(NeuralType(('B', 'D'), LogitsType())) diff --git a/tts/NeMo/tests/core_ptl/check_for_ranks.py b/tts/NeMo/tests/core_ptl/check_for_ranks.py new file mode 100644 index 0000000..b936e2d --- /dev/null +++ b/tts/NeMo/tests/core_ptl/check_for_ranks.py @@ -0,0 +1,155 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import shutil + +import torch +from omegaconf import OmegaConf +from pytorch_lightning import Trainer +from pytorch_lightning.utilities.distributed import rank_zero_only + +from nemo.core import ModelPT +from nemo.utils import logging +from nemo.utils.exp_manager import ExpManagerConfig, exp_manager + + +class OnesDataset(torch.utils.data.Dataset): + def __init__(self, dataset_len): + super().__init__() + self.__dataset_len = dataset_len + + def __getitem__(self, *args): + return torch.ones(2) + + def __len__(self): + return self.__dataset_len + + +class ExampleModel(ModelPT): + def __init__(self, *args, **kwargs): + cfg = OmegaConf.structured({}) + super().__init__(cfg, trainer=kwargs.get('trainer', None)) + # dummy parameter in order to allow DDP to execute + self.l1 = torch.nn.modules.Linear(in_features=2, out_features=1) + + def train_dataloader(self): + return None + + def val_dataloader(self): + return None + + def predict_dataloader(self): + dataset = OnesDataset(2) + return torch.utils.data.DataLoader(dataset, batch_size=2) + + def forward(self, batch): + return batch.mean() + + def validation_step(self, batch, batch_idx): + return self(batch) + + def training_step(self, batch, batch_idx): + return self(batch) + + def list_available_models(self): + pass + + def setup_training_data(self): + pass + + def setup_validation_data(self): + pass + + def validation_epoch_end(self, loss): + self.log("val_loss", torch.stack(loss).mean()) + + +def instantiate_multinode_ddp_if_possible(): + num_gpus = torch.cuda.device_count() + trainer = Trainer(gpus=num_gpus, accelerator='ddp', logger=None, checkpoint_callback=None) + + exp_manager_cfg = ExpManagerConfig(exp_dir='./ddp_check/', use_datetime_version=False, version="") + exp_manager(trainer, cfg=OmegaConf.structured(exp_manager_cfg)) + return trainer + + +def setup_model(trainer: Trainer): + model = ExampleModel(trainer=trainer) + + logging.info(f"M.Global Rank:{model.global_rank}") + logging.info(f"M.Local Rank:{model.local_rank}") + logging.info(f"M.World Size:{model.trainer.world_size}") + + trainer.predict(model) + return model + + +def get_rank_info(texts: list, rank_key: str) -> int: + for line in texts: + if rank_key in line: + rank_value = line.split(":")[-1] + rank_value = int(rank_value) + return rank_value + + print("Could not find the correct rank key !") + exit(1) + + +@rank_zero_only +def check_model_ranks(model: ExampleModel): + basedir = os.path.join('./ddp_check/', 'default', 'version_0') + file_template = "nemo_log_globalrank-{rank}_localrank-{rank}.txt" + + world_size = torch.cuda.device_count() + for rank in range(world_size): + filename = file_template.format(rank=rank) + filepath = os.path.join(basedir, filename) + + with open(filepath, 'r') as f: + texts = f.readlines() + texts = [t.replace("\n", "") for t in texts] + + log_global_rank = get_rank_info(texts, rank_key='M.Global Rank') + log_world_size = get_rank_info(texts, rank_key='M.World Size') + + if log_global_rank != rank: + print("Logged global rank is not equal to trainer.global_rank !") + exit(1) + + if log_world_size != world_size: + print("Logged world size if not equal to trainer.world_size !") + exit(1) + + +@rank_zero_only +def cleanup(): + if os.path.exists('./ddp_check'): + shutil.rmtree('./ddp_check', ignore_errors=True) + + +def run_checks(): + cleanup() + + trainer = instantiate_multinode_ddp_if_possible() + model = setup_model(trainer) + check_model_ranks(model) + + print("DDP checks passed !") + + cleanup() + + +if __name__ == '__main__': + run_checks() diff --git a/tts/NeMo/tests/hydra/config1.yaml b/tts/NeMo/tests/hydra/config1.yaml new file mode 100644 index 0000000..71425c0 --- /dev/null +++ b/tts/NeMo/tests/hydra/config1.yaml @@ -0,0 +1 @@ +dataset_name: dark diff --git a/tts/NeMo/tests/hydra/config1_invalid.yaml b/tts/NeMo/tests/hydra/config1_invalid.yaml new file mode 100644 index 0000000..44ea0bd --- /dev/null +++ b/tts/NeMo/tests/hydra/config1_invalid.yaml @@ -0,0 +1,2 @@ +dataset_name: magic +password: secret \ No newline at end of file diff --git a/tts/NeMo/tests/hydra/config_subdir/config2.yaml b/tts/NeMo/tests/hydra/config_subdir/config2.yaml new file mode 100644 index 0000000..e773e40 --- /dev/null +++ b/tts/NeMo/tests/hydra/config_subdir/config2.yaml @@ -0,0 +1 @@ +dataset_name: ala_config2 diff --git a/tts/NeMo/tests/hydra/config_subdir/config2_invalid.yaml b/tts/NeMo/tests/hydra/config_subdir/config2_invalid.yaml new file mode 100644 index 0000000..f06f3ee --- /dev/null +++ b/tts/NeMo/tests/hydra/config_subdir/config2_invalid.yaml @@ -0,0 +1,2 @@ +dataset_name: ala_config2 +password: ala_secret2 \ No newline at end of file diff --git a/tts/NeMo/tests/hydra/my_app.py b/tts/NeMo/tests/hydra/my_app.py new file mode 100644 index 0000000..dca19dc --- /dev/null +++ b/tts/NeMo/tests/hydra/my_app.py @@ -0,0 +1,44 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +from dataclasses import dataclass + +import hydra +from omegaconf import MISSING, OmegaConf + +from nemo.core.config import hydra_runner + + +@dataclass +class DefaultConfig: + """ + This is structured config for this application. + + It provides the schema used for validation of user-written spec file + as well as default values of the selected parameters. + """ + + # Dataset. Available options: [imdb, sst2] + dataset_name: str = MISSING + + +@hydra_runner(config_name="DefaultConfig", schema=DefaultConfig) +def my_app(cfg): + print(OmegaConf.to_yaml(cfg)) + # Get dataset_name. + dataset_name = cfg.dataset_name + + +if __name__ == "__main__": + my_app() diff --git a/tts/NeMo/tests/hydra/test_hydra_runner.py b/tts/NeMo/tests/hydra/test_hydra_runner.py new file mode 100644 index 0000000..1da0a91 --- /dev/null +++ b/tts/NeMo/tests/hydra/test_hydra_runner.py @@ -0,0 +1,95 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import subprocess +import sys +from os import path + +import pytest + + +class TestHydraRunner: + @pytest.mark.integration + def test_no_config(self): + """"Test app without config - fields missing causes error. + """ + # Create system call. + call = "python tests/hydra/my_app.py" + + with pytest.raises(subprocess.CalledProcessError): + # Run the call as subprocess. + subprocess.check_call(call, shell=True, stdout=sys.stdout, stderr=sys.stdout) + + @pytest.mark.integration + def test_config1(self): + """"Test injection of valid config1. + """ + # Create system call. + call = "python tests/hydra/my_app.py --config-name config1.yaml" + + # Run the call as subprocess. + subprocess.check_call(call, shell=True, stdout=sys.stdout, stderr=sys.stdout) + + # Make sure that .hydra dir is not present. + assert not path.exists(f".hydra") + # Make sure that default hydra log file is not present. + assert not path.exists(f"my_app.log") + + @pytest.mark.integration + def test_config1_invalid(self): + """"Test injection of invalid config1. + """ + # Create system call. + call = "python tests/hydra/my_app.py --config-name config1_invalid.yaml" + + with pytest.raises(subprocess.CalledProcessError): + # Run the call as subprocess. + subprocess.check_call(call, shell=True, stdout=sys.stdout, stderr=sys.stdout) + + @pytest.mark.integration + def test_config2(self): + """"Test injection of valid config2 from a different folder. + """ + # Create system call. + call = "python tests/hydra/my_app.py --config-path config_subdir --config-name config2.yaml" + + # Run the call as subprocess. + subprocess.check_call(call, shell=True, stdout=sys.stdout, stderr=sys.stdout) + + # Make sure that .hydra dir is not present. + assert not path.exists(f".hydra") + # Make sure that default hydra log file is not present. + assert not path.exists(f"my_app.log") + + @pytest.mark.integration + def test_config2_invalid(self): + """"Test injection of invalid config2 from a different folder. + """ + # Create system call. + call = "python tests/hydra/my_app.py --config-path config_subdir --config-name config2_invalid.yaml" + + with pytest.raises(subprocess.CalledProcessError): + # Run the call as subprocess. + subprocess.check_call(call, shell=True, stdout=sys.stdout, stderr=sys.stdout) + + @pytest.mark.integration + def test_config2_filepath_schema(self): + """"Test injection of valid config2 - using namepath with schema is prohibited. + """ + # Create system call. + call = "python tests/hydra/my_app.py --config-name config_subdir/config2_invalid.yaml" + + with pytest.raises(subprocess.CalledProcessError): + # Run the call as subprocess. + subprocess.check_call(call, shell=True, stdout=sys.stdout, stderr=sys.stdout) diff --git a/tts/NeMo/tests/manualtest_model_downloads.py b/tts/NeMo/tests/manualtest_model_downloads.py new file mode 100644 index 0000000..a3ed173 --- /dev/null +++ b/tts/NeMo/tests/manualtest_model_downloads.py @@ -0,0 +1,92 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +""" +WARNING: Running this test will download ALL pre-trained NeMo models. +This is bandwidth and disk space consuming. +""" + +import nemo.collections.asr as nemo_asr +import nemo.collections.nlp as nemo_nlp +import nemo.collections.tts as nemo_tts + + +def testclass_downloads(cls, refresh_cache, model_names=None): + for model_info in cls.list_available_models(): + model = cls.from_pretrained(model_name=model_info.pretrained_model_name, refresh_cache=refresh_cache) + assert isinstance(model, cls) + if model_names is not None: + assert set(model_names) == set([m.pretrained_model_name for m in cls.list_available_models()]) + + +for refresh_cache in [True, False]: + # Test ASR collection + testclass_downloads( + nemo_asr.models.EncDecCTCModel, + refresh_cache, + [ + 'QuartzNet15x5Base-En', + 'QuartzNet15x5Base-Zh', + 'QuartzNet5x5LS-En', + 'QuartzNet15x5NR-En', + 'Jasper10x5Dr-En', + ], + ) + testclass_downloads(nemo_asr.models.EncDecCTCModelBPE, refresh_cache, ['ContextNet-192-WPE-1024-8x-Stride']) + testclass_downloads( + nemo_asr.models.EncDecClassificationModel, + refresh_cache, + [ + 'MatchboxNet-3x1x64-v1', + 'MatchboxNet-3x2x64-v1', + 'MatchboxNet-3x1x64-v2', + 'MatchboxNet-3x1x64-v2', + 'MatchboxNet-3x1x64-v2-subset-task', + 'MatchboxNet-3x2x64-v2-subset-task', + 'MatchboxNet-VAD-3x2', + ], + ) + testclass_downloads( + nemo_asr.models.EncDecSpeakerLabelModel, + refresh_cache, + ['speakerrecognition_speakernet', 'speakerverification_speakernet', 'speakerdiarization_speakernet'], + ) + + # Test NLP collection + testclass_downloads(nemo_nlp.models.TokenClassificationModel, refresh_cache, ['NERModel']) + testclass_downloads( + nemo_nlp.models.PunctuationCapitalizationModel, + refresh_cache, + ['Punctuation_Capitalization_with_BERT', 'Punctuation_Capitalization_with_DistilBERT'], + ) + testclass_downloads( + nemo_nlp.models.QAModel, + refresh_cache, + [ + 'BERTBaseUncasedSQuADv1.1', + 'BERTBaseUncasedSQuADv2.0', + 'BERTLargeUncasedSQuADv1.1', + 'BERTLargeUncasedSQuADv2.0', + ], + ) + # testclass_downloads(nemo_nlp.models.IntentSlotClassificationModel, refresh_cache, ['Joint_Intent_Slot_Assistant']) + + # Test TTS collection + testclass_downloads(nemo_tts.models.Tacotron2Model, refresh_cache, ['Tacotron2-22050Hz']) + testclass_downloads(nemo_tts.models.WaveGlowModel, refresh_cache, ['WaveGlow-22050Hz']) + testclass_downloads(nemo_tts.models.SqueezeWaveModel, refresh_cache, ['SqueezeWave-22050Hz']) + testclass_downloads(nemo_tts.models.GlowTTSModel, refresh_cache, ['GlowTTS-22050Hz']) + + +print("############ THAT'S ALL FOLKS! ############") diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_cardinal.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_cardinal.txt new file mode 100644 index 0000000..fb668c0 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_cardinal.txt @@ -0,0 +1,24 @@ +nine trillion seven hundred eighty nine billion three hundred eighty two million five hundred thirty six thousand one hundred thirty~9789382536130 +two hundred and fifty four~254 +one hundred forty seven thousand four hundred fifty one~147451 +one million one hundred fifty six thousand one hundred seventy three~1156173 +one billion five hundred ninety three million seventy two thousand nine hundred sixty one~1593072961 +ninety seven quadrillion eight hundred eight trillion two hundred sixty four billion seven hundred seventy two million seven hundred ninety two thousand five~97808264772792005 +seventeen sextillion eight hundred fifty five quintillion thirty six quadrillion six hundred fifty seven trillion seven billion five hundred ninety six million one hundred ten thousand nine hundred forty nine~17855036657007596110949 +ten quadrillion ten trillion ten million one hundred thousand ten~10010000010100010 +minus twenty five thousand thirty seven~-25037 +one quadrillion two hundred sixty four trillion three hundred one billion nine hundred thirty eight million one hundred four~1264301938000104 +minus sixty~-60 +forty six thousand six hundred sixty four~46664 +sixty~60 +zero~zero +two million three~2000003 +one thousand thirteen~1013 +one thousand one~1001 +one thousand one hundred~1100 +one thousand twenty six~1026 +one thousand one hundred twenty six~1126 +eighteen million four hundred fifty thousand nine hundred ninety~18450990 +eighteen million nine hundred forty thousand seven hundred twenty two~18940722 +eighteen million six hundred ninety thousand nine hundred sixteen~18690916 +eighteen thousand eight hundred eighty~18880 diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_date.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_date.txt new file mode 100644 index 0000000..3ec4268 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_date.txt @@ -0,0 +1,34 @@ +july twenty fifth two thousand twelve~july 25 2012 +nineteen eighties~1980s +two thousand and twenty~2020 +two thousand and nine~2009 +the twenty fifth of july twenty twelve~25 july 2012 +the twenty fifth of july two thousand twelve~25 july 2012 +the twenty second of july twenty twelve~22 july 2012 +the fifteenth of january~15 january +the seventeenth of may twenty ten~17 may 2010 +january first~january 1 +july twenty second two thousand eight~july 22 2008 +june thirty~june 30 +july twenty fifth twenty twelve~july 25 2012 +nineteen seventeen~1917 +twenty twelve~2012 +march sixteen sixty five~march 1665 +sixteen sixty five~1665 +july two thousand twelve~july 2012 +october nineteen oh five~october 1905 +july fifteen o six~july 1506 +the twenty fifth of july twenty twelve~25 july 2012 +july twenty fifth twenty twelve~july 25 2012 +july twenty fifth two thousand twelve~july 25 2012 +july one thousand eight hundred seventy six~july 1876 +february twenty fifth twenty sixteen~february 25 2016 +november twenty fourth twenty fourteen~november 24 2014 +nineteen ninety four~1994 +two thousand three~2003 +one thousand eight~1008 +nineteen seventy six~1976 +june twentieth twenty fourteen~june 20 2014 +nineteen seventy three~1973 +nineteen seventy five~1975 +eleven fifty five~1155 \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_decimal.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_decimal.txt new file mode 100644 index 0000000..2cd2272 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_decimal.txt @@ -0,0 +1,63 @@ +five point two million~5.2 million +one hundred sixty four point five eight thousand~164.58 thousand +four hundred million~400 million +fifty billion~50 billion +four hundred five billion~405 billion +four point eight five billion~4.85 billion +one hundred billion~100 billion +one hundred ten billion~110 billion +one hundred thirty two billion~132 billion +one point eight four billion~1.84 billion +one point eight one billion~1.81 billion +one point five nine billion~1.59 billion +one point four five three billion~1.453 billion +one point seven two billion~1.72 billion +one point two five billion~1.25 billion +thirteen billion~13 billion +thirty billion~30 billion +two thousand eight hundred five point eight seven three billion~2805.873 billion +seventy trillion~70 trillion +thirteen million~13 million +eighteen billion~18 billion +four hundred fifty million~450 million +one hundred thirty million~130 million +ten million~10 million +four hundred million~400 million +five million~5 million +five hundred million~500 million +twelve million~12 million +thirteen million~13 million +four million~4 million +forty five million~45 million +fifteen million~15 million +fifteen trillion~15 trillion +fifteen billion~15 billion +two million~2 million +eight million~8 million +point one two o five~.1205 +minus sixty point two four zero zero~-60.2400 +zero point two six~0.26 +point zero two~.02 +sixty point two~60.2 +eighteen~18 +eighteen point eight five~18.85 +eighteen point five o~18.50 +eighteen point five six~18.56 +eighteen point nine~18.9 +eighteen point o five~18.05 +eighteen point one two~18.12 +eighteen point o one~18.01 +eighteen point o o o~18.000 +eighteen point six~18.6 +eighteen point three o o~18.300 +eighteen point three six~18.36 +eighteen point two five~18.25 +eighteen point two two~18.22 +eight hundred eighteen point three o three~818.303 +eight hundred eight point eight~808.8 +eight hundred eight point zero~808.0 +eight hundred eighty eight point one~888.1 +eight hundred eighty four point three~884.3 +eight hundred eighty two point eight~882.8 +eight hundred eighty two point zero~882.0 +eight hundred forty five point nine four~845.94 \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_electronic.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_electronic.txt new file mode 100644 index 0000000..6267f87 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_electronic.txt @@ -0,0 +1,7 @@ +a dot b c at g mail dot com~a.bc@gmail.com +c d f at a b c dot e d u~cdf@abc.edu +a b c at g mail dot a b c~abc@gmail.abc +a b c at a b c dot com~abc@abc.com +a s d f one two three at a b c dot com~asdf123@abc.com +a one b two at a b c dot com~a1b2@abc.com +a b three dot s d d dot three at g mail dot com~ab3.sdd.3@gmail.com \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_measure.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_measure.txt new file mode 100644 index 0000000..4f6f540 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_measure.txt @@ -0,0 +1,112 @@ +two hundred meters~200 m +fifty six point three per square kilometer~56.3 /km² +two hundred kilometers per hour~200 km/h +twenty eight kilograms force per square centimeter~28 kgf/cm² +forty two thousand two hundred fifty nine per square meter~42259 /m² +minus two thousand twelve kilo liters~-2012 kl +minus sixty six kilograms~-66 kg +two kilo watt hours~2 kwh +one point o o o o two eight cubic deci meters~1.000028 dm³ +seven point five peta bytes~7.5 pb +three hours~3 h +one milli volt~1 mv +two cubic meters~2 m³ +ninety grams~90 g +one hundred twenty four point three lumens~124.3 lm +four hundred forty milliliters~440 ml +thirty one thousand four hundred eighty square feet~31480 sq ft +one thousand six hundred hours~1600 h +thirty one thousand four hundred eighty square feet~31480 sq ft +two square miles~2 sq mi +zero point one nine square miles~0.19 sq mi +one thousand five hundred thirty one c c~1531 cc +three hundred micrometers~300 μm +sixty five thousand square kilometers~65000 km² +two miles per hour~2 mph +two hundred forty five miles per hour~245 mph +one hundred fifty c c~150 cc +sixty point two four zero zero kilograms~60.2400 kg +zero feet~0 ft +zero foot~zero foot +two feet~2 ft +twenty foot~20 foot +point two meters~.2 m +two square meters~2 m² +eighteen feet~18 ft +eighteen mega siemens~18 ms +eighteen ounces~18 oz +eighteen point five kilometers~18.5 km +eighteen point five two square kilometers~18.52 km² +eighteen point nine one square kilometers~18.91 km² +eighteen point one four percent~18.14 % +eighteen point one six percent~18.16 % +eighteen point one square kilometers~18.1 km² +eighteen point six percent~18.6 % +eighteen point two two kilometers~18.22 km +eighteen point zero kilometers~18.0 km +eighteen point zero percent~18.0 % +eighteen square kilometers~18 km² +eighteen thousand eight hundred giga watt hours~18800 gwh +eighteen thousand seven hundred hectares~18700 ha +eight hectares~8 ha +eight hundred eighty five astronomical units~885 au +eight hundred eighty hectares~880 ha +eight hundred eighty kilobytes~880 kb +eight hundred eighty kilometers~880 km +eight hundred eighty nine feet~889 ft +eight hundred eighty six kilometers~886 km +eight hundred eighty two megawatts~882 mw +eight hundred feet~800 ft +eight hundred fifty five square kilometers~855 km² +eight hundred fifty megahertz~850 mhz +eight hundred fifty meters~850 m +eight hundred fifty nanometers~850 nm +eight hundred fifty one meters~851 m +eight hundred fifty seven square kilometers~857 km² +eight hundred fifty three meters~853 m +eight hundred fifty three point six meters~853.6 m +eight hundred five point four six square kilometers~805.46 km² +eight hundred forty two point nine meters~842.9 m +eight hundred forty two square kilometers~842 km² +eight hundred gigabytes~800 gb +eight hundred horsepower~800 hp +eight hundred kilograms~800 kg +eight hundred kilo watt hours~800 kwh +eight hundred kilowatts~800 kw +eight hundred megahertz~800 mhz +eight hundred ninety four c c~894 cc +eight hundred ninety kilowatts~890 kw +eight hundred ninety millimeters~890 mm +eight hundred ninety two square kilometers~892 km² +eight hundred seventy horsepower~870 hp +eight hundred seventy meters~870 m +eight hundred sixty kilograms~860 kg +eight hundred sixty kilometers~860 km +eight hundred sixty miles~860 mi +eight hundred sixty six feet~866 ft +eight hundred ten hectares~810 ha +eight hundred ten kilohertz~810 khz +eight hundred thirty eight point two millimeters~838.2 mm +eight hundred thirty five kilometers~835 km +eight hundred thirty kilohertz~830 khz +eight hundred thirty megawatts~830 mw +eight hundred thirty nine kilometers~839 km +eight hundred thirty six meters~836 m +eight hundred twenty feet~820 ft +eight hundred twenty kilometers~820 km +eight hundred twenty meters~820 m +eight hundred twenty one point zero feet~821.0 ft +eight hundred two point eight nine kilometers~802.89 km +eight hundred volts~800 v +eight kilobits~8 kb +eight kilograms~8 kg +eight million two hundred thousand feet~8200000 ft +eight point eight kilometers~8.8 km +eight point eight meters~8.8 m +eight point eight miles~8.8 mi +eight point five centimeters~8.5 cm +eight point five five percent~8.55 % +eight point five megawatts~8.5 mw +eight point five meters~8.5 m +eight point five two percent~8.52 % +eight point four four percent~8.44 % diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_money.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_money.txt new file mode 100644 index 0000000..24bc64b --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_money.txt @@ -0,0 +1,48 @@ +two dollars~$2 +one cent~$0.01 +four united states dollars and sixty nine cents~$4.69 +seventy five dollars sixty three~$75.63 +twenty nine dollars fifty cents~$29.50 +eleven dollars and fifty one cents~$11.51 +nine hundred ninety three dollars and ninety two cents~$993.92 +four hundred sixty billion won~₩460 billion +thirty billion yen~¥30 billion +two point five billion dollars~$2.5 billion +forty five billion dollars~$45 billion +fifty million dollars~$50 million +fifty billion dollars~$50 billion +zero point two million dollars~$0.2 million +fifteen point two billion dollars~$15.2 billion +one point six nine billion yuan~1.69 billion yuan +one point four three six billion yuan~1.436 billion yuan +four million yuan~4 million yuan +one dollar~$1 +fifteen thousand dollars~$15000 +one dollars~one dollars +twenty dollar~20 dollar +twenty point five o six dollars~$20.506 +point five o six dollars~$.506 +eighteen dollars~$18 +eighteen million nine hundred twenty five thousand dollars~$18925000 +eighteen thousand eight hundred fifty four dollars~$18854 +eighteen thousand eight hundred one dollars~$18801 +eighteen thousand eight hundred seventy five dollars~$18875 +eighteen thousand eighty one dollars~$18081 +eighteen thousand fifty two dollars~$18052 +eighteen thousand five hundred forty two dollars~$18542 +eighteen thousand five hundred nineteen dollars~$18519 +eighteen thousand five hundred seventy dollars~$18570 +eighteen thousand five hundred seventy eight dollars~$18578 +eighteen thousand five hundred sixteen dollars~$18516 +eighteen thousand four hundred eighty two dollars~$18482 +eighteen thousand four hundred seventy eight dollars~$18478 +eighteen thousand four hundred sixty eight dollars~$18468 +eighteen thousand nine hundred three dollars~$18903 +eighteen thousand nine hundred twenty nine dollars~$18929 +eighteen thousand ninety five dollars~$18095 +eighteen thousand one hundred seventeen dollars~$18117 +eighteen thousand one hundred twenty eight dollars~$18128 +eighteen thousand one hundred twenty five dollars~$18125 +eighteen thousand one hundred twenty four dollars~$18124 +eighteen thousand one hundred twenty nine dollars~$18129 +eighteen thousand pounds~£18000 \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_ordinal.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_ordinal.txt new file mode 100644 index 0000000..1ceaaf0 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_ordinal.txt @@ -0,0 +1,33 @@ +one hundredth~100th +twenty five thousand one hundred eleventh~25111th +second~2nd +zeroth~0th +first~1st +second~2nd +third~3rd +fourth~4th +eleventh~11th +twelfth~12th +thirteenth~13th +twenty first~21st +twenty third~23rd +one hundred eleventh~111th +one thousandth~1000th +one hundred twenty first~121st +second~2nd +tenth~10th +sixth~6th +third~3rd +nineteenth~19th +third~3rd +twelfth~12th +forty eighth~48th +seventy first~71st +third~3rd +forty second~42nd +seventeenth~17th +twentieth~20th +twenty first~21st +seventh~7th +second~2nd +fifth~5th \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_telephone.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_telephone.txt new file mode 100644 index 0000000..c689d9e --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_telephone.txt @@ -0,0 +1,4 @@ +one two three one two three five six seven eight~123-123-5678 +zero two three one two three five six seven eight~023-123-5678 +o two three one two three five six seven eight~023-123-5678 +oh two three one two three five six seven eight~023-123-5678 \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_time.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_time.txt new file mode 100644 index 0000000..ecdb1d0 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_time.txt @@ -0,0 +1,27 @@ +eight oclock g m t~08:00 gmt +seven a m e s t~07:00 a.m. est +two p m~02:00 p.m. +two thirty~02:30 +three o'clock~03:00 +quarter past one~01:15 +half past three~03:30 +eight fifty one~08:51 +eight fifty two~08:52 +eight forty~08:40 +eight nineteen~08:19 +eight o six~08:06 +eight thirty eight~08:38 +eight thirty two~08:32 +eight twenty nine~08:29 +eleven fifty five p m~11:55 p.m. +eleven fifty three p m~11:53 p.m. +eleven forty a m~11:40 a.m. +eleven forty five a m~11:45 a.m. +eleven forty p m~11:40 p.m. +eleven forty six a m~11:46 a.m. +eleven o six p m~11:06 p.m. +eleven thirteen a m~11:13 a.m. +half past twelve~12:30 +quarter past one~01:15 +quarter to one~12:45 +quarter to twelve~11:45 \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_whitelist.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_whitelist.txt new file mode 100644 index 0000000..4f69671 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_whitelist.txt @@ -0,0 +1,8 @@ +doctor dao~dr. dao +miss smith~ms. smith +misses smith~mrs. smith +mister dao~mr. dao +saint george~st. george +i like for example ice cream~i like e.g. ice cream +s and p five hundred~s&p 500 +seven eleven stores~7-eleven stores diff --git a/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_word.txt b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_word.txt new file mode 100644 index 0000000..4d12a42 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_inverse_text_normalization/test_cases_word.txt @@ -0,0 +1,50 @@ +~ +e s three~es3 +yahoo!~yahoo! +twenty!~20 ! +x ~x +—~— +aaa~aaa +aabach~aabach +aabenraa~aabenraa +aabye~aabye +aaccessed~aaccessed +aach~aach +aachen's~aachen's +aadri~aadri +aafia~aafia +aagaard~aagaard +aagadu~aagadu +aagard~aagard +aagathadi~aagathadi +aaghart's~aaghart's +aagnes~aagnes +aagomoni~aagomoni +aagon~aagon +aagoo~aagoo +aagot~aagot +aahar~aahar +aahh~aahh +aahperd~aahperd +aaibinterstate~aaibinterstate +aajab~aajab +aakasa~aakasa +aakervik~aakervik +aakirkeby~aakirkeby +aalam~aalam +aalbaek~aalbaek +aaldiu~aaldiu +aalem~aalem +a'ali~a'ali +aalilaassamthey~aalilaassamthey +aalin~aalin +aaliyan~aaliyan +aaliyan's~aaliyan's +aamadu~aamadu +aamara~aamara +aambala~aambala +aamera~aamera +aamer's~aamer's +aamina~aamina +aaminah~aaminah +aamjiwnaang~aamjiwnaang diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_boundary.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_boundary.txt new file mode 100644 index 0000000..3b9d66f --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_boundary.txt @@ -0,0 +1,7 @@ + 1~one +1~one +1, ~one , +1!!!!~one ! ! ! ! +(1)Hello~(1)Hello +!1~! one +1!hello~1!hello \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_cardinal.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_cardinal.txt new file mode 100644 index 0000000..3d505b2 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_cardinal.txt @@ -0,0 +1,18 @@ +1~one +2~two +-2~minus two +3~three +123~one hundred twenty three +13,000~thirteen thousand +13,000~thirteen thousand +123,123,000~one hundred twenty three million one hundred twenty three thousand +123,000,012~one hundred twenty three million twelve +t-0t25d12-f~t oh t two five d one two f +133-ABC~one hundred thirty three ABC +B2A23C~B two A two three C +25d08A~two five d oh eight A +C24~C two four +W2s~W two s +1-4-a-b-1-5~one four a b one five +b-c-1-5-b-s-b~b c one five b s b +1/f-4s~one f four s diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_date.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_date.txt new file mode 100644 index 0000000..b5f95f4 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_date.txt @@ -0,0 +1,32 @@ +july 25 2012~july twenty fifth twenty twelve +jul 25 2012~july twenty fifth twenty twelve +1980s~nineteen eighties +1980 s~nineteen eighties +25 july 2012~the twenty fifth of july twenty twelve +25 jul 2012~the twenty fifth of july twenty twelve +22 july 2012~the twenty second of july twenty twelve +15 january~the fifteenth of january +17 may 2010~the seventeenth of may twenty ten +january 1~january first +june 30~june thirtieth +2012~twenty twelve +july 1506~july fifteen o six +july 1876~july eighteen seventy six +1994~nineteen ninety four +1976~nineteen seventy six +june 20 2014~june twentieth twenty fourteen +1973~nineteen seventy three +1975~nineteen seventy five +1155~eleven fifty five +2006-08-05~august fifth two thousand six +august 23, 2002~august twenty third two thousand two +20 january~the twentieth of january +2016-11-03~november third twenty sixteen +2016/07/03~july third twenty sixteen +1980s~nineteen eighties +01.10.2010~january tenth twenty ten +10/06/2005~october sixth two thousand five +1910s~nineteen tens +25 sept.~the twenty fifth of september +1000~one thousand +SEPT. 15TH~september fifteenth diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_decimal.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_decimal.txt new file mode 100644 index 0000000..1b839ab --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_decimal.txt @@ -0,0 +1,8 @@ +.1665~point one six six five +2.0~two point zero +2.00~two point o o +2.050~two point o five o +100 million~one hundred million +0.1 billion~zero point one billion +.1 trillion~point one trillion +-0.1~minus zero point one diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_electronic.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_electronic.txt new file mode 100644 index 0000000..1c5f5a7 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_electronic.txt @@ -0,0 +1,10 @@ +a.bc@gmail.com~a dot b c at g mail dot com +cdf@abc.edu~c d f at a b c dot e d u +abc@gmail.abc~a b c at g mail dot a b c +abc@abc.com~a b c at a b c dot com +asdf123@abc.com~a s d f one two three at a b c dot com +a1b2@abc.com~a one b two at a b c dot com +ab3.sdd.3@gmail.com~a b three dot s d d dot three at g mail dot com +email is abc1@gmail.com~email is a b c one at g mail dot com +test .b@gmail.com~test . b at g mail dot com +email is a-1.b3_c&-d@gma4i-l.com test~email is a dash one dot b three underscore c ampersand dash d at g m a four i dash l dot com test \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_fraction.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_fraction.txt new file mode 100644 index 0000000..15d32ca --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_fraction.txt @@ -0,0 +1,11 @@ +1/2007~one two thousand seventh +12639/12640~twelve thousand six hundred thirty nine twelve thousand six hundred fortieths +2/4~two quarters +1/4~one quarter +31/32~thirty one thirty seconds +22/3~twenty two thirds +1/3~one third +142/1~one hundred forty two over one +1/2~one half +2 1/2~two and a half +1795 / 1805~one thousand seven hundred ninety five one thousand eight hundred fifths \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_measure.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_measure.txt new file mode 100644 index 0000000..3279e68 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_measure.txt @@ -0,0 +1,15 @@ +12kg~twelve kilograms +12/kg~twelve per kilogram +12kg/kg~twelve kilograms per kilogram +1 mbps~one megabit per second +3 mbps~three megabits per second +3 cc/s~three c c per second +100 million kg~one hundred million kilograms +a 4-kilogram bag~a four kilogram bag +55-millimeters long~fifty five millimeters long +a 123.2-millimeters long~a one hundred twenty three point two millimeters long +covid-19.5~covid nineteen point five +covid-19~covid nineteen +a 4-kilogram bag~a four kilogram bag +7.2-millimeter bullet~seven point two millimeter bullet +4 1/2 lbs~four and a half pounds diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_money.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_money.txt new file mode 100644 index 0000000..22f0b58 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_money.txt @@ -0,0 +1,38 @@ +$2~two dollars +₩460 billion~four hundred sixty billion won +¥30 billion~thirty billion yen +$45 billion~forty five billion dollars +$0.2 million~zero point two million dollars +$15.2 billion~fifteen point two billion dollars +1.436 billion yuan~one point four three six billion yuan +4 million yuan~four million yuan +$15000~fifteen thousand dollars +$1~one dollar +$20~twenty dollars +$20.506~twenty point five o six dollars +$.506~point five o six dollars +$18~eighteen dollars +$18925000~eighteen million nine hundred twenty five thousand dollars +$18,925,000~eighteen million nine hundred twenty five thousand dollars +$18854~eighteen thousand eight hundred fifty four dollars +$18801~eighteen thousand eight hundred one dollars +$18875~eighteen thousand eight hundred seventy five dollars +$18081~eighteen thousand eighty one dollars +$18052~eighteen thousand fifty two dollars +$18542~eighteen thousand five hundred forty two dollars +$18519~eighteen thousand five hundred nineteen dollars +$18570~eighteen thousand five hundred seventy dollars +$18578~eighteen thousand five hundred seventy eight dollars +$18516~eighteen thousand five hundred sixteen dollars +$18482~eighteen thousand four hundred eighty two dollars +$18478~eighteen thousand four hundred seventy eight dollars +$18468~eighteen thousand four hundred sixty eight dollars +$18903~eighteen thousand nine hundred three dollars +$18929~eighteen thousand nine hundred twenty nine dollars +$18095~eighteen thousand ninety five dollars +$18117~eighteen thousand one hundred seventeen dollars +$18128~eighteen thousand one hundred twenty eight dollars +$18125~eighteen thousand one hundred twenty five dollars +$18124~eighteen thousand one hundred twenty four dollars +$18129~eighteen thousand one hundred twenty nine dollars +£18000~eighteen thousand pounds \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_normalize_with_audio.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_normalize_with_audio.txt new file mode 100644 index 0000000..436bff1 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_normalize_with_audio.txt @@ -0,0 +1,107 @@ +~123 +one twenty three +one two three +one hundred twenty three +one hundred and twenty three +~$123 +one twenty three dollars +one two three dollars +one hundred twenty three dollars +one hundred and twenty three dollars +~$123.2 +one twenty three dollars and two cents +one two three dollars two cents +one hundred twenty three dollars and two cents +one hundred and twenty three point two dollars +~1.24 +one point two four +one two four +one point twenty four +one twenty four +~$1.21 +one dollar and twenty one cents +one dollar twenty one cents +one point two one dollars +one twenty one dollars +~£1.00 +one pound +one point o o pounds +~t-0t25d12-f +t zero t twenty five d one two f +t zero t twenty five d twelve f +t zero t two five d one two f +t zero t two five d twelve f +t oh t two five d one two f +t oh t twenty five d one two f +t oh t twenty five d twelve f +t oh t two five d twelve f +~133-A +one hundred thirty three A +~B2A23C +B two A twenty three C +~25d08A +twenty five d zero eight A +~C24 +C twenty four +~It seemed to her that the jacket Oswald wore was darker than Commission Exhibit No. 162. +It seemed to her that the jacket Oswald wore was darker than Commission Exhibit number one sixty two. +It seemed to her that the jacket Oswald wore was darker than Commission Exhibit number one hundred sixty two. +It seemed to her that the jacket Oswald wore was darker than Commission Exhibit number one hundred and sixty two. +It seemed to her that the jacket Oswald wore was darker than Commission Exhibit number one six two. +~"Father, let this cup pass." He prayed--was heard. What cup was it that passed away from him? Sure not the death-cup, now filled to the brim! There was no quailing in the awful word; He still was king of kings, of lords the lord:-- He feared lest, in the suffering waste and grim, His faith might grow too faint and sickly dim." +"Father, let this cup pass." He prayed -- was heard. What cup was it that passed away from him? Sure not the death-cup, now filled to the brim! There was no quailing in the awful word; He still was king of kings, of lords the lord: -- He feared lest, in the suffering waste and grim, His faith might grow too faint and sickly dim." +~1970-2010 +nineteen seventy to twenty ten +one thousand nine seventy to two thousand ten +one thousand nine hundred and seventy to two thousand ten +one thousand nine hundred and seventy to twenty ten +nineteen seventy twenty ten +one thousand nine seventy two thousand ten +one thousand nine hundred and seventy two thousand ten +one thousand nine hundred and seventy twenty ten +from nineteen seventy to twenty ten +from one thousand nine seventy to two thousand ten +from one thousand nine hundred and seventy to two thousand ten +from one thousand nine hundred and seventy to twenty ten +from nineteen seventy twenty ten +from one thousand nine seventy two thousand ten +from one thousand nine hundred and seventy two thousand ten +from one thousand nine hundred and seventy twenty ten +~W26s +W twenty sixes +W twenty six s +~5-3-Ws +five three W s +five three Ws +~401-ks +four oh one kays +four oh one k s +four hundred one k s +~The box was 25 x 7 m. +The box was twenty five by seven meters. +The box was two five by seven meters. +The box was two five by seven m. +The box was twenty five by seven m. +~4567 +four thousand five hundred sixty seven +four five six seven +four thousand five sixty seven +forty five sixty seven +four thousand five hundred and sixty seven +~This example number 15,000 can be a very long one, and can fail to produce valid normalization for a such an easy number like 10,125 or dollar value $5349.01, and can fail to terminate, and can fail to terminate, and can fail to terminate, and can fail to terminate, and can fail to terminate, 452. +This example number fifteen thousand can be a very long one, and can fail to produce valid normalization for a such an easy number like ten thousand one hundred twenty five or dollar value five thousand three hundred forty nine dollars and one cent, and can fail to terminate, and can fail to terminate, and can fail to terminate, and can fail to terminate, and can fail to terminate, four five two. +~$1.01 +one dollar and one cent +one dollar one cent +one dollar and zero one cents +~$17.31 +seventeen dollars and thirty one cent +seventeen dollars and thirty one cents +seventeen point three one dollars +~25.] +two five.] +twenty five.] +~Francis I--test +Francis the first -- test +Francis one -- test +Francis first -- test \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_ordinal.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_ordinal.txt new file mode 100644 index 0000000..dce8934 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_ordinal.txt @@ -0,0 +1,6 @@ +0th~zeroth +11th~eleventh +23rd~twenty third +1000th~one thousandth +1,000th~one thousandth +1000000th~one millionth \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_telephone.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_telephone.txt new file mode 100644 index 0000000..2e586f6 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_telephone.txt @@ -0,0 +1,9 @@ ++1 123-123-5678~one, one two three, one two three, five six seven eight +123-123-5678~one two three, one two three, five six seven eight ++1-123-123-5678~one, one two three, one two three, five six seven eight ++1 (123)-123-5678~one, one two three, one two three, five six seven eight ++1(123) 123-5678~one, one two three, one two three, five six seven eight +(123)-123-5678~one two three, one two three, five six seven eight +(123) 123-5678~one two three, one two three, five six seven eight +123-123-5678-1111~one two three, one two three, five six seven eight, one one one one +123-123-5678-1~one two three, one two three, five six seven eight, one \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_time.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_time.txt new file mode 100644 index 0000000..5388be9 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_time.txt @@ -0,0 +1,14 @@ +01:00~one o'clock +01:00 am~one a m +01:00 a.m.~one a m +01:00 a.m~one a m +1 a.m.~one a m +23:00~twenty three o'clock +1:00 a.m.~one a m +1:00a.m.~one a m +1.59 p.m.~one fifty nine p m +01:59 p.m.~one fifty nine p m +1:59 p.m.~one fifty nine p m +1:59 p.m. est~one fifty nine p m e s t +1:59 p.m.est~one fifty nine p m e s t +1:59 p.m. e.s.t~one fifty nine p m e s t \ No newline at end of file diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_whitelist.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_whitelist.txt new file mode 100644 index 0000000..7eaa637 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_whitelist.txt @@ -0,0 +1,3 @@ +dr. Evil~doctor Evil +mrs. Norris~misses Norris +Dr. Evil~Dr. Evil diff --git a/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_word.txt b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_word.txt new file mode 100644 index 0000000..e10df68 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/data_text_normalization/test_cases_word.txt @@ -0,0 +1,23 @@ +~ +es3~e s three +x ~x +X!~X! +2!~two ! +—~— +aabach~aabach +aabenraa~aabenraa +aabye~aabye +aaccessed~aaccessed +aach~aach +aachen's~aachen's +aadri~aadri +aafia~aafia +aagaard~aagaard +aagadu~aagadu +aagard~aagard +aagathadi~aagathadi +aaghart's~aaghart's +aalem~aalem +a'ali~a'ali +aaliyan's~aaliyan's +mother-in-law~mother-in-law diff --git a/tts/NeMo/tests/nemo_text_processing/test_boundary.py b/tts/NeMo/tests/nemo_text_processing/test_boundary.py new file mode 100644 index 0000000..9074230 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_boundary.py @@ -0,0 +1,39 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestBoundary: + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_boundary.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize( + test_input, n_tagged=100, punct_pre_process=False, punct_post_process=False + ) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_cardinal.py b/tts/NeMo/tests/nemo_text_processing/test_cardinal.py new file mode 100644 index 0000000..7c19ea3 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_cardinal.py @@ -0,0 +1,49 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestCardinal: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_cardinal.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_cardinal.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_date.py b/tts/NeMo/tests/nemo_text_processing/test_date.py new file mode 100644 index 0000000..42fce25 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_date.py @@ -0,0 +1,64 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestDate: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_date.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_date.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm_uncased(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic + + normalizer_uppercased = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + cases_uppercased = {"Aug. 8": "august eighth", "8 Aug.": "the eighth of august", "aug. 8": "august eighth"} + + @parameterized.expand(cases_uppercased.items()) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm_cased(self, test_input, expected): + pred = self.normalizer_uppercased.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_decimal.py b/tts/NeMo/tests/nemo_text_processing/test_decimal.py new file mode 100644 index 0000000..267fcce --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_decimal.py @@ -0,0 +1,49 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestDecimal: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_decimal.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case="cased") if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_decimal.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_electronic.py b/tts/NeMo/tests/nemo_text_processing/test_electronic.py new file mode 100644 index 0000000..a96ecc6 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_electronic.py @@ -0,0 +1,51 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestElectronic: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_electronic.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case="cased") if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_electronic.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize( + test_input, n_tagged=100, punct_post_process=False + ) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_fraction.py b/tts/NeMo/tests/nemo_text_processing/test_fraction.py new file mode 100644 index 0000000..24006c4 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_fraction.py @@ -0,0 +1,38 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestFraction: + normalizer = Normalizer(input_case="cased") if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_fraction.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_measure.py b/tts/NeMo/tests/nemo_text_processing/test_measure.py new file mode 100644 index 0000000..12f4137 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_measure.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestMeasure: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_measure.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case="cased") if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_measure.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_money.py b/tts/NeMo/tests/nemo_text_processing/test_money.py new file mode 100644 index 0000000..e132866 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_money.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestMoney: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_money.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_money.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_normalization_with_audio.py b/tts/NeMo/tests/nemo_text_processing/test_normalization_with_audio.py new file mode 100644 index 0000000..0034583 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_normalization_with_audio.py @@ -0,0 +1,33 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, get_test_cases_multiple + + +class TestNormalizeWithAudio: + + normalizer = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(get_test_cases_multiple('data_text_normalization/test_cases_normalize_with_audio.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, n_tagged=700) + assert len(set(pred).intersection(set(expected))) == len(expected), f'pred: {pred}' diff --git a/tts/NeMo/tests/nemo_text_processing/test_ordinal.py b/tts/NeMo/tests/nemo_text_processing/test_ordinal.py new file mode 100644 index 0000000..47ae51e --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_ordinal.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestOrdinal: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_ordinal.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_ordinal.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_inverse_text_normalization.sh b/tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_inverse_text_normalization.sh new file mode 100644 index 0000000..268f88b --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_inverse_text_normalization.sh @@ -0,0 +1,64 @@ +#! /bin/sh + +PROJECT_DIR=/workspace/tests + +runtest () { + input=$1 + cd /workspace/sparrowhawk/documentation/grammars + + # read test file + while read testcase; do + IFS='~' read spoken written <<< $testcase + denorm_pred=$(echo $spoken | normalizer_main --config=sparrowhawk_configuration.ascii_proto 2>&1 | tail -n 1) + + # trim white space + written="$(echo -e "${written}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + denorm_pred="$(echo -e "${denorm_pred}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + + # input expected actual + assertEquals "$spoken" "$written" "$denorm_pred" + done < "$input" +} + +testITNCardinal() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_cardinal.txt + runtest $input +} + +testITNDate() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_date.txt + runtest $input +} + +testITNDecimal() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_decimal.txt + runtest $input +} + +testITNOrdinal() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_ordinal.txt + runtest $input +} + +testITNTime() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_time.txt + runtest $input +} + +testITNMeasure() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_measure.txt + runtest $input +} + +testITNMoney() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_money.txt + runtest $input +} + +testITNWhitelist() { + input=$PROJECT_DIR/data_inverse_text_normalization/test_cases_whitelist.txt + runtest $input +} + +# Load shUnit2 +. $PROJECT_DIR/../shunit2/shunit2 diff --git a/tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_normalization.sh b/tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_normalization.sh new file mode 100644 index 0000000..c06dc05 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_sparrowhawk_normalization.sh @@ -0,0 +1,64 @@ +#! /bin/sh + +PROJECT_DIR=/workspace/tests + +runtest () { + input=$1 + cd /workspace/sparrowhawk/documentation/grammars + + # read test file + while read testcase; do + IFS='~' read written spoken <<< $testcase + denorm_pred=$(echo $written | normalizer_main --config=sparrowhawk_configuration.ascii_proto 2>&1 | tail -n 1) + + # trim white space + spoken="$(echo -e "${spoken}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + denorm_pred="$(echo -e "${denorm_pred}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + + # input expected actual + assertEquals "$written" "$spoken" "$denorm_pred" + done < "$input" +} + +testTNCardinal() { + input=$PROJECT_DIR/data_text_normalization/test_cases_cardinal.txt + runtest $input +} + +testTNDate() { + input=$PROJECT_DIR/data_text_normalization/test_cases_date.txt + runtest $input +} + +testTNDecimal() { + input=$PROJECT_DIR/data_text_normalization/test_cases_decimal.txt + runtest $input +} + +testTNOrdinal() { + input=$PROJECT_DIR/data_text_normalization/test_cases_ordinal.txt + runtest $input +} + +testTNTime() { + input=$PROJECT_DIR/data_text_normalization/test_cases_time.txt + runtest $input +} + +testTNMeasure() { + input=$PROJECT_DIR/data_text_normalization/test_cases_measure.txt + runtest $input +} + +testTNMoney() { + input=$PROJECT_DIR/data_text_normalization/test_cases_money.txt + runtest $input +} + +testTNWhitelist() { + input=$PROJECT_DIR/data_text_normalization/test_cases_whitelist.txt + runtest $input +} + +# Load shUnit2 +. $PROJECT_DIR/../shunit2/shunit2 diff --git a/tts/NeMo/tests/nemo_text_processing/test_telephone.py b/tts/NeMo/tests/nemo_text_processing/test_telephone.py new file mode 100644 index 0000000..5ea68d6 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_telephone.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestTelephone: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_telephone.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_telephone.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_time.py b/tts/NeMo/tests/nemo_text_processing/test_time.py new file mode 100644 index 0000000..84e05a8 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_time.py @@ -0,0 +1,49 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestTime: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_time.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_time.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_whitelist.py b/tts/NeMo/tests/nemo_text_processing/test_whitelist.py new file mode 100644 index 0000000..8b3daf2 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_whitelist.py @@ -0,0 +1,65 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestWhitelist: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_whitelist.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='lower_cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_whitelist.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic + + normalizer_uppercased = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + cases_uppercased = {"Dr. Evil": "doctor Evil", "No. 4": "number four", "dr. Evil": "dr. Evil", "no. 4": "no. four"} + + @parameterized.expand(cases_uppercased.items()) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm_cased(self, test_input, expected): + pred = self.normalizer_uppercased.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize(test_input, n_tagged=100) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/test_word.py b/tts/NeMo/tests/nemo_text_processing/test_word.py new file mode 100644 index 0000000..ae60100 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/test_word.py @@ -0,0 +1,52 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer +from nemo_text_processing.text_normalization.normalize_with_audio import NormalizerWithAudio +from parameterized import parameterized +from utils import PYNINI_AVAILABLE, parse_test_case_file + + +class TestWord: + inverse_normalizer = InverseNormalizer() if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_inverse_text_normalization/test_cases_word.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_denorm(self, test_input, expected): + pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + assert pred == expected + + normalizer = Normalizer(input_case='cased') if PYNINI_AVAILABLE else None + normalizer_with_audio = NormalizerWithAudio(input_case='cased') if PYNINI_AVAILABLE else None + + @parameterized.expand(parse_test_case_file('data_text_normalization/test_cases_word.txt')) + @pytest.mark.skipif( + not PYNINI_AVAILABLE, reason="`pynini` not installed, please install via nemo_text_processing/setup.sh" + ) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred == expected + pred_non_deterministic = self.normalizer_with_audio.normalize( + test_input, n_tagged=100, punct_post_process=False + ) + assert expected in pred_non_deterministic diff --git a/tts/NeMo/tests/nemo_text_processing/utils.py b/tts/NeMo/tests/nemo_text_processing/utils.py new file mode 100644 index 0000000..d2bb355 --- /dev/null +++ b/tts/NeMo/tests/nemo_text_processing/utils.py @@ -0,0 +1,54 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +try: + import pynini + + PYNINI_AVAILABLE = True +except (ImportError, ModuleNotFoundError): + PYNINI_AVAILABLE = False + + +def parse_test_case_file(file_name: str): + """ + Prepares tests pairs for ITN and TN tests + """ + test_pairs = [] + with open(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + file_name, 'r') as f: + for line in f: + spoken, written = line.split('~') + test_pairs.append((spoken, written.strip("\n"))) + return test_pairs + + +def get_test_cases_multiple(file_name: str = 'data_text_normalization/test_cases_normalize_with_audio.txt'): + """ + Prepares tests pairs for audio based TN tests + """ + test_pairs = [] + with open(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + file_name, 'r') as f: + written = None + normalized_options = [] + for line in f: + if line.startswith('~'): + if written: + test_pairs.append((written, normalized_options)) + normalized_options = [] + written = line.strip().replace('~', '') + else: + normalized_options.append(line.strip()) + test_pairs.append((written, normalized_options)) + return test_pairs diff --git a/tts/NeMo/tests/test_data_dir.py b/tts/NeMo/tests/test_data_dir.py new file mode 100644 index 0000000..931e02b --- /dev/null +++ b/tts/NeMo/tests/test_data_dir.py @@ -0,0 +1,27 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + + +from os.path import exists, join + +import pytest + + +class TestDataDir: + @pytest.mark.unit + def test_test_data_dir(self, test_data_dir): + """" Just a dummy tests showing how to use the test_data_dir fixture. """ + # test_data_dir contains the absolute path to nemo -> tests/.data + assert exists(test_data_dir) + assert exists(join(test_data_dir, "test_data.tar.gz")) diff --git a/tts/NeMo/tools/ctc_segmentation/README.md b/tts/NeMo/tools/ctc_segmentation/README.md new file mode 100644 index 0000000..bcfe5e7 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/README.md @@ -0,0 +1,31 @@ +Dataset creation tool based on CTC-Segmentation +----------------------------------------------- + +This tool provides functionality to align long audio files and the corresponding transcripts into shorter fragments +that are suitable for an Automatic Speech Recognition (ASR) model training. + +More details could be found in [this tutorial](https://github.com/NVIDIA/NeMo/blob/main/tutorials/tools/CTC_Segmentation_Tutorial.ipynb). + +The tool is based on the [CTC Segmentation](https://github.com/lumaku/ctc-segmentation): +**CTC-Segmentation of Large Corpora for German End-to-end Speech Recognition** +https://doi.org/10.1007/978-3-030-60276-5_27 or pre-print https://arxiv.org/abs/2007.09127 + +``` +@InProceedings{ctcsegmentation, +author="K{\"u}rzinger, Ludwig +and Winkelbauer, Dominik +and Li, Lujun +and Watzel, Tobias +and Rigoll, Gerhard", +editor="Karpov, Alexey +and Potapova, Rodmonga", +title="CTC-Segmentation of Large Corpora for German End-to-End Speech Recognition", +booktitle="Speech and Computer", +year="2020", +publisher="Springer International Publishing", +address="Cham", +pages="267--278", +abstract="Recent end-to-end Automatic Speech Recognition (ASR) systems demonstrated the ability to outperform conventional hybrid DNN/HMM ASR. Aside from architectural improvements in those systems, those models grew in terms of depth, parameters and model capacity. However, these models also require more training data to achieve comparable performance.", +isbn="978-3-030-60276-5" +} +``` diff --git a/tts/NeMo/tools/ctc_segmentation/requirements.txt b/tts/NeMo/tools/ctc_segmentation/requirements.txt new file mode 100644 index 0000000..b5ef916 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/requirements.txt @@ -0,0 +1,2 @@ +ctc_segmentation==1.1.0 +num2words \ No newline at end of file diff --git a/tts/NeMo/tools/ctc_segmentation/run_sample.sh b/tts/NeMo/tools/ctc_segmentation/run_sample.sh new file mode 100644 index 0000000..d865a57 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/run_sample.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +# default values for optional arguments +MIN_SCORE=-5 +CUT_PREFIX=0 +SCRIPTS_DIR="scripts" +OFFSET=0 +LANGUAGE='eng' # 'eng', 'ru', 'other' +MIN_SEGMENT_LEN=20 +MAX_SEGMENT_LEN=100 +ADDITIONAL_SPLIT_SYMBOLS='' +AUDIO_FORMAT='.mp3' +USE_NEMO_NORMALIZATION='True' + +for ARG in "$@" +do + key=$(echo $ARG | cut -f1 -d=) + value=$(echo $ARG | cut -f2 -d=) + + if [[ $key == *"--"* ]]; then + v="${key/--/}" + declare $v="${value}" + fi +done + +echo "MODEL_NAME_OR_PATH = $MODEL_NAME_OR_PATH" +echo "DATA_DIR = $DATA_DIR" +echo "OUTPUT_DIR = $OUTPUT_DIR" +echo "MIN_SCORE = $MIN_SCORE" +echo "CUT_PREFIX = $CUT_PREFIX" +echo "SCRIPTS_DIR = $SCRIPTS_DIR" +echo "OFFSET = $OFFSET" +echo "LANGUAGE = $LANGUAGE" +echo "MIN_SEGMENT_LEN = $MIN_SEGMENT_LEN" +echo "MAX_SEGMENT_LEN = $MAX_SEGMENT_LEN" +echo "ADDITIONAL_SPLIT_SYMBOLS = $ADDITIONAL_SPLIT_SYMBOLS" +echo "AUDIO_FORMAT = $AUDIO_FORMAT" +echo "USE_NEMO_NORMALIZATION = $USE_NEMO_NORMALIZATION" + +if [[ -z $MODEL_NAME_OR_PATH ]] || [[ -z $DATA_DIR ]] || [[ -z $OUTPUT_DIR ]]; then + echo "Usage: $(basename "$0") + --MODEL_NAME_OR_PATH=[model_name_or_path] + --DATA_DIR=[data_dir] + --OUTPUT_DIR=[output_dir] + --LANGUAGE=[language (Optional)] + --OFFSET=[offset value (Optional)] + --CUT_PREFIX=[cut prefix in sec (Optional)] + --SCRIPTS_DIR=[scripts_dir_path (Optional)] + --MIN_SEGMENT_LEN=[min number of characters of the text segment for alignment (Optional)] + --MAX_SEGMENT_LEN=[max number of characters of the text segment for alignment (Optional)] + --ADDITIONAL_SPLIT_SYMBOLS=[Additional symbols to use for + sentence split if eos sentence split resulted in sequence longer than --max_length. + Use '|' as a separator between symbols, for example: ';|:|' (Optional)] + --AUDIO_FORMAT=[choose from ['.mp3', '.wav'], input audio files format + --USE_NEMO_NORMALIZATION Set to 'True' to use NeMo Normalization tool to convert + numbers from written to spoken format. By default num2words package will be used. (Optional)" + exit 1 +fi + +NEMO_NORMALIZATION="" + if [[ ${USE_NEMO_NORMALIZATION,,} == "true" ]]; then + NEMO_NORMALIZATION="--use_nemo_normalization " + fi + +# STEP #1 +# Prepare text and audio data for segmentation +python $SCRIPTS_DIR/prepare_data.py \ +--in_text=$DATA_DIR/text \ +--audio_dir=$DATA_DIR/audio \ +--audio_format=$AUDIO_FORMAT \ +--output_dir=$OUTPUT_DIR/processed/ \ +--language=$LANGUAGE \ +--cut_prefix=$CUT_PREFIX \ +--model=$MODEL_NAME_OR_PATH \ +--min_length=$MIN_SEGMENT_LEN \ +--max_length=$MAX_SEGMENT_LEN \ +--additional_split_symbols=$ADDITIONAL_SPLIT_SYMBOLS $NEMO_NORMALIZATION || exit + +# STEP #2 +# Run CTC-segmenatation +# one might want to perform alignment with various window sizes +# note if the alignment with the initial window size isn't found, the window size will be double to re-attempt +# alignment +for WINDOW in 8000 12000 +do + python $SCRIPTS_DIR/run_ctc_segmentation.py \ + --output_dir=$OUTPUT_DIR \ + --data=$OUTPUT_DIR/processed/ \ + --model=$MODEL_NAME_OR_PATH \ + --window_len $WINDOW || exit +done + +# STEP #3 (Optional) +# Verify aligned segments only if multiple WINDOWs used in the Step #2) +python $SCRIPTS_DIR/verify_segments.py \ +--base_dir=$OUTPUT_DIR || exit + +# STEP #4 +# Cut the original audio files based on the alignments +# (use --alignment=$OUTPUT_DIR/segments if only 1 WINDOW size was used in the Step #2) +# Three manifests and corresponding clips folders will be created: +# - high scored clips +# - low scored clips +# - deleted segments +python $SCRIPTS_DIR/cut_audio.py \ +--output_dir=$OUTPUT_DIR \ +--model=$MODEL_NAME_OR_PATH \ +--alignment=$OUTPUT_DIR/verified_segments \ +--threshold=$MIN_SCORE \ +--offset=$OFFSET || exit + +# STEP #5 (Optional) +# If multiple audio files were segmented in the step #2, this step will aggregate manifests with high scored segments +# for all audio files into all_manifest.json +# Also a separate manifest with samples from across all high scored segments will be credated if --num_samples > 0 +# --num_samples samples will be taken from the beginning, end and the middle of the each audio file high score manifest +# and will be stored at sample_manifest.json +python $SCRIPTS_DIR/process_manifests.py \ +--output_dir=$OUTPUT_DIR \ +--manifests_dir=$OUTPUT_DIR/manifests/ \ +--num_samples 0 + +exit + diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/cut_audio.py b/tts/NeMo/tools/ctc_segmentation/scripts/cut_audio.py new file mode 100644 index 0000000..50bd931 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/cut_audio.py @@ -0,0 +1,313 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import json +import os +import time +from pathlib import Path +from typing import List + +import torch +from scipy.io import wavfile + +from nemo.collections import asr as nemo_asr +from nemo.collections.asr.metrics.wer import WER, word_error_rate + +parser = argparse.ArgumentParser(description="Cut audio on the segments based on segments") +parser.add_argument("--output_dir", default='output', type=str, help='Path to output directory') +parser.add_argument( + "--alignment", + type=str, + required=True, + help='Path to a data directory with alignments or a single .txt file with timestamps - result of the ctc-segmentation', +) +parser.add_argument("--threshold", type=float, default=-5, help='Minimum score value accepted') +parser.add_argument( + '--model', + type=str, + default='QuartzNet15x5Base-En', + help='Path to model checkpoint or pre-trained CTC-based ASR model name', +) +parser.add_argument('--offset', type=int, default=0, help='Offset in seconds') +parser.add_argument("--batch_size", type=int, default=64, help='Batch size for inference') + + +def add_transcript_to_manifest( + manifest_original: str, manifest_updated: str, asr_model: nemo_asr.models.EncDecCTCModel, batch_size: int +) -> None: + """ + Adds transcripts generated by the asr_model to the manifest_original. + + Args: + manifest_original: path to the manifest + manifest_updated: path to the updated manifest with transcript included + asr_model: CTC-based ASR model, for example, QuartzNet15x5Base-En + batch_size: Batch size for asr_model inference + """ + transcripts = get_transcript(manifest_original, asr_model, batch_size) + with open(manifest_original, 'r', encoding='utf8') as f: + with open(manifest_updated, 'w', encoding='utf8') as f_updated: + for i, line in enumerate(f): + info = json.loads(line) + info['transcript'] = transcripts[i].strip() + info['WER'] = round(word_error_rate([info['transcript']], [info['text']]) * 100, 2) + info['CER'] = round(word_error_rate([info['transcript']], [info['text']], use_cer=True) * 100, 2) + json.dump(info, f_updated, ensure_ascii=False) + f_updated.write('\n') + + +def get_transcript(manifest_path: str, asr_model: nemo_asr.models.EncDecCTCModel, batch_size: int) -> List[str]: + """ + Returns transcripts for audio segments in the batch + + Args: + manifest_path: path to the manifest for inference + asr_model: CTC-based ASR model, for example, QuartzNet15x5Base-En + batch_size: batch size + + Returns: hypotheses: transcripts for the audio segments + """ + # batch inference + try: + from torch.cuda.amp import autocast + except ImportError: + from contextlib import contextmanager + + @contextmanager + def autocast(enabled=None): + yield + + torch.set_grad_enabled(False) + asr_model.setup_test_data( + test_data_config={ + 'sample_rate': 16000, + 'manifest_filepath': manifest_path, + 'labels': asr_model.decoder.vocabulary, + 'batch_size': batch_size, + 'normalize_transcripts': False, + } + ) + asr_model.eval() + wer = WER(vocabulary=asr_model.decoder.vocabulary) + hypotheses = [] + for test_batch in asr_model.test_dataloader(): + if torch.cuda.is_available(): + test_batch = [x.cuda() for x in test_batch] + with autocast(): + log_probs, encoded_len, greedy_predictions = asr_model( + input_signal=test_batch[0], input_signal_length=test_batch[1] + ) + hypotheses += wer.ctc_decoder_predictions_tensor(greedy_predictions) + del test_batch + torch.cuda.empty_cache() + return hypotheses + + +def process_alignment(alignment_file: str, args): + """ Cut original audio file into audio segments based on alignment_file + + Args: + alignment_file: path to the file with segmented text and corresponding time stamps. + The first line of the file contains the path to the original audio file + args: main script args + """ + if not os.path.exists(alignment_file): + raise ValueError(f'{alignment_file} not found') + + # read the segments, note the first line contains the path to the original audio + segments = [] + ref_text_processed = [] + ref_text_no_preprocessing = [] + with open(alignment_file, 'r') as f: + for line in f: + line = line.split('|') + # read audio file name from the first line + if len(line) == 1: + audio_file = line[0].strip() + continue + ref_text_processed.append(line[1].strip()) + ref_text_no_preprocessing.append(line[2].strip()) + line = line[0].split() + segments.append((float(line[0]) + args.offset / 1000, float(line[1]) + args.offset / 1000, float(line[2]))) + + # cut the audio into segments + # create manifest in /tmp directory first, then populate transcript values with the batch inference results + # and save the final manifests at output_dir + sampling_rate, signal = wavfile.read(audio_file) + original_duration = len(signal) / sampling_rate + print(f'Cutting {audio_file} based on {alignment_file}') + print(f'Original duration: {round(original_duration)}s or ~{round(original_duration / 60)}min') + + # create directories to store high score .wav audio fragments, low scored once, and deleted + args.output_dir = os.path.abspath(args.output_dir) + os.makedirs(args.output_dir, exist_ok=True) + fragments_dir = os.path.join(args.output_dir, "high_score_clips") + del_fragments = os.path.join(args.output_dir, 'deleted_clips') + low_score_segments_dir = os.path.join(args.output_dir, "low_score_clips") + + os.makedirs(fragments_dir, exist_ok=True) + os.makedirs(low_score_segments_dir, exist_ok=True) + os.makedirs(del_fragments, exist_ok=True) + + base_name = os.path.basename(alignment_file).replace('_segments.txt', '') + high_score_manifest = f'{base_name}_high_score_manifest.json' + low_score_manifest = f'{base_name}_low_score_manifest.json' + del_manifest = f'{base_name}_del_manifest.json' + manifests_dir = os.path.join(args.output_dir, 'manifests') + os.makedirs(manifests_dir, exist_ok=True) + tmp_dir = '/tmp' + + low_score_dur = 0 + high_score_dur = 0 + with open(os.path.join(tmp_dir, high_score_manifest), 'w', encoding='utf8') as f: + with open(os.path.join(tmp_dir, low_score_manifest), 'w', encoding='utf8') as low_score_f: + for i, (st, end, score) in enumerate(segments): + segment = signal[round(st * sampling_rate) : round(end * sampling_rate)] + duration = len(segment) / sampling_rate + if duration > 0: + text_processed = ref_text_processed[i].strip() + text_no_preprocessing = ref_text_no_preprocessing[i].strip() + if score > args.threshold: + high_score_dur += duration + audio_filepath = os.path.join(fragments_dir, f'{base_name}_{i:04}.wav') + file_to_write = f + else: + low_score_dur += duration + audio_filepath = os.path.join(low_score_segments_dir, f'{base_name}_{i:04}.wav') + file_to_write = low_score_f + + wavfile.write(audio_filepath, sampling_rate, segment) + + transcript = 'n/a' # asr_model.transcribe(paths2audio_files=[audio_filepath], batch_size=1)[0] + info = { + 'audio_filepath': audio_filepath, + 'duration': duration, + 'text': text_processed, + 'text_no_preprocessing': text_no_preprocessing, + 'score': round(score, 2), + 'transcript': transcript.strip(), + } + json.dump(info, file_to_write, ensure_ascii=False) + file_to_write.write('\n') + + add_transcript_to_manifest( + os.path.join(tmp_dir, high_score_manifest), + os.path.join(manifests_dir, high_score_manifest), + asr_model, + args.batch_size, + ) + add_transcript_to_manifest( + os.path.join(tmp_dir, low_score_manifest), + os.path.join(manifests_dir, low_score_manifest), + asr_model, + args.batch_size, + ) + print(f'High score files duration: {round(high_score_dur)}s or ~{round(high_score_dur/60)}min at {manifests_dir}') + print( + f'Low score files duration: {round(low_score_dur)}s or ~{round(low_score_dur/60)}min saved at {manifests_dir}' + ) + + # save deleted segments along with manifest + deleted = [] + del_duration = 0 + begin = 0 + i = 0 + with open(os.path.join(manifests_dir, del_manifest), 'w', encoding='utf8') as f: + for i, (st, end, _) in enumerate(segments): + if st - begin > 0.01: + segment = signal[int(begin * sampling_rate) : int(st * sampling_rate)] + audio_filepath = os.path.join(del_fragments, f'del_{base_name}_{i:04}.wav') + wavfile.write(audio_filepath, sampling_rate, segment) + duration = len(segment) / sampling_rate + del_duration += duration + deleted.append((begin, st)) + transcript = 'n/a' # asr_model.transcribe(paths2audio_files=[audio_filepath], batch_size=1)[0] + info = {'audio_filepath': audio_filepath, 'duration': duration, 'text': transcript} + json.dump(info, f, ensure_ascii=False) + f.write('\n') + begin = end + + segment = signal[int(begin * sampling_rate) :] + audio_filepath = os.path.join(del_fragments, f'del_{base_name}_{i+1:04}.wav') + wavfile.write(audio_filepath, sampling_rate, segment) + duration = len(segment) / sampling_rate + del_duration += duration + deleted.append((begin, original_duration)) + + info = {'audio_filepath': audio_filepath, 'duration': duration, 'text': 'n/a'} + json.dump(info, f) + f.write('\n') + + print(f'Saved DEL files duration: {round(del_duration)}s or ~ {round(del_duration/60)}min at {del_fragments}') + missing_audio = original_duration - high_score_dur - del_duration - low_score_dur + if missing_audio > 15: + raise ValueError(f'{round(missing_audio)}s or ~ {round(missing_audio/60)}min is missing. Check the args') + + stats = ( + args.output_dir, + base_name, + round(original_duration), + round(high_score_dur), + round(low_score_dur), + round(del_duration), + ) + return stats + + +if __name__ == '__main__': + start_time = time.time() + args = parser.parse_args() + + os.makedirs(args.output_dir, exist_ok=True) + + if os.path.exists(args.model): + asr_model = nemo_asr.models.EncDecCTCModel.restore_from(args.model, strict=False) + elif args.model in nemo_asr.models.EncDecCTCModel.get_available_model_names(): + asr_model = nemo_asr.models.EncDecCTCModel.from_pretrained(args.model, strict=False) + else: + raise ValueError( + f'Provide path to the pretrained checkpoint or choose from {nemo_asr.models.EncDecCTCModel.list_available_models()}' + ) + + alignment_files = Path(args.alignment) + if os.path.isdir(args.alignment): + alignment_files = alignment_files.glob("*.txt") + else: + alignment_files = [Path(alignment_files)] + + stats_file = os.path.join(args.output_dir, 'stats.tsv') + with open(stats_file, 'w') as f: + f.write('Folder\tSegment\tOriginal dur (s)\tHigh quality dur (s)\tLow quality dur (s)\tDeleted dur (s)\n') + + high_score_dur = 0 + low_score_dur = 0 + del_duration = 0 + + for alignment_file in alignment_files: + stats = process_alignment(alignment_file, args) + high_score_dur += stats[-3] + low_score_dur += stats[-2] + del_duration += stats[-1] + stats = '\t'.join([str(t) for t in stats]) + '\n' + f.write(stats) + + f.write(f'Total\t\t{round(high_score_dur)}\t{round(low_score_dur)}\t{del_duration}') + + total_time = time.time() - start_time + print(f'High score segments duration: {round(high_score_dur)}') + print(f'Low score segments duration: {round(low_score_dur)}') + print(f'Deleted segments duration: {round(del_duration)}') + print(f'Stats saved at {stats_file}') + print(f'Total execution time: ~{round(total_time / 60)}min') diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/normalization_helpers.py b/tts/NeMo/tools/ctc_segmentation/scripts/normalization_helpers.py new file mode 100644 index 0000000..7e971e7 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/normalization_helpers.py @@ -0,0 +1,69 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. 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. + +__all__ = ['LATIN_TO_RU', 'RU_ABBREVIATIONS', 'NUMBERS_TO_ENG', 'NUMBERS_TO_RU'] + +LATIN_TO_RU = { + 'a': 'а', + 'b': 'б', + 'c': 'к', + 'd': 'д', + 'e': 'е', + 'f': 'ф', + 'g': 'г', + 'h': 'х', + 'i': 'и', + 'j': 'ж', + 'k': 'к', + 'l': 'л', + 'm': 'м', + 'n': 'н', + 'o': 'о', + 'p': 'п', + 'q': 'к', + 'r': 'р', + 's': 'с', + 't': 'т', + 'u': 'у', + 'v': 'в', + 'w': 'в', + 'x': 'к', + 'y': 'у', + 'z': 'з', + 'à': 'а', + 'è': 'е', + 'é': 'е', + 'ß': 'в', + 'ä': 'а', + 'ö': 'о', + 'ü': 'у', + 'є': 'е', + 'ç': 'с', + 'ê': 'е', + 'ó': 'о', +} + +RU_ABBREVIATIONS = { + ' р.': ' рублей', + ' к.': ' копеек', + ' коп.': ' копеек', + ' копек.': ' копеек', + ' т.д.': ' так далее', + ' т. д.': ' так далее', + ' т.п.': ' тому подобное', + ' т. п.': ' тому подобное', + ' т.е.': ' то есть', + ' т. е.': ' то есть', + ' стр. ': ' страница ', +} diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/prepare_data.py b/tts/NeMo/tools/ctc_segmentation/scripts/prepare_data.py new file mode 100644 index 0000000..47373fb --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/prepare_data.py @@ -0,0 +1,412 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import multiprocessing +import os +import re +from pathlib import Path +from typing import List + +import regex +import scipy.io.wavfile as wav +from normalization_helpers import LATIN_TO_RU, RU_ABBREVIATIONS +from num2words import num2words + +from nemo.collections import asr as nemo_asr + +try: + from nemo_text_processing.text_normalization.normalize import Normalizer + + NEMO_NORMALIZATION_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + NEMO_NORMALIZATION_AVAILABLE = False + + +parser = argparse.ArgumentParser(description="Prepares text and audio files for segmentation") +parser.add_argument("--in_text", type=str, default=None, help='Path to a text file or a directory with .txt files') +parser.add_argument("--output_dir", type=str, required=True, help='Path to output directory') +parser.add_argument("--audio_dir", type=str, help='Path to folder with .mp3 or .wav audio files') +parser.add_argument( + "--audio_format", type=str, default='.mp3', choices=['.mp3', '.wav'], help='Audio files format in --audio_dir' +) +parser.add_argument('--sample_rate', type=int, default=16000, help='Sampling rate used during ASR model training') +parser.add_argument( + '--language', type=str, default='eng', choices=['eng', 'ru', 'add other languages supported by num2words.'] +) +parser.add_argument( + '--cut_prefix', type=int, default=0, help='Number of seconds to cut from the beginning of the audio files.', +) +parser.add_argument( + '--model', type=str, default='QuartzNet15x5Base-En', help='Pre-trained model name or path to model checkpoint' +) +parser.add_argument('--min_length', type=int, default=0, help='Min number of chars of the text segment for alignment.') +parser.add_argument( + '--max_length', type=int, default=100, help='Max number of chars of the text segment for alignment.' +) +parser.add_argument( + '--additional_split_symbols', + type=str, + default='', + help='Additional symbols to use for \ + sentence split if eos sentence split resulted in sequence longer than --max_length. ' + 'Use "|" as a separator between symbols, for example: ";|:|" ', +) +parser.add_argument( + '--use_nemo_normalization', + action='store_true', + help='Set to True to use NeMo Normalization tool to convert numbers from written to spoken format.', +) + + +def convert_audio(in_file: str, wav_file: str = None, sample_rate: int = 16000) -> str: + """ + Convert .mp3 to .wav and/or change sample rate if needed + + Args: + in_file: Path to .mp3 or .wav file + sample_rate: Desired sample rate + + Returns: + path to .wav file + """ + print(f"Converting {in_file} to .wav format with sample rate {sample_rate}") + if not os.path.exists(in_file): + raise ValueError(f'{in_file} not found') + if wav_file is None: + wav_file = in_file.replace(os.path.splitext(in_file)[-1], f"_{sample_rate}.wav") + + os.system( + f'ffmpeg -i {in_file} -acodec pcm_s16le -ac 1 -af aresample=resampler=soxr -ar {sample_rate} {wav_file} -y' + ) + return wav_file + + +def process_audio(in_file: str, wav_file: str = None, cut_prefix: int = 0, sample_rate: int = 16000): + """Process audio file: .mp3 to .wav conversion and cut a few seconds from the beginning of the audio + + Args: + in_file: path to the .mp3 or .wav file for processing + wav_file: path to the output .wav file + cut_prefix: number of seconds to cut from the beginning of the audio file + sample_rate: target sampling rate + """ + wav_audio = convert_audio(str(in_file), wav_file, sample_rate) + + if cut_prefix > 0: + # cut a few seconds of audio from the beginning + sample_rate, signal = wav.read(wav_audio) + wav.write(wav_audio, data=signal[cut_prefix * sample_rate :], rate=sample_rate) + + +def split_text( + in_file: str, + out_file: str, + vocabulary: List[str] = None, + language='eng', + remove_brackets=True, + do_lower_case=True, + min_length=0, + max_length=100, + additional_split_symbols=None, + use_nemo_normalization=False, +): + """ + Breaks down the in_file roughly into sentences. Each sentence will be on a separate line. + Written form of the numbers will be converted to its spoken equivalent, OOV punctuation will be removed. + + Args: + in_file: path to original transcript + out_file: path to the output file + vocabulary: ASR model vocabulary + language: text language + remove_brackets: Set to True if square [] and curly {} brackets should be removed from text. + Text in square/curly brackets often contains inaudible fragments like notes or translations + do_lower_case: flag that determines whether to apply lower case to the in_file text + min_length: Min number of chars of the text segment for alignment. Short segments will be combined to be + at least min_length (not recommended for multi speaker data). + max_length: Max number of chars of the text segment for alignment + additional_split_symbols: Additional symbols to use for sentence split if eos sentence split resulted in + segments longer than --max_length + use_nemo_normalization: Set to True to use NeMo normalization tool to convert numbers from written to spoken + format. Normalization using num2words will be applied afterwards to make sure there are no numbers present + in the text, otherwise they will be replaced with a space and that could deteriorate segmentation results. + """ + + print(f'Splitting text in {in_file} into sentences.') + with open(in_file, "r") as f: + transcript = f.read() + + # remove some symbols for better split into sentences + transcript = ( + transcript.replace("\n", " ") + .replace("\t", " ") + .replace("…", "...") + .replace("\\", " ") + .replace("--", " -- ") + .replace(". . .", "...") + .replace("‘", "’") + ) + # remove extra space + transcript = re.sub(r' +', ' ', transcript) + transcript = re.sub(r'(\.+)', '. ', transcript) + + if remove_brackets: + transcript = re.sub(r'(\[.*?\])', ' ', transcript) + # remove text in curly brackets + transcript = re.sub(r'(\{.*?\})', ' ', transcript) + + lower_case_unicode = '' + upper_case_unicode = '' + if language == 'ru': + lower_case_unicode = '\u0430-\u04FF' + upper_case_unicode = '\u0410-\u042F' + elif language not in ['ru', 'eng']: + print(f'Consider using {language} unicode letters for better sentence split.') + + # remove space in the middle of the lower case abbreviation to avoid splitting into separate sentences + matches = re.findall(r'[a-z' + lower_case_unicode + ']\.\s[a-z' + lower_case_unicode + ']\.', transcript) + for match in matches: + transcript = transcript.replace(match, match.replace('. ', '.')) + + # find phrases in quotes + with_quotes = re.finditer(r'“[A-Za-z ?]+.*?”', transcript) + sentences = [] + last_idx = 0 + for m in with_quotes: + match = m.group() + match_idx = m.start() + if last_idx < match_idx: + sentences.append(transcript[last_idx:match_idx]) + sentences.append(match) + last_idx = m.end() + sentences.append(transcript[last_idx:]) + sentences = [s.strip() for s in sentences if s.strip()] + + # Read and split transcript by utterance (roughly, sentences) + split_pattern = f"(? 0] + + if min_length > 0: + sentences_comb = [] + sentences_comb.append(sentences[0]) + # combines short sentence + for i in range(1, len(sentences)): + if len(sentences_comb[-1]) < min_length or len(sentences[i]) < min_length: + sentences_comb[-1] += ' ' + sentences[i].strip() + else: + sentences_comb.append(sentences[i].strip()) + sentences = sentences_comb + + sentences = [s.strip() for s in sentences if s.strip()] + + # save split text with original punctuation and case + out_dir, out_file_name = os.path.split(out_file) + with open(os.path.join(out_dir, out_file_name[:-4] + '_with_punct.txt'), "w") as f: + f.write("\n".join(sentences)) + + # substitute common abbreviations before applying lower case + if language == 'ru': + for k, v in RU_ABBREVIATIONS.items(): + sentences = [s.replace(k, v) for s in sentences] + + if language == 'ru': + # replace Latin characters with Russian + for k, v in LATIN_TO_RU.items(): + sentences = [s.replace(k, v) for s in sentences] + + if language == 'eng' and use_nemo_normalization: + if not NEMO_NORMALIZATION_AVAILABLE: + raise ValueError(f'NeMo normalization tool is not installed.') + + print('Using NeMo normalization tool...') + normalizer = Normalizer(input_case='cased') + sentences_norm = normalizer.normalize_list(sentences, verbose=False) + if len(sentences_norm) != len(sentences): + raise ValueError(f'Normalization failed, number of sentences does not match.') + + sentences = '\n'.join(sentences) + + # replace numbers with num2words + try: + p = re.compile("\d+") + new_text = '' + match_end = 0 + for i, m in enumerate(p.finditer(sentences)): + match = m.group() + match_start = m.start() + if i == 0: + new_text = sentences[:match_start] + else: + new_text += sentences[match_end:match_start] + match_end = m.end() + new_text += sentences[match_start:match_end].replace(match, num2words(match, lang=language)) + new_text += sentences[match_end:] + sentences = new_text + except NotImplementedError: + print( + f'{language} might be missing in "num2words" package. Add required language to the choices for the' + f'--language argument.' + ) + raise + + sentences = ( + sentences.replace("’", "'") + .replace("»", '"') + .replace("«", '"') + .replace("\\", "") + .replace("”", '"') + .replace("„", '"') + .replace("´", "'") + .replace("-- --", "--") + .replace("--", " -- ") + .replace("’", "'") + .replace('“', '"') + .replace('“', '"') + .replace("‘", "'") + .replace('—', '-') + .replace("- -", "--") + .replace('`', "'") + .replace(' !', '!') + .replace(' ?', '?') + .replace(' ,', ',') + .replace(' .', '.') + .replace(' ;', ';') + .replace(' :', ':') + .replace('!!', '!') + .replace('--', '-') + .replace('“', '"') + .replace(', , ', ', ') + .replace('=', '') + ) + + allowed_punct = [',', '.', '?', '!', ':', ';', '-', '"', '(', ')'] + # clean up normalized text and keep only allowed_punct and ASR vocabulary (lower and upper case) + symbols_to_remove = ''.join( + set(sentences).difference(set(vocabulary + [s.upper() for s in vocabulary] + ['\n'] + allowed_punct)) + ) + sentences_norm = sentences.translate(''.maketrans(symbols_to_remove, len(symbols_to_remove) * ' ')) + + with open(os.path.join(out_dir, out_file_name[:-4] + '_with_punct_normalized.txt'), "w") as f: + f.write(sentences_norm) + + if do_lower_case: + sentences = sentences.lower() + + # remove all OOV symbols + symbols_to_remove = ''.join(set(sentences).difference(set(vocabulary + ['\n']))) + sentences = sentences.translate(''.maketrans(symbols_to_remove, len(symbols_to_remove) * ' ')) + + # remove extra space + sentences = re.sub(r' +', ' ', sentences) + with open(out_file, "w") as f: + f.write(sentences) + + +if __name__ == '__main__': + args = parser.parse_args() + + os.makedirs(args.output_dir, exist_ok=True) + + text_files = [] + if args.in_text: + vocabulary = None + if args.model is None: + print(f"No model provided, vocabulary won't be used") + elif os.path.exists(args.model): + asr_model = nemo_asr.models.EncDecCTCModel.restore_from(args.model) + vocabulary = asr_model.cfg.decoder.vocabulary + elif args.model in nemo_asr.models.EncDecCTCModel.get_available_model_names(): + asr_model = nemo_asr.models.EncDecCTCModel.from_pretrained(args.model) + vocabulary = asr_model.cfg.decoder.vocabulary + else: + raise ValueError( + f'Provide path to the pretrained checkpoint or choose from {nemo_asr.models.EncDecCTCModel.get_available_model_names()}' + ) + + if os.path.isdir(args.in_text): + text_files = Path(args.in_text).glob(("*.txt")) + else: + text_files.append(Path(args.in_text)) + for text in text_files: + base_name = os.path.basename(text)[:-4] + out_text_file = os.path.join(args.output_dir, base_name + '.txt') + + split_text( + text, + out_text_file, + vocabulary=vocabulary, + language=args.language, + min_length=args.min_length, + max_length=args.max_length, + additional_split_symbols=args.additional_split_symbols, + use_nemo_normalization=args.use_nemo_normalization, + ) + print(f'Processed text saved at {args.output_dir}') + + if args.audio_dir: + if not os.path.exists(args.audio_dir): + raise ValueError(f'{args.audio_dir} not found. "--audio_dir" should contain .mp3 or .wav files.') + + audio_paths = list(Path(args.audio_dir).glob(f"*{args.audio_format}")) + + workers = [] + for i in range(len(audio_paths)): + wav_file = os.path.join(args.output_dir, audio_paths[i].name.replace(args.audio_format, ".wav")) + worker = multiprocessing.Process( + target=process_audio, args=(audio_paths[i], wav_file, args.cut_prefix, args.sample_rate), + ) + workers.append(worker) + worker.start() + for w in workers: + w.join() + + print('Done.') diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/process_manifests.py b/tts/NeMo/tools/ctc_segmentation/scripts/process_manifests.py new file mode 100644 index 0000000..d3ef987 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/process_manifests.py @@ -0,0 +1,111 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import json +import os +from pathlib import Path +from random import randint +from typing import List + +parser = argparse.ArgumentParser(description="Combine manifests and extract samples") +parser.add_argument( + "--manifests_dir", + default='_high_score_manifest.json', + type=str, + required=True, + help='Path to directory with *_high_score_manifest.json files', +) +parser.add_argument( + "--output_dir", default='output', required=True, help='Path to the directory to store final manifest' +) +parser.add_argument( + "--num_samples", + default=0, + type=int, + help='The number of samples to get from the beginning, end and randomly from the middle of highly scored samples', +) + + +def get_samples(manifest: str, num_samples: int) -> List[str]: + """ + Samples num_samples from the beginning, end and randomly from the middle of the manifest + + Args: + manifest: path to manifest + num_samples: number of samples to extract from the beginning, end and randomly from the middle of the manifest + + Returns: + num_samples: manifest lines + """ + samples = [] + with open(manifest, 'r', encoding='utf8') as f: + lines = f.readlines() + + # first n samples + samples.extend(lines[:num_samples]) + # random in the middle + for i in range(num_samples): + samples.append(lines[randint(num_samples, len(lines) - num_samples)]) + # last n samples + samples.extend(lines[-num_samples:]) + return samples + + +if __name__ == '__main__': + args = parser.parse_args() + manifest_dir = Path(args.manifests_dir) + manifests = sorted(list(manifest_dir.glob('*_high_score_manifest.json'))) + sample_manifest = os.path.join(args.output_dir, 'sample_manifest.json') + all_manifest = os.path.join(args.output_dir, 'all_manifest.json') + + if args.num_samples > 0: + with open(sample_manifest, 'w', encoding='utf8') as f: + for manifest in manifests: + samples = get_samples(manifest, args.num_samples) + for sample in samples: + f.write(sample) + + print(f'Sample manifest is saved at {sample_manifest}') + + total_duration = 0 + with open(all_manifest, 'w') as out_f: + for manifest in manifests: + with open(manifest, 'r', encoding='utf8') as f: + for line in f: + info = json.loads(line) + total_duration += info['duration'] + out_f.write(line) + + print(f'Aggregated manifest is saved at {all_manifest}') + print(f'Total files duration: ~{round(total_duration/60)} min or ~{round(total_duration/60/60)} hr') + + sets = {'_high_score_manifest.json': 0, '_low_score_manifest.json': 0, '_del_manifest.json': 0} + + for k in sets: + files = manifest_dir.glob(f'*{k}') + for manifest_f in files: + with open(manifest_f, 'r') as f: + for line in f: + line = json.loads(line) + sets[k] += line['duration'] + + total = 0 + for k in sets: + sets[k] = round(sets[k] / 3600, 1) + total += sets[k] + name = k.split('_')[1].upper() + print(f'Total {name} score duration: ~{sets[k]} hr') + print(f'Total duration: ~{total} hr') + print('Done.') diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/run_ctc_segmentation.py b/tts/NeMo/tools/ctc_segmentation/scripts/run_ctc_segmentation.py new file mode 100644 index 0000000..06b4f36 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/run_ctc_segmentation.py @@ -0,0 +1,180 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import logging +import multiprocessing +import os +import sys +import time +from pathlib import Path + +import numpy as np +import scipy.io.wavfile as wav +import torch +from utils import get_segments, listener_configurer, listener_process, worker_configurer, worker_process + +import nemo.collections.asr as nemo_asr + +parser = argparse.ArgumentParser(description="CTC Segmentation") +parser.add_argument("--output_dir", default='output', type=str, help='Path to output directory') +parser.add_argument( + "--data", + type=str, + required=True, + help='Path to directory with audio files and associated transcripts (same respective names only formats are ' + 'different or path to wav file (transcript should have the same base name and be located in the same folder' + 'as the wav file.', +) +parser.add_argument('--window_len', type=int, default=8000, help='Window size for ctc segmentation algorithm') +parser.add_argument('--no_parallel', action='store_true', help='Flag to disable parallel segmentation') +parser.add_argument('--sample_rate', type=int, default=16000, help='Sampling rate') +parser.add_argument( + '--model', type=str, default='QuartzNet15x5Base-En', help='Path to model checkpoint or pre-trained model name', +) +parser.add_argument('--debug', action='store_true', help='Flag to enable debugging messages') + +logger = logging.getLogger('ctc_segmentation') # use module name + +if __name__ == '__main__': + + args = parser.parse_args() + + # setup logger + log_dir = os.path.join(args.output_dir, 'logs') + os.makedirs(log_dir, exist_ok=True) + log_file = os.path.join(log_dir, f'ctc_segmentation_{args.window_len}.log') + level = 'DEBUG' if args.debug else 'INFO' + + logger = logging.getLogger('CTC') + file_handler = logging.FileHandler(filename=log_file) + stdout_handler = logging.StreamHandler(sys.stdout) + handlers = [file_handler, stdout_handler] + logging.basicConfig(handlers=handlers, level=level) + + if os.path.exists(args.model): + asr_model = nemo_asr.models.EncDecCTCModel.restore_from(args.model) + elif args.model in nemo_asr.models.EncDecCTCModel.get_available_model_names(): + asr_model = nemo_asr.models.EncDecCTCModel.from_pretrained(args.model, strict=False) + else: + raise ValueError( + f'{args.model} not a valid model name or path. Provide path to the pre-trained checkpoint ' + f'or choose from {nemo_asr.models.EncDecCTCModel.list_available_models()}' + ) + + # extract ASR vocabulary and add blank symbol + vocabulary = asr_model.cfg.decoder.vocabulary + odim = len(vocabulary) + 1 + logging.debug(f'ASR Model vocabulary: {vocabulary}') + + # add blank to vocab + vocabulary = ["ε"] + list(vocabulary) + data = Path(args.data) + output_dir = Path(args.output_dir) + + if os.path.isdir(data): + audio_paths = data.glob("*.wav") + data_dir = data + else: + audio_paths = [Path(data)] + data_dir = Path(os.path.dirname(data)) + + all_log_probs = [] + all_transcript_file = [] + all_segment_file = [] + all_wav_paths = [] + segments_dir = os.path.join(args.output_dir, 'segments') + os.makedirs(segments_dir, exist_ok=True) + for path_audio in audio_paths: + transcript_file = os.path.join(data_dir, path_audio.name.replace(".wav", ".txt")) + segment_file = os.path.join( + segments_dir, f"{args.window_len}_" + path_audio.name.replace(".wav", "_segments.txt") + ) + try: + sample_rate, signal = wav.read(path_audio) + if sample_rate != args.sample_rate: + raise ValueError( + f'Sampling rate of the audio file {path_audio} doesn\'t match --sample_rate={args.sample_rate}' + ) + except ValueError: + logging.error( + f"{path_audio} should be a .wav mono file with the sampling rate used for the ASR model training" + f"specified with {args.sample_rate}." + ) + raise + + original_duration = len(signal) / sample_rate + logging.debug(f'Duration: {original_duration}s, file_name: {path_audio}') + log_probs = asr_model.transcribe(paths2audio_files=[str(path_audio)], batch_size=1, logprobs=True)[0] + + # move blank values to the first column + blank_col = log_probs[:, -1].reshape((log_probs.shape[0], 1)) + log_probs = np.concatenate((blank_col, log_probs[:, :-1]), axis=1) + + all_log_probs.append(log_probs) + all_segment_file.append(str(segment_file)) + all_transcript_file.append(str(transcript_file)) + all_wav_paths.append(path_audio) + + del asr_model + torch.cuda.empty_cache() + + if len(all_log_probs) == 0: + raise ValueError(f'No valid audio files found at {args.data}') + start_time = time.time() + if args.no_parallel: + for i in range(len(all_log_probs)): + get_segments( + all_log_probs[i], + all_wav_paths[i], + all_transcript_file[i], + all_segment_file[i], + vocabulary, + args.window_len, + ) + else: + queue = multiprocessing.Queue(-1) + + listener = multiprocessing.Process(target=listener_process, args=(queue, listener_configurer, log_file, level)) + listener.start() + workers = [] + for i in range(len(all_log_probs)): + worker = multiprocessing.Process( + target=worker_process, + args=( + queue, + worker_configurer, + level, + all_log_probs[i], + all_wav_paths[i], + all_transcript_file[i], + all_segment_file[i], + vocabulary, + args.window_len, + ), + ) + workers.append(worker) + worker.start() + for w in workers: + w.join() + queue.put_nowait(None) + listener.join() + + total_time = time.time() - start_time + logger.info(f'Total execution time: ~{round(total_time/60)}min') + logger.info(f'Saving logs to {log_file}') + + if os.path.exists(log_file): + with open(log_file, 'r') as f: + lines = f.readlines() diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/utils.py b/tts/NeMo/tools/ctc_segmentation/scripts/utils.py new file mode 100644 index 0000000..713f8d4 --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/utils.py @@ -0,0 +1,173 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import logging.handlers +import multiprocessing +import os +from pathlib import PosixPath +from typing import List, Tuple, Union + +import ctc_segmentation as cs +import numpy as np + + +def get_segments( + log_probs: np.ndarray, + path_wav: Union[PosixPath, str], + transcript_file: Union[PosixPath, str], + output_file: str, + vocabulary: List[str], + window_size: int = 8000, + frame_duration_ms: int = 20, +) -> None: + """ + Segments the audio into segments and saves segments timings to a file + + Args: + log_probs: Log probabilities for the original audio from an ASR model, shape T * |vocabulary|. + values for blank should be at position 0 + path_wav: path to the audio .wav file + transcript_file: path to + output_file: path to the file to save timings for segments + vocabulary: vocabulary used to train the ASR model, note blank is at position 0 + window_size: the length of each utterance (in terms of frames of the CTC outputs) fits into that window. + frame_duration_ms: frame duration in ms + """ + config = cs.CtcSegmentationParameters() + config.char_list = vocabulary + config.min_window_size = window_size + config.frame_duration_ms = frame_duration_ms + config.blank = config.space + config.subsampling_factor = 2 + + with open(transcript_file, "r") as f: + text = f.readlines() + text = [t.strip() for t in text if t.strip()] + + # add corresponding original text without pre-processing + transcript_file_no_preprocessing = transcript_file.replace('.txt', '_with_punct.txt') + if not os.path.exists(transcript_file_no_preprocessing): + raise ValueError(f'{transcript_file_no_preprocessing} not found.') + + with open(transcript_file_no_preprocessing, "r") as f: + text_no_preprocessing = f.readlines() + text_no_preprocessing = [t.strip() for t in text_no_preprocessing if t.strip()] + + # add corresponding normalized original text + transcript_file_normalized = transcript_file.replace('.txt', '_with_punct_normalized.txt') + if not os.path.exists(transcript_file_normalized): + raise ValueError(f'{transcript_file_normalized} not found.') + + with open(transcript_file_normalized, "r") as f: + text_normalized = f.readlines() + text_normalized = [t.strip() for t in text_normalized if t.strip()] + + if len(text_no_preprocessing) != len(text): + raise ValueError(f'{transcript_file} and {transcript_file_no_preprocessing} do not match') + + if len(text_normalized) != len(text): + raise ValueError(f'{transcript_file} and {transcript_file_normalized} do not match') + + ground_truth_mat, utt_begin_indices = cs.prepare_text(config, text) + logging.debug(f"Syncing {transcript_file}") + logging.debug( + f"Audio length {os.path.basename(path_wav)}: {log_probs.shape[0]}. " + f"Text length {os.path.basename(transcript_file)}: {len(ground_truth_mat)}" + ) + + timings, char_probs, char_list = cs.ctc_segmentation(config, log_probs, ground_truth_mat) + segments = cs.determine_utterance_segments(config, utt_begin_indices, char_probs, timings, text) + write_output(output_file, path_wav, segments, text, text_no_preprocessing, text_normalized) + + +def write_output( + out_path: str, + path_wav: str, + segments: List[Tuple[float]], + text: str, + text_no_preprocessing: str, + text_normalized: str, + stride: int = 2, +): + """ + Write the segmentation output to a file + + out_path: Path to output file + path_wav: Path to the original audio file + segments: Segments include start, end and alignment score + text: Text used for alignment + text_no_preprocessing: Reference txt without any pre-processing + text_normalized: Reference text normalized + stride: Stride applied to an ASR input + """ + # Uses char-wise alignments to get utterance-wise alignments and writes them into the given file + with open(str(out_path), "w") as outfile: + outfile.write(str(path_wav) + "\n") + + for i, (start, end, score) in enumerate(segments): + outfile.write( + f'{start/stride} {end/stride} {score} | {text[i]} | {text_no_preprocessing[i]} | {text_normalized[i]}\n' + ) + + +##################### +# logging utils +##################### +def listener_configurer(log_file, level): + root = logging.getLogger() + h = logging.handlers.RotatingFileHandler(log_file, 'w') + f = logging.Formatter('%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s') + h.setFormatter(f) + ch = logging.StreamHandler() + root.addHandler(h) + root.setLevel(level) + root.addHandler(ch) + + +def listener_process(queue, configurer, log_file, level): + configurer(log_file, level) + while True: + try: + record = queue.get() + if record is None: # We send this as a sentinel to tell the listener to quit. + break + logger = logging.getLogger(record.name) + logger.setLevel(logging.INFO) + logger.handle(record) # No level or filter logic applied - just do it! + + except Exception: + import sys + import traceback + + print('Problem:', file=sys.stderr) + traceback.print_exc(file=sys.stderr) + + +def worker_configurer(queue, level): + h = logging.handlers.QueueHandler(queue) # Just the one handler needed + root = logging.getLogger() + root.addHandler(h) + root.setLevel(level) + + +def worker_process( + queue, configurer, level, log_probs, path_wav, transcript_file, output_file, vocabulary, window_len +): + configurer(queue, level) + name = multiprocessing.current_process().name + innerlogger = logging.getLogger('worker') + innerlogger.info(f'{name} is processing {path_wav}, window_len={window_len}') + get_segments(log_probs, path_wav, transcript_file, output_file, vocabulary, window_len) + innerlogger.info(f'{name} completed segmentation of {path_wav}, segments saved to {output_file}') diff --git a/tts/NeMo/tools/ctc_segmentation/scripts/verify_segments.py b/tts/NeMo/tools/ctc_segmentation/scripts/verify_segments.py new file mode 100644 index 0000000..9d648df --- /dev/null +++ b/tts/NeMo/tools/ctc_segmentation/scripts/verify_segments.py @@ -0,0 +1,143 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os +import re +from pathlib import Path + +import pandas as pd + +parser = argparse.ArgumentParser(description="Compare alignment segments generated with different window sizes") +parser.add_argument( + "--base_dir", + default='output', + type=str, + required=True, + help='Path to directory with "logs" and "segments" folders generated during the segmentation step', +) + + +def _process_log_file(log_file: str): + processes = {} + with open(log_file, 'r') as f: + for line in f: + if line[0].isdigit() and 'Process-' in line: + process_id = re.search(r'Process-\d+', line)[0] + window_size = re.findall(r'\d+', line)[-1] + path = re.search(r'\/.*?\.[\w:]+', line) + if 'is processing' in line: + if process_id not in processes: + processes[process_id] = {} + processes[process_id]['Window Increased'] = False + processes[process_id]['Start Window'] = window_size + processes[process_id]['Final Window'] = window_size + base_dir, base_name = os.path.split(path[0]) + processes[process_id]['Audio Dir'] = base_dir + processes[process_id]['Audio File'] = base_name + elif 'Increasing' in line: + processes[process_id]['Final Window'] = window_size + processes[process_id]['Window Increased'] = True + elif 'completed' in line: + processes[process_id]['Completed'] = True + + df = pd.DataFrame.from_dict( + processes, + columns=['Audio Dir', 'Audio File', 'Start Window', 'Final Window', 'Window Increased', 'Completed'], + orient='index', + ).reset_index() + return df + + +if __name__ == '__main__': + args = parser.parse_args() + log_dir = os.path.join(args.base_dir, 'logs') + if not os.path.exists(log_dir): + raise ValueError(f'"log" directory was not found at {args.base_dir}.') + + log_files = Path(log_dir).glob('*.log') + dfs = [] + for log in log_files: + dfs.append(_process_log_file(log)) + + dfs = pd.concat(dfs) + summary_file = os.path.join(log_dir, 'log_summary.csv') + dfs.to_csv(summary_file, index=False) + print(f'Log summary saved to {summary_file}') + + segments_dir = os.path.join(args.base_dir, 'segments') + if not os.path.exists(segments_dir): + raise ValueError(f'"segments" directory was not found at {args.base_dir}.') + + all_files = Path(segments_dir).glob('*_segments.txt') + all_alignment_files = {} + for file in all_files: + base_name = re.sub(r'^\d+_', '', file.name) + if base_name not in all_alignment_files: + all_alignment_files[base_name] = [] + all_alignment_files[base_name].append(file) + + verified_dir = os.path.join(args.base_dir, 'verified_segments') + os.makedirs(verified_dir, exist_ok=True) + + def readlines(file): + with open(file, 'r') as f: + lines = f.readlines() + return lines + + stats = {} + for part, alignment_files in all_alignment_files.items(): + stats[part] = {} + num_alignment_files = len(alignment_files) + all_alignments = [] + for alignment in alignment_files: + all_alignments.append(readlines(alignment)) + + with open(os.path.join(verified_dir, part), 'w') as f: + num_segments = len(all_alignments[0]) + stats[part]['Original number of segments'] = num_segments + stats[part]['Verified segments'] = 0 + stats[part]['Original Duration, min'] = 0 + stats[part]['Verified Duration, min'] = 0 + + for i in range(num_segments): + line = all_alignments[0][i] + valid_line = True + if i == 0: + duration = 0 + else: + info = line.split('|')[0].split() + duration = (float(info[1]) - float(info[0])) / 60 + stats[part]['Original Duration, min'] += duration + for alignment in all_alignments: + if line != alignment[i]: + valid_line = False + if valid_line: + f.write(line) + stats[part]['Verified segments'] += 1 + stats[part]['Verified Duration, min'] += duration + + stats = pd.DataFrame.from_dict(stats, orient='index').reset_index() + stats['Number dropped'] = stats['Original number of segments'] - stats['Verified segments'] + stats['Duration of dropped, min'] = round(stats['Original Duration, min'] - stats['Verified Duration, min']) + stats['% dropped, min'] = round(stats['Duration of dropped, min'] / stats['Original number of segments'] * 100) + stats['Misalignment present'] = stats['Number dropped'] > 0 + stats['Original Duration, min'] = round(stats['Original Duration, min']) + stats['Verified Duration, min'] = round(stats['Verified Duration, min']) + stats.loc["Total"] = stats.sum() + + stats_file = os.path.join(args.base_dir, 'alignment_summary.csv') + stats.to_csv(stats_file, index=False) + print(stats) + print(f'Alignment summary saved to {stats_file}') diff --git a/tts/NeMo/tools/speech_data_explorer/README.md b/tts/NeMo/tools/speech_data_explorer/README.md new file mode 100644 index 0000000..9d431f2 --- /dev/null +++ b/tts/NeMo/tools/speech_data_explorer/README.md @@ -0,0 +1,26 @@ +Speech Data Explorer +-------------------- + +[Dash](https://plotly.com/dash/)-based tool for interactive exploration of ASR/TTS datasets. + +Features: +- dataset's statistics (alphabet, vocabulary, duration-based histograms) +- navigation across dataset (sorting, filtering) +- inspection of individual utterances (waveform, spectrogram, audio player) +- errors' analysis (Word Error Rate, Character Error Rate, Word Match Rate, Mean Word Accuracy, diff) + +Please make sure that requirements are installed. Then run: +``` +python data_explorer.py path_to_manifest.json +``` + +JSON manifest file should contain the following fields: +- "audio_filepath" (path to audio file) +- "duration" (duration of the audio file in seconds) +- "text" (reference transcript) + +Errors' analysis requires "pred_text" (ASR transcript) for all utterances. + +Any additional field will be parsed and displayed in 'Samples' tab. + +![Speech Data Explorer](screenshot.png) diff --git a/tts/NeMo/tools/speech_data_explorer/data_explorer.py b/tts/NeMo/tools/speech_data_explorer/data_explorer.py new file mode 100755 index 0000000..e760915 --- /dev/null +++ b/tts/NeMo/tools/speech_data_explorer/data_explorer.py @@ -0,0 +1,717 @@ +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import base64 +import datetime +import difflib +import io +import json +import math +import operator +import os +import pickle +from collections import defaultdict + +import dash +import dash_bootstrap_components as dbc +import dash_core_components as dcc +import dash_html_components as html +import dash_table +import diff_match_patch +import editdistance +import librosa +import numpy as np +import soundfile as sf +import tqdm +from dash.dependencies import Input, Output +from dash.exceptions import PreventUpdate +from plotly import express as px +from plotly import graph_objects as go +from plotly.subplots import make_subplots + +# number of items in a table per page +DATA_PAGE_SIZE = 10 + +# operators for filtering items +filter_operators = [ + ['ge ', '>='], + ['le ', '<='], + ['lt ', '<'], + ['gt ', '>'], + ['ne ', '!='], + ['eq ', '='], + ['contains '], +] + +# parse table filter queries +def split_filter_part(filter_part): + for operator_type in filter_operators: + for op in operator_type: + if op in filter_part: + name_part, value_part = filter_part.split(op, 1) + name = name_part[name_part.find('{') + 1 : name_part.rfind('}')] + value_part = value_part.strip() + v0 = value_part[0] + if v0 == value_part[-1] and v0 in ("'", '"', '`'): + value = value_part[1:-1].replace('\\' + v0, v0) + else: + try: + value = float(value_part) + except ValueError: + value = value_part + return name, operator_type[0].strip(), value + return [None] * 3 + + +# standard command-line arguments parser +def parse_args(): + parser = argparse.ArgumentParser(description='Speech Data Explorer') + parser.add_argument( + 'manifest', help='path to JSON manifest file', + ) + parser.add_argument('--vocab', help='optional vocabulary to highlight OOV words') + parser.add_argument('--port', default='8050', help='serving port for establishing connection') + parser.add_argument( + '--disable-caching-metrics', action='store_true', help='disable caching metrics for errors analysis' + ) + parser.add_argument('--debug', '-d', action='store_true', help='enable debug mode') + args = parser.parse_args() + print(args) + return args + + +# load data from JSON manifest file +def load_data(data_filename, disable_caching, vocab=None): + if not disable_caching: + pickle_filename = data_filename.split('.json')[0] + json_mtime = datetime.datetime.fromtimestamp(os.path.getmtime(data_filename)) + timestamp = json_mtime.strftime('%Y%m%d_%H%M') + pickle_filename += '_' + timestamp + '.pkl' + if os.path.exists(pickle_filename): + with open(pickle_filename, 'rb') as f: + data, wer, cer, wmr, mwa, num_hours, vocabulary_data, alphabet, metrics_available = pickle.load(f) + return data, wer, cer, wmr, mwa, num_hours, vocabulary_data, alphabet, metrics_available + + if vocab is not None: + # load external vocab + vocabulary_ext = {} + with open(vocab, 'r') as f: + for line in f: + if '\t' in line: + # parse word from TSV file + word = line.split('\t')[0] + else: + # assume each line contains just a single word + word = line.strip() + vocabulary_ext[word] = 1 + + data = [] + wer_dist = 0.0 + wer_count = 0 + cer_dist = 0.0 + cer_count = 0 + wmr_count = 0 + wer = 0 + cer = 0 + wmr = 0 + mwa = 0 + num_hours = 0 + vocabulary = defaultdict(lambda: 0) + alphabet = set() + match_vocab = defaultdict(lambda: 0) + + sm = difflib.SequenceMatcher() + metrics_available = False + with open(data_filename, 'r', encoding='utf8') as f: + for line in tqdm.tqdm(f): + item = json.loads(line) + num_words = len(item['text'].split()) + num_chars = len(item['text']) + orig = item['text'].split() + for word in orig: + vocabulary[word] += 1 + for char in item['text']: + alphabet.add(char) + num_hours += item['duration'] + + if 'pred_text' in item: + metrics_available = True + pred = item['pred_text'].split() + word_dist = editdistance.eval(orig, pred) + char_dist = editdistance.eval(item['text'], item['pred_text']) + wer_dist += word_dist + cer_dist += char_dist + wer_count += num_words + cer_count += num_chars + + sm.set_seqs(orig, pred) + num_matches = 0 + for m in sm.get_matching_blocks(): + for word_idx in range(m[0], m[0] + m[2]): + match_vocab[orig[word_idx]] += 1 + num_matches += 1 + wmr_count += num_matches + + data.append( + { + 'audio_filepath': item['audio_filepath'], + 'duration': round(item['duration'], 2), + 'num_words': num_words, + 'num_chars': num_chars, + 'word_rate': round(num_words / item['duration'], 2), + 'char_rate': round(num_chars / item['duration'], 2), + 'text': item['text'], + } + ) + if metrics_available: + data[-1]['pred_text'] = item['pred_text'] + data[-1]['WER'] = round(word_dist / num_words * 100.0, 2) + data[-1]['CER'] = round(char_dist / num_chars * 100.0, 2) + data[-1]['WMR'] = round(num_matches / len(orig) * 100.0, 2) + for k in item: + if k not in data[-1]: + data[-1][k] = item[k] + + vocabulary_data = [{'word': word, 'count': vocabulary[word]} for word in vocabulary] + if vocab is not None: + for item in vocabulary_data: + item['OOV'] = item['word'] not in vocabulary_ext + + if metrics_available: + wer = wer_dist / wer_count * 100.0 + cer = cer_dist / cer_count * 100.0 + wmr = wmr_count / wer_count * 100.0 + + acc_sum = 0 + for item in vocabulary_data: + w = item['word'] + word_accuracy = match_vocab[w] / vocabulary[w] * 100.0 + acc_sum += word_accuracy + item['accuracy'] = round(word_accuracy, 1) + mwa = acc_sum / len(vocabulary_data) + + num_hours /= 3600.0 + + if not disable_caching: + with open(pickle_filename, 'wb') as f: + pickle.dump( + [data, wer, cer, wmr, mwa, num_hours, vocabulary_data, alphabet, metrics_available], + f, + pickle.HIGHEST_PROTOCOL, + ) + + return data, wer, cer, wmr, mwa, num_hours, vocabulary_data, alphabet, metrics_available + + +# plot histogram of specified field in data list +def plot_histogram(data, key, label): + fig = px.histogram( + data_frame=[item[key] for item in data], + nbins=50, + log_y=True, + labels={'value': label}, + opacity=0.5, + color_discrete_sequence=['green'], + height=200, + ) + fig.update_layout(showlegend=False, margin=dict(l=0, r=0, t=0, b=0, pad=0)) + return fig + + +def plot_word_accuracy(vocabulary_data): + labels = ['Unrecognized', 'Sometimes recognized', 'Always recognized'] + counts = [0, 0, 0] + for word in vocabulary_data: + if word['accuracy'] == 0: + counts[0] += 1 + elif word['accuracy'] < 100: + counts[1] += 1 + else: + counts[2] += 1 + colors = ['red', 'orange', 'green'] + + fig = go.Figure( + data=[ + go.Bar( + x=labels, + y=counts, + marker_color=colors, + text=['{:.2%}'.format(count / sum(counts)) for count in counts], + textposition='auto', + ) + ] + ) + fig.update_layout( + showlegend=False, margin=dict(l=0, r=0, t=0, b=0, pad=0), height=200, yaxis={'title_text': '#words'} + ) + + return fig + + +args = parse_args() +print('Loading data...') +data, wer, cer, wmr, mwa, num_hours, vocabulary, alphabet, metrics_available = load_data( + args.manifest, args.disable_caching_metrics, args.vocab +) +print('Starting server...') +app = dash.Dash( + __name__, + suppress_callback_exceptions=True, + external_stylesheets=[dbc.themes.BOOTSTRAP], + title=os.path.basename(args.manifest), +) + + +figure_duration = plot_histogram(data, 'duration', 'Duration (sec)') +figure_num_words = plot_histogram(data, 'num_words', '#words') +figure_num_chars = plot_histogram(data, 'num_chars', '#chars') +figure_word_rate = plot_histogram(data, 'word_rate', '#words/sec') +figure_char_rate = plot_histogram(data, 'char_rate', '#chars/sec') + +if metrics_available: + figure_wer = plot_histogram(data, 'WER', 'WER, %') + figure_cer = plot_histogram(data, 'CER', 'CER, %') + figure_wmr = plot_histogram(data, 'WMR', 'WMR, %') + figure_word_acc = plot_word_accuracy(vocabulary) + +stats_layout = [ + dbc.Row(dbc.Col(html.H5(children='Global Statistics'), className='text-secondary'), className='mt-3'), + dbc.Row( + [ + dbc.Col(html.Div('Number of hours', className='text-secondary'), width=3, className='border-right'), + dbc.Col(html.Div('Number of utterances', className='text-secondary'), width=3, className='border-right'), + dbc.Col(html.Div('Vocabulary size', className='text-secondary'), width=3, className='border-right'), + dbc.Col(html.Div('Alphabet size', className='text-secondary'), width=3), + ], + className='bg-light mt-2 rounded-top border-top border-left border-right', + ), + dbc.Row( + [ + dbc.Col( + html.H5( + '{:.2f} hours'.format(num_hours), + className='text-center p-1', + style={'color': 'green', 'opacity': 0.7}, + ), + width=3, + className='border-right', + ), + dbc.Col( + html.H5(len(data), className='text-center p-1', style={'color': 'green', 'opacity': 0.7}), + width=3, + className='border-right', + ), + dbc.Col( + html.H5( + '{} words'.format(len(vocabulary)), + className='text-center p-1', + style={'color': 'green', 'opacity': 0.7}, + ), + width=3, + className='border-right', + ), + dbc.Col( + html.H5( + '{} chars'.format(len(alphabet)), + className='text-center p-1', + style={'color': 'green', 'opacity': 0.7}, + ), + width=3, + ), + ], + className='bg-light rounded-bottom border-bottom border-left border-right', + ), +] +if metrics_available: + stats_layout += [ + dbc.Row( + [ + dbc.Col( + html.Div('Word Error Rate (WER), %', className='text-secondary'), width=3, className='border-right' + ), + dbc.Col( + html.Div('Character Error Rate (CER), %', className='text-secondary'), + width=3, + className='border-right', + ), + dbc.Col( + html.Div('Word Match Rate (WMR), %', className='text-secondary'), + width=3, + className='border-right', + ), + dbc.Col(html.Div('Mean Word Accuracy, %', className='text-secondary'), width=3), + ], + className='bg-light mt-2 rounded-top border-top border-left border-right', + ), + dbc.Row( + [ + dbc.Col( + html.H5( + '{:.2f}'.format(wer), className='text-center p-1', style={'color': 'green', 'opacity': 0.7}, + ), + width=3, + className='border-right', + ), + dbc.Col( + html.H5( + '{:.2f}'.format(cer), className='text-center p-1', style={'color': 'green', 'opacity': 0.7} + ), + width=3, + className='border-right', + ), + dbc.Col( + html.H5( + '{:.2f}'.format(wmr), className='text-center p-1', style={'color': 'green', 'opacity': 0.7}, + ), + width=3, + className='border-right', + ), + dbc.Col( + html.H5( + '{:.2f}'.format(mwa), className='text-center p-1', style={'color': 'green', 'opacity': 0.7}, + ), + width=3, + ), + ], + className='bg-light rounded-bottom border-bottom border-left border-right', + ), + ] +stats_layout += [ + dbc.Row(dbc.Col(html.H5(children='Alphabet'), className='text-secondary'), className='mt-3'), + dbc.Row( + dbc.Col(html.Div('{}'.format(sorted(alphabet))),), className='mt-2 bg-light text-monospace rounded border' + ), + dbc.Row(dbc.Col(html.H5('Duration (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='duration-graph', figure=figure_duration),),), + dbc.Row(dbc.Col(html.H5('Number of words (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='num-words-graph', figure=figure_num_words),),), + dbc.Row(dbc.Col(html.H5('Number of characters (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='num-chars-graph', figure=figure_num_chars),),), + dbc.Row(dbc.Col(html.H5('Word rate (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='word-rate-graph', figure=figure_word_rate),),), + dbc.Row(dbc.Col(html.H5('Character rate (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='char-rate-graph', figure=figure_char_rate),),), +] + +if metrics_available: + stats_layout += [ + dbc.Row(dbc.Col(html.H5('WER (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='wer-graph', figure=figure_wer),),), + dbc.Row(dbc.Col(html.H5('CER (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='cer-graph', figure=figure_cer),),), + dbc.Row(dbc.Col(html.H5('WMR (per utterance)'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='wmr-graph', figure=figure_wmr),),), + dbc.Row(dbc.Col(html.H5('Word accuracy distribution'), className='text-secondary'), className='mt-3'), + dbc.Row(dbc.Col(dcc.Graph(id='word-acc-graph', figure=figure_word_acc),),), + ] + +wordstable_columns = [{'name': 'Word', 'id': 'word'}, {'name': 'Count', 'id': 'count'}] +if args.vocab is not None: + wordstable_columns.append({'name': 'OOV', 'id': 'OOV'}) +if metrics_available: + wordstable_columns.append({'name': 'Accuracy, %', 'id': 'accuracy'}) + +stats_layout += [ + dbc.Row(dbc.Col(html.H5('Vocabulary'), className='text-secondary'), className='mt-3'), + dbc.Row( + dbc.Col( + dash_table.DataTable( + id='wordstable', + columns=wordstable_columns, + filter_action='custom', + filter_query='', + sort_action='custom', + sort_mode='single', + page_action='custom', + page_current=0, + page_size=DATA_PAGE_SIZE, + cell_selectable=False, + page_count=math.ceil(len(vocabulary) / DATA_PAGE_SIZE), + sort_by=[{'column_id': 'word', 'direction': 'asc'}], + style_cell={'maxWidth': 0, 'textAlign': 'left'}, + style_header={'color': 'text-primary'}, + ), + ), + className='m-2', + ), +] + + +@app.callback( + [Output('wordstable', 'data'), Output('wordstable', 'page_count')], + [Input('wordstable', 'page_current'), Input('wordstable', 'sort_by'), Input('wordstable', 'filter_query')], +) +def update_wordstable(page_current, sort_by, filter_query): + vocabulary_view = vocabulary + filtering_expressions = filter_query.split(' && ') + for filter_part in filtering_expressions: + col_name, op, filter_value = split_filter_part(filter_part) + + if op in ('eq', 'ne', 'lt', 'le', 'gt', 'ge'): + vocabulary_view = [x for x in vocabulary_view if getattr(operator, op)(x[col_name], filter_value)] + print(len(vocabulary_view), len(vocabulary)) + elif op == 'contains': + vocabulary_view = [x for x in vocabulary_view if filter_value in str(x[col_name])] + print(len(vocabulary_view), len(vocabulary)) + + if len(sort_by): + col = sort_by[0]['column_id'] + descending = sort_by[0]['direction'] == 'desc' + vocabulary_view = sorted(vocabulary_view, key=lambda x: x[col], reverse=descending) + if page_current * DATA_PAGE_SIZE >= len(vocabulary_view): + page_current = len(vocabulary_view) // DATA_PAGE_SIZE + return [ + vocabulary_view[page_current * DATA_PAGE_SIZE : (page_current + 1) * DATA_PAGE_SIZE], + math.ceil(len(vocabulary_view) / DATA_PAGE_SIZE), + ] + + +samples_layout = [ + dbc.Row(dbc.Col(html.H5('Data'), className='text-secondary'), className='mt-3'), + dbc.Row( + dbc.Col( + dash_table.DataTable( + id='datatable', + columns=[{'name': k.replace('_', ' '), 'id': k, 'hideable': True} for k in data[0]], + filter_action='custom', + filter_query='', + sort_action='custom', + sort_mode='single', + sort_by=[], + row_selectable='single', + selected_rows=[0], + page_action='custom', + page_current=0, + page_size=DATA_PAGE_SIZE, + page_count=math.ceil(len(data) / DATA_PAGE_SIZE), + style_cell={'overflow': 'hidden', 'textOverflow': 'ellipsis', 'maxWidth': 0, 'textAlign': 'center'}, + style_header={ + 'color': 'text-primary', + 'text_align': 'center', + 'height': 'auto', + 'whiteSpace': 'normal', + }, + css=[{'selector': '.dash-spreadsheet-menu', 'rule': 'position:absolute; bottom:-36px'}], + ), + ) + ), +] + [ + dbc.Row( + [ + dbc.Col( + html.Div(children=k.replace('_', ' ')), + width=2, + className='mt-1 bg-light text-monospace text-break small rounded border', + ), + dbc.Col(html.Div(id='_' + k), className='mt-1 bg-light text-monospace text-break small rounded border'), + ] + ) + for k in data[0] +] + +if metrics_available: + samples_layout += [ + dbc.Row( + [ + dbc.Col( + html.Div(children='diff'), + width=2, + className='mt-1 bg-light text-monospace text-break small rounded border', + ), + dbc.Col( + html.Iframe( + id='_diff', + sandbox='', + srcDoc='', + style={'border': 'none', 'width': '100%', 'height': '100%'}, + className='bg-light text-monospace text-break small', + ), + className='mt-1 bg-light text-monospace text-break small rounded border', + ), + ] + ) + ] +samples_layout += [ + dbc.Row(dbc.Col(html.Audio(id='player', controls=True),), className='mt-3 '), + dbc.Row(dbc.Col(dcc.Graph(id='signal-graph')), className='mt-3'), +] + + +@app.callback( + [Output('datatable', 'data'), Output('datatable', 'page_count')], + [Input('datatable', 'page_current'), Input('datatable', 'sort_by'), Input('datatable', 'filter_query')], +) +def update_datatable(page_current, sort_by, filter_query): + data_view = data + filtering_expressions = filter_query.split(' && ') + for filter_part in filtering_expressions: + col_name, op, filter_value = split_filter_part(filter_part) + + if op in ('eq', 'ne', 'lt', 'le', 'gt', 'ge'): + data_view = [x for x in data_view if getattr(operator, op)(x[col_name], filter_value)] + elif op == 'contains': + data_view = [x for x in data_view if filter_value in str(x[col_name])] + + if len(sort_by): + col = sort_by[0]['column_id'] + descending = sort_by[0]['direction'] == 'desc' + data_view = sorted(data_view, key=lambda x: x[col], reverse=descending) + if page_current * DATA_PAGE_SIZE >= len(data_view): + page_current = len(data_view) // DATA_PAGE_SIZE + return [ + data_view[page_current * DATA_PAGE_SIZE : (page_current + 1) * DATA_PAGE_SIZE], + math.ceil(len(data_view) / DATA_PAGE_SIZE), + ] + + +app.layout = html.Div( + [ + dcc.Location(id='url', refresh=False), + dbc.NavbarSimple( + children=[ + dbc.NavItem(dbc.NavLink('Statistics', id='stats_link', href='/', active=True)), + dbc.NavItem(dbc.NavLink('Samples', id='samples_link', href='/samples')), + ], + brand='Speech Data Explorer', + sticky='top', + color='green', + dark=True, + ), + dbc.Container(id='page-content'), + ] +) + + +@app.callback( + [Output('page-content', 'children'), Output('stats_link', 'active'), Output('samples_link', 'active')], + [Input('url', 'pathname')], +) +def nav_click(url): + if url == '/samples': + return [samples_layout, False, True] + else: + return [stats_layout, True, False] + + +@app.callback( + [Output('_' + k, 'children') for k in data[0]], [Input('datatable', 'selected_rows'), Input('datatable', 'data')] +) +def show_item(idx, data): + if len(idx) == 0: + raise PreventUpdate + return [data[idx[0]][k] for k in data[0]] + + +@app.callback(Output('_diff', 'srcDoc'), [Input('datatable', 'selected_rows'), Input('datatable', 'data')]) +def show_diff(idx, data): + if len(idx) == 0: + raise PreventUpdate + + orig_words = data[idx[0]]['text'] + orig_words = '\n'.join(orig_words.split()) + '\n' + + pred_words = data[idx[0]]['pred_text'] + pred_words = '\n'.join(pred_words.split()) + '\n' + + diff = diff_match_patch.diff_match_patch() + diff.Diff_Timeout = 0 + orig_enc, pred_enc, enc = diff.diff_linesToChars(orig_words, pred_words) + diffs = diff.diff_main(orig_enc, pred_enc, False) + diff.diff_charsToLines(diffs, enc) + diffs_post = [] + for d in diffs: + diffs_post.append((d[0], d[1].replace('\n', ' '))) + + diff_html = diff.diff_prettyHtml(diffs_post) + + return diff_html + + +@app.callback(Output('signal-graph', 'figure'), [Input('datatable', 'selected_rows'), Input('datatable', 'data')]) +def plot_signal(idx, data): + if len(idx) == 0: + raise PreventUpdate + figs = make_subplots(rows=2, cols=1, subplot_titles=('Waveform', 'Spectrogram')) + try: + filename = data[idx[0]]['audio_filepath'] + audio, fs = librosa.load(filename, sr=None) + if 'offset' in data[idx[0]]: + audio = audio[ + int(data[idx[0]]['offset'] * fs) : int((data[idx[0]]['offset'] + data[idx[0]]['duration']) * fs) + ] + time_stride = 0.01 + hop_length = int(fs * time_stride) + n_fft = 512 + # linear scale spectrogram + s = librosa.stft(y=audio, n_fft=n_fft, hop_length=hop_length) + s_db = librosa.power_to_db(np.abs(s) ** 2, ref=np.max, top_db=100) + figs.add_trace( + go.Scatter( + x=np.arange(audio.shape[0]) / fs, + y=audio, + line={'color': 'green'}, + name='Waveform', + hovertemplate='Time: %{x:.2f} s
Amplitude: %{y:.2f}
', + ), + row=1, + col=1, + ) + figs.add_trace( + go.Heatmap( + z=s_db, + colorscale=[[0, 'rgb(30,62,62)'], [0.5, 'rgb(30,128,128)'], [1, 'rgb(30,255,30)'],], + colorbar=dict(yanchor='middle', lenmode='fraction', y=0.2, len=0.5, ticksuffix=' dB'), + dx=time_stride, + dy=fs / n_fft / 1000, + name='Spectrogram', + hovertemplate='Time: %{x:.2f} s
Frequency: %{y:.2f} kHz
Magnitude: %{z:.2f} dB', + ), + row=2, + col=1, + ) + figs.update_layout({'margin': dict(l=0, r=0, t=20, b=0, pad=0), 'height': 500}) + figs.update_xaxes(title_text='Time, s', row=1, col=1) + figs.update_yaxes(title_text='Amplitude', row=1, col=1) + figs.update_xaxes(title_text='Time, s', row=2, col=1) + figs.update_yaxes(title_text='Frequency, kHz', row=2, col=1) + except Exception: + pass + + return figs + + +@app.callback(Output('player', 'src'), [Input('datatable', 'selected_rows'), Input('datatable', 'data')]) +def update_player(idx, data): + if len(idx) == 0: + raise PreventUpdate + try: + filename = data[idx[0]]['audio_filepath'] + signal, sr = librosa.load(filename, sr=None) + if 'offset' in data[idx[0]]: + signal = signal[ + int(data[idx[0]]['offset'] * sr) : int((data[idx[0]]['offset'] + data[idx[0]]['duration']) * sr) + ] + with io.BytesIO() as buf: + # convert to PCM .wav + sf.write(buf, signal, sr, format='WAV') + buf.seek(0) + encoded = base64.b64encode(buf.read()) + return 'data:audio/wav;base64,{}'.format(encoded.decode()) + except Exception: + return '' + + +if __name__ == '__main__': + app.run_server(host='0.0.0.0', port=args.port, debug=args.debug) diff --git a/tts/NeMo/tools/speech_data_explorer/requirements.txt b/tts/NeMo/tools/speech_data_explorer/requirements.txt new file mode 100644 index 0000000..54d1535 --- /dev/null +++ b/tts/NeMo/tools/speech_data_explorer/requirements.txt @@ -0,0 +1,10 @@ +librosa +dash +dash_html_components +dash_bootstrap_components +plotly +dash_core_components +dash_table +numpy +diff_match_patch +editdistance diff --git a/tts/NeMo/tools/speech_data_explorer/screenshot.png b/tts/NeMo/tools/speech_data_explorer/screenshot.png new file mode 100755 index 0000000000000000000000000000000000000000..c892347bc307b8520a67f428fa470faedb35cc56 GIT binary patch literal 1135618 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
@%>MO5_D86 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ηTTZbw$G7&>Chl{QyxKzU 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�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 z zF>3Qafjd;`EQXDR5?Ab!iOHRPpF3aAqey*FJKaPWUHWDgE6S&@mwR6A_5(E?zn3!O zLQHFPkt!&kMluF}Q=OJ4dt5v4&@+x4t6d@#Yc$`&uJC&3>CP4zF5M9?Y@_Fd z^n;EJ7=0iOTp*DfD>a@u>GVtKoL(X>H)92j_#Ntoy$PqJ2`q?piRj(*r|-rMb*~#K zo(c}~GY#j+(KDK^)WjWnJ@xn4_V{mW>Ayf~jO=*s^uFb3#GZ4mT6f##8uyKhq9%&I zFPSqx1DPJp%VxBrvu(fL0nI-``!2%M_&~j1-|ZKm)P}Uj(x|p3rXRoYJwZJ9reXSO zR{P=2Amsk%@i015Fj`;Gn=NnppR~xJ_Gro=$gRDEdMLU55zzeaH~U(F-i&Q!`e|*9PM6rk=)OWm;q0b;=Uq3> z{cVRh74q4fyQ|ivkt11}G((JvCEShG#6b&BdZ>ASrv$Uo6R@hVXsx6%{WA+&%B+;? zv`4S_2ht%N&i(?&j4^;3LFwqzo3MyCVyCs3y;CUM1QGCbnsu6#1elIC13m3gR=$ zt@U2TqwqLU-pi*vTvWxVU!J>WG|3#3@nBocMVsK}kob6&yC9eTZ!yC3onxXPeI=3w zmjwXp-HacL^_rDSjQ%#OUmu8ld0mp3#_@|S68U&*E{@v~guFr5&@~;aRBeI%Q+=SF zLO67P4rJQ^`&aQ}wVDT~#bPv4*&J~{8sA2%M(~f9pp`>N?BDBiUW~Bq58^Qnzy}5B z`toG?`Jza}-$&;b^3O{gJRNY=yJ=GgENjxWb*nz?;-()pGbXr5B&E2S3UB@6oN-O_ zU!B`WzO}p1I^^bPhcV;d%VXlpsdj5sX}Z@&P!Rv3NK!dNJegGS-+Td-Y&%oYjW}D3 zbRllGpODrZO6456SG*?Pas%8kW1}2ABQ*_|CTYHQZgqMqByOx@OiI!g+MlQrx1M?h z^Hp}*A&1HxpiW%^;=@Pw+wk2WxED(;usKenNn06FePm18jCF!SKz(_9zVkAA@Td-c zd_Z+V(Z;MTz(Hw$(M#gxUsNjyL%6n&n6D*}%~pPP-bjQAoRxy+V!Vc=e31rrg~)~M z&4U+ll*eIt)BD_n7rw>*ZpxjbQd`R|F+14{PBRfnu9a-!tLuidqryFIjKP-1w~@qL zjaaQ^DN29uy6~m6fCn$6xK@AuqI|x_L^S=?wZ+vhYVHtihRJwJ&~@3TjjxB<3E#7f z!~2FP&eig3CdgVf_$lV_kvKa&n3DEhBXh;Ry~vkH|9~RjKatBS?{f-kbaEVAcrQG* zugthtz2h6c56?wm_o|&Tqed6%};D+c~1~34Yz(b~ALs^D0h25zIlijCus`Hj7BjNKQ{dA5;G@Cqc z-+6_i>-6@!oLNrCDfh>8*spNgh<07n8`*r~sP((&^DbEPdh2>XIW%(nQEFU+r5TWF zbI<{8_<|nw=01Q{E986~v96sr=^me2DtCLoTvxK?Ft}Z{#ud!4D$76j;?;W&=+31H(wB8+%aUT-v>geg96=^NQCGP*8Y5=nK> z|Ccj~*2nFC#H2(?kcoU%NIjoq45Lgn zvIy28rZ8l<-^5o#q@4)da^2NfZm{K#P}%M1i3T={g6oHAo~r+dswKz-#qJ^CnP04!6G$o*e=Fr008TTKSiJ900o<5m-4? zRO@udBV3; zoux=IHrl|V+t%TqMm|JM3VlB?TmRpMX7T@bU{P`An2UfWjlvn9*ud}O28dvy@BI&ANZ2q8q~C0Vdw^m zUUu+jpq^vMg80Q;gJ~U7HEsSt;^4k@KbcSK#mws@Rr3pdY9aek&5>r1{bHI~x$pk{ zG|}(cw1FhoA8M&4T$`=#yn!U)8WHcjD?w4SM?p6uBsqGxJ41(Krqj7I;lGuTBETcy zoKBv^g?+a6b6bw1q;H=z5nmo69%KC7goYmt@GQk}SLZ0{vrrUlIT~4K^Y#sRTJ~m! zrPtOl*i$E4DpiOM=vS~#`xfojX{2R6u+s&^J-}9i(24L?Z=SA3%D`TYy-9N?U$u8j zHuqAlhKsqK)<-=DIb|apO3;>F6!>{_!J)DHB%(hSptRR@=ilXbK&Mk%4-q1RyuBz5 zXX;{1EqUgq$N$>witvW}mVT>5{ysq6@{eHoQo+>TfF9{hfF*DnnC~98RB< zJ=~P~H>#%?+==IwgqOk!i^RiF`XNioBnZFrw}2=w3;W*NpfwI!(m6M=cpnqs2$W6^ zm8I=!J6o(T472ak3)u=K0;HdDAZ=PDMzc#J=vqs(RC3~`m!UI7byk}@3S=JMn!UVz z$;8pIaFmvy8`#gOxvGJ`b8IbJOXHv=LKE|ECH7F2@D$)JCsc(9b0LYaTu^cH^;k%62~;lFI|g!SHOB?%Qe})0gwqPZGU`h~uK~^bzo!xJ5R#45 zn)&6pJ2pUP-8`E@u(24_X-$wOqSDig4*z_A1&yv;`=l~v^yYmqgX6;Zz74uUkNn?| zaFj2!D#&jDfs7fCLoh!+#rhaizvrJvUxXU7RE&<1ecrhJu--!x18p%u-u*aY(P-S` zq@2+8Cy}>jjf)G+P8%+Czik#`9uvYve>+aJR&U4z?4rJSrX`77xtx??SBreYW17eF zLv?J*O8=VD6_ql+R~hBcyzEL%pFX^BW9`=RP<0SCi|Fdc_gC`IjWfs(mnOVg)onTM zLmr-4-o&k&)ps35>^|C#=lYk(WIe!77_Osw9^+OY)%X?#4+a{hz;q_EFPLWiqEUK49MCyU4QG*vv3Rk(IDU`{eiFrFb^6lw7(0Mk_m zD_)vm>Ue(x8~@clfil_s*;EKDkqHI=iLv|$WGDsRAh-Xia((?GQOQN3N;YNpb{B{T z>B%qWh*?NG3|JFlYFa`@RTtD%k1K>1u5rnab2rxH+ODYc--L95=^Q?nFvj8gEgDP? z+?7OG_*60gSARm&O48q4a4BZj7N%D^FPL@sm^R=KF8#(bXJ3=SR7LG#aDbgb8C+pt zq8?7(Ja57(n|G`K!$%Y>041g+QJ`pAfNpuEN_DgUre0vF3&H9_qucj2`4YV{IF>@4 zpk;%PBl40z!n|@Eb(yD^GGA&CnrpbZ#GZNq{bY0y65qylP=(X5IMQ@=G16<$r(ZZ<8c_u=FI_iA%+S z$xq!x5&xPmVN_RCMtg70k1kul^pD*!6**}l>lNWCrg^@cC~{Px^=+ z^th4v@(1G3snf1Q0MXX*2`3|ord2?NR7=JGjxAlZ|f511>cGuby~FlL9Tu& zaqkttP0?^EAC^l2j5L20*T~6c@cg=0&F9l<0Y#RM&{Athpj_(tiBkCYlm~8|JBfeN z+v`*H6&DSNj(KFl2XBzjQ!HAK8%D zi02i6@$wj*rG#MIwfYQS4W)`bD!#g|t79mkiwk398JUw{-6Wdx8gv@z3sHQ6F;Wmm z#&4IGt}?c0{})r|9?ygy|9ea=iB&4CVM<8l{ta{4Tq+fze2c!W8A&Xc=c|&{iGv1B8Is}~ z<>~Y*X?J@GoL0uGRE^e2Oi>xdO}@M~+5CU(%KuPkevE~x3BsJh+A?+BJ8 zDBoI)XbA8!h3?1p?G?$rSSQ}D|9+9mU?skK#{D+#R$-2RnQuRZZ9@&^Zb3>Z>*!#erzQ)IE=+X1gSB*KnRV{>(pQCnQR=Q*#7AQHDW@h6(>V=I`x--A?4BBOaCtau?Zbv-z(kj zC*XaF;FeV#gdvv5`u=%xZ)sF+a!s1s7e8ihE9sTtYK*}g-Z2(jKA(PK5UqKT>GWgj zU{YN24Tx9v@QplidVqRZaNLGisi8@zP9{2#{jJ6AM3Nv;+=Ks(@tjzKA}CFz#Zfry&C5RAMDC6#wLqv z<8vCubebQOuU-EQy!q<2cKgtqInL7AsC33yD>1%RYVR0JHBMq|Y8f){kd!`;jc)X7 z*PeV0`L*X-4$YpJ?F7x(Oy#?`)Vq1fr!MZDuy6lbiw95?J)a|-r_z)BnjTBSCe1}? z`ddkN`1NFWk#(!9KIPC|+4#Rji`NN82@W=x%9DY-vO6O>4Fr0a?VFm4NjJ^~Bltga z^%29grOp2?W$qq*{x1D|;uZG4Gqd-9$nLhvL9-QVwYNa4gcN4=8$Gm%&dlFKeu+b$ z)69qoNAj?Y2(68EjyZJb7!}R$z?p`R7U@aO{WXOqUuqe~o#1Q*f1nG_gJj=l$Rc)2 zWb#_`Gg=R-&u$KCkv`CY9dh%jE;4ea`iTMP^Y{6lSlTj+ z?h~)wq~R-nzp~Ti+byph{u{G>%+&7Ncx+$BS?`Hhk#iRhsQ*$zKcs$NB!K?giUIVI zd|s!3M7Gr?PAf9>AqDD(Y0__HPc{F+d0R75uMOL}Qz_eP8Z z;h~2PjUd}Y4P5rHJraZRook6^gtYoumzD3TC1W;=@fg(Ft3SOy5j#~%KZM)eyhXq( zYiH@wQZ27w<2*pa+IYxjrfJY+(atR>?9_-;IrMv~bIY&Eb^Fb|&(-hrmP@xw7mnSf ze-9pUySCCtw6D3WyRE8G8U=UxE7*plbmeocHad+6(nFG-TYDeha=W2uxiLN3Ro?ZH zh|F1CN;Td864i)-_m6biouL_~B8-`c5cvbMzzTESp&P?1 z_a1*IW<`r|?jx^i@mqkR*knzAw(3zkj2K{Wwwf}gD6#!~`R#=R6$Hz+a(LBjT^W)b z|3Wt)M}3xNm<786G=vTlEf}pq)u2a?ie;H$7k*LopD3E)=s;q!uaX(FI7GjZ;XC<4 zw{sf<)#D>SzLh5Zu*>V#P7US-?9M}VpyWTH(*HDf=%;4;J|u0iV?FrZ9ts2{WgXn2 zU9&5@of4W?&{Q5r=UAN`G#bcPrvH#`39KCztAqM7n8n^cvkviNVeDKf6 zF~lD1r2Uw`d8VI&L-3%251Gl&UQ4`E=`1b{j}$L7+Z?Hw?&BBihD32#cImMkV~3yjkYy>plpA78U_a68aE9_VZu@*P${4)_yvzX6P& z8ZPJO@%?U&p4Rq!4J_Pg-2U$V{TKDem(Hm~xP(R5MT4gC1T@&Q!wV&Wzl-&$jy4d{#fJ}fb(K|MNR zJ#>hPfrBO3I4G{hChU2+hl$Qh*!86K!JjABrbKss=_t8=}bCxip~ z!-)kl8q+@)U!sH_yqb6-O~yr{d>GlQ9s8>YX0_)1Ibh-2xC}+#r+PI8yPgz~75}xM zs^GZm|Dq|32oCI^uVB3^Ri};zJ(Oh696UGkBE9?k4Vaf%5^COk1_0KA(}v>x9vCyp zJr*>4fQ3;==UHmL+4zQBp^4VZ=CdXib0DmicW+Myq~ZMffN4}1GP>3GOX^-6_>1Q^ zx8wC=bAQ{#iZgV(TJIfs>KvzyGV+&xzs|41tBL_7RI96xCJ&h|^l2}pRfg#RUWT_m zTx516Yc+`IRY}&5jDec?i)Xs)Oq%z*d@|6sXq{2z%`x_~BMlQJ8+Z}duFRD}s|^0R z!mXp_O#T}y%?0gCM}$eSBmHRE%R%SqcN0OXuitv}zt>_o`dk;8kF}7rK_{~0yr>wy zzh+iU^LHuwLXx{fd9zBT9H-99*!%KEZEA8e$kNlamnfz_2P0VS9+mUnUXA8)0=LUP z*`6bL%QM;MpqJUZk_oJ`Exuxmcs;ThsqRusOZsd)w*7Eo$1u8nO#$dvW)5xsk#~zU zu;%jl2AMIVGvQEADwB}DA&sHh;j&kB_L}&Pq@q%$zD0WKNV(W!IWA6O_PRrkR26ko z$U|G^&|~*zr56nh({b0XK5qlmTQ6%BrNlH?w310?5O%3e`=8%cX=}HbRLm#oTwy>&FNL04vV43AWx{%g>T*xJ@qoK2=Aefz0oyD zEPfmOhT`BWx$pTXuWJjVgd+isFP~_OXzUw8qz1HSN$?{4pjq#1y&C!pfkP`hG2%W3 z1_T%+M67$bca^GbZXD>niMUC#Wz|3OC}=zq@35e^sUd?hyF&;L|Erz00TbN(q80kchmIAPFJA*Au`y=!!YC12s z1v+>^2AMY|LUT+CJ+8;Sf#cr#*-Z47oOxXwW~HkGEj-vUZ!dK9D#`kMDJrUBIOOX& z^#FdVCg<$jZ~!c*O*y6QIE>lyCF3#o2W4b!>cNN%I?13K6pe#KqSzE3DkQ~o=)LRs zJB_gM>Hjuaz{AUO#YHGgR$2)5PyUd@y;tS*%LYVYuWtW$OFg_{BY*gtEK`smZsAyg6&pm$;8G_~&_`YrQCbc>ZbZbZUWKQ$M;8>l)&cOw{YkQ}0{utNSsZYW~ z^d~uUs^Z6}nd{R!_vz|X50jE-r_ls?+|akdNDsxf#*nW>ZM6cAl?p9f&1-KNWQhEV zPSI#8yaJ(Abz4bsj(R04pdarmxFj?)nB%Z80B5SHCejCIvD%(-jPpZf&8c_tP`g8m zUpMOVjp7wIib1y+14B>g5*u%&0KG5utHYx_hO`VJ{^%#)toYml!w_ppwU|Z~tK)c3 zt;GZ4@^)rIsA?`xl>Rm7A#|Wt(@Ap!*(f6_ZnoRoJkTUrdJG+F9CFvyL3$21tNU;K z-pS;92OA!FNYGyJEy}$wStZI#Um1?B;TkBP*aRuNF4_m-5qyJMsbJS(w@CFw2}he( zCwsju3O{?7&~Bw|Trv8FrL{qut3;C1!XlcbB!w?w4ILmqI~God^do1=ia<24+6-Ao zYESHgZ_@$`CVGrU?8$E}w)-5T3%8s;hqTy{xj(YrW*1j2wVJM&UfQZxO(F42)*hEe zs1mwEF#xC2Q6)KB;e=bZ*7~|{k=@=lTCSUu&UCR5(d4Qs6MC`VreXg zNlHUZHJp!OjBI{bFN!JAO@6JEZaA^C1iK_l+IjA@r1V)z11yU2qgDQEs-X~CxKbDA zv;zx>6eryrje8KXkr#J65>f?nL2DH`BPIX zcJC;GJS!%i2hZIY-N%)=M7F%yw89I&RVO`^7p&rC2my z-?sX;&UMnfEv)7_EviP4e(QAVdY3Dtrdsteuv489%D1L#v^J~>c1=I`6(A*DRiv9k z3TT%HuJh-b_F>Ha;L6HtVA{FTBqktq(mOLmuyfNr#y_hH;dRe$RB8Rp81EV%UBcV5 z`uX9toD@QhA;YfOm_R+I+z}~o>cx2NyIivKJe#wS!P<}_|7ad2B!k{@4-h|NiT{nHK`ab zjM#*3^QAv$daS%m%Nk*6tzfbmdXMt)H98$t`fZQz4?0EFp~pH&Wk9pxbj+W%a5hy1 zZYXAfx-dPKSSJ$c<=pr)M@(C)i%**Dje(p<^y74jSrf0Io?Oz_Ctj7tG6mu*g_S_% z3HwrtOHUaoTetC$(B1!$h9AH?rb>_T%!c*Zsw!tIXrHo#hyR(SX+H|Jvr$a=b#es% zPeP|IaNg1Y+e=kQQ!g?@7{&x}$_wK8QZx9I`{m9>s9#CAk@SOzSS{!8HC{s&oP$+n zTKYSN2T5aP%4_W=mtq6GCE&@u-sdmXg!THnPo5{hUh-a6Zdj#Y>GemTlhgO-#hm}P zDX^1Rk>VSxPCX>ZaI?rVNUAzo>`3I7jWxoGt?!K3{N<+l+vNBMt2w%e+U>qG*5Ptf zgurPbbXW!eheIFCfH20bJnem%GYc0MAD^wW2=WCj{s zC@5L)>L-+}Zx6~`b$48h6@3gnjb5PGJ~o3T1;pK(R@VUI!xWl`i`qrf6jiUAC=-s( z2M>t(KIaxVLdDRcP_9a@DoI1u%}@q{j#ny$#=9TjDN1jBK^@@p$ z_mWKDJg`IqcFS5D#m>!ky<|OZL6%wm12(_DE;?*~s<1`L z*9qFc=@HwDi#=908Hmr8VI_iKn~UB*k3U)2{K5?FwPhMeUaqHmY6j~?(odirj^bBf zvg*^phT@o^x-vrJ-k~V$rOEyyUhq$6hF1b)%t~8~;?+-Zb7G&6o*^>sFtN|7HCMw9 zJ;xREwp&k)ExpMyvsF*sHd^lWFOl;9TeoHNW5VRXgZI*^dr6*gCS0X}uyPx};j0CU zdf-`KgOhdzG^L%I3A-y3dkPD>FQ5JXa|eGOn@c1?S><6t&@`?^^T^7?-Mae$oPyDx z*Qz(UuQaAYjiej=LDuTE2fZZ z;F|Q#JMXXEG#8@ed71aM#hP6yZE_I}dMkyXKkG<;ft zHS)xqE^y(ZH$0_aT9+84)C1h$Xq7){mz)L9p7MV-uKFazZ8B_BqvmQ&ar$~cJdIs& zSvYyRbJJ`$P4BT?S9a=NMHZZ&-P3cSy{O6gER8mWWOrCr#$zW(H(gqwDt->v4^${L zeW*Cdg4`S+$k%+8s4X2Q7RBm*4|u!_J6P5ah__R?tH^rfVX*0yZUqg-CzY4qAGbT? zsxMjIb2`!bx4(Ss`wG(SpX%6a-y=UIyhfZsA91)=evx8z!jG|MWiWT7s`nx!*6j?qn#G}O`0}N&> zC$*5q_lK{0#R7HV)4iL`k{yoxfEFj`nLh1<$VMK<`sH0d9d*^{GFVcrWx)dSzBMez zg7{(G*kERk+7R#@^L+5E;Y2kbMqgG=R>F4vn>iFnD9G~0qLd#%O9=Tdd5*3IFP9~` zqTm3Iqps^qXxi2tMOB8EtAx@&?mXlWU6 zmhEU%gD1_OKQLYzEkUt$L)(=>mexZt!9}8ePg|?feDh?oEhYpshSSz4HCOq1%fo@4 z>}TVA8)&CatOHj7!{m?Gv^$QE0Z|(<8Q9`AT0wYGoc;%v&P>M!kWbMbLdO}f^e69Y z8BjFb9@!gC{w!+w>()y-Jn!U$^)9Am&rupJT3h@|9!;X;(t4)3B99Nh`z$7ReK$$TF z@F5MY`8DB+>U61-!)e%-I^`=#Jom zCT07_kN^41l8gsgDUKzUw7!^#yZT)$_8C%WJhnt_Nnm;=)&%jCHg@5mA~siM>8_4= zp|t{n#KOC6a+ z-J2T~Dm{X}u>9mZF=5)Y4$Cls^lna1_2XfSx*#6_(#} zsz_^2?CvR56hR=-j4AgQc3&cEO> zPC?w#ffvh`Zo3Y%)daqXZy1H35yTph!|A{Zk_`{4{I2vQ87fT5IE7Z$iJ`=0iw$3& zx36dGNZJGsXD!08FlrY76}Vh%cwcWp{=uw%r%=)zacAye3{Dz26Go=qH-XY^>5lcmYB{Kus zW>Q$$O7N*7ZRGI{6E~anh<;XEbFvZsbap_M=j29C+{wozr>tmMl;wp~4W;ye=h$=p zodrW8bgEXogooZzke5saH6!DDY~TUX0f&MSh5nW4!v$WhN*R|zy9YDF?tYLW+edAr zoB&I*8y^*TFV<@*<~ums9k+|O2J>3=3pU;G4PZ!b4QXUHSRK*%;M`~BoZUe|n!}yb zZwEgtB8pIT>vDzoGpyX~Ws}n8nkw_n&8$4;n(nWVxHm6=k5YcbOy0uPXfk4@r!x-I zuRNOaZK+Aw4_mES=#ME3Y58|=Y-Iy#kb-sMC(oV-k;{E=P6w&B!XvBQGL}JuH&;0h z3>AIDrRHL%q2kx-B}4@jfEcCv_n+V7&+12=7DN{2X0q@God!SlwA^V6h=0G0jnrR8 z@FINXx7I9tHp*)^0kS{r5fyG;(u)Q;HLThxg#hEV3?>vA1^-cJfqd(Wv zoR0KQPzU`j_OCYL-|XXdTPCu}QY#I=#wX!DCWE}&A^u0o23SsRBr9ot6v=A;*we2{ zL+2({LcjhVz+Ta2LPyO0LZ;qg^}|C+GI#e4@WZCWnlC0pM->v$@xdirU+T^3pP$W@ z=0^=&vo6u}x@>;_M@GkBs=N;{pTXG}e&7T9ptedyhcX<&?z~k0asb$&tue5C@exgb z=sr$;4w+Y5kwaK#NCXpD0=bihUqyc3-}my4>q9gwZJoGRkg(Vj^JILrxxL!VF1+l& zO~;jMciTD2nlb#bDV=ed+0{Ta~4LTW6VB8}{Y)=zG374dM2(QaI@QMu2W6~eg?@r4-(fQcyi)j(! zBPZB~<7g5;#Q3B`XuG&W)ST#k`R!nU;_IK)uDi0NhJH=Bo9^!>OYEYA5|B~eiNV!Z zDv#PYo0mLb#BkqijR(HEJqPGr_N-rd!PriUY|QGq>Nq<7)>g==a&dAk7!YiEO=JvC$6Q)%}UZ_1#m_ zE)C=IRXuR3a1kEc89kD!4gpkTea75zzWIdSi-x~l(>3YdiLz* zJU`I5&^!cpsZD_wS}HtB_dT59kwX>p3%va;6%=$;X%qX6QXV$bxCkRvrV?N z^sCFd=djVSzk(jtJhYTX6@=4l;2IMc{m7m%{9`BRTs>PKA+JGHemro$OMWTlfn?{Q z4b8n=o*H*ku1eLtB{-JKQpSEstr$31b{mYt?X7%paZBBc^)|-dVl(+f*Y&R-f>WDo zSRa3?{$jY3;uh%sBSV<@#Yv<51LD}Q`VXZ$Jkcle?I97*k?%gyFL4t$=RW3Uu4!od zF^s?oiv6j6#WlHnYE|Nmk$No$Jx*_em1Ay(d5Bc>FOIM^&=pqH7;u0zJd6FjB7N3p zT<8`m(tao+z~%X%LwZp()4sAQPt3>wd2FCm-U@&BTURl%{!>F+3}S^PzT|#+ZF>OW zvv+VoRA-#su!#2yi{Qj+h8qqWV0@kw;n{1Eg-c7Ytic>OsV%Vy){}0jgJ`3RJ^AE)HC3$NZhrBu z53A1pAMV-MzkM>nzxXb;_WX1D7usSb_5V2=yz6hS!~vA`uf+Iw!@@C42&4IqBae6V zM^4dbQ1sa3iMyMAzGol(org?aL#H`gpquV0%G~-rV(&SPXJH76v+rOpX&s8|YP^ER zJj0=YXLl2Jer2IE%NHOHZ83|XqOzdMLqo@h6e*}qj^Ok+XrjW_H)(r^uez?{PWIT) zy0f_Vd-uOr^g*2ySxpI>z1k)&6Lm^{-akY=wv1$bi`PRw6FaqK4mX4-C;xGO6RPLW zNDH0j02yFd+6^9=)p96<1WV;8*60_k2tTv`pN$YlKD!5V8|t{&Dpjz?I0K|rt76O8 zw%RnlYb`4FW-hfPS}8rO$AiI-jf4)sk;f=)U0F*5q#_*@o<}TO7i8$fy@&Zb7Ti|% zS7k+tq4EvrX1NZW3Or}fNM<4MqzykuNWUEt4}kq%x(M_DVD?Wx=WHY_4_Z2hbFwY$ zhtWOq`3A`Re-6@H`32C?N~yL#$kiE(T5DwV8OU~w^TMJcwqAzuQDDKn(GW`#d4cK3 zQX`}^^7%rsppcPL{eOrZ8|v!l#2R6)n9OiA7SM95uk?z&q^AnUXyjvb`}^;})!WqC zH_1ZW*lSK!N8fT^$Bz2S>Y)Yvjzma>+z$9UgR_TdVBNe#kj_-|*acZq^JG(a?Y##o zwZS5DAibdMY-rfKaB4_)UyMgotQJYUA`|+zPqKZu_F8L%cJc&@d@57jd$05K&6rKa6tyA zUCuU>CD`PCYyVMFlXbYKWi?ocJ{M#4y%0s~R2Pa5DV3t@d=kFXjk#Jf>Eu&ZYrT3q zQ@=C3vI}x$!tNWwC+`#)TkW%aDX+Mi;!H$;=6Iiqi;UtaObSzhPPJg~^Iy^bk*nJ> zwn9#Jy=jlRuOfTqRa(>e0*>ZM(2xT~@DJznw0%1Fk{Ta>lUS{KU{)vKg2XURctA3n z>M62jOmQ%Z<;VumC5g2{ehaTs^lRi{TlVQUS{Oohj&Gld8Uy1q1(@lb4BrKQ-jyb~u#a&%w+4@uA|o#jc94rvBz*1mT9CLew= zwW>gQS5y3k9y)2wL)E|Ii?!1S^j>v z2AF>3-leAeb8-G9gU#2)Q1Yk;K zmNH5h)Xa+~pwfrq8l;Ze@k#68`W0k62lUHDDzI!HQb@7io#(h!!a-836J15ERGHCn{Szo%#dV4-_hwhg>gZ01J@J5dFGLp-&*J5$ZwFCNQ1fQ@En@Tg60>-SZ*fRCDIh)Pwfaw?2 z&%Dcrrq#=u2A2iK%Vw)^m{X*TlZ9rpnr&m#G(LcX;(2cLF3?AR>FgrRWK@6hv>rAy zTDr6Bewlo=>27CM!v|T#18f6C;vE@TZEUYML6<7`i1c24Q38gv4C!)AvPRA1BJVg1r(!#8cyZOL}JRGZfoHtcNKix;y|QnO}oWPXi*SDzgQ*Lt=tzEJ}vUrH<`KX925 z)!8?Ol(E!9zcP=?smoD!bH$f7kW~MRiFmmF%QT=7*9|7C68gHz6e~2k-RYU>t8hT; zwA_j95YBx2?4O9{B26p=^v~pX^;WW`q0Hz2&?HiGQA3#>$p5HfnEy^3SUAsP@olv0V zC{-ExP@;u)Ax}U3xK>nhy@yc8c|N1+(%Y;lg>%|h>PO_}6vbV!l_j^C+YbwC7(_F~ zIi%m`M~Eda-5iY?b&G`onawm)<}LnpfkR7ij@7t@$WXOytEjknr2Teae0G^C`h`kG zGNp)ZNXw$1w1y`rK0>e?lgzoXX>01#Dhz$(^o1V2?0QlanHq(^w52%5QVlw=$p|x- z)P7a}I<&H@fPHrZAhKOpLAof~LAOj(+*Uh$ER=;F-+Qh*=e>I2?%}Y8om(S?1NqRp z=DUj*k?ez*W)C(IMg>lGIBrQz)e36`N}J8bR-g5XF7c4jrD%JR=k*I5-hUu}ZB6wY z8*?7rG?bnW%{O?gF96|KhGc2du34(ZW8TLFmHi3IX4heS!{-gXU02T@M5Ky|R3prF zo?X#d2Idw&bEwziwBag1Ai%!V?+M7KVGT z@ET|l9ZJSw*5N+?T|U|!bVEUcU+E|YVv?%lzsc)0c$uiQDoLo`W8>l zEH-T*MH;2%^xMXE{vC+v?iis_?4QUH!qSp71EV;xq7SeaOF^8@OFLI;Vl6Qj5;y%5 z`A#h@UEcg9l==QOGdE?GBZd9|y|@(m=!4xN%q zs;lqScW5S;9ShJIQDLr{kC?g2t;4V19w+amSP(@u9(mo2)Q3IqFewtR$pp;!Il70o z;@-UmLwRW=CV=9`DBrg#j<5GkI8&+~)zrQ8h7}O^!hrg#f985i_KE`UTI7-|@%Ci~ zsqVthljpV2|0E%))#?a)30Q!c;drCSY;;YUNg`4pcWO_!+420p_Omi^pvytBInV&< zS<>YfB%;s(|DpG47W}nfT0`j_M&6dH8~4AY*UP}mYj?sZ-~NUvE?Ky`H->Dh>w3*0$S^woa`1Tv$Sr6Yjs$L{4LJn*ieZZx)s{I zX7~n_{m&PsH>ddYFde$puUGgj^^~&B5^fHEM>*eMp~(s;jV^W@HnVXF#Jp zvif99=#f5qk14zo@>LpP`SZFc^f zAB~;57Ui4($2)K=cuI&;AITOD=+yfn@%*2m=-^Q#(fiF=se78gh&!0igi8#-Hx^c3=cFo*B=EqCQm&vwk$OF7mb;Qd z?M`fPo{{XeXr65XW{VBoaE!r02@>RJLrJ^gjgP~iyDM`$7X#|saq*z1&%^iT-Wo{H z97u-yrfHLI?!9^+^cv|X@!E-yxFf`}4a%Cb3y%uGVa|h=C3XNiq2329zDgRV^Ulo} zNcQ7lSE!vg6L)}|GU$bs(>dxJp})r7JCV}0`W}`ff5*u#&4V0h1=6EQnd}JukFQYH zCe`Wzd<;0u7^(l=0xu7=r-wi)K>B4U)sT@&w9tVySpGT` z@kh~)pMg#R0YU4HA&5=wma1{@QtPQW0T!7i(3wlQ_^6bg+=18K4*2@jC0Chr$lg7f zzpD?}Ooi*?AIrV8r&gKe#I7fMP}TFjv(38zUS!sd#|aus^O6R{bQ{{}C_I4vF8$Cn8%(a|WYFX3P*fNp2-#9?Avby~TOw+DKr zUH#GJ*RZGYC{1^mg4b=l-;5j=oG^5ln*ki{UD^7pEslykCjBt}kvT2fn{C-U+proO z0gaTduQ0{BK{0<7z2}6pwjtrj(#&#We$rZk3m7C}F*B@J{H^yaurOR{HF9ZmV*A%9 zbRWI|LV06IkQ!EC#C})X|9L6M@F*)|GCPD7T7nQ-?yTRy*|F6-4N2W$GxO=`KTZy3 zIKRCcVr(~Za7>_HqzhNCG^MTmb}V*>IMj2rVSB4*Rf>9ee!%yOi5@btYnZ5Tq#kCG zU2^}#nx25b{>II#M*kWT;}rZaB+5II+I$xVULr`i)>6o3EcgLRkR!WZMHS11_0$RI z(z>MtP;W{~r(XmY;nhVs!#XCMa^L}fbbbaag0MrW&&eWzp%v&j*4d4wAA4^n)&m>w z9QpEfQ|?i#N!eJ6i^#eUvH1jKsfEc>^F!E{*NRT;QnXvQTYDA&*Y|{Q-p45|!i0ak zY!HdAH?AjVe9MC|y_m=rMW`3*YM1w2h+-%nS zHLx{tYV$CL;Mp6-?8`!5%Y-_7^kxV=OM21ehNzi7tcegocEkvS z^|GZQ?C8DTZ#QnDpGotT$gzow{Zv5dj=+^te#Yiqr>(%6P5`n}?Bjqn>}ZMTgr0K@ zwl(ySsH?^C;xPyy4|cq83rbnq5q#!Uyid3XC?)Ys{k|bufv1>aoc6cnTIj|iq%=lp z@Fs?Cu6w^LP4aNfab^to#{Pdq70|Hfddy4x2p9=4Hu}YQYptDjW;Vu?l5N;R7uS;+ z=m>Ucj!V<>GP*bSspT52&vDrqL}`|c1Vf<;n_*uGa?EsL)(>@1DLKXrB;MU}{V?zB zzdx;-3mL*^WWO*$nDC@W!XRUW1AN`)YOwybkGlZs?o=^i_>-f&tmEG5@p?L7&?BMz zBroqoYsOaf%j{0@5pw+x8|uR~lbH3F+!!%-4x zy0T7e9Q#}vOKB!`%lLcwjnP*pT@uzL@Kd2P*v^xF z)?sxji}6>!b6<#pRwZq_8=Z2zu0vP!f(kDp^k+cQ+b_|-&(o0^MBr(?6GY2V{(x+- z(Q_|e0;jscugO^#c%XFOPolV9nEzjk{So9osZ^(6qc%|$jq-oQWGB`B3c9usQS}}h ze-@byo#fP>7|io|`heO@(o!LO4gGduGJg4r#=i-mL&kpqQPpD!;nS^kf&t|T_%v-~ z*RX|P2;;b)m=!fcO#z)Ot4J6Z@hV|Fr5!DB@wXt$Ws5h3xn^ww!J^!ZMuKmTA-pt` z0tp*~fT@=S{V1ATSSNJskW2={=GyS2d~A0{0cvH2K|4kf&FejNKFb<&l5zB-uJAC>;3qXLd+!h zLW79QxngNddJsSV5E~7ARd4Zq{93BpmlYoEW&OnBJz(iP3sSg)ENsTxPH#5tt96~e zl`s@gXv8ky3HT=kJK?wBhE1be$W}+eQ7fnA6gx+#-ms~U z4ZQjVea2TBJb$A;Jj~oU^5XjR`s^vsAiQ|)z=Dtg5#F^b;S@FLUX!uU=Z1@T4h;{^elrIqQBA1HasGb4ZDF;*o0}G2<0mFq;b8IoCQI^bL8Dwcbu^*Ah@GW1yir zckZwyKk}xu&snUcZfD{fuoUmzYtT;czR>^6zVXIK<$laY+-@(*yXy4x;xKbYOhEgA zK>gTu>);R4*sHRnHW>(XdiD`H?kLs}a@1k+`QeF;byjk+@i#s@*&<{xuXFF@*kucI z$kXLmdH=EAKGoCO+B)lu5=@&6J%Bmq7RtF5GUo!=FOCa7K4s$KPK=Q*)bG?{rIlHJ z18cIS-y2Tg+{Gi1gCM_YvHq7m8%E>miGb;<7?t{$^8nXIju0*4ld=A8hpyHw_ICC{ ze0&zb4ZZ8D}T3PfTFijue5HDcOlrzP$@Mo;RL9#1EyotV=^So!o!=_}yL;MuN? z_nk2Nw(6<{_wk4L^ms5p{ga8*Sa$A-?N6#hZ|TnCt8JnkT2s;Si`DELZTU_Zh`wqi z4zfht+w;CB^*7Jbd$c>erYjgt1AXqGP1QlORVp3{EWQC<+a>C(%lz2{42B{%moBPC z1l=lQk=6)T1;2%O0|xDCbaT~!hOi`Ek=cp8!9PJ12z;Zm;i)-9AdTMu2ac|hC}0|K z>=h+ENa}{z*Bh#_fKT22npoMzy4T9|N;vYqIDz<25?t!DZk3yOuFed=z>v#q$Md=6 zWJ|Uuf)|WBd!I1M3by3^dt}%*>p8MxE15(I%@pL=j%enG-tJTJ>!8>#n%b$&2rp@> zcGlg0m3expfGRaFH=1Z7lO7f3cCF^@TfFdIoScRA=MUYN5v}-K#l4}+#kqNH>i}D@e&ymidXz2(KAjA;~({^|4 zudO*yo@1)SG<7FZVonTo0drM2ISabW-oZ4~VRnpuXm87n^3h{bRH-@8WR_(Cd*V_Z zL6{U)oTB@TWyol{7JBR{1){V9jGP}OxrXAVQtu4EnR`h%T;1||`E!Xh!+Gn#u=bki zTm6i)g$*s!fQ*D#4Ds>kBu^&u-pyv)x1rXVK3`j9TGkKjvU2W*m*qAI-E)}|+;V@j zW9p;7OKR4G3Nd4DtU6669B^jj^^dijqW9{>Vx_bfTNI0<@2WwYD8*h*-@KxAJNB2O z;q1?eLEM7ha*x7(rx>{IHF^TAnOjQyt(OQcusLTiA8vXvUs7H1SEnwS6+JfVuRL@% zU^e*rOZD$3djltg8?2mm8iK*AdHVc?85)cLn#MN2G9J z3hT?8Z#>nXnbT}XJ_bBr8cAqYfAB;CHXGhssh-@6#NzBq&FXE@H1}Oz}t>U zcv#kdOFCIp*`G-wr|!$K_ZD9(aGVISrqyyCA`(#y-%xtT$pCjn_aFSvAcCHwn9jOE&t9u6cw+Pz} zPd7$6stWA5m?sO_F_PBEo(0G%G1&Clc*}h&64Ol>WVex};B{1@Bi`R=+_t=X0x&8h z?b2m`cj&{;4YIya!cRT`45N<6WCl7$u=8&lLU^khI!}=?j1!PptYeG{tN1D99&N~p zqh?dUJeSTsUfkSGYBnTuMxU#@LNIfuSDi>|F@sxMQ(;FMy}SM2V=v}8Q@h}aO>@7x9KzbC5AzEv zn)jW*NLe~D#TeRm*kP52*`Te-3lk+AxZ~6n8M_G1n&86vOz8(HqbAo8ll4S#CU@~4 z8*UTR^P(vX*htt=mlx}s)hCbXDNbi#e#>A>t`r`@cFLMT7K!|e5iK?n8^_s5VjB_< z&bb>fKK^JPLhR;-XUDhZ({n8k^UzBS?DO#5%XLrNkKBgPD0Q1DC=qT&I8j(?)QvsZ zy+)utuOVmJR_9ngmED|2);t{DH0CxweI=EE{O04e|u3$@jhKvfi92GALE~GSv+C<+1W8? z2|vdkgZ_(;SjpvwLLUMqoxA2Qjjq16ba5QXBzxxZIYemkU}{+y*Y z1hn1!%6trkt1L6Zzok*zF5-zNt48rUCpAfo z2;FQv!u&kYmXSg86}9>4cvRJ&!Z zvIe-5!HAW-{Qm{t5E~{vqL8RDFI&o<{;9$7XOG+IV;k}#vD1$_#p2R+T_dmpdd+?K z4sq`fq3yy+o6)CdqyRpj^RbB<^AKkVOz2U$T$Hha|0b|XbQKv!hG1#GuQQIPkrjO! zy8ztkRNnNYvSLk;`_?wm4wn#+njU$gcnj?KRJqcMr%TYJ`~{C_d^?(a-l)x@Aun{Y7SzL@3)GK1GMfRw|UoKKXNBc+G{e4rGi|XYL;!x zj37?IKLSr^;^7u0x)TRS`;FM{SIUJv!d|UKYfRJ?bP8gBYq+iR9F_5QM)kIW&eOV& z{sN}?c1U~%e0!>t1T>HdW^SG1H^?2$PUqY;J@a5PM|u51VIree^r`-_2Y~0_=QJ|Q zP;b3Ts`=mogF(bD)XPPFHc=V=O(rAo4I^!+1@o$9?PBTuPuE$s@h6X$O@EG)EXO`p zj|!*@o6l3_)x!Pm1{XO%Xa(Sc1WrB%+kbLZiBRApLr*MMFKNSES7A-`L2>eG`Yvx3 zSoM{{F36l}OG&h_szO6pHf%)+o_~yzabd}uuU`(MiG&cHfR`bN&lMWdwXZfrwBoh=$N8-#5j(b3O z=>gf+^Ru5Y4W2?p>eWSxrxij5Tei=qRZK` z;Wc`!=}usuz75S?W$mTrVhMJvq53&^L;`uMQgPi`7hL6M*o~)#am&SI6~HPDBe1Bv8TR!p?Ig}v=HLS^H@Fk z?N!5#Tz3aX!< z%^1|lHb@BcelV=bPgaE5ryFwR07L_D>c)VgR!n~iA8vH%iC*H6C`{`vR@XMMBRS>j zOIai~kN$uT7k99ni&E8p{Utd!hq08w7X8(YM?g#MWb%z3=Alo7HhizwMc3OWm*dpg_ zyhFBc8zpSqURWAGzO-|HP#U6Yhr6(X)70O7pHD6kbtP~l_aq+IX<3< zW#dl2t2~S6YH|jip zkhp?rN85xQ+xB!&^-RQsamA5QMUj8sIk*c4an&{Yk!wcwpT*&ApuZ|^A? z(c_UV1wp^|9}Kz23P6`wvfoRnJ(2bbdL>@31C8y!_;$LvkKz$g!MCpjDAq%|AA2_` zE^TSuoSK92#Q7V!RGpiMrjeMhdp}2Kcdsa6jKBf?Rt+*CrP^Gy!QZQnP3ZB%-)Zy~ z#0R#1=Q<^pF~?fr&cxdevm$T6|0vrVI=YiPkF9{74^Rw9>H281geQE|v(>MV{c=_5 z%{lx^t=PK6lOcr1Vny~1dZg!iBA9{+Oz2Ru;ToXg#PZHdz-i0%evK#tALEKq|Eh8a7kRAw|z47K9b zU>g|r2c77Rr~Uvp=~aUkgmd>g7uwtDrI1#x_SbO|l$K5TuV+t^OG0)GrnPo>g%t(A z&N{5l?{g+V6#l~IZ!zB>%KHcHP^fj&@2@Z6=d1n_g9X5}l2hSjYkWX&9K9*uD?Nj1 zX#6KwUZA@A?{@q(zY9yns}I8ksb3uvL?hxrM=`>5XN%;Zb&0Z3N5)?uo2H~X!jyHy zz`VzExo^5*sdO@iIG25Be`|V1Z6qOr$-7)4obQWuAFRVAnqTr50c^g}f7}tLOxQ+W z^M2@=mQ~YM`r30Kqo0lzE7`Hk-E@ln6;D7NFW9GRSb0_DOAp8ty4F*E1fvR7{v2)s z#R&O4*~$9*JYx54qR})@Pn9jt#@^u*-hR+lP)of1w$tv9lmDXOE@hfTr+2FtZ*${{ z=vUQ4^yiXWM#7|ceSDR<^i1=)h9gIx4l9~Y$FO^u!X>59?0p2;#!{N|-{WNscB^A> zp+>~{gnuvkYJw&NKz_SduPzb;R{~OQZ8>!h^lu`DC7JInZh~IvB4D`OYcictEz7Z| zxN5k1o1-1(F@U{X^81ztLZkCZvx2_pUFbO;xT5!(+(s02zL6&@d z`tUtT1Fb*t#n~F<%J8>!o?KJ_>#17L%YGTMB2ZPvpwoZ6an(|X##N+-W{QQA&K{QF ztC3LK%Ff*5Q3|VYXKDsD1r`dWmVk7aqVRC1$v}mSFysTr!;4g1g<+abq9}1z#Uft= zHbggm2k~$m%Y|!WqOJtM4_@i*cb$$iIgni|qiF6}$#z$B#tvs}#|_Z`1PcVv484aa zFO&!Y$LiFAmRA!4!4vA&mKNsX9wWxRvgZ zsEVA|%vye?nWk@VvgG#nW83g+3S+4AIO#&&di8GvHB6cA*XwS?r{GVk#lox2#H2?u zPLi24!`!dir58pYK*|?aV(Y#-bb*E(Dt9Z?EXWU6qWQyX2ViJ>g88>iZLX=XR-@1N z>B(L{y{AaCN5p%wiSZ%r#tc_wTmyt%21G<&>FgN;eSYXoO}AVoMF))nZO=&a4cVHW zVJy^jIetCZs@na#O-X(ZwyN%q)q(pCIDTRSUyjsfts(D&T^x!;me+i33a{XMQh_$K zZoXd}zM2=6|BfVVmS!LC_8)PGp_FZM3LC7RCj#~iOli95y1@RO*awqt$I4^NekuK8 z26>d}?+|pIP=(=(8djo8)LtXt;x`a#o_ua<^MvLCZpN!&^E|LCysm<8Z)l$FXExiL z@q0z(iyiqo72RgqH76=sr2n&deU0`VqN5as9i)og*FksFyQkmjg1>dI@U_;3vCqi3 zXZ7x$>>pQtvt1hPn~YxAjLF|N0Z&Uxjst&45e`^EAW|K}4vKbRu z&46B(LJ4P!lD+&rF>?hp-Y{RsXuBd$!k|pDHS`NF;z$& zo&1xS#w@_}3bmkbl4nKUc@dq`+%b1st1}9p9!2KYer{B>M7{g9r|KAW6+4=>HX80G zS+m=t5q9IPaO4%Zrv*>TMD>q~Z39+6pGy(pG}^P=TC+n+fjRT#Dnh|pVQt))nA;@H zm+!Iw--sgo+@Ss7c#HMukj=jVlSi}wyEhXtQc@zVxAfQ-2C$2NA@F4Oie(jW>F){$ zs*g4)3@PXPZm(9jQssUXvOdq`S=GBcy2HJoo}+tlDhBm4eZO+4@`$SWouUuy9|!d! zR759o^VH1UJTHx%n|~?k_f0EyI$XOmN~vYR;e0nCvi^nPejwTr??M}OmYzipXfQ13 zQJ&WY>Rr@1a(I{q&`QWrDU`ep<=5i211ro)!kV^qVM8bEV}pnCxtp~+Q+;jvHZ>ix z+baO^4{}@CQ9VBU&$0KMjE_E#WOGWMFaBjOZ!{vTT1(9&2gP-BVNZG2Je7aLPd8is z?_1y;rw+sbrUS2patL3$@4dOdNb{?zQXIAa|8@Hf(v zwm?CsskC?N@Wz>nA*sqy_XIs;aYdH~rq|pdLBb}1@9E17Gdw6$V{z9zW+cf5ll@n+ z-5$WqM!`m&@L;e{mV_ah&_6By`j#tlTd+B`j?<}to)|E@2)1gS{bF1mnj4Zq$j9&9 z!R!krJWVh2&lu+dxS5cptAtx1oyANqmHQD`lRp@h=Mjv`gft`Hn=;sUt{a%y%@d+t z+SO;px`tnL;$W`P+WszY-%9VC(pkm`koTXf(DYAMQrKHBlcz0E_2dh8DF6B+4n8~4 zg*e}GS$1i%kfdiBJi zw%36Dpd}F2UC|*8LKNWR1S7D$O~2w4p@$WfRPS<8frR6`1f)=9P8kaQb64?A;5m-_ zF>cckDP1gL4Zv-5f6LN|)TOxOMxiKb?9;iy)T|w>gpw{(6kn&eO(6N^qt2AzWKeQ= z1Gb#Q!B=!^#|n6MVgH~V#cFh9Wi?vv33vL0{o>n!DVL_dN2_Tx>>T_Ff<^3iGVO3X zd-rMemh&AHor5jLGuM-w>`!F1gYM4y_Dr}0Dh{mIFc{bYl z7jMVFs*Aa#mt4ATo0_hGGL?ep)sMaeD?>(SEMJ z13|rkn;g(}^Txhte~z)5?C?KUD&|Ru|LQg6FAmSt3NMsA4SSRW5M|zdIeCuEw1GSv zKeuqX*>HnTls(#w3ilmSq{(Y(&umIgw}QcczvTFWiO~V3y^V3_#(Z;2PchFW%maql zU8dC$F%imab@Is-->+-2ZkiP}7{m6n#L&WPunVMYg>2Gb^j@Tss{-O2+(TN6^h=-Y z9|t7afo6EKFX+!?psLb1)mqTQ^AI`wL@&Oa;*IcJ5gUqcl5^I!`&9t!wOI6_Sy`+)KvOXi9~ zXUsroAh}cWU!vC`XtxOAH{c%bJl(bzj?WU|Ag2}EqrsQx4CXy&NK58?pDghIWq3KBOjB)0-Av zyK37n&zeMaH7zp#epp>Yx+pfso@fXBa{MiPEbP3@)}O?^P>5Z=-RSFg?PZ3jko*t! zB#rL~ixUgTK*SD7isJW{^Lul5dB()hCJ`|IoezC}R)=c%5MzJ4@8)>9zKm1}@C#w4 zv^McV6sD={$I~GWHVz02vM^J=wXRE%Wte-P7ChO>5W)mSO+F@yux7sxOyLKL*j?H# zdLhyo`FZ};!%~GLHN^U};-Nl4Y+XqOSwi_M={4yWKRMUNQE7CtxN5#-JNE;+@ETpJ zgdEV|oI*{ZrnWE{UiiRo!c(GLI>TDgXC|1~)cK&@_1|JL2Lt8b z^gqpuy}{OZaZ`#~htW5YHYG!Wth%AyA)b5?ZUA2V)&dQzh3xf60ogOdD&G{+PA?Nu zPD&F}(w(s}{~l%qx<@obuQ!^{#IzCaXH5)6v8QagHYnZE%|atW6eN4G}hd0Sbr{K2l>jsE**`_2jg2 zQM!kp<~~m-9U19&PY?hP#;@J)lqLK=@ZNdy56BwTN6Oje>roZ9pm7okH_osvpL!mo z#`g3-lh=^CP>FPn+U_Y8p{FHaRxhdn%22SyYD9r>z^~@su#2R#T9xOPkJ86GJBm
C78xAg3tK4FGL!6ntEg@z{=^j+}WondV<(tu&d{~1S zBE0=||Az@1$JTNvM?6;3gG6na(C`_kD|EnFoOt?=dh@agm^q^W$W{umxIk#4-E?k! z8IFx1S7L!j!HerVi4dB# zh}9}2#A#j1jtlis4`}zBgLkGhT&$`{9L%zEBVH1$a?bU%L2(g6#Xx9@L%^VT$(4&f zB%`M*Z8mOU*iX*Xzay+Ry(YEC!TY74xBn|vS5yeca+*>EtI__jO;`hBE z)$G-^9oiD>tr)(xo%X2HmDM(KP>-{0r-QsVD{Nk{n)7BH_gY5g9a-!35i)8Z2v zJiZ3-LKns{X770do*BD&e@w`i&T8(ffk+0NC!6FSoKF7fZmkzSsKLGt{S(a1-9AW& zhWr-`YWoM)NShdng{hJ+(zEgj+3wWg?H)IVR_I zZ{(q`h4Sq|FRdt@kU902M|8r9lJ&32a28}O#){c>G=8g*i`7Pn_7-@^PE~Wy7%3G{X=pik(!?PlzK>o`jY! zxL_l>!%@%vTNv5x;3ef`%(7ox0;fnt?hPk@&kPHwI|$FOxEF?QxP{)Bfwz_9+pqGl z<)dntRPDAF=c5XBz+#7Q4j#C=5|MnL4N+!w#A;D4o4NhWU|#&AXoG8>zQ_0{vfxrp zPAJ+H@+n0k3kJ70fxcQjzlj)ZxEP{!b7VQx+(bNfS_)cgxoi|NQ2OB*CzaIALWwtF z!+VU==^4vSfcE*Z3{t;lI;z_04R7SBng?b9^z^Ym zefz$Q1G65E%>qsiBv0b2({<^zH@-4hBCe24T+4E$-W_^WSv~)_q6Fo{``k;xAmR2& zu@JSOr_U-Q*btl&Uv6y3#*>}>PrLqCkJdF9qB;&U)1OSbOJDxb9*POIN0DCsD%z`WX?wqkXmI zj1~iVkL~rZmHN~F=J70)o+J0uw+)>w_i}Lj6Q(DLYUY6bL|)M#Wb2O_o^k2)H}Osi zx~B(?Rca4udlhi<$!9RZ>{2DU)OVip)&ADg(m7XX9WbC=nhKTtL$5yY`1wWc@*ssf9}`^xmo( zE1*KYSQ#NI^S}RCNToHHw4e^PQKsH)ooL|dck^FzR|ZRyY5kWJtP?f2bmYlgDFy@j2Lf#14NgXLJ?Pvdl-WlHq#p?!rH{DaIq38h?(cD$hX74ZKWUo zo^B~7&lFt=7#ty%t$77*3X)Xx3*+0b0d;C46iz`7FNag3=%8jlV9p>CfgLA$t3i%C zyc1^CzDE1rR~poZiDwl#xJb*cu>_X-1gHY;J~cO{xXDtXJ^F7o%!+%Byz1%O&-?u4 zyvejw5u{maY3A1AZn9)^9tZO_0nXZS|# z!~}GyKR3t?xi6s!?Q6DC#{l5#C<#0C$C_1aG4S8-^m}@)QPnQ?+-plZ4NwCbRj#`u z>6O|3Ma4>0zKNH}LbTD8*M+{vw;Qx7>vY@=8~M(WCagnZjr{^pRPVs}(q0t^`btop^`$7epErh)kdwOv1GrPEVvs zD0jJ|KN`3(%_ODxpgZC-hof4o!*++WJrrDJ^_?3`UQSG+5=14Obp6h=xH$!fv?=Xg zJ_@uF1Il)WB_wJ#&T=CP2=!G+B(uVAq^u!bpRR|q!w(_;Uck}u+dABELc<y4*3?7+ZwvEc9#1#ifQaqIs+! zciZRwA%w=&TMjRSWoKeviH^r)&Ck(}EUa%8$7*!_H*|7Ka(oOE2mTw(ZRMBgV~)7b zbqzgZI2#{DlZGhGeb5Vijh%+!?x6gN;iKcW{UyK%?0fOx>#ydHx+rIvt$yOg`Aw$N zUsEoDm$t=c?Il+$u9Hi%Kvy0RjUJEZYV`)LC+jSDI9_#B`h4F0k?q0D-y01B&pz5+ z?Q1~zszg{Pp?b5XQITKPR}um{zHVfm_q`z*_@$Y1VU)4jnVtAC%Ref{&f3z7qm zep$gs%tUlCN9Y@8Z>3XTTW{T60I2a#%MD-fxWWrzTM5qLf;CA?r$ra}VmtgFoMIoc ztRKJ2DOiiF!Sx$g2$NL7E@#3uf8%e+_*1C3#t&D-(7A+8(Z^I?P5Ge3P?W6Z^x@^~ zQ@@j6X~~ahO&jDq%Ka-9>yHHr)XWrQBcCUzxVnKTwbufqy2L&52r4_+uWjCXe2Mjn zRczXL?9DQe%Tt0M@vw_GH&pX4Xz3VUX)GytP~xlKT!X83WN;jxhX!m=yja-9-SIJF z>w*A#yaV%T#d2?=AXlX%qDy=pW09Yw@%+w|Eu+Zl@JRsEvpa-aP)hAT+nIq`9J<*P zyp0g@kknHg%Ntb~4D3=t1;7rGEFF-!ye%JR+GBWNNs`#Q9IMBEY!cR})FEoab^0c^ zQ3ZUS#Or|3$6)*`(q~6@w=5NzhGR9qqQ}|~&f~*C8HBEjmEHS`t_K0eDr{LZ@6roz z2in^Rw-Yj+C=Lb>|1eNo$Js1BC{@(Y}>dyF0jdzY>mrpSh!RJtKgJ_~qIQVed`{8)Je#^6nx*_EG zwWRjlxkNs6X~nh^!tu{IJdacNOJz;G;$?N``=@wSsDb)Y^}rr~soBpxlMOB7H`B7$ zM+~tfuR|P(3;fKJOp@dmnM+Tf#Kv~K?*s*ZM|6EYQLX~=cqJvYAhhtkNl~CAyfgOF z=fuH*Qr%nV8&HdkS}ElQ)t%Hh2zWR?L;VodLPl}u_ib#WNL>m;JT}`Pz3ES#psknZ zX|;PfgNlAq{Y84KD(yn?x!e!nSmX8|ud)VmA0^&?E>zZE}flgA}7SuM{@-BXZ0<k^=F%>2MNdk4sgbO6inzr&RpKG8094am)t%^y1?hXEh;bZHVp#7-E_`amn8o{kk-yx*<)SOvF zvG>1Mx-JPn2QTcweGGXwbwb_5g`!!U+kT(4JiV$0`?u>eE7KGx~~E05y4xVJlY&RcXUL zUzTO?=c!SdmLWVn*1ty5^eYFxAAcY5X9QHu6zci1bl$NGq(@$&5zE>ZxRbjWv{dYFF#B7a zJ6oKf{bq960u9)>Q#YjZw}5uaz$H}PCSBWC8lcnUOI zaBPTgRKarnn@_l39P8P?#C7j3(;d0Oc+H}n<1 zm1T8w)ur69a7tLZ45*9J0(3R||1jwJzMM6xduX6>gA(t^9)DAX4bCqDT~TyYa#UnI zDO)sG^wm$iGHdO%ZQ>L`g(pdl?P{NFj$Zy-9C#wj1e*Z7af&C9SsbGEYVJz<{%b0- z@qN9h=i?kn0{eQ<9=|6rB`!xL;{NO+&pV*N18&EZCb?n&vc2{gp6&(AwCB4%eFiCt zjhPS~{z_dBO=`Y-(T`)RvZjRmkLD`*hls>Ky!TjVEgvj?Z96J@F@u4+{%r>2w7wp4 zDNL(mNL#-m>%3~s^vD9rWp5Jz?boM#1{?`EriuxAA1M`(uvD)H*HbK(W(G+6-OsBo z5@v~84yOcYbt>_~%xG}fe|37(ul(hJ`5yCQc6W57(#2i$oLhT_OX)rfst0u@$&_1Ex#HnCp3&I6=2)ot zNZXHp=3%?JUOs4Wa>J;Z-Sbs$j!*+~$P7>_rwN39@{E;Al6=nPo^*_N77f*>4Z=S` z5hc2qL-;{K|LZ{?3HBO9jZE&Lfp6<;C%^v*cSn$#PgPAOp^q|l7ym~5gZ|6V{i&52 zu2ebelFVx|JFnc0!B73`X>e@uO}6V5=3#PBqOJDyVj!YDuZHQTZ=KsAg!-U+Kg`+J zL{aP77{)RBdYR^i155HnKQZ~V5xD9p?c9esR*RT<6F?iqLP#s{aK5kY8u)JJ^qwv! zkg8}2u8J3b%jtuz-E`cUmxWeD%;$!o5~@dHAF#btelB!A-B^q|b*#SAAul8;{<8nb z!f`D|d<{tb^`t_`%p@QyYeGRuWF^*V_Yxg-r18E+X}2R)r}To*6D4Z)-KC9Ir|7Y5+gE$~75Pf+pa) zUHfOj$W=q=VIpqMj8)FJ?agrjmb{Il-jbS7tCYgU07(Ng;^Qs}QP8E@T-d7LFlt=2M^t^CpV=-7Kl1O*PWNP9W$evz0$sb0URfDM z6V6I0qlhaM4c$z!&+#%b$Yd12|F#vyKN4|9U+@f)_Sa3`vyi@*r>|hilXE)29)5oX zSDiEVyHVw=LY1ZD?1rvWBH`jaX}HsHlFFIVTq|WvRZTkS1ajPmE1c4FyFv}ENEq$Z zd;}Ko9ts|X>-K5Mkj%d48OS(HDbQ`SO|YaUIX2dQh%cjBqLQH(b4bto$B~JYnTr)| zhqtuf?iooy9xYy*IZyozDi~cb_fE_bIPB3q56=Xg?@N zj1@U9nt|rBYHaB!`Rzw~8w%&bj$^!h-ZZ;dkUq!I>U{zl$M+c1 z@`-C?Fr-SLrm`uFkJt`TRX5G*?SgET2Ng%G^O&ywrSAGt8l2(?W(M4`_Q{8jP;3Ob$$OBB=py*NdH?eDAK&bm{S@sp)BcQs+t@;1;vq?z>w;7?MIkxo)J!96)!CLU zh>%YPXsIJTlmtCSv?6zlBV4xTbD2ltS;Tt>V*Q7gGxGv;)1)*g?|NVTlcH-!@6Z|jcshhS|D z@*!-J4A0Kkk?v_uo3DT=tw|$k|HW;YAiD?I@0BxQaqqZKy(^LDGeodTg_Ho#)eaQJ zn(#tZWDKQsLav(NN)=Xi7LEn%_J$zt2b}J{82GV4(klUQcIW--#nHZu$C{@>yKdHin zrG93d^c2#12~T*e?$!?CzjRcl|Bn%L!DYb?Artw>?d6B{fFG7P88u)15Tm}vw@zw* z_bJy+-%NpC2I;u=SqIj;Bmm!>GHV0RG5BEMKa8kj;Vi>Kf9En^k7;{+g+?IzM zlypy`eq7hW_NizRZ!EWzh|t`#8X{Fcg+Sk{<0kzbny-28WQ1Dly=_%G4Zxo?O2`C~ z1kR5GuO_9h2FZl#J3mxtF8CWOrdPsJ!Sn7FeD|uHzL$1M8al`nbP@U3C6x>{#SW#Y z4#TlLGL|m6rS7@ztw`Q1t!d`4xLau(=2d8bz{|0`0JKXUgGWW}us%v$(R^Qr5=!lm< z5tv&2{ujqa)c`Llp@1+MT*S;oF(wMK?{%h}XB)8IabfBGnnfL?;Gv)WfGRNJHB#wS zotiVguJvP(eS)Fpl=rw#gM=tN7iEnW*Uh^KW1d+adJ?H#FYu=Ng_&e+E>+-X|Axzd z>S$e8+RbSIZ7!F;6!??IQ5=zWll4z{12?(g#((~&R!f|U6d@*x?9od>9dom;;ySUo$82Lo(5C8 zUaL>UHn^@c^EW>C0(r5hY7tiA;mxZIzQLZzq34C`HF+)&c$qiNQT*WLWW>6AS|w4) zsglrm74#1EJ2sswZ&7$Y0-pnsuW#;(V*JI-+B09w7%U*KNzXq9G;3^Bd~_ac11%#p z-@o~!+>+-e#hbMepBW?*T>7;I`OQ>DihmF=Dx&XseuHzS{R^S%3=4(-;DNKwxxJQV zPMoB7Ws{meEh8R4ospk<|Ng~{!BM^bjR3Yh0xD2(Q*eEt{&1<%1ziitlWg6?Sc@zs zMfY*yNtbIx`UP0D?qk4=h^>EAoXI6%Q_NqydWM#Y{B`6#od3^CIR_=_sXK+(QU)vX z3+WMf`QdaOVegTu*c3cjt1`koW>DMhYLTU49GGNKoK5(Wt^S&B ztgot8xCTD5TWd()zSU)+x|^lS`|iUZyZn3Oj3g&KyEPF13LhFj#k}Y|g|z@pN$06V z)+N{M{ug^s0;(<&{MDtYv9}{tPj*pzWg)Ho1^Ch(ki(-fH0U9nZ~Chlq?4E~qPh-C z+`hAu?tOeNZwFP->o})(3-@Mbj(iKbWk9EVxUj0biR222pE7&m&TZcwZW9SO*2{C< zcGef=R^iq$78AgD&57mv^YleU<^%5lbcYzOJkV6}or zx+pUp+nZffK`~hTS$B>nG$H*75)89r{v-~HjUFiSVt!mjM5(@lKBwd=QbuDE{EHJ* z44ik5P*Wx}S0DHW=|pPS*>RriG+zqAf~x6r$>!<#ia+GZK3J4E8Bs?-BB7 zI)#tzE{SlhhC3>|{Fdmf?^LBH4LDXQO z{S9K2o-=c3QAu#nbFAYvp{J86)!OjY%ZMwLHvX@{W%UFQ4zu?|U*^$9tHP{#O^JQe zV#}Ii8uues6ky#p+yBiKB^XSp$k!FLH7L>*Jc59)u3qPYSC1D-n?eo>wD=PQB&ht} zfSH#EDJUoOHN&ZRxqql#p^iVJLFki-;Js)Z!IJGXc^MLRHW7aKS{-@+^yMAy<$Eo1 z)yxsDxw{kz?DS>j8ZR^>@ivblxV>rH13;&1*e?|J9k7E$#z9z+h~l-*CAAJGR-ENG zD&t~>j|OU4r=hVUiwS6i>@Y|0C=3RHp<)1BOaTQPhGBFgTB6hU8%DTC;s{n6E`kn1 zQW&6vpCfqAvZTH{>m#0yYru2<7&jl9MN-Ar_aQU`Y4lnDp%%a*TEtC`C zkr8a>6xgpzN+@@JZum6X;WZc3G?C`2*T9I*lWYJeZLHo+;GzB9|Q=^r}$it}SxwFYbY?8%f(~zdUNVTZEJgp8|m0H?ncJhlBc|?$%HLIh+3^ z4Mx!Y7q+P1Q~&Fb5WN>Rai_w#3mf7YPvw~k?%VULZR#9u1gxI*V?X|7M@Cio-JX5c zw0ReGm|D6W@xjtMFh3F5&wox%v?SozkUz1DzTPZ69@E0>5a6>=3-pU?_nro93GZab zrj}Sp4TmszUS=v}R39P`u-B1(-gb=UK*c*1r+tHU4l|z+M(MBC2hGqwe6h5zdh92> ztB#vL2Ng3g2B1u^L7!B&O{kVz5{v6Fq zOZWe4c{z^}r-&e~^`@r3Lan=95hU9cE2A;oR;#L_*SpF|`&AG~O`mIEb_PDJ>i>Y5 z$=o}nC{$IDvl5XYkYC9qwGqsuy+{0ytp6@Chn~pJD!*!405NrOP7n&qbbrnTbE*NP zAX9f`NQg^IB^#IJp|ZrZ_HqRe$kH2a*vbVe@9!LaSyebpoZ4^9SOK!^rvoAkz|#U9 zzsEu=eot9dh#-nnVg4eY-hSxOc66 zPZT?%jxGRt8zM(BEH1&P_mKXR5R)Iiy_LzkTW_2?2OOipRbk(Uvr0aMTk*|+8OjZ* zZ7lcgI}vLp0ZoNvbjXc*u*{%SA`a-k&fswi@%-jYlX-YuzE>j(Z@2EtkB<^&)GRYV zCXeGj7r{2V-?n%DtXwqMJh%|U;p_g)XKJ_*od255AfLyd4IYG7N1)pK_pYl~Q>t#_ ztYjL_=(_YqSMQ(81;t2!GMhHhpAh37s4Skpjvrb3^`H(r}#okjTlZTb^E-aGIb z>8L<o&U!4`swKqNV6ZlG;QX(DkXwgwPAk3*TjGdqx=eH>hMkYpL(mJ?5&%8HB(N+3Fc*dnYy$6$_IaONJAme z!MFFwKNWRn8Mxk&b!?(JQI=YKK#R&ITqlXr1Xp`*Z*-XgGE3EP{ICi!Z{phNre~A| zTXURYgHng&_;2b-(aZ2Qfju<`^gM>k8Vab(3=bTw$bqf!;?@+Q8S;{ zGF1lGVyg2Aj+1+q5!j)Ot%I6#dgyx3&0 zI;ir#lmW%ss{BppE$1;ALuCZ=0Ztdw8!zR=)Wv7~`Fz ziZf&gqL;$OH@T|HSWD=T3NJYsFdfQ}Y|Y;guXPyR(2^UAskSFZiz9)C;n|jsJBJX@ zi+e25UmW^rJeqDI;tF5=bgg8~vLnSUe()LQsaHG_skGfsJ-<`IIr^rOynd&7cw2ak zTWZHFd{*dj&=MY@x^spd8@gB?zKiv- zkWiS;Zxi{AX)`3g$xhZOuqU37hCP#iA~ekRC*$VPp%84Xu$?6sna`x109Kb8t%SOo z4|(Nq6z?!)72>8**r%0yXAg}=DTQ@a7p73&>E508l198#3z|u~m1z=5&J=S3qqr*o z@4~`7iAw0i;jiiwzw+*B6+p1Tn^}1$M(>IcKhv;>JVtcG%J<_!(gw5=UQb^#HH-^a zH*TwlU^^Lw)fqlN)1U}UN?X1KEvQo_)Xq0IrvQ^wxpI0wE(Sbw&}3LnMLP(Mlt`j5 zUv+vWGTS~ai!ExOkRVA(k~58y=%?K_;ze=gMvSH&WzB=9fK<_$B*DZXZooL4pPvw6 zqC4AJW0_k;rboBPcB+k>XRmdu952}$&Ugo~%ZzxbHD$qwdNhbO6;vZmVvnn-8_pBF z0q7fqleLM=)zFdlvk5wnmI?=?yIrHFBT$cCg+1jwyN&uZUpe2Zw_z^5i8~#vm;TDr z<5M;@8%or~1`%MRQ?k2+U`%8Is?Ti0PTM2x)#&$|sBbbAn0AUxl6EwW@=EzaN zHYDr4a;SG02^FjmzHa0@v#@;=2&;5t>JZ+%4i?ZR#I^E^ZJKD@2r_%guYAL)0826q7|ld z6yX;#IEKs=hWTg${*jL?nP~jkR|{tycvAepm48rJ^6B&I;FB3ZOuBx+`tjMmbz@&* zZncNkSKzy}_&QLw3I2(Ty%b4&Tm&d6rC}W#0MYv$j!E z(T|u(ke`ilu14|4SZ@|i$3=Q48aFxJa9E{F*aH+A(?7(xjLIG&npt5oM&Xt5H?dngaDe5Hg_u1(eRkf7;hSOlGcq>C} zapLQ>$eX;SUg;eZ(IGxRG|ADXmLu>SZFAIAo;oo`igM^A=>L%Q-hWB|;lIDDd|N5K zv!OYtT$!nvd!)>dp?>{3AzMB%y8J`CC2S{Jk?G+F^z zmtQkjU2RgJ$dD^;BVQQh4@`Ixw(@KMKC*qLUEG5hGns|&=-ElB&bx`_FHt6nL-0_2 z@gBuQFCu=r+^92D?QRhwfTBY^aQIdT!E?B_H35Kbh)z2y6<-iwV=FK}vjBp)(3{qg&yN5-wUfKR~Te+*XM zDKY{aaVnvDgql8g+NX2(YySj7f~O%HVA6SwRjoeY{WF zPKmG1lhjtc1o(WiDwArJXN7gPUokncvXlP?1pT=4-qRLaqleDSjoZx&M|PoC*=IiC~>h~5jo+6w*X3Nn>E$zB}#<6($df}w7@#K9p5gk z5&z_h9Je<5-;Zg`c+rg&y%@gHxP$ir@dEnCJuCdP2Kh48*Df^i8~#|MSqS-Ts5NK%pLm0OQ5^h_z=#sQv}e{kjVKk= zR~Od!ke_8YR6#noTVDg!=|$bZ@r_hcPcL9P1iY)p@r@JLF`(p?rL<5Nnd}@444%+~ z4Ox2nfxsBvlQt3~8i0osR?lQV>Hj5Sz;G#F=nwxHC$XU;vXMJ4k_sZ6+kqS?zr_RT z0rpKAOTyUaZ7XgLmh7|QWn+{=mcW{DHUJhp`<27YA%ONU6UTu6WldaTM1g`5K;~rK zA3H;+uWb7!ce+CrW4cvxZ|29W?zB= zu?A%Ae5(eHR1{%YOG^sOR7Od~ksUL&zDNB{T#*c}yfgtMP+l@Lfa#^6K_`Cj?s!b3Te@%DNGaA-3PZfbc{Q=);|4$Ku$iKKt|{5 zY->;F1OF7V!yeR!t&f`uom*?>sgYo~&mI_#BaO4V9C?ypAo>TovoW z(K;NM$Cl}i<0R;5l|ae7*$NJh@K?nASodh>js3nxNCT3x!G2F$?c9r}^|gfOZGQjp zf2#i3ogtj6KVLR)r#!~&*np=}sg+4Wpyrc5<^w+k1x!ER1;NTS6!u+t-}(M|sd@5h zELc=3)Te_BF?)X-`p1M_ zUif?xHcZJm34GtD;rrKe>v;9tW3;%;r0#Bvc-7i}dpYX89#c!2<&WZIh<_8y0ajd+ z#k*1NL}bBJKVC7%^gquBS@r$=zB%!7Os)nF2MF9|AVh79PNuqZ$j-=C)mT8V7a-U$ zUuJ+;`5<$UAXem;XhjG)FP}f02L}uX4LS**Ack8lh91Z3+#1&mjDKXeWa!glz*MnS zdjI7w*MlLmsokiH<7rE}8NS5u`;I%>PU!x)W>>wxrvck|ez9=)sqL#ik4RPseD}r` z+XS<1Sf z5?4#2+(Ld+;c&evvj>gJh@GgxI>F*2J`GB6m-i>3`qrAPP3h!Zq-Rn`7H^k-L)HbN z>Uk&K44#mk^dS`EabrlwDr}w z_oyebIId8AgPH12{G)jxcnlI*z#3zi6eyJFeft1?n+y;UL_R(`n3sQ%lb*m&dtMF zg4P}}oSiEE4f_;k)!UJVJkj!TulvWDu=9w7P}~y+-FK zJt4T$DnRn}KMH%$NsmgC@Yd#TtrhL>V4+FnsviysmiJ>Z9S{8fuKu?+#U1wD>zr`m z>?QP-4u;s*0m-vF&2x0t?b*5?7DAtH0h*QQ-G_E374AmEV>veCEIW9PMMxr7J9w|9 zOKz*etY5&J;HA<)LGV6{(Qw%g=UV!r?2aFm#NeWXgF8*-@h4I7QbPcJi3kDOCmksE zJXN@;V6KfB;V8nZ%Z(q$1?XTDgW;Izu+bSnJ`R<2SkD({R zu0Bp{lbu$w)qGxVaiP6|7b)PP;!#%{Sd$+}H7yj{6$ku%oHb@2g;}UGCb@Z;9_&Pw zQzMPCr-Phm&y{H|9_YQZ!!i5Oo;YyIX6jsXVB+8zKZ2i6tGgSg!Pz?y=?gL-tst;= z&%@M<`2yRl@fZ#VG(NX^ysNG>QJz2DEQF@oSyzdDYl`L#E)OT3?LB>W&zs! zmO~Vh;a>-HxM8->)2gR!LJw6>aUNjAGQ{jAER8k)BI^EUD$Cn}%)GGre9a+f8|-&v z;5g+pr#u`tsl9%C51dmKWF*$BYrhea*Ae*lCo>{?>YMUczpo{(Ip}l2x}@0VUfs&B z=>m)9RQsl#NMDMty?%GaD@ET3I4w-v8N&(|5+DFCP3?F(Xn1n2E?@fYQy zK!)X|lCKAY)4d05RYctf)=rB4tH*qZAyLv#M1HXZj<+f*oT2GHkKjz!)npN_j&$Bq z0A8x7L)FJkvDWt({7*1f;HHJR6A`D$(NcmO$i@=hVrsjfV$P?}1{(*U-YFDB@X>k% zN-d6hRZB|A;`hxDbP0jDSBefXS7Y<3UGZbaVd%bUN^pwQ>^t2X{8JX;*niSF?2YR; z_?K-=pG3lNAC7Vw@ukBYE14FC-<;vA+20DiCI9*zMs0|wpR`}Vt`W?R+%uiH#t}Uzk0H%2u-K)C)5JyY zuvn(T`JLcI!i0}QTC>FuJrFo^fqi!G@YdXgs|N?fL?lY)8Rb=V`FImq8d%%AOTmZ3ZcW9LLyPmH3XJ068wJ}&vMB)*v)iz1g+cOl7UkRGw+QW3+6zhT26>swQbV71(l~A{pA-*WC^~N+>pShm$<1@>^Uw$w zM71%C$q@c^M-B1(4k?3R~TehnE@q14nF0N4SF3Oa(MUug8+O* z^JQmJeLtZ-{OM6x7xl>D5)*^G+>5$SoV-+ib@Ep4bPpH0s9?zKvKRoA1dCZYZ84JA zS!d4~ntBsJWQQn}hV}g?^7y_&eU2liCN#5262bpqG%>7Vm0qzv>3Lo+$?vzD1P!q!=5Kd2d-bJg zq6bSsy@!wU9|o#2ZEC*jx`X9B@5b%xPFzN~ShQ}Pbq6*G_joF)%5mA_u6Snq!%cxL zbPMy4DBT}!LXr&U+3M>CKO|8 z+h-Lp#(4moSql0g0Ow!Q3z`9;Asx19mx;nW5jxjx#!z`!^Dq@ z_v0%=21Pitm$sj`@eL$KiV^RR=DwO1a06!OR)R!a9nGlWT&^mO9Ww1EMl>dB!I!)4 z_8TT|mOqOaX@isi4(tJ1C|sYR-B5_)4D|B)FA-<#DK!tQi>{~+exIU(*ZOuZD6e+M z>Gzq8|fOTgHFcYJVFzY9eQb@q_hhNn zrq12C0O}?wwBI@+?7!-@HJ1O6#W)9shjK|08e{|s17mG}RmfFMKxdwe{zUD>rmptX z^8~OxgA}t3AI!vY^25y)?>|7~YdUWBx3b-H;z2__{wq1hdk5hbOLDB-75+*5#Hq?D zg}ISUnPap+D~Y!%QEj1Fv`uMCh)NZ3-#e1LH;PY;Rw_4dNy{uy!WQ6 zQh0F$v^Nxs380_EE_m&Pe>MN;(a{^^FoB5+QT`EjwKpcgjmQaXAM9+X&xQ$>1sf1g zbKF^}8ZNy}_`!ZGo^Bas|q?JRb+IizJ%em8bRkjE=X7NNhcs(UJaa%jC zwIi-NZFhNBkVHXs#!!n@%F_7uHG)nL zQ=6)O?SB>y~S>+ER$txSJvi2oFkYvC%q_;Ad) z(85!4@OOgpZsh8mdgmJuO?oq>M|m|-d3Rntnw*Y9L+`b$e-^W~oPkQLlglD5IFO>k z9@Eo|iOm)Cyml-Hf!Q7juH40iC04mkSuE^6fpCSj-<@1UhsEAHHpR4cd0Mq$W&>m7vZ7|(x|N1a(WtYCZx2zVXe~FtQ7#Y^STe-g84>@cY;oc<0lMPdFQKle zu|9Dgn#l|6hL^N5HvZk%(VOxjuZad4W7ngvntBIYbH&J!VG*5PqKHs>3%HVoVf5`} z4Mz|%T|1~xKMIB*|NSH_+dpMa(1OVS%tj?#HV&(Zd#8(mIwY#OeJ;tbOKYhkzlByv ztxvRJoxE<^DmW<&eGmue7I}$VSs#=OmyvV4VnYfdh}Ax(S#TN;%SeSJqp|g#Ow5Av z_hhf$&U;_Ez_)d}e8HK~DCo*wsQa;cZ6p8irc5vOZR(y)_}iV$%GFJSW~SEcDskCM zC15(}6JfQ%6%b|D5urnzaQ^|?4t#zJM8|UnG+U2kfO2yh(i9*SiUn*};)I3~(papc zXRJ>v;pEj!)VFIsq%kwj=W1N7VVO78DnOUyF)dmK=UJM`I@-`oo#yTuMq*vlM(xA4RdwWg}xx&2G&FblQ%9#&B0GAg7^Qcb8~n$ zzDZ}3IN>gL;i{ZT%s(s1iRpeZ-LJlP*u6TST+uYTG#4pboYR|_q%XwuDc_N6bJmxi zc5=Q8dBQlY7?@zM<#6?LYY0cX(t;i{;lwMEQdV>R_0DhAUBMDlGF=;QV*p7-|Gc_BzSUw_X`QDdPN0D z3J7ULt8{Y2rugAS(`qR0EAktUuf~E*B>n`6S9pA2Eyq+tC&H~x5NQ|6L^!rQZBEME zJ{hVTJ7zeJv4(r%Zy4z0glTz)4F(=&@urX;9=9iRFcb@RhD(F>w~&lNGbT1q<11-B zII_AZ=@Fh-Fthtn2w5)mIcHJ+nXuSs9xP!7@t*qMea9QJRN}NJ;QkQQnJItZEnEk> zJ2eN8eQ2tC)l59gW8rU#->Kfg!+2fnt4dq6Kk@9Osr^dcMy;MolH3{&d|)2d^Br_N z@vYwPUvJKB!Tt+3+AecZn#!KO79!d3*C26Pm>zfIXW;bJ^ONM7pbuwzMz$jfXaX`N zpuTcJe1jvFMZ9Ls)|_M}T~zR)|A@Y3IA8PNx9^@)>plG`6*1o^?YZy#%O1)ZfRrkW ze6o{og&<1iC6ee5u%WS>AHG}vEk6U~po~iTt=E5xSZ(|)TQHdFw))BMbe`2vPx@3% zzTTXDZf~?vsL0RPP`mRL#m|!DKA*h0>bqRf__Q`Ma0o!{-HzYB^g)98p)1ey z(#fxK$-m_8pKr~v=(zI_&djc(VQIr0+*a(0UkK`;7CMS;tFN5JpTw}^Gn*GKKk9Hk z(Lz5>1Kc&4s2~5Vjm&9eq0}kw)w`b()X`qc;+P95xUoSXM&;x}FE@TOYhaAC6)A&N z^|x7usS9+n{|O^GM>eb^pc+t);=v}XBDhm+MaOx=>F%Eu_^{si%ZlFMFd}q zWjXd+H8la6OIM|@4FrAwEV$!$W}5t)lE@)m>z8*0!i}ON$hlxHnqQF#a*_XP=9YdK z+CJYdTZF$70LrXW%M-o8@FSXZ2Hdodf*D<}1#lK`yIyN$y2C@kTcJsI6^1HE*<`4= zyagKnjuqVkt+7XvYL!#Aq9^TEvBonKa90l@j2ae0O#qEy`y)QmtosnV&kxAi(#;UX z;F-8-sWxlQth~kwidwzKeCV)RDyOxu+W~xq#!MyEY%H>imfF3ha29hVO6$Lszttb! zv9I(Q-~F<8vFZh1L_uF>$kLv9$nmU7&_wT-Gz^Z%cBcriX5S#2ZkEdjtDVtGyFwGd zc0Dc5*&2&aRL`K@oD(&4&~*1^5H^=a)xD40?(;WuMy)zB(6Vt5?iV`{5ScfT=zaJ6 zQHH3RHX-K5@vcb^pRs>e2$oC2Bbh8oi`;n8ZobWAwSLf@c`Z9Bwa(Gb%3VKo2MmlW zf4|q#HC#bU6J*XBSq9Rl`NX7W(vK zjuI{>NmQ~&@;JwSC{|8bEhD}zC`)`8Qa!YK5mpgI+OOg1FuTaOOV{1M-n8*wL?Zq9 z;_uKtD>}1$=6nI_(}M4xMl|!}>F*8^DwEI1ZyOGID(*}|+Z?O{)+o{HgKY~T>up*Q z=~uQfbWUs`<>pk5$u@tD((urMrMnDALYiFtU}#&=DK2C|+c2BW2U`XfK+QSx!UyFE zHGK%u+>{y3u=B$5B?e({AWbDOn>W}y-$b6p)VYO6iq~XRk%LQy1XxfnqJr+G4ZGh# z2O4`fVy!ZlgLG3OF~mMQ?rsFJVqeQ0{e+S-k%Oehy&X-9BQa7w>s946JJ&{%Vg8%t z%M|{fd$C*#J8W(zv#}Bh%gxT5w}${Y1NHwcj76}-j&|r5z|5M;NmL$(4aqy^8~Thn zxvrH+I@+(M?S(Ir8iADgclq_KLEnQvG)>N8L|K~SCFLZ|GM%jSj?PSJhI^k5fRnL5 z%)C9Xb7)a=bUq0&GGYwgBGHl=HDJV5uny{9Sz|*dl7igQ&~ZkDG3a zHwF4#fyQi$v~0%qB$@h5Ch+Fnq*pFfHxl_qu#czj-`t9<*mO1bEXhASpq!LI|ANk9 zAbn;{cx3crs`+Vz`N6pWyXR>ju zd6iqv6Wl1?0uJ@mo?Wk^S;x)N9s8a=pFLftv=uo()23iUjvh+gs#u%74h(;LCBiso zu7D~QppQ;nc%2XLuvgtWkJDL(o+6ZPS4VFbihK1Sc%!ZN~&MqBM#c()w$` zT0m=R9NCBmq>?^Q0~G=5B8#<^V?YQPF9>UphMfM6tg9`Zc>+ z`eNVj&pu7L3Oz6w``G@-q48U8K-z>0JiSmbdWs(}_|Q7!211s5Ykx?~Mni@MdL<3r zH1zOIl}*V4Ukc=Cek-&-9Lf)GXlGUg-HV(_5G-s1uNfwVWQMR!i&4>mI|-LrQbX_m z=%%0|<0X4B9*1dM?VPnW!!D_!57anSB9TSzk<}b*4p9OHhL0$ck$Xm)I(u?UeI_V!$r{4q|$uh8Ni z(b_0X74|q&;mLw^jUR)HAdJIi6)JA0gWiw%Vp9W)EegC>7B^k7F*EYYRU5lfrE}+& zJP6GhUF9CO75pos{4itU|)(94FpxCnTM^z zRw)**e0V(foB>1XJiV~JvcQ4$NL=7qt*_?K0s=TKPIfYabD;&Nx1R{hoZWkP`2nN( zO;UTKv;$aVE7QLCh`QjvAuWs2E9&&GJiG_~8`46|`vRuV@3c1F>Da5-PkX1fx|SwC z1vJ@nxhwWV()PpN3z=@iX%<ctha6!GMfdy7ly!JSkmNA|~O%y?ueV=e#+Lsv>bIh?e0YRgh0rx@sli$_iI=D(OhiE)h`>n-?zI~$F3bG z+A~+=M!^9g_V5{#p&8x0)uXe;kfbzy9b&t1`h%pV;dhg6rXk38J=~TKbNJW>0YOGy zbX-ArrBSZN_&;7#d!i$d9)#kzdmF#G8NIQ)zx*2ptY`@X?afU1_&>CYV^mGJhNqG% z<)8e?oSCaRKIZBR&@LZP_3$dNAf3Cb5>lBVUfZ|Icy|Kp!XTAu2 zG@Mq;Uxv^=s%@9DN_h>4aS5>qiZ&h&nZW7Zu?bVi?sZm}xDn8U6<-MRM#n3|p4pUR zc|K<+Nk5*7nNs2oC0dAGg2`DN42i^c^x_I>{rYRkz>OJDV@bH{T19EPjmJ5$0((6~ zd<^IXY++Y^;-)GtJw$V_IRo{mZ!?i?QR!f;eg#mIU6n+XzMz#zcO!9*$c=2Z8KAH}(L9jrG-^6StsTq`c=-14pj! zID1bzL2w@F$=chQ8seJsS}a4BNF}tlh22v}Zt>Q>W>XLOY(evk`U~dhlDhfq!ItI{ogc z$}$4PPfHvYD)t5kgo6m_hROm}at6c!mXKEz*yTosG={z#4|~xItuW)z%7>eNnVEOi zeGNBRb4t^OuRM(s=RGuL$?oKGxUX-&S|05--m#Hqwj&Yt@}hkzd!Nvin~QsomAAY+ z51%VBPp~JyK<>`=Nk$=WcT5T!MyxmE(r@q+N(%*fUi8L}-J#rnpN&reE!&+<&ITQ$ zoVvofjrr5fqQ^QDoUntKZM}46koPCGi8}D;9c*iKgKWJz^j`LY{2cXxocp%s;<1LJ zz|^{bdAIvRGAAzP+p69n^D&~9A;xnjM1_0UZ77+crm*CStQt6}g?8-KUMG17*16#f z%tJk6Vj&UKxRP(b!dAs+Ha`Imm)iqRKx$b_N9{I^7Sob#Cz%Ru3yVRaZ3h=5ZBVO* z9OYdi^Bafa$}FKOe?S?0tXT2L+0^~!uHPc>#KFqD{oup-tW1wlu>AYQQggxj#Ba|H zYqyShXRG@71n>&Z{FRy*Y>UJWx<7DNN>%~K`_j744X5ZoSrWOlJGJrn zl2OPr2TR9-A(5u3dENp}0Yg&T$3@0BV_P=TcdhORqc>Y*HvM?n{xPH~6xZN&A|T<^ zCPxknvT-b?8S9HrJ|2|GDNx=PI-s|*{hArf4~g35Tiif^%Cr)9uj5>R6(+Dlz7)tM z-??Roz{iZTDDcKU$Gw{?ZT~J(G&BkTnSN<4>|HTi;P=?JGj zUNhJeuGDTVZ7=1-feOm*B$<`Ar(MsbR(T`X*D9;t3&CyaO_zTHgpVC?Ww9M}7Lx#H zYk;}zaS_)&DEM#i7s6agS$GR^f86unRKpueFog#Xb~=)87T3hd^PBg{TJ-rPC=woJ zHGt&W@0ctq!*%Y))5-geV#a^6H%}n!ad5>e15Mk- zSICYAwrQd!so)95m!UwH8ym?`hN}76B`%oJ5`Q$j>tjaNa6=)6TDJY~I<3ChADdgS?p0@*{ zf1sdGri@i932za^TC*={H)O*r539jV=Kh0!w8*wU50a<&UkhX(Tr4knrTAcA7+@N-sb>^fJI#lJUj>-^Cu zn9`P$z}f`$OrQlxJL(K9+vd$)dgUS4GS5KJM!gA|Ge|W&9<5p9e+KP^Mt-#P?d6oq5N-Ufi>l#8Y9)%V_j*D2(6&#o z0>4zKC6fnN@4KWOdGW4c#=-kK{*_6mEJZ9SYLD{|Flj@oxkEv(gUR`4x}iU^Dyh;?^h!#A=Dp8h~K{H zSP>zqOV#^+?(yzI`!8(euZ8-5TToRv@j?K#M=MppwK&J?2ZHR6d%~%rx%HRi?{F`T zS`+6*>?3u_7%yAfQOb#(v^dUxX-}8B)<$PJ-B@%~`i3vX=TUy4FPhUldwQizk)>J@ zGHX2FB;gxSB=wWbI=v@!n4<)-(NUMZLF?MdhV{NK=iRl+)HuW>E!!UCtcJt5tmMcq zqfrdm`pUH&In3(uGYXuQ=Pj|00Mu76uL=P1T~>|X_;Qf$@|?($mE@JA>(CtJB<~WV zL-hGciGI!v0@mPRnjGlDm6ax4ZG=vV>Do`L5cqt=r+p@8i(`8o1~$}}B?NA1WufGR z8=UjEd|*GpfGkZF4v=b{)io98WW1~aQ6Bp{EcE`3G2B_M#5@E)yRb2Rxzh8m`av6e@R>P+M^0`SW z19O<5LUL6fBpB3S8*N6xe;Es+LB~C5W2wxKIBLUNnDVXgeJs7A@i3kS?_3Ac8|57j zXpT+DJ;%^)I*|#O3HpxfU`)X3p}uX~aYqLZI zpbkbK6x7xTkO(jZa&Gcme7$Dx?|#-Jo6YT?Bl50nxu@jsR@Ch@{@8p~12p;^I1I4J zRP1a0CM}xiK-~Hl-7s1=il$yot->6=`kcEB-;Fi@* z;NPzE;LArLyxGCbZ0vI(ronTg_Flp54o?S0?$FjxK=#=r?3;bcpeoRB#HL#hY%~K% zx1Ivrw|!o6kD*iP$H~>6xgWHi^9fzL6zVV01b)|7e@Blx7GmnC-;9REsa60Pe@iUx zAqv31^?K*?J8FKyZJRd$qAM7U;pXcg@LHs<>C9ZuBiD|m6z-G{iE*EikBPoMI|eHr zUkDtFEF7QsWjpaDQVLoE*lL`~&3c=qz~E+uNPbPGCvS%jfRUtl3zdc|de!;H9&jp6-a13=vu|;b^OMk^XbJv?5g{Di0Pd7uFr>ZeC8tksi z54_Y+tcSL80Ihz9?*5G(3UBAjvUyz|xKsJ{oo{l8A$A+^+#m|cuebl^N>=19I6p+YM0@oZht;MAWrGOA;?jWo{C7)j55W=0uR?iU(>^4N8FT=zUp15cNvae`+_*^*f;-6zJqI zsDp5rtG~>>SUQ1ndo7=WBaXb9FxpEvLo$AmAT|kRQB_bWar9+J(UmT{6HKeSJn$@S zQLp}|=1#V`W51L_qC86~f7~9oJ$i5b)9dQQ_4Nn(mCgxTf&G9>O2#DroG{c_rj#vo>$YwB%iE`pr=#wDoJ&6Ll z{u8)d)g5Y^hxmQH#nM#^(y}24r;A8Y$5Ecxp3Ztn!}3_(aa=aMzlRBXFk4BRSlCi* zZVYQz!W>#kgz0ZcF^Pi+b)eIoS;(0}R6Q~H8Ijpzm&tVg;^L4W#pDlf%D*JLcZ&Jj zS^24cWm1r6CDV=?pBR=&4{EOcwc4pvY6*M+yO|8=o--rb0g{Gmo?+OaH!CvUwZJ!H-#Vz#W9P|zaIrU5&>VeSdw-qtsbw+Bqy)q$ ze>{zA%9vIWz-7Z;8){)Rzq-}W{l|Z8%nCT1SuM8=1q^gd?%kRE2Cf`bE8Y<}M)OoN zw&koZ`kRZbSWg zMr3!@S@-nU_P1FTAs_7Rao?)7mqy(oxTS-suYs4KJd77P6d{7f3iej`2nttVrq3D^ zkvoQ}%4VzCT!A^;k1O5ovNf3#dNf!_l_KAadWmsE4_st%ziLi z=yr@*=--^R`Pdxav8;pRDb@v-pvCY9?&oxtn&Z=ZN;ysW$Va5oO`?Z4`uCXD*ds^# zU1aSVuVlx+B>)M^7Gw7<-uL6H1mQ3R+vG`iJ5{nti>G>0`DNcVZg2PXC@%!#^tc*7 z<(v4u$fI{cTUK#$g2A7re9g;rXSI|9cw62x47E{Nw;UVR z(kL`iNy9$7!UCFdH=@;nSBI#i3YhIFn4LRg)ewA|VeQYpe%|YKeRsEpu6Vm^V&{`x zu}3#|4nUzDh^H=Z`7dRtZ16pi1LX0KOkdTcm8Pj$t&i!Nfg;;MHhrRVZ+d0S4+`^Y z#!9YNt?_?0NdhFw;9iL3)5ma0&`hr8NBGjT7ZN;`eW|);u4_wSgRw+BW@q`SCVI+3 zAfS!mlz(Yds35&-lWJ!Y*{;hEI-XT4Z3M)Yb@-no4?4Qcx1{=8jO698CjY}FlS_H= z*_@E8DMy^?_KqW*cgt^3bi+bB{Txz3n$3_c#6=2b$Kl>b}t zApH{bohZB^doPE#>Wzu{)zzo{yXk>7Nh9@x{?SluH-G*Jrw)#vw$QT1)}{X7r>h>1 zPs);8QjgYVp@%S$s1gfWmIwKsbE>dFTYoyUQ+4?*`g{3RXp(|%0=3~V6l=&c_Y-AS~#y7>0q$@gPH?Wn&m zD%D=G&!w~!?Mgi8-!+e$Dy5o=q!1E8 z)+!(iTiy`VwE?q4MwN_(0#H}WE?C{8@Q>M?+R0NDk~}lD9ZW_l>?W(8`3yJpBDo z(1xL5*VEj%0#FjqP<^EK`Z20)ameeb?R6-^r=Qt_;~iVv+jn-ZPTE_{ufLVr0!{4f zIuK{FhIjrNw3RdMd4rD5C!zR-*F3<3^3XI6^?E;&UGzTY7a{+PJ3$(Lsv3mj<-E1B zp}xo~ZZib!7i#W%qq2*27T2+9{vWcbVf0cPFq79q(wTm4NfT+IvvQh>m#>RB(`=&h zAWj*6BWu(2T8vLX$zGsS0@gDtf3*VVAtb}>4*_y~>IqYp>wgBc3K5oghU}I>c(NEy zDypqoZhN|EyK+_u{6dv~*5rfa>46-zEa7dQT{Y-O)QS;PI|)EFQeFM|OPOyfUs~mI zOvf!p3E~K#a2DK~rL!%+saHyW&W_p2$LOK3$ARcDPG`2= zRetE4$5z%lb;my`p2eZ!Niyr5BpRrlRdzK58!CiE$LY#^vt`tM{yH5vr<)~(fsOJb zh_Rz3Etc8Ka-LzTWGDp2?c(oH^;Jmq5;YOOeUpC7G;C}Yu8JruNJLVftFlUzm)Nj} z=T{Vrh1_!kG7Dgl;u?hmq$#}5o^?fp7!%7e6t$J7+zLBB-d|O z9??fT4@|F4ro?dJ56KXksIgs?_g=T{o9o9Zix*GRbLzD+iHE9+X-_mOWQ+R#ye zMt~JaT!1URsDs)nxkSCy_+bAUT`fS1PLGY$pc(FNrUXR7wxQXDv$|$8b%H@#@#&ft zS=n`h=>~GjmXw>**+SE23wnak)qz1{9rVxLvOVY=SOaOI&a;&%038CacC%&Q@e-{a zF7g)I>#Uf!!t>)wHqz~iHkv~4g0t+8|M2d7IfXv|7jJPxIcp{o-dFuGJ?IhW3rNBW1w(?n@q=C`i+{(MB;A z_6rKpffQa`45}bh^6q_|I?)*L8RC3Y9%@vJHtA~mT!=N;#}_DZTw#L zld33(pZ?FLuIz#|rvF*yf8Q_1fI+K)PRdWNB?3fR5#t*-+ya2_fmdsC4^vmmdDS8) z=_>u(T}swTUPCbNy&SvygphPZsf8H5R?s|zrcct*=yy5lQx)01{oK)>77QMV<68px z)=O1+hz-lq@$m2T<$)Gs(l0Zj(&U6MV|_Xq6Wy{#y0A>OMxnAQcRuOC?!PHFjMH+5 zL~4&K=q#qFbrN63ukqf>*iX@vE7e3weagx28|BybW7J5RhH+eGKxRSPaAr#uKc;#~ zYPF|)!h)DGzN`Sr96jD8g!D6?yuhqf#PsTZ+tEWxr-$j7c2dSsG4j6Gov;ZGbTbf( z3sG?3A|{%wA{~U;W&F&m8w?z9jYg7*Kjs@6rW!ltmHY1I0Y)6L>JZ+9%ZpJO9J(D? z?fBx3+gdd8#qI`!ICSna@^c40O10MPD7|h{qR- z`@pQNDna`$KkBb~rC543X}IR^nr1B{FUX%A+r6Ob27R;#_#13k8nGLznQ`Xrs>H(y{tgu1dGt6ADftF|r_-!cXytt>xxMv+~e?FjjRsjhA5XycI(d-mSMG^peT4ibC$d>1Q?~R@m#)=AHM$ zIiPDnDu)BmmRX4jJHn6IdU3nI5ShjL31&=Q zUf*`IwmmnD$8g((cNdH9FJm1=wyx~SthNUAt zuEUuAj%1)0WruAXRm1iW;t-Z$8TXrfbNv^mQ@F&=O#14twH_pxEvh*ZOMEP|?Cn!S z$riwX^-nPt_X_ef=F`oPh^g}&qI@B`rk~qeBu14nQ1gU@gk-@M`YllAdv8@F^EO1` zc}0o!E)^G2bii%>|BI({acBDf<9-rCSw%?>(*gAr!Z*xeNTqU&`bx-QSYl3#4BH$k zm2;HIVU$ymvmtVBa~M-jvpI&%VI#(3Gw%KF`?~JGVAr+leSO~V*Yov!J|8zLj`u3( zn|{#y%l?+PsJTixg;>7CD-A1mZ_Ft3@#5}j!7Ortiq#TJIFE9RFiaZIP67S>?)$rN zZ&W|9d-sEC-foqZWgT+!#;-?SF*_@b=LnLED#&j~qfx~P{8}4m=D#91UmICIXEiKc zZQc#n={M$WSJ^MuKX*2B?*)}3WiKsOKjP)uit9f?c113rMiIGMz$?i{eou5mGS7n# zAFVT9C?lMr8-P30%Cdg74Bi}-iU0Q|X3kBX+7XUAOp|qL(4!=MV_+va({i>JZqXXSwI)oV?GwYsPPL$ z5nMdpu`R<;3`5~J;aOX8l>&%@KA_>QXvlp>gs zDtKq1wr@{;iUH)a9ujX~3Hhq~ANPQr11Oa>Y)EqMB+A!5LXS4B)!iR^r#5Fp72)O=UP%`k_! zy0#hWDqfenyXT!&nXx0(Jkz5lE@U{BsP66G*wfQJ;j za&Ktlp#H?6%BL^$e(&$;TBEs>uAv;*KBWR|Z_&Mn}F&ctM?SgK-A|qs*Gg(wRa>;C;VtLF}9p9B;O#Q?B5j9iv zDqvs)+xC6~&-{H%aYg8pB5GcVBQvD#U7z@3L&q&GOE#TmN9OnG!J;0lV?j66`AJ9y z*V~tyRIZzTV58~uFMkRtJgOXYGkII9xciBX;a#Rp#zfkEQtTJr%OjABAYk~b$^n2; zna+M!>Y|3QkH!;~iSI(rGaJIGC^PeS;A3iG;_Iqc->3inK9Y1~V|NG7y`f$ryHKX_ z_Pn?HTQ2Qcf0Z{3F6q?#ADsEFnt&Z#`0Dg5KFK%PX$PT(|H^v6?orciGNL_)Lv*p1 zd>}1!y~-SJf|5=umUYlpBeQkDJ!+a;=lA>T3O)+es|~pHL*1J$7BWTF!nfp`BG*e) zfjoAA$0e86i^qnw|4Yz>8CAUZClymjL6E)8jI&pDYK<=E$kp#j_9Sdo3oHUz*tZRG zgzGdJMeStq*~X+`kr2rw*{ykXY8}D(7)=30&?m@7IGSfK>iu^~{ItrzrF2~3k*bAA zAm`F^X!CJyVq)Cljf=dZe+ioPwt8HBxbIuK zimq)$dQweDH*4oGGhQcZ{UV@*|6rz_0fm@Q4tCF~5b!(Z`!vm?MQ9vTwuPrE(P4Pk z+HDL}$*NjeOBY%_Zw}4}<@ckMYt4A-B6e;h6j^0X>%YautPPz--~iZzpv$dR)AEk= z#3r0&o)!-tGCv2o&0wDmCE8H3A)n=T&YdEGuF2XCCdqA(dx8XHVx|0{^0&r`Ds3%6 z@wIcfZk<%bRR2*ru~vuy;h*?&A)-0X#?9fJicqMWNVE%R&cjunfjMu=&GzlRkZ8I? z6ku}9`H(0AZi64_-iQkA4q`2r(n*K&k6t9R$$ZjRRcC`fKp>7PIU=!k&(APwHmgLy z_rs%r^t^>C)TL15aFv3GQUAk}t-KfgPXzt`8_8N>9^`!2x%NIAuUGqoC#@XL4ce88 zIQl~2ru3rV-s?_{v|%V!#7gVs`%5hkSsR7=^j15_#XmRv!?NmTW|u^6?EUk~xPW;2 z_>X3FeGM^k{d6BuXjLXT zQhpF|`6xeH`UG*s-&64$%^4ZkLnxT}Mq4Ug39l=M?e^XLS(qyc(g-VAe*Fy}Cx-oXKKq=0j# z@@->764Yz5TBfo(7jNKacT9}RU$4D4G`!a_7NlNo_Xp7y>E*9A{irl(T{}jvkpEN3 zsJAts_ipS?!%wuM7Eac+jYDrD7w_h&)>Rngp>X1a$56mAn*lR7^sn;JMe(NzQG`QM z%aA@DrU3Pog&0+1+&C7InqGmgGFfwWAzu!lR>`q(vWS;InYZHPr_|XUg za_%5!??u`nI+W4;kS_^#4k_z2yD~XaVb=7DKS9$UuEx1Bf1++w*Bq59qR;NdIxgo4XJV7T++mL)6a8MFulYi!E#0 zM1|5DzERGL4Bhmg9m%uE#vcF*F&D>9kdtd;ksRx0JXEf`aZ0G$8=F}_K`NRsb**ug zBtP#yi(Maoj}l_LekN&j>zE|@I+yfs+DtOcIbORn!)KFeTGY_)?0A=)(8rx3UG=Pc zWZ@UF@&vH#T>{cFlJW z0^$u#)U*QN+3+KF1F+x@!vd*I5?m!5^z0d*C55~-IjNH z$1O4nSrVjQ;-CBj;n`T4k(#HAt2q4*#oEmxCZTiZ`X!>;LhWlg$bpgea)dSTnz5rw z3ITBMnaERkWU(LqNa!Bi`9$PRxb=E-{h!}|(fgEd9&vQ^tbsKN$uJnrojZ=0?th_S z+X!u)2jsM@kL|Tj?Mc4@@+^wcbIH6v6a;kp{Qgiqc5mCEJV&r17d21a>skV!N=E&X zyC8gVB5l8a$!R}U;}N&@dL#{))3TDx>lwoCysq2F{TV4<+m_v5TBdIsiPkl)>9|Yu`(c8+ErSINI*<_D7a<>v9RpM)`w6(|VQqW9h*QCo(@>sFvARA1JfI`j?hkr66NPw`!6l9Wyw~Md;Vgcw?&M zsEj$q%s61v)Q?&YbT{fIpJ+m^RAwNDTfltme5e6LxL3J2xd2j7VG(RFkbOb27kYWI zh{SKFEZlv*r;X|kL)47GKeW_|Ok%e<+Wdam831?c>1bRa_wD!e9E{dt8i4t#zQ%av zK*)H2Uo25+7~OmK$umkSrz>~vK$U39Z6~%GS54j?*PdQu*bb*QA($~WJ zrY1Mw#fuLmt8mf!{Rag*KK7VmPnix^$RGl zb}nFfUi>o(0)uh|86U zN8lzP(O`b(lfAWLY6w0rc|xSSFu6cWrhWqypaio&MV2TNY|PnHE|S2d_UrK-L)lVz zpHXKM z0Dsf^6fzy9iI7-_N8tK)o#Vz|`n}cXmRl}I$w4rj4xRa3M!{sn)n4B*9_<(X%vft> zSLY)IT{2wujQF>&(pxerwdx@Z2*2_?yDFwO3(W5ju~$#!7}y%m6&}J1)&?1t#TuXa z@}2(kODwYGE1C1?I*iqsHddO;x(rh@KVEofyBN!$8uJ9}m8#3V7_o>8=I~YJ>LeJ_ zJ?)o1Q^sbMuBUf%x%lYgoV}vG3%3v@mj`pTHnE2DoTLXO4h{;0+b}`P3ppa!u<1+o ziW=JGJQ z)Ok3Ur{51yr9=Db+2Jr}+nf8}!C#S^Rh{UrI0=9aYxD`D_NzyQ&2iP87GRPq<5AuY zqkhr<7Am-`+XX95xy>uZ!QG&q1KQJmpDK)Q8?iBIQTnN&QJPUM@@`Ze_aibEy{F@G zWbfRE0a>;V20r#NwHZ2o4muFY&*FATFzSLt@3mBYybx2vR%99eY}KYoaRKV=Uz*0L zU1*_;f`N%P5w{nr3RR< zZb4tM)qT!6v1R{QHc_-Y`-~0kG}+-58hH5M$uR=YW&Dmi{M~$BRBT zyqO~0oZ^1Dr<1BHd^i}}P!KY%u_8oGsJfo?jrcXxZ|qcHc64x3f3{#7awQ!O1QP2K zq|Z1|90=i=gY5M7M{GiP{*ix$sasjLuHKAgB|HD#6^9uTYh*w-WH7StGi0YE%nmG? zo^{B66z1_q4yaGs+nYweZ}Nzj1~15#h$E67EE&1&wM&;wRA6*%_gm3_H|gj_`sjc` zX89wZ@8bDoSmE1`XN{>$nIH{QfPd>^GrkAF~6EYw|0TSK0v(ltHYG7 z{tn3^iE4@vjjaE}!Nvi>i(rL@*-k-Ps~dWcQx|ew>4B&6P@e zVn7PaU@!@Zv^;oKGS1VNAF6IY${hQWD7(^u z5KLXsFd|vy@CEB>scSu_%{G<0PvKxi!tuuzG7AT)TkikE zTpA_X3o*N+$AwF%OD6Q& z*Bn_nJSBBdK0k5?;~Y**-Gk3f)LRrZV?w%*JG>W#6g@Sls?qTIBt`c2Z>xRRcts+A zy3EWw34P6R7orQ97?skY*vfz%!Jfnf z)I1X<-*)1+v|mXDliyRSCw^!lW73D#%KE_8wt&}JK}Ax2+UkyDfZ-obp5BHAkDo~! zvoodBW9Fi_Kw!-I8XF1=b0>?fvY_JcD@mCcuYu8}kI8C^EyG({j_DlyVm zVo-S^$Cn&>B;m*Dl284i`9{k{MpSioT#XUot%i4QSxBG#RW{GfE2#X2qgk~Ab1NWq zODwNo@1{$th_YLS18GEr2F^LP~#0rK>dfw^O?WhDb>cQTz|SnCeKlJb63*voT2iBU zh83b7UAiGdz>wY#f=IHrfg82O-JaUf>?yCMKzcZH=W09HxtYnk=YBpP zV3%S>bI%>>ui1%PcIy+lxP5ufu%BK;-r2svF>&60I3KQ>y5T1&c)@?I^py|V<5AiH z!nCue_19vlZoO7#!Ux}ZqSLaXcz@x!zx%($ltrQo&!A@)aO%)pM=pGiQG zr2SGP4s%dDpgYY8jQ*?w-TuI@w`P36Bis#?LijgsCe}qB5xVEIc6U(to1I=j4G@0_ zHoY@GZf1^jH-6n-f8wnL^)x{i;#fU!cG+8Ef~0RM-*{G;dTIPGrmd(Y3YRYOdBxDm za))0{W+BhBYVEd#N-Q=Ff|k(4yb?1Womjykiyd@ZtU8fLkvKNi%%G_h)h*eKZ8c6mroK3&my?v;~NFVCAyBsvn zh<<T z%8kGG-u3d+2G19xdB0GX&>cE=xQ8W|w4)_>SdhsyYAuq4I;H_XCQoxkq4G4=)96>C zcD@20?Dw;b++@9vz>Q)29{fK2Jiyjx73;%VKsR0g4vrrr3%rJZi%go_xoO9f6%1_o zjm{7xOyLq_3NCl+{mde`y^n%%lVCj2xldBsv~;NP+WkU}s3fUwPlXyAzs~Uh_F4Ta z%;+TtkcqXH#-f&T`Hihh!}o#YfVn$}lgxMFBfont=qd9fa)WATz`LnwSo#jA5BC?41k}HO=?j<6wfp{8nGqMH6v}%# zooy!;e4$u@ohgzjNC71Ws#`jm=CGfKaIo-1(#EbKL7JMrNUSTF`xtq!Y0-pVPh9o# zb9}bcDm8-vxB`sfB}8<5OP6HGrUh>oO(O=ZPdnkN)T-*@mHuvt-=H)dT~dv<;twj{ zfnn=Str0Mns!kSg?&$DzBbx|Inynl7_P@zHx20-ZLvDY9AFEg1>q*}Gvt+QpY|h^% z80;@@rU8wC7B)PNh7odPZTrj6*nVyWm^bQ5i!YvzAw}+Pp5I?_H9~UZ_A7?W(d?0- z&LRG~VM`W0x8#c=tr_xCr+1vJT{pJ>XE7);Mse)-MLJrWb#142erte{I~jW)h8&Pv zt!U2V{!{=6xsz5p`^L4Z0sMbm1gz=5$YMHpcebv6rlaeJxw=Vch`K_4yh8EWLMDay zeIl!K1ywF(_(Md3*s)^+CPxx_=`^? zy1XpLHy#G}LgIwvLpRV&juH@}b~_qhwA0!C zp+W5*5e}DiDkOB){0ZC6KQ{X>nXas*#rp%(1P&}_(YlUVhgE)>zT$%1wDQ3HHTxCf z_eTZ8vIv0m%l_`r<*h$AZ(OTic+pf(Jc`TgOSsC4g=Ea#WemuI9E?uY-j;PuYLnBT z_8l$Q0YDhnAhITxX3UUaM`0l>mzZ~2n;Vy~!jxCDSEAVC0r2`hZ7R){+L3(? z7yZqrQ^(Dca%fQ-SZTDCs0JzOCn?~dSUKG`!{@jmnseXjlr20LV+I@@xW4?%ZE}YedMjBV*;zNlJTC|0rQJA;!qcM0q-IGnuyoeZm*S zERw{H`7$5}|K+<69N*OfX_RfUFackpfd`eV`XR!OoD|+Io{Qn=y6t4?J792^PMA&N z+K>%)XX=CRfi04j?$6htf5y#gCV%WGPPtQFwz@yS3bPozH!W~qA?z(Ek*V;x^7uMsaSmxhGg|{8F&Z(S<$~^Qxkt(7{*P+xKg7z3M?dIOM?|gJIOI0GEM&girO-|NkjF@!XT&$eAJzmp?HJHl6{XK+g2y4?1l)<1QjG5YMY>skTORug(aLaAo^Abj^sk7U^mJ_xcvu%{DYIN8p`*Q4gB-1bwbGCR zUS~s+;@Xm>x*i*6!fnxH%veTp$AAci8`Bb4-k|};7|5{vTdw>yRL00IevsTH&SmfE zwUBR0%O0e1qUSs14(xjFSH*)j9~4T>`{vgC)K%aW0%V80Ud#xhzF zhXx#8G5pmVk2Vm(o-O2FolC6qjc)yC{klA1V&7{r$2VZ~`Do)!zM_7n>|3#KcI)=S z&=T^prSt<`!~bxRGh*Ang;y`J>|V8uF(#rml{R8Dro;O?hp-?1UXI78h$N3m7~ix+ zCeZvVV5&CdP^d&oNWU6pp9tA#H7Jsa1Gy4gndA7zw`+NoeIYt zv>j*6J7F9JZPunyP56D@n01PIWMk5?t{csumhKvCBN0R2w%*^q?M46@M5}MWcemop z=Tb0Wd5t@i>Ky&ee5Qe?5f%Sjf*)(`m8{w6!|)%l>5}Z9+ot#g*d?M3?ID8T4^7rt z*`AoI=$!1du3MMst7}>$%|0QK?8;f+X@3=>-CA2q%XC&{x8e`JiShY+b0=wOtTLeM z2JtncCeZm}p__lOe;-J_(q>;~q}1Nqz9!od?`Ms+vcWyu<^fM7m4 zy{j|m)$YKw95m|k(*!0U(0FB#1QOgz+xXncmII`2$i!7z&Gf;OTWYZQLoc)j_f{i4 zj1By$58uFVrA_=56`uDqJ~vb|)E0UusPLDwnx>y4=^reZ+{n5*Ec- zAsIM02mPSSjfs?0gqer!MYPa2C;p<=D5{luf6n#37%aSz=5~Dc8u7)ep_E@jm*O)K zLGQnH+&GGQ?XDg;^3(hrPfXpzvCB@3`(onLlu2T1f=vN{DMOdI1R%$;uZDcJu+1Qb zGAa+Nko?x3s(7#3zl6cDZkO}-hLRDz&V_)dMF7T1XQZWP4qJYIv(Aj;Cc9H>zKi$D z#tpsyW)h(wJ1P#pd8r}gdV)A;bK_O&Cz{|A ziYxt^I00BMB8Y#DI*H*Dv-V7>ntg)m*|=sO)A0a#sGO>9oc-^+jT6b9ihOj{G)iPo|cH8MYI~vdgnT)^7*0?<{43ib0J*_ z|Bmh53KQh->UqkoT~BsjXGYA`Cd2)m^})YXx*r&N59VO+8k|;9YAJ@X&J$&>hc3JM z;-VE@q%PR5)Mi<0B)N8%Gd!JF$;`vg&1z82nz&H+iJpH z7FZ|lE=hvulmP|uh|FJTmD6VIhq{@ZGlKZpZTR02d=NW4m6>B?LRClO{pGLFJU#e3 zOdolZF~}XG(N>!=&}`8umMOBP#&qQ**gvs4}me<0{6B zo>T0g)0zgYEWJ5_C*_(ucJJoi0FU?rFd5G^Rc_$=;SwRW2GU>WSaHspp^JK}ZMfZp zkCU1~2JQ;${ZOUCD>^(ukB*jb8DQ1idC13sa8G$(cT14#lzPGoyTyQ*)2aLw%DPf| z)AL$^&DZi9i{Co+=>~iYo9#ySQLVIaRA_!6io9 zzO*}*!7?dG&M{iH6V4ilt5wUc@iCVjt}5^LJrQN~cuEUAPjj}%gAZCL*tR-BLIV<= z1o!KB<<&!f`TTjqsb9D&-cgr_McQ=lsl!f77m^oHBFF+4SRs0O$(3Ujm>WHw1fE!` zHi9ilf6#`Qybo$8NO0^F7?J#)50uLP%aVR552fR9M2hi!Ypo8} zwLmt-^CN`|Wb2X)rkteVtp&}i%&PCyxP(&60>i+8o=t41oej{y)A()2+%J8`phj|Z z4zsbsaEpB2cxg@tIqz*eS=?OER3l)7+X$m>bs|}}fm7;5Y9>eU(dft6l!aY!dkx5c z4yPpxO{}dKJ3}()C#&K!PiGFLOX4AZCbC_gPIv}?FgRDL5PBg`!m**ISV1a)kgL@Z zS}wUGk!gpiAf7~n7FK(KW4+G08j>(oNQi3#Hsm)Bm!O*;nFQkTM~by!_^xI-TekA( z2%lZ!=}bPa3wkfQFciln=dMSm=j5sJKCMh(LZdc5$J)RvI}O#NanHbQjPt>4EA%-S z*TzomQ{|dCjCP+3H8B`mMbu=4cADNJ{0(s1Z^%U z+PiDKAkpRJmyy!wra+pTz!7T(Q5+L%1KPhK&om3sNk<W%~1~65Xt4ja(zd0eqYRdq1;6Pv6G=Y2$mWK?T^5n4=^ct zU~0-$9i9ME(Ey^}j3L>%te@Hx95!x^5Db}bsKOVnzqs@a8O3>{3U2-X6F6^@KY?%N z*EzTawP~c}iw8){wEb{WmvfG6IM8$HR!;n#Q~c4y+sob@%^A3HJa~H`{-oD~z`H6! z(p8&rb{7HLAEnNq+0vE~CXVi9xAVdJLlP$M!}vAQjHb|c76``MG@`}1t>=iRm+b+L z0qG^hfK%_>D1zMu@|*W?DE zV|R28GxF0Q5W^^a?o+{qEb)6q;Gw|JY%@T`2zt0{B>+k&Tu%Nqx%9fzd9@m@YTbn4NU?A;+Tw&~VF{2e~Q!~dor<2O(q8Q3|Y z`=)2NP7^TOGBDw&Bk|*foI~5`E2Pr^xY!H05#d9278eAFV$;K{#9$^o&{zr;xy0`{ zF-$&L$uhmnFaW%s4#j^0x?K$Z)S*9hs@q8r5%Gy-@@Garz{~yeW4d_C;_9iE8!xkD zub@K)!i);`X9e{hCD<#V+x8Aq`o;BYy(Avn(AGr<`}A==%t8_A{!4{zFCm9n9j6@` zZs$Wz^ooU414TK9>!7W(5U=>4CE5GphUr~q)`kg6i=SM-=v55m7E+_a6p`61lJi~b z6yQ{zz_>8^$A1Lp#vqg!-aW|*|3ZNy1FTM}k{X4U_h%w)oO&f=^=q?Km%Sr>oE~d4 zi-GPDICmRsTY{cv&G$h}Fa=gG)$|7!EO-g|*XbS#n_Ps#I14 zRIyAI>vC)=x#``v0LVVa+5ME(V;YF?Bc+1i8 zbX({Hhv((vzsp+)E@Yw&OzZpQQzDlB}&ookw- zt%zB#fmzC_AQBXWv&mW!Z;4vL{(6%E_#1u0O77mH+MFA|Alh+q%cf%5z`Z8LVjwXuaJOW@sA|8GTg= z(0L6f@XfHS1Hj;fLk{rH{E{8JL=+ilCyLVT2IT3vEI=g;IbbylX4BSn=&lD_`6L;b zO63o%=S!a7|@*Id>-`zX=Veza1hlfQ9gfIihy=o&e#^FR-_tU#AOo^)#_6yM>%_Fk%3@ z{Q5j~92ACXADHH`88reCqVw!WbsB!uSZZ>Oh{v^tSqiD&}k<@Cc*$146R5m z{)jb7?~p4_CdMl`I^sbc7rzXnh%t?2-4fY?NpZ+)RlHrmM3{-%O_PNm!~ROe&11poxJ>n z5l|-TfE}FG_*(FNuTS+P1ZkWU~>f9bnX;cU`YDZeHKC4zf{+u5B zdZLD=Z+3tALH#^ZXF28Xp21-UqgFkQyKg`$bZ5b&Iuqs0HXR7vITtQy4EGNtE(Gan z@&suKdvJ9D`a=&qLbMC2egOAf_ao4czFxI5R11+`FdVo9El;tKzf^g4NCNXMN+($x zZ!Wg*O9Tn`W7y!E)pnZ!~ zg*af_GGnTCu_*k8?7FuBXM1W#Xwk&fsM;1iUS5%@ooA?Yh-{`qSGC0>QW0#qRQ==; zw*1E3g`mmrl+DsLQThxqOOxS-IzcAjtpn)OD7W|^FU!>9wHB-ke`;hcNCF0@raY?otj1zXUj#*7aLLfGZf$V$Ydac3{tBPaPfIY?QHo` zksrxV>Q!W50 ze61rS_TH(nkeX%r(Q#|ebI4obx@nWEd&9}k8DghTvWnx0S(v|>~{Brwe?w`&Z1?8yp z9w95O)GBJlW)|C}dpxekF#w%59GjlS?HyN6=n0FWe#Y|2hl@~&(0hA#g9NB{H*@AC zh9Plbd3ghk2ep!;kf%N)f(q11%D8D9eirg`#gV*6`=g)ISi%pir>|itMp6A9nNNa) zK0j<^#*^6M8GG&-IQY*^ht^83nST`X5%8P;iE-V@e}{zwq-L4H2Xko4l8eTUkLF+U znQ$}82GWG7nN?JVob(XV-6bU8UU}q!j5x;~*qE+FRVWS|5V|!W z2X)UHd}L?o7^z%*nRSjX%pU^enZ1XYn?jECEMye#r3uW=!K+n1Mc}J^FjKZTtF9kA zeXv_!=WQHZt_CtuIomJ-cD*ulf-NoXYrs8V%9bYU&|7y7dnk%(!ITWsFr$E0hSdPp}969p@+k7dy1Qd`n(BHZvEO~{d=dk$2FY9}g5vT#R$a>^f? z10Ej9)q#DQ3iW!Nwp?(O8pTxHnkY_O|3F`r*M8rXF4=gLTo1(mqopHSq_J|T-~B`Z z;Iqb7L3e1Xj*ra~xLuBC(p5_ruU~O|g~)_5qJs(U2;WKHuPG)<@xij#@}hD zdFGW$s`QSD#)u$!HvbC2WdB-LdZsZ?rkFb_I^S=zObvZ4$}NC>o9%2VGg3H(*v0?> zS1qDKEGyja42bAaV7#%Fv?nXUKd&BLai%71^^X%1>;C){F8wJ-A+TRtj-S2BsDm}I zzxs~qfS=UtAJO-e^@xwV$uWIfO=?+rrto0h^cYt(TJud3Wa}%}HU!ps>r1x^x?GM5 zD`x*R_E0POPI~W$_P;mo8goDATi3|g;WC3Kts~2=Ey^VzA9Pw_a8l!)S?6vL9(SnQ z(`5i#7MGChE5)wL2;9A3YdtMVu|Bx@ef7{V*CdnIO5d#dMyU1djQK2=&pbmjRG?u9h>B*UMMRa7IU zz9Uc{1LCi7d5+@i_qPZ;{yl7+g}1F;jQYk}*YqCI<@9T^jGik~y%KygyMt z@L&Qj+)`%dFEUq4I>#*PcNA$a2P3_W{$!WCF89RIi7wM!u$}QGMJ!SfqguMNHx7Xrktpm0uW)C(>ZAC({C=0DW+$M%&Wz78ooRhw9OeQw2X^kA6= zLNN;nUB}%~Ag=lf{JsqA{rfGpn$LNi5%9gUd{*V;*vG}MQva4{{1xeYUd&ld-sr*A zKbHdrtIC(oKcCBhTwQn^czZ*Gx<(uUz7TJk@N zTe+W}>vw$wE;9t#@QE3i$uuIij4iZvg`3QGgI%ngjg;E|i-Hy>yeYq%5b6;@{qO-K*y!4{9FQir6e!wAD-Vy*6+ zeG-$AcKy+~MK*>xU|e3$D2BBm-6GR(=SghH{H=vD+CnqgBhgEJI`ivuq1Qn5(YWD0 z&F--Fqmv&Y85&-BEyj?lM!#oHRci)n566oB>p}gyMTb|&zd4XuPC%)qTkVzJx%PMz z2iAUhJ}Cz7`8IqFun>k3PuY0gY3|pVGeOk09Uz-f1UN4;mTT1bvF1!ikwmE0++&DZ?QjLMZKR>Al=6C%TY-%*gS8z)2c=0AU0D4DO z5aq}yK>ME_aIN{7g!E&*zl2iD(HxZ6%F(P$tSGZr$a*j8X|JFt!dS6}ifo38oAKcy zwQ4l5$&^qY@&t$6FX;6%3skf30UZmyLl@V2w0oGH>6;!CmQviDj(ts3)Bl{Y?&YUA zm&HjrT@dIT>{lEAdXF`8WAd0-K>4S5r29WlvUD`gWpH2WmU5XvBQt_W56CvVd;-R( zg}PkbQ1L_9&i4dw-gq}ue2%o6x!PPJw2N5CXiT+gDb0=3e&5LMOME(YA=vq_!+G6i zo_zw!R6Q(fDE3@{ws2QEh9!JOT|Q!Gb}SF18?11cm8AA`MB2|_G)DiG0xozW{aJ3Y zQRE*X_m&+~#2r!^BGR^^r5p09zQt%~K1X|81o4mR}pOD>uUIzhW^p$QXQ?jBc) zAguofyN0;KSP@rTaqb1(;uf^&Y%D>}@yivi=O*WW&~bT#DkaQzl+Gw!0BD)a6ahOS+M3O zh+_ul0Xb?VX*9D38C&E5R(zyX`fYB9&MtAAzj^ANbH;w3`h;av=n$Vx+;FLyCfrM9 z%ES^RcYZhY!LL&v2DyAmJ7_?WT()#H0WLyvYwjZXkf0aXw`kj~W-G@(dD{`MnwGbH zFAZK*UO6$U4ep94H>|Hw_L}U=dO!O$@4KJ-Xmdl$*}uCB8BHf+HP4fI&RUB=Sl+Uu zeTd`M_)WjEG}h7KZg%H|cOt32>cH@UIur0y3PK$j{T(&*=&4OMIjn_JjTJ`jAnx%qXLuV9Zx{PQ}yuHJGRDrL z9D|sTJkizN;92%w2HF8W=&5~^@GI2KIgoOY^63IFJ*EL8o_+mV&(dpktRjy z)#pb@ zD6x#Oze0V6lxmuQHqE6CVuSIq42dL*q(sjAc>NT8_iBKGfsEOJOLPFY=k(;~P_T^v zD)6YoNGg3`Yk974TS#kO4CL{GrdU;40~iM+TljgXCf{faUCn~PJi!A0%X8xP-WsuV zqRYY!EM4w!F>E`ubga~(!K&M`tmID2rp@E{hC@ud$M)lVb(=7A?s~n7#MLNtZ>cKYd&*55y)QP}%!@58S&1uB4XBU;R=PYzk{D%E!uJLu`*#teoOzBJNIMe9V-+ zw7usOVi5=IGZ0Y~!vfubsNV`&g>D0Z5_wWf5WW#Pmu^%+3nPXJXzF84adRSEoG7;? zzMXFy<6UF9- zE(!i0vfe$O>Hd%ZcL+(WQsHte370chn8T1tl0#H-Ic5%t5z81hBuV5DIW&wAO3vnd zNSGLNA&1TRG^Y_`Y_s|8^S%9k-+z98?f>`fz1REod_EqJ`@@;ReqE!Q#YE)vQsAqu zPfoWUO|S_68=8^a2l&VdIJR}DHO6;leaiLZU_!^nl`To1|KIO!(w{E;F>XD!rA|fqT3`jP7Z~wEe`TH zT`&}BYkG2l5bH+*?fEN(^KV>FjDGUoUZF$Q##(YS8kQ#G8CC5%lB>Z<{Z&~#8RBL% z)^dwkP1b#$U<=&ayy*}*Hs|FUo+jovzA56mMKY)#LmTtKH`22;idyN+P0GliTBdk+ z{qcU~s6~drBh_p6P^0Ni)mvzRM}F{VUvc}d*xPIH!)deC=czgayLYNvdQ81PA_7|{ z0iL4(i3x26Xl!ASJYM~MIaK(x&KNv=zV*qfz#hx4`8GD_!ZHXbE1zhDRk*g39j=yj zZBK>-yYPg|lY?$Nl`B{f+549Vs%GOa)PXtOy`#}>zu;Uj-K!l|_N^u$=;ALOfDOgw zJUni?`_B*A-gkT=IkHiMA3xv8HZlr**o+gSh6|Nr9xMC>IJN541xsQ6BNFc?0(C8l zoWff4kay+$tQo)91VF1I=X~-QO0$9Uq%pcQ_2!yop@CP{;jG)R8I^kuXkWzaV~Y6_ z%w>MIS`8Wah?EB8<^)|$b|wE^qFme_1r>By{EymQmkRsRwxvTHw!_ZnxiBkCS?)0GCPvtBe|5R3=8T*UP6Uov{GnmdnNSS{KF3 zy^ocH$ua!qkFfUo=ra6dd%J?`nV0_kAQQTq0!AsFLU>li%9S1~{XiBk0`x?3|5zb>17$b~*( z^zy~?I5K7YAoim`>4Ytk(|^)%*p{#&n18a@DjEOzk6zTs5*9`-Rw4Wu4CR89Oz(60 z+20YD(vmqypPA}Hld|i6Vi*nq9g}$&j^KW)kvEljcoFxB>*UpJ?c=|_&oW`NA7b*8 zOa9haIPi8&c=*d{Y4Q}a5dW^g^BvBiLM=-l?i7@`)Io`JKMA>m?V#?;<7#QO)*p_( zi%@SEk&K68&7KQ&(HYp||#P=|7xi!gC7u5-1M za_sgsDyUg?GUT7mgV|kwiqoPN^+8g0jZ7U1a$eXU?C59V*B4ROj8JVZ|wGdwrDF;cZdy`!{ z8mBi>7j(JUA>g1>&4OZE4_iR7tXux#!o^v8quv-!YBeWW_~Mvn#llt^!_F!^T{HEd z+r-EKV8VFw9#~TH-HbClqQu%fk)29Hb!5vE((ND5O!3w|6~E6me2zDzHA`i7hOHrQ zo}6Qkx&LUVQg~$q!li5pzTN|r&4}WiN!uR_@YJ8^B`sJKQ5dj4sd_EFD zcX_K5EfF&@qE4vASwX4L{Y; zKV>3L!@FfKbIW*H)Qs^9Q%tmR&?SD4^O=B@S~L7yXEF%f*#etUdi&zTUOByAa>clZ zMXD^t`yF=Lt51XD)~?s{X{kbh6AIjT)`C&%|GZ%A34D?qkPk{ZaLo#mj#zE@KlHdu zXtV#9B1e&CyV09=80~EJ`A6r?#JHO<0f301YQ*)`o7|1(rZ~fuZ;nVcr^P$x3fOGy zekAY5x?UMkD>#c-%JdlK5gU#}cen5 zk&bgl8>crFcwmIbki!_^We!ydkuRM7f3DsP-h9wBtn*#T<(~AjaS6HgS6_I=cfOuM zIz)8zmwfF=|LpAR7A-!>;_n$xhGCjCwoys=k1MtGvv&5aF70rE8*)u=hGJ!n{`-Y9 zT*42Y>%eg?XSS9I5!X0-$53yg!jiKa1h8V7_-Wpw#T>2!{+!L0CV@KHoXGiXZ>y5S zww=Ky(}|0F%>Ysg6OHGpb7-7fI~%tMd<3>@qezhcp}pE?ZZhL4__2I&?J1v_ z>NLK;cR+P=SslkC*+Epkj&|}}NHl_)T5N4&6L5Aaq_Z7VV?;2HgPSY*wY)^~Dkd9x z6kr3SlIz6dhWUc~ODw@w!+8ixnQwy@S$bkI8fS(MC|Vp2Nq}Xi@GL-8!a(a}2HEbi z8=kG|Wu`!=PgmdTZ9NT1s%KqT+X><-9|*&IoSPD^Bg&g7YXN+?9bWF2Y>oYQQVh#~ zZ^r4ocj~|BmaI{}-5P5j<CZn6YVq-7=8;{nr60T$2=dO%D%e}(nU=}i)|^nS zAiE+N1peau@1a6IAOwq@MuYYwcKm@_L5(s6CW@q^s-|B$`&K<%Xg zQPmZmk=|A}N8Jf;9KZW{Kd3*>*Zhohf47QVrIY0Rl{dCNdzcp1rnnMlys7Q6VtB=a zCyePbyqVN78^dD%t)uc$;;V!60p4EUuh9z{_hKAo)%(RE5u&+jexap86)ECL7BO$0 zd5or4S@qXnsIJ|nE+khdg-H(kHa_=ueW8-#8`jyJcp$;_QVEUF2U;roTiig-tv z-}hGX?uJ$VwJl*!&nb1{8^< ze9$%usRvYf>gT_2+MvM+g_dHeL6i5wqsY^I+rCQR5uufRp8b#7x-M(Pbe=IwX{pSy zz})Un=TT95+3MHTiGOA$v~SF9r{6!B)LsPVEpw;(?MoH#B$i6FNWWvNIgz* zhgBhnYduYdp%ZS>_5~(O@;3Y6DrJ$Rupzor3k4ozWS>yf8|`b?K?laI!l1jW#7>m}5) zL%8>>memlcBBaEH5EFnE!N?)TM5_F$&PB?@^6&>q7k4MjwkJS`e>s>zPi(4KtDIgN zVT11~s|K3YCtCO?%HU`Lgx{*G>v~7JJrL}ScLm`N5ZsL0GeH&Y_P#lc8)go|6zcN| zfl~qXTOBz2Tv^x}J@!WbX4O_WKKGSD=cC{yN=&e7q@3o+-ep`X!{HNnDO5&@CuqnU z`!dOu%Q^W+oornuE4pTs?*Ph*A-Y>_5rzjr!+9VW6Qyl{wR^61uw^>F!m2Q$BBVN~ z3${YT*}&Uq=(S>*$3xudQ?3Ql1^D#Qk}9+?;a+$rND~mBY#W+%wel)?%l-10zEoGE zSHzYn*u2Rh6ZuPnR&=r3pyTHam;B0ZzX2G+B$b+IBDs;9!0#agdlvc7IZ50m14Dl@+m*wK<&aO7szWVWPVcO zUKAt?{#3jrT?+($;|Ep)!}K?YGdIpGOJpV{Ai$rNKJ4=Qg*p9Y*UM3^1?bB1a=I`F zy`LS|CoZx{4T=nFz4vu?FZbp8A@h6HXj2K`(d@Sm(o2VJWw9Bquzytu$5n%0S**sp z@CZ>QdyMpW#4q+At)ysnXW$gggM80b5I+{RRSiG1!0h);#rxONIkT z0S}g)xT)ve;zA8pIbot^?#3`Wfo9C-0C9a6z~@o@QP08Kr6&;}gVi+&zCh>;TP|Wg z6=#$83f}R)X7yPu^lXi2&V?~VEQLEq{Hl=cIE;wwP)In(lKL_8f2#$R; z5s=S1a1EJlT4cM!NdMOzM$0WBz2kfGVmZd4X`Vy%@1Rdj>JQi-HqjhRr_<@^>7gDx zWU}YllSZ;?dv$_Pg1^70Fgt>D`JVEgg77+<7RL0b4lV0AF^F=GSndJrhDLLEgK$vl zf460Vm*Wxy=^QxxRvb}v5z6T!RL99yrIFsVRhd+8T$z4BWN?)h<)+X5Q4w{%NfR}; zuGl6ivALzjpsZdTz9VvJM=)*cVr@l7XYJhY6p>oy3vTUq%$1k_!E8-jkD>J(!1mLm zf{)?9?fpMM?P%IBz@Nnbi`bpf>54P-kAiAVi;uF`sinH~JE4Q}b9dPvTvS{M4N6%x zzz%9$7)vz`!X4q8-c(#%Gu}AT8mGx{VnP5pHSdLjPy(ODkzXp2efgz^g#RWkU)#P# z;OJBO$vrmQWIBs3)m{^6ZDl6&y_QPHG4<5iD(SR~bAMEeXnCeT=QLctZSjG}LusU4 z#%j+^yxN{Hu+TL}Eq(?Z6%n=7f+)5G()(%YFm^ye%WU$s*2&d|Xo?c{gT|}wD|Ke; zG4d^0xp8IRRNh+k^6qDdi& zTa#`2EJF4Zk`pa}=389)RB_2?2A!;uBw&6XOH+hxHs;^lT1qr|m&ot1bgtK!^t#XzcJX_h*0pp)#Ry*LM*+7ox?U{Smwe~e?BIRUcT5@?Ci#<(_omk z&~Gx>Lr%0JARUYM_rKp!r&MB8fat>n$EWj6hO`5<`}37}h^x0xrmQ1I@Az!3r!}Wr zuc2+{@gV-C>}vKB20-fdGtG5=Q~RmqBFOCr(eLUQuWNVJorS0T6D{Qy=yLpRR`=mg z&3)V40QlQ~tF~7XB$2PL4}WBO`C#lFA+QLVv9m1o_oZ#&xoRm_h#+kFCh6O~*=?+= zz{2;)h63{AlP7U2pB!zHagH`My_wGuf)9XCCGp&=FTCxC8`zL7=8Jo@XoI&`CFW)% zIH0Tt%|dlT4kQ7Jze|W#W*cVXI9AQC@$rb%pQA$mp%4=L0ABv{-LIdUFbe8yM=Hl^ ze-X+bq7;$WM$Dc$`6TNl`>^Xk3bMKHG14@akpw<^WNUA<`Oj9H*B^BHewHs4_=K*1 zl7&P~{O!Vecw)L(fyg2o225O^Ul@q{t#+4*(;}vT{)_C$s(mkE61;Yj6Uo2)1+Z_J z*`(SlWIWz_rO+rk>0-pwLGB-8v==^a7DYWHwntYRuYXC-8R%ZAmaQWh;Fbi7l=ElU z*C$!NBXzS^VQ;4s;k^QrI)^^ee{8l#g9T6SI}aRkH~-GqxI({P+HJ*8b^Y~s&5X^J zi`BnqDYW}~QW?sCVSZ>zQ$G^td&4c@7iprnV`tRt1=Yhjy>pg;=YOrA%&lT zK5&=-mcr#GLqPv+!=0)ulWK=ThgT%Jod%91M8Lx#gu7coy+23Q+FlL~w&J5yFlj!H zj_I!;$q0`EcKyf+35cScCfQ-MwDS#`3fbqV*V$Lv&vHhk?jnpkB$B73)gk!-pj-Wu z-b;5Q9ne)$b3yJCBI=uD?j<*I^pfjC(3QhDhe%S}EHbJ&h+S%p?3E_nTl~ANY5S#M z)MQ|uvoSgx5AiOLuK5?%c+&URXk1032<_LW$YI8Z?!ER;sGUffADWT5c3LVAc`(#8 z)Y0pWPCWH+F>l8oYG0EUF<7Lx1yOHz4!H%SPNu|X$Gaa+*YR|-k{|_c}>Ve zEEA`Q=0=)jcgA57WfxdOndmgGxpTNCvXkXiNkX*tW_Q|W`#F7Kp{MH`lNvd zc6~!+KnrG1E7LXw(BU|}@=}M@XTr#6ufj(ZUv$!`zVqd!(?}es*1z`ygvvK`l%k~? zoDv9nY(yxvl@z&8lx?XP0M%$v)P=RS;`E z)7a{28Wq-w98&Z9*_jZzt5)${3AV;pn($sizEbgVAXvHGcqNZHvdKMW@3c$n4sS26 z!c;acriL!aBNz9(teIo*rwdn6u~`Wa5tR!zXpi#?uM*Naq%YnSyLafhXgecRJA3rU z5*297_?S@QbSx928a6Io31Jr^L=(%rRqIo0gndHfjeunNw^|}8nfWR|w5fYs7TM|C z1UBWvv&0}PSn-==c8!Bkf$}xL2axfhcZ;5_W0yo%j&Rvh`_lZAPUN|oewKUP)(^sT zr1{y$JRV&-B0s;gY(56j`8xQT1$lUMC@UHi;e zZ6ee75!XJN!?C%rWYUz5+g!R`2F$adrX{OviH|1&e&0^VOqp&hJx zJ4dz)WOMzysr8wSgOZ4C0pe@z@=PByE~ZNjn}*$BcgJy6e7J%v#_gsWIP}j%{MaLT zh$8x6+j?X*)O1sLd^_JCWC^|nv@jwqC7tRfwYHVu^SQo+(m(1!$>X{ zt_8UD8fuUgOCWyN(+l$8i*Pd_`EBBD;Imxng(*xeUyTY>&Q`4K$Vjt2brj+pf$27Fe%047#qe(ql7Ir)!mEj)d2 zmH58ifl)PK|4niwspJBOv+uff^S0L@-thPgLnhRs&l7b)M5p4?yCd>++=6h(YF%`PDJNiwTBIm?jb~bb5K3~(Z$iTgC za^2d*$|<#hioP@5Gf%>noH8~9Lj`?u^f697?o!4WV!#^kvWJkCh&~sIpV42E2RlWa zw3ent`Cx1OZjyz)sXU@FHSt^MhhDv>>Yl0|TYcE1Oh{FF{kVfFQmv@9oWX@ z%qTG;ez~3ukw$A!l<%aW5uP!i+BX#Q&V$ud80ryvdD{GI62%LWFjgBWRte_wLu;+;lFOX6C-?Z*Gj8kSKTrxr{l*&a}uduK?b2>#26piEheW2*2GI>1t;> zg*@}HUl9922Kj+r<@{{7A#%3%yW~@3>42_(Okj~@0p9$F1PVRF(ZK}=bFQl)zDVS- zhid1kGH4lc!ahP1nG*i{@E*&*dZO@>8tLABHeKUN6 zr@A1h`^_NXP2b1t4B@18xglE4k^z?aAb1#jWwY*k$3DRJF?``DT;kA4f#GlndmEX8 z7!tiOCI8g*DIKG_a*&ESkTW5is&#&*v@+EoU7HKe<15W4Nqan#y|aV{7q>rD-AsIM z`)*$#eeRc)Xbk8;-(+UXv{$XX<&=l#hL`h(BO1q2ur>g3WY)Y2d|?2Cn@c{ERy^Q@ zn29*P($i=trZ-$!3F*UZ#nnZ2Ax$?1qdjkm-)wTCED>`~ucZIxt;udkPa7+4MR5C# z-dWe+b_h69f7W$WHWARvUyfQr>5ctb=U(GG6Fiz^Jk(xNfv}dulvr=hTCq!NhFMi@ zF+pqm4FFURW}_gp2o9a^H+y!QV8^cIsaKOu7(s?;D!k zg1F!*4&q604B!&*s9PB1XWHB&-%KTUHU4Q~XmWW;*9zrk+YuFFHB1?00FS00o0Ut6 zW@~C>;A1hqu@!3$8}Ul=`H^!}A+*6a=swY*8*zEIWOoK&a?@YwQXI6(uS z7Ugqre=5QYqVu-!?ktn*bBFSid5F^Cx4DQP^J=a3q24pEz`UY5bIN^_v~$Vx6Z1^i zMn6i%Y&d5!(pVA#m*8Y-+H$^hUuWZ&i36 zni`+kIGU+38bW%TFAdD(*v(RE;MvQ`Ty2VnJR2I}qe7F4r2>Zx>^3rO*-T_rgw3lh zqq`k-p85!MU~zJ`H#_6Mso;&H-__qjrA1z=JwT=mtdDUBpLPgO4BzO+7j_uS&d&&Ca>c)#>Q4?`1Q0}F-%Eeyf; zCjkR>CC7CI&IkUc8_y$G|3gr6^|ZYE^x|MtV>Z$WH&Dk{7cG^;T7JE^Zp~bmP2DqQ zbf@MEO#w5;P~68^ItvC-!u>xJO=(;5xh;-JJ7b_zg$n@7qS zGoRxi_O{XE`q^gRA_rD{=DF3cgNG6=XYuZ_q(Ho=Z zUH8i-z@*O;t&*-fIS2HCk`3?IFEDl<-+Ks36HW$y{tI9x7#s$hrpD1+9QQfBx>_AE z?96+8HD)sy&i_Y#0RF<}j}48v5_2HS8Z2x7MEaUEqlT+Gc>arW`T38WEbI#SccuP~ zKE!lJ0gdAwRFM=%976el4RS~_L=H?=p~DWVjwc5X#70v>LJTa$IkLy5IE`AH5_G~h z0J$?a;;CMdoD3w-ERnb3ab|IMpx5%go7uF`o0pqqDKk!4VV2gO|8AzQU`2D&Q_`Dt*%(-7fJ^oL_5 zgw6@MZ~w0l+}J=%m0@NG_we^LIw)|$kheSyWLBmgo5@%Y$dZRp8J?K>_ofY#1Y3T4XF;_Q>WA!onF6$VKp<#Uss^p$BVW); z)#TG3wrc;QPp;kx^q8y3U5c;%6+Xc=)9S@VeXq$-tZ~j42w{GC=~A4;{Nk#`w;$W6 zAWSgBMsRFM+Ic=3sLp{uMI-GlI1;!C=Lu1LVlnwipdvvw#Sr<}BO-69c4zfWQ??y> zK}3w++irs_NxRrLicaU-9?b)qhOEB3Xz)NYCA^ynTN7 zhMcu)#*oP)?5;9j%kjQfRMX1k-#mS7wv>~PdOBsM`k?radOMD1#{X*l_^BBQg`Jn| z{Is+(0?!s5dPF*a{?0@p&-aNxN}V`&{Gxn9YJfLu>7O5s9^1l0wK+OKuZ=GV(zm5A zk!!joMk@s`Sh8_Dem_+i6wyY($^Wk7mPFi?7^TVkD0TU=B@kqi?asV%7|m3d@4j9W zP%EfESz?9i3oj2k?%3;xORAL~3YPHi?|)tJCYaBq1>IXfnGb_^7>tWJ_1e$&3s_tyRl<(ho? z1Xi_u-=u|k-Gwl^ofz*MzD#eoe6M3<)4%iDp&@R77hQ5J!>?mtFk{rEr*m)vaS}|t z+ROw-`aj<%MJUpz&ZaCN#pWp}{L=~X#`90^ZmaDTg9-h*46Sf+>ElX;2 zGrO+2(@8T%8d}-%cGU3`s*ZxSxAb^W-_ z^Wut$WP*UmwO4fW0_T^v*m(@w7KbjU#-XD%fPlumA3Zm*&c&|ogGW`j+wQOFL`!Lt zx&#!^VN`R&;4gWTzZ4TBsC}G$+Vhx$G`4*=px+{Avfi3VKeg({w;?(Dnhtaw1j<3O z3#VsI7)L=;z}ZP}&I*6RSS6^X{V1=8KC#SI-HmEPLwa~MF1Gb8M+>dW{dT({eXTXG z;gMI2c6_D7rAxCk>ygW}8bU*VpqBVzt+a;&lMEhXFGaEAQE&hU~8#hw1w_&`v zFx@Qyb{b6`WuruHfHozn7TiC`=O6ZhQb=;HhH&X9h%ijv)cn-7 zjg5%(saZ8mW`0tN`zY+RZ(&;_ zAJtk_rYEyI9j(#QG1_2tlK2e)CaP8X@hzW4u|;mO+(+xbQ0kdBRk<2d{^-}3e7!z_ zjWM(2&m97pF;K-3lo2nH@yeO)ig8TkrL8As2HAH1ylh#Y0I!74Uz~0 zSP6B}Lw{J*4maO0oLDumbYRxx9+>}t^y@9Ke zY-{K$KmMjj=;@+xFY44(Lpl1z^tx}w%3$nWaiCH9qdaZDnq(D)f2H(&rH3n#>fc@- z@8PrD{7ttulOb%h@>)@z4d9HQx`@1;2%Mo>uEpyH3feA>bL!nhYOV~A_MQSR*Txv# za5jZGm1xenad-4QdT9tvQ`_A9qu=(J!K&v(#3UAj)q;j>Z-uk#!;Y>oHU@I<6IIsu zijr(D8>T?qlC;R{$&jGZ++09@4h4-^h_I0-PL5BU+5@5krYZ4HPGRcERJqUIbMY$4 zVuYMXH@Z1a+fRPPwZ9rN6dlCx`9+l-Fn+HQ#=OG8ak6iI%jDsZ0q^?2w$q1Q&R))` znb2$LI!WfyDxl0z^;q&ge=hjKv!5V!RUh%MDDB@ob(UO&L7g2#sfM)xw-d%~*b zCY|;pHa;ao#^2DyhMKA;YKt43W_8UlteS#07lCxa9pUiGEVetQk3^HG$?N1j{D)R> z?NBG4pXTx{qwVL=SN%mt?G4wR+Pp}ch~mHdakR?k7v~&<%YBETf)SJ7sH}v*+d+Di zGa)Y|B-GYhqoMZ;?!q+?&6fA!t;NZ8-`O>YhtrudM7g_jt7g)pyf37gEE9+2C}xHr z+&C9mr!sAgri$lthh$-*nE8X$r0-jSLN5d>os$X;tnV>Skps4^amZ_b228zQUa63l7>mKW3|q6 z{apR)veC+Peu!MXY^m@V5p9u$e7}-=Axk9Lgn@<|k0TGW+F{oNZ+g_rjuqT*xf%Wn z=H91qPodHpdWxJ--3%zTIQiinIkEHaP5Z4sUGm7*xtlZd5h%A9~BI1hjPF3^X zS4C8P0i8s7>z;1!$X1E(&Sd|Oj zPu=TRWG}ado@iCXvx}B;CRZGW-y{Qd-uh6v9Uxawdq{j6HwK`#@jgKl93`gZs%-RlONXqiK2hYVDy<~1PMx}T>z>rZXCvoidcXRkR<;Lk zJ3!b6`T2WuqH3~7k#r}?Ro@`F2JPaEcAU=gCgl~kZfSjzcqNH7SH*^GU8 z6~PVmnl*4~YPWm%T9NT^D)g&gAUF5$cz};0RrFHRf*M_L?03Md!mL7UF+sQe_(cbS z_EERnt0Vf$F~3wfyq=yFknfd9`wh3uZs>ISF9hm|R=m<=;lb*&Ulq&3mk%tdZbm~! zlWk^48tde9#79B%5nb@;AkqLl1*BY`4F%JA_Z@~L<^v9SpKlpcPT$U}yC|qIU$@<2!+3-=@lnjgDeyTW#|Mb>10r$kLb|=exJ{jHm}{aHG#_@s8vHxsG5nKn;lXxw*vM2fz-|JGmemTZ#E+z&}Yv3$7gG9gQZr@iGWWXmt$ zs+cE_j&7g1SodJgcd|G=7^M6oCg>Gkv8z&vfwGE|&h8iBZ2B+L4l|*zNjiUw!M)n9 zYk!6{knupLR$9v4$Eq*$zO_pa-RX!rW`2$7?)o{}t(ZY9JVgbZ7#I(tWhR`-dD2me zR?hoLzNeK0m^@;X&jeRlv)kjZqV!JOEvfNdMJ2clG%n&ax?t? zl>u)~wh<8Rn|FL%wKF-;E7SFsUp{A;{My^QGWX}1s-`?!gYb$>FZO5Ku!EN2mN1bOWHJ zTjDR3--}K1(N%?~PWUOARJK~Z&YiP#w(4m_7c$LvB5T8KV)qf7EEN~T@)kX&i4wYt)v`lJG$cppW(`V(504mjv0C*q<5w~Y1F=Wl{lyni@77YLUnBhM{`72@mVh=9B3Z$qTLO9^Tzp`uv6 z!vdPcKiyMC50zU8-)2TjE<2=gxxj)tmeHMNslG9Z$$_K=sqx2MfwP0+#_Vj^OK}HM z)QeWw67Td-^*?VUVW6sC8gBp_wU*&)*S5IHwl>!KIaswmNR%pw4QYMEYOHxcPK10$ zC>v!~QMgMp<1w_iSt{={TmQg&CHmmTOamh@vHF&XIJ^An^199vC(bBh(KV8gKNdM| zay-Q1z{IO;rhMG6lCf@MSCg*FkODJS&jX{Z>G_bQb9Gaybqy4rtvHPmL$bGI^YHYR zpQZlIsWL6k_k4?HuEq}cHWhh@RJ$s&!JBOEt#fK{3!JEM-}b7O-XzRXJbmn!A9qWj z#k>*tMR@N=m^bQfNB@rdO?0RXS*xT)G)HZ1Yc(2qK`f?8c-%X;vjTeSK5btxQ7Je| zV=5zze%_CgIk7$Nz0vkA^PqF7`tsW5(O%kN>QT;ChyNQ%_n&inQ`7{SX7#OvM=KYM zq9lUJmCy9i+{g8ed_A&&-$Md`S-T?tBsr${oWWKKq#vx5tXPf0XJZ?}&$>&C-BXm1 zw>W}Tr(v}8QD^G$wM0oO^t(#Bd8 z2_6G`dsT;fkaTNTsvOj&u|1j&GdNj{v%Is5LsBM!4|TO&qQRCb#A9sWiI;Qs`f zj@eyYYy@Y72lBrN|euvRI3Kk&BP46-6DTLXF!yN)-sxt_Ba2j$U;J zg8f{-LnoA0P&%y!2OCr9HNKRuD$;)zIP>fi47$1ZCi4UG#BrCZ(97=v`wavrt32P; zOB}G;2b#qFg~q77k}K9^I0-#vjqQg-OHeX^Uxnh#B7reh zzjwI}#}&J_Yc9ibH=46PFv|=7BwXG=aF`k>Fw{g8dGsnGlhi`TL2H;vY-Z#Ew-Lq6 zcfDa^n>eBaJ|V!16zLUj8uHY!VG#+mEs8$^1qxb_W?-o*ix%*MFhE$-&r1wSO=o{<6%I z7w)^pL%FGc6O}S2#D4HjFwJqX=SWx zGLj)%*WyiNlwzyBa97zT`jnp{HQoBbMKUgaTdVTb)8FB+%2jay)9?|n(LOK%RQX9=S2w-xvqN}3_#?Gwjb5W-X0);RuwI02 zN1rsJKXBOS;#wd3;)s9pIw-wYEkzbP+%D@a&8g|5b~tF_PUR~FBlA1w#sbmWOQY7k zSWGZ`W7}guf}&`(2~$TGy5B0d593?ctxq@{f`0D4hFcTrwdB|UZ&z!F;ENHn;X>Q)^^&59qHKybJ1-?k2%vQzDh0FPO+%)D z=Z^aVQeTy|5Z`|QI4Azui2GvnD55NMiF2cWlUegi#Izi`{%syV&~dy+Yj#o>N?O4w z(ykv4PkYBJ(}#pRb<378#&Nr^xm<_jnI(o%i5i?_+f@UezVpI3q>Mn>0O*yX4tQLI zXe^$R89V)b`oWpr`X(x80Bf~zsrJcCBIhy-_j~(D-32r{uL=q-|Cz*oUK|?&_)AA_ z$j+I`(+7%aT#=KXkesmnR1MORRk+*sH&dS^m>Y6FK~rO8J+i{OR+2#hi6ET?ba}J2 zNY@YexB9cC5uXz3O03ut_+s=c2)K`4mwMo~&ApTlk&=!IJ4n3Ee#sbwR~yf~drgc| z!4igX{O+hGe5jMa#!peGkx6@1hq#W$5=xsxGiB1V3-(ks9mUG=tTJz^fxmN~hAtqK=0-IE( z(ZSRhCwx=&05s_%MRftLgjGUVMCa_4$=W^^je#hFBl9~eC{Od^{47rDd}1bbVSBC7 zAlS3REc?t0xj3<)%GMw@VyaO78TNXyx)fQgP@Ru|Gtr2$xO*%6fTLv%C?rgXjTY%3 z6UWCd>9e_?Cx1+R@j2ee%HVNBhUfpd+ic`XJj$D*R1tddi9x8WNm$HBo;ZQ{Yr*E7 zT&HSw+|6xuL=;|OeC&+YnscwIs@*H9-Y!LpKiS=X-$Ge+T)x73GD+5DoW?~rr$9D- z`Hb*L%Dvnrcco&As588Dt~DT1^=wJyDF&UlSLsKhfa9c>cu{Mh=+d>jw6SWoQDWL_ z==&V)Q+5AV3v&4u8-0IvB(OxvZB9T1IvZJ&9(s9-Wc}Jyb^oyfUu)o`PH6&b>hsdm zM1nctWY(oTl8=_0FyayU)VZ3`dGF*yXew1qc&+*Qw@Ar2orWfp_Ld)HQ3>!(=MN{^ zRo2f@;0~^;L-?zYKp_(vgjK z`=I=bt>wb1w83VJZf8MkU@NTsIlALTiibh;?hxE<%UolnfGj33IhER%wP}7Jys?nH z)F+-iYrK1O@2c-vVLHA#ZA%zyfc_h=jSc{1^=Stii*q?_S8`$A%!?aou^u&T7<>77%MmyxP!{7#!5~#9K%P(y)Fd%@?#9hd4E=rngGW znO>DWNP9J%Vzk-@MeF%>@iR#g8NJ*iBHA=t)1Vv;RW31VF*sBE+Ck@$3}|;pFO@lF z-c)p8jQ*AQt8v7?e+Z%IXYDw(jnqV#`b8xYpL7<3My#4pzKPjXnPI8PDT^Z2u(S&i4m8}L8en_9`rByc?#{E5eKX|o&Gb0IYm7Q>aMTSaEWKbt^HE^c#%w8O zVnEy1Gg1Z?^T13b)a{kdeN$;rMtNH3H>Z>M2k|2}v2`2QT&Y!;H;jDR-&#-Hl7z1J zKi8`)`PvRHWB01PW`0?_x(Sr(ieYO-?|ub`R@QRq(3{?J?~MjvmBMm4!rSb%L+{d_ z{?hhENxSZ4K-OI2noO7?V(B=*68kZ&{rtzk*mv8rELa-aW{PlSTofC~(ZR{4z~frL zjw5-L7w$uY=_uqi7^SrUJ@!kR2o=X6EsJvDxSdkS7L6uHo=95T(v9B2r4%4P3MYJcOs|Pi6QBJP|_F3guFVXlT~a`YmG>X z51Qm#^V0X_l2XV;PZ=|iEE36_VCiL$qPNVUHw@2W-W6}cvm?WwiX;uOoq@x7fu4?- zk{ocMbpaswH-1tRn*vQIEi8q>QlVE!_2!jvbB~DdV-t1*a5%YP@b3d2AJbm&&GC+k z%&VLGH?o&>m#&DIN1d(S8UO4~mkFtzlcD5-UekMdr}&bpJrcz>>-Z-hdnMIUd9CP8iOS%&CWg$}JIqcC!#|MCA0NfPU- zuH<7*X#LuJnr`o1|Wk5o6N0&k=?kVjG@gg=^?$ZV`np6(dI`fCY62r z^q#PmrT@mRyHxVW`>-dSFbp-;VlPk}w>Gui=~Q`~o%i2HPT?YV7_Ax*UnW@UQ%jop z5W{+!EBHOMUnqhJY-{MF-Z;AYfw)VzMgJDn-fH-L3#Wd2=r5{bAb#QN(^I-_W~5uJ z5i8Pj-!PTcK;JHWgIfg6ioA6nMg@$17g%jSyXtxkFXS%UdmDY5g194|WYWmsRdZpA zvv16pC2yJ06w_@ydd)k4oB@I(D@a0hYH;stH>D9o*e@uZwJaZ7TdmyZ-HvTkquXp{ z#w^!9VLJ$h&&*98eitosrJ9CGCpE8#B{R1S3M}SU_5G$k`0_m=2N$EFS^1(t4S!`z zC5Y>o&Z<(s(rG-0!{6O{+}Db$XL^KI#wHQd?)dls&K`+t^ufb4-J5y3zxWP>zc9c_x9iOZV`cD6tE~PU;V4n&B3v7RK8aQ;4L?k+*vY8*(F#z)b$6l?K0#XymL46} zc#~#*(r3$B9H9EES0MjbnQ)o5G;Nu`M5E5VWdL3TNX~6E0t|tQ*N4)AVGW?g+IxMP4)-FQ(hA!QyjXBOCZec#z$qDQ&zXi82j@mhVQ$+vCe6GE5D*CmJwmy?iH zjscIZRbBT}**&b0En^ItbljAmJ}uSz2`@-IfmJ2zO8-J!#w9}0ZTJ?HCj zWHfM3%3ogW@5?2uCx9`n=Lf&=ljXT>2EbxMSt+4dYdozbaenh}B^fG5#_BtD_?0vv z)nz(NWlD`z^6kED3EXI#NeZc@LKi#1KZlt`fWf5TpTCcrg8Obd!U*W0!*$k4f%#vJ zw+*B6m_F~PrTkcCkZ-7!55N?9|C7=yzNxHV$-S<%ZWy{;uSgij`a-}X-TCpPt7_@2 zhXh@bs3vYoVToUyp_Sd15zESAUu9oyP&OvzA5O)REVJ_f0|9wqn!UNhdjoL&lHicG zVvs@*Pk3#FFI34d;AT`?5O>_lF0#Osp*aaRdb7^ZK43IfO9A94+-p-H=)f|cPU7>m zx6J*O>NIiBu=g6f6UScqE6w`29+Oe4#dzDqBh`CXpLG?Oy)Jcj^)s~*i=tJ_3!w5D z-w!1s2Aa7MHyt5TBCk_e-+z2;z@@l22R`~G?B)qN@$k~WfV$i&(IbB_96_Y22&IPfB$KRWq=@`j3&fD(~5h@g?k#v#=e-rkb&FaD*M31 zFzA*4ei4Gemn6zV^n!6>Y~J7hmMI-0YV`AY7iifY{ho|9-kbqtT2$61JBCH-B$SQ* z09fyK4fcusXti0KuVL}uB$^M>4H75g2{WC_-qF|DWBXpHknyJtlo9dk>!6j zcK%Xg5;7F6wVN$(23FXY3t>uKimlMv7I@uN9n<%(Hd$u=54n?LG0_fsjbIh#qu4wN zSA?pTiS{1&I?bS4OsV2i?mYtKgDploA9poJ!;q)VY5I@*rYwa*xDfIdz2L^A#JeE` zZM@mgmp0LgV6@JB?x=G_&p9^o(W1u_n@1?pa8`m;)f{Bhwi%Swe#M+Ew;R0GslQz> zJJPSm`JH=#c>aHUU~|%AC8(`ct{3+j`R8CTvp+V7_(M#g@SbCwp>a7vvgqJ&TaA{I>>!+9+`_>GcGv`5DM8d1 zqr#myu?Z2%CEsaaLKnB+80;0Z^mR6nGvz(=4)Eyre2X2@rfuHX4>n&5Iq_hBCpL9V zkVDmrxo)r{Lb`ic`~C3LCBr`caTKPKFUP7cG{Axv-g}Ti(JoSz!AJ^IUo*~7vKB8W zde)AgcbnTh$FllE2*1>)uU((%&gW=^!u=(Wh+>`Qj=5Ju4mTj%l~=SrwLTg(eUugN z=wk$7**N7`Wj%NJ$(+vNy%Q`wxxJ{ zEUbf&v}~KpY8UZ>-ms_Wtp~ZUB`TxV51!6g#_q+%BCLcm^3mmUn_5S>(pFl}Ce#&Q zTebM6dz+;v-G5d+`?EPyrVt}(ygH`HYgvO+Dl zDq_jXF~i8;`YGNUBj;XATk@XME|+9yKNIZ}Dy*EiH=;NsepN{~B+H5df|rVxuxU!Q zB9ttJ^!GDpH^{gL8CB>&bB5&b2PP=fZ!r6dyagC>NeJ|Ll1ZkPn@{PG-b#wQeK>b1 zCg|Z5Y7$~#I1k{@pSBZLPZl&l^TR|9PzsZa$ef*P{^$P!Iu3~cLu7`+Ohh%Y(i@IS zVr?A@puM&^B+F>?&E<-{gF^fUw^StB!51lz>UQ6y{~gbBF1;}Rq?_aGh3GL8ZXe^k zWTF?~U7GMCdX>m)ztQif?f@s~&&!md8{eG5s@GqFZ{ZDy*n}zE#mxb8j@dhYF4rnn zpi=u}Fe@!Gbx)BuOg!yYELs|zRNCh4Ot+Hj zN{mGFeCWewmH+wL$RiG(z0`N}CgAe%LxZr0IGHb(DTzX%LuEC&?Z>DtubV3;5#@J# zHoofm8yCFPutEF}%9#%nu_1?N3KCyBACI)yn3u&=; zlUfg}7<{v{r%^`I2XBX@pt$0m%HOt#s#^})(&bHf(;wRRmDuqg|9z6Mt@oma2rs$| z_n8Z8&M}(Ius9R0%{0ddHoJgF5~UR+1gKBZ6BLJ?ugT-QJ0WoGB=tKpCBbCXsiI^0 z*)Mh|_`Mlh(`IS?OxHVxq&cB6(Ux;(N5B@6-0Yizny%BOt*}V7|8ycjLp{3%1Zk6TESD4gUrX4J^z!6S8$DSSe$l)*mqmxPfDUy z=h`CSo?2q$3!AUE$cr@VG`!_kNf}ibs0pFFr zmxMvFd0W{xv*}B2mP6(P7d>+kZotNT)QYa_oC#n z5Y|+uU222uJo)>x)|MB_ArhM@)BP5!H17UTzH4t0aiur#jHfN|v^^$v5q7IbozxFK z8zCN#_G*7oR;mgLkfP-kgLZu7HBwP9NGfmlv!n4eu7jZLMc9aedquhFuGYWpjEK03 z9i0eJIs8uy>wuI3ELq4IyI!;sYUWtU`}tVoW1g9U@ri%^%H_RtziuJd$X_&H-Fmd! z6`$VP);lXl-p&^MzNS($OufNY%{Y)fbu58n@U$uox{e!?G~ecdW;4=I&&|YI6O4}< zWU1+aPCtT$@W6)ebs5}EBQf@{&GozQP;#&Z_)Q_~@0Xj7@0@dqTYG(N1cPQP?zO`9 zUlO{$q@g^Xz-2$uY4P`kmag)g< z@|3nR`A`o=OLYP1X0#-F1OH-8`mfrd#2lrq+QnR8tp0hQv*!4sA?#+K!Q0g3kkP}h zhC634bAQdf%o@GDR+~TG7F@5n8BCs2-7q)k)r&|bjw)`Y)dHvFhyu_zh&gg{o{)?S)Af_T%JU$0W*uaE?^-R_p3 z!de2H)WS{Zyqp_iF41;GEa$2(Ln)c@%A7X+YA9;MH4Z&;8!VvScCeM*eOv#Wet4td zq9$dv*(ew$qop zkvM5!5MIeLRwhwh=c+1X>ifS{l0R8$rlVx-i(BC>3sHce=RerN9eaqF(aj-$tx~#D z@=h&`t40AQ`Cl3dvAhGTq3bGfJOy)m)PgrXGbM%(yh1)+VEieo*?IVVne1{Q2K^aQ z{p#04n=e$%FPB$`nk#?D!j~=-lU!=W)~PuajKPzXmjIPGsPx0;&@Ym050KWyR#R#L zw3vswPQEtZhHBaAngp4kD^l8+n|>{d$@kIU{BbiN3+%vsF!UP)8y|m&0Ojhpjn4D# zb@j@5`RJc=T1cP&kd&eT*vp$&JDE%n=O+&tvV5gVsCIvzs@^c>9&tU99n9`+Z=t+- z>tEQfuZ_6}*So!H^ZZ<6z2OJSg{mZQ*3MLe7ogZDIt&aA(daoP5McB6>k?PBB`z`Y ziqjc^rbJE&8n>#K7;Y!J^l0x!HFZ-Em+8YT);HLm*kf$?;c!#BAnCo+$v_=Zjot1p zhxfM#c05h2QPC208E=f@Xr*4d&8$PDV}u|7VF+9d{NQVnB}MWyKube4NI7nB?+fD~ zAzyd$<5-fjel}N(uo(-$Lx?#De(|$~j!%-A$(jv4SIM$k0yW)6`Mu-gW>xF{FEHoO z6HwDEB~K)�?m}EoAuTt4MY@^oMj1_EqAu90Z#kT6Kx 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%0D$U>STzalzR#8_p*eG#9SyH=|wExa(N1=U^=bPR8 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%0ALtObtY#Z@MOxw+enQZ?AKcU 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%0A=arv6Ob7uZ`W97Wo2zG4Lz$F#)z7{bbp2?Dr zYf_>T8>w~22`vuAQevA^kkAKbZA2Vse}vBj{!@K zf3Ax#wkR4bMo7#^-Bz4D8k(7=K4zSt>zb><{t1y`o-tcq+A6F8X(`}u^~rVe`!oJ1 z?%&Vvi|57ezoS|}gr)$UDsWi}8>~m{)H?%}ea*5ZYrxA#GlmsMPE^S0E_MB%Em@S# zjy#fqNkTVsIo1#w=WV4o1~?9|R;ke}z{D)$wzlcGzg)O2*?2W2D6lh#{oZQi~ zm@Q+{ASPTyPTDTItnAJJ4QF4^c}J7@apmpTuS3C`e}I;!=sovYecMz^si@<4LS>dM}Fy|lL_E~l16f@YAdQ;>+6Ny2(Cs>AjoGs_uyGsnGw!H`92RFq^DU< zhPmv)}j zn9P9sqXT(@=aPJel*16W!8J4vRgW@vn~S>mBQx8|NjB=8roI1+FoHuvdX=9qQxj?7 z2_H#e1^AcSy2`$HlNdPwx`)k&jS@!{Cm>{M)2o)_L)5hz=BiY}-t}JlTz40e7ZM>y zi%{b2&G!j#Z?~Fau>?jpz=1ayK3SgdW@z^|XuSG*?}n}eOZchJtlL0$5qbprMrr-` z%vol$Rv}nI8>w7QR_NpjA1zUC^0KH@Cf+J5yaASZUSjDj`=?Pj?g(OBV}hW7Fp-?%Mp-Fav6sZ`=^*J~DO zFy_|BlM|gR{WV98LL=Sm0E6tXOM=^Lf?8Im%VmMV`EtV`OJG}rajk`~7x+!)2o3TU zZn*1JuBZruUwbJAPUBk2M01FKKD!Y?j)V{>0)JTOny{$0490P7Ft~YMy@}kH-*rc% zoc=e(nolonOnJan0ad;Fqq^oADz6GB=kDWerg;{4;^MU!341{v7O3!Rb6;=k{w^I= zf$9R5Z5HnYmVQ~75^xg3@D=xrM@pfFU*sl%sXG70M1rv=@^eI^P_iEAwd(nQ=YqeN z!Bek2CVEXvVkF*!t%6W3NbFFgGhhWxfg-*<(1u+r`X%mBwP>8%WqJ~FRGByZ$xUDb zSk0r5W;8`Vl5cLKjwHzbNEq)nm2~N}qTPu7+8%l`8`qlU5t_IE5Xo`~Eg1~B9P{UB zVL5k$Zx|*+{n#A`$1vr4E!BFc(?*Q+nZbpMXw7sHDITGAsthpTo_fqv)Nj&{DL9TZHOP&ntf#?3m@xg_u>C$LQ2W|g7vhWzH+D!h17O&-rDR$@~DD z2>&Y7-1J)Up>6YST%RBx$cuj9>=q$&DaBURNb6BP&l;$ofv^bH;>X(%3AyNMLJ2Zb z0vFyAkPg|AMUEn+U3Jmc3;lOuiE$(~kV%8iUurkFUm0sQ0`^iUQ(=DUt4`?5ogGS* zWSQ;nW%py2bGJ9zZYlgr*yqik{I%sj)+pm$rIj1oh=&Ah-y>~2Y#(XM5ZT|DAqn|e zyU~2{z?|R7t2t07r6vmzC%X6G6sVmaAV>b0fvzPe_i9r*Vtg-j`E;!$-+!->ca6&= z?^qpFl;9-ZL5fl3Ky8Z!E~0ozNSqNI`yESxL?(VhCKcl%a22eiL`U!**O|Jj=A(SX z=)+THQ!)U|`-r+eK$4!puFw&!aCCI9(9QStUy-&EWibVkrmsgs$q(I)&pA%WWc8O> zEXY%{Sk%(7bbLF?wJYFF;JiYs{vZRv8TOjvKmO|IR;xr8ily8u7&c`KxkRK}OF(?Y z*OB;l0<&zR9SVph%sVmrR0~VG@F0=M)`OxX!reQVC25}7nIbSVW&DH5?{D;h`}668 z`x@Dse`rROL>3>TmiKu2=GOfV3{*D>S?I5jQ{QXn43%;+Lm`C8Mt0;nfW>5ugIvt) z;aE$Bt|FuY-%8>5?6G^AHE^3GywT%q&Fxk-s=n zFQ*OILq0c&Zkjx{SfnD)s#val`g9!HJhQ-3Zc`~36Q za-!IP|CT$9O9fqCy?ig82Uo`a7FBT1J`fPg8}bcey%fJq{mbQ*M$;ZpXoUQ(WzTd| zvw&rnj|d=@=fk~%>J(h(+5UY^rv79#7ciVuc-Enw_ohist0kMD$>K$8L{ULT01@S z!fcdtpgl^wcZ$bxjbM-F2-?3FqGiG z={#XjvzXqr%2iYTdTZ>EV1%Fz#>v?)C$&|GA)? zc#+9<7u1r%>`ZM>yl-q*E;m;PUo~unE9sF(E5DZJtpwKCPM*d_h!)7-M@Ji}x1c}9 zkWa33s@XL@A0n6~%4gR-W#2(5oj?k@n+y9cMCluIIQNfn5)gB z|0(i*o`yT*wO$=8rtpu3P?Y80Qt56G<+=ZKUh^WBeB=YOxP&k!s1#i1-g9MK?IgJR7Wp3n=Hw@;enKN%^{jdPGarQwKUp8e`4nXj z!Q@NmI~D=wuV-pl-Ne5DU{~#udzn{F|L#&&Z#1~`MmyxzrpeSt2%w2-$vv6)&*h4{ z&>b0)%tS|;Rp90y&u4U`df62K*+G=QiM(ZC8K&qhc>2Y74@Vg!Fph72x#(RZf$UEZ zwF$B}AgSe}Oq}K=dv{fh;nJl=?;bK-vDVK14haT*0qjSXnTu?gaA5^(=E_7aaa<=N zWq^zNxEbV)Wp)0LzB%H!WK8wWeZyBYe_MvSMaT=w;88Y|-A}G11JP}ESAx%smQ)`3 zj~<)_*CV#RCjxyKty%tV`t@DVc)>@`cnWpMWP?CBzkC;2dD5Z!)w!?l_O)&wg2ola zkVxv6u=TLzo+nJ0(TkiG6+&;3?*O5lC<+GB+oZo0CpvQ0JGpl>V@HEK&kP-EuKK~+#6Y;gKV09Io@-Vb%+6NR7i@0g^ zC5DQ<8A{p8WJ8+CxGNU%qJ}NJWmCVqJfKj@dkJg*c3W96D6%tnMgPT?Dtpi$P>cIZ z=kwCtlF2BLdX=OdQshha6;`eK%uh9O(A>C}X+P{T#joeEctZm|0Zn$ZY^!2cJ`1&y+c2JD{t4P`_cQ1ZoGnme`n@{ zUx)gzNF{i+-)*RWooK8^oO#|Z-PbmXlLcDTeclix_C*H0QS{#DIWlh14fum151Q*+ zkwt5^X@dHo(x5rmmzwQD?+{M*of^r}+VJyMI>PI8wz`M=x?jrh9{|I__vKjD^OYx! zzrcAFj$}qodv6{8bO&v0Lg<%$&WJ5FiT$widyv&8#lymO%pm4`H=!5cwM27sW06TI;LR|e z!C4mgh5k~%MXG^*eL|S`hHXVu-Hz05E0{Gsy1ZW9?wD7yZwaYlgSkZ*ML|dm$v-m% zZkpEHJ2Y`)s%@vkRTJ;edE}e5OHhMGp0WDxyVw&u$ZyS^ncc33#Sh5*#y5@1{!5m> zxs!p1we|q}-wHNa41U8(2BQvTD-5&%4f089s@ooH&2pqRmZJ}m>Q+ti>x8ua4Sz7B zWJd~w=vam;t^bG@jPvy+h-uCrpt%WThX>FliAU>%dNP@fP&6atWG2i^dBD>W`uOfoafpYg>CxAriU z349jm&sY2KFpl4`>~+$YGDChCdbM{pa$mLxdTa2Z7H@GSqL<`yJ0)o;vR?g@b1j2& zzqtwR-J@{1jtztVR5apDQE%;-8Z&lpTN@B^)>XY1W0rmPVjI`f%O?YjW{j`LB?FZp zLpq4$nx&*|*}=!MjP^`;dh+xEp8wyq&sAp$i~7 z)0InvAo$*`uXzwST#l81V-A;Uduz@v;f-%CyzfYmaY`P2%Sx+5Ge^F&K$J9z$Tj{b zB>d&kvltbtF+@_E*<*Ls3+vLm8i6nd21r?j?6d?Q6<%3#Sg2FDaqKJNW ziPOv16~QYfHeuRIa(=4{^7EwO%Lyr^o-atWznxE_U~hccEuZzRF8@w8IL+ zI^G(nEsTLG^ka&kPh7nwPRd-a*6jV^PBBL?RQGjFZd>{s^j)RMCLeHxAr5~hdpeV~ z#$&SQoL%!vsKTje4Pihc094`z0-g;N=#iQ0MvdiyENw@Aj0)1Tif@{2cy_oPo?9t| zypDiIbQ=_r#PoSBW%E(v%ta(|4$Ms=1{2|=9EL!a>#KuQ6WTm zl@vzKIVI+}134Bsm-8t?CFGd%v7F6$&S!=>j%{o<-@QLSe1F;>@Vs1hdED>!+wFQy zao&3h?Q&ssJp_Br&-H;L@s^+l)44vDFJYa^5oCyV^XiOujdA=MjYX|PlyO5v61168 zdsqqmCmbc8{hvKo@R;IsP+J;DPN^UJ_LUDeG`&Y62`+`(4w<55_#tI&r>P4vQ3@5p z8XRu#B`cY&R#L*Zgb3PQzd=s8(ZCxzfqI2AJ1jP7<;4fZrw#M+9)t%?DABvvZykZz zRslJG%E$$}GT73aVJXnMhk9vbcG&$pv3Ba)W_spkZzI)bX=f3*?5>N=F0A96eF6=A zD8Z!`9~pbqmJq8Qe%g|0&nx3jZtro$jelV$gD6g;Ym}GSn^7BH2TYKH;&KgR$*h%S zs{vxpz|Zc{@d}Hanam!(M~9lDfg5GN&w6RvWeg3hqNVzzA|Rw*3pIsx0b;fjw_DIRfm*p6Pw*CrCwO^QRKzxj3=GAKJ@nE_UxTFnbN z2%I-o4Xt{6@(ht}*gqO;2@x>f3{~XgKU0fI$%wHO2aS5+I}NeYA)Jh9cPo8xjXM1I zayEASSy}_P&!4Q->w#ynW~=)lBptp2BN%hfrU$#DFXBeFBaG|*3PBLxA^K0`^4J3#9aN0GGGZ<`SAf=5%*85u3Ye{fur3f05l{5tzW1N%k9FGTylt8q@gn@Wy)MR9RBg@Ol(w1#&v&>v)=! zZSvw@gG{WFzQE@j@eY&z#!{Ru;*qv|cGuvRJSQdiNYj7brDHY8&rU<_MYepnD%`(> z6l7d814`^l9G#^kY2H(xSTz|}ATTWz)MN52w%@Pd=U$&<-S#AHKREW?s(QfXWrX#u z)a?31|MQ8z=M zeQfTpLLMF~|p{GzhDePBYq_0$gLp?YP-VrOQt{60Gar&p}8qMrl`8rZG(ns1c5X(Ud>ZC z6cR%|Qu}Y3ua50wX~$vjSqAI-$dIL8P|tjDMJ2!A!t7-hF%PqqkmB5vm*EC5OeE3o zUl+w%C$l;DM|vNZ1cB`h3K)k!V3*XWihpZT0w;0!_n!=)YsU<0rf0rzCj zs8q}iu8G-1LZG&FEw1h;?1oT$ z>E>&Y`oFhBSj*FAMA^nL9XpMXL z>O({5tOQr>6ZYEpxrqI^rru_+#PjVhv8%o%rui^~=(>NC>ozQrA*SCdk$@+hOF5Te z1qeY@WP2w9&T^Ww2EJ3#rF?0Ry|3j5ca?C#lU9|b{DRzDeU zV#T@*7TuqRPE>lf^KP1@Y1@DRqJyV7{<-dmV(%h>ic05yO6mD-*i31@a$uSH-wW53 zX>Mpc(hcWGqbDm1&`rZ@%i8FVjdUD*We|l3Rv!vU(1lzUb3GAGi7h4tcZ_jXA$6w2 znh~MVZfgy+pr4^L`cr^ylbsUa3*QfjwHh_-Bzfic<2Y$m6xy}~sp406`< z-gGP02y3EZv+eak!}u`FPx?oUn$zcyH3y|TmOp^np|3H`JuLZwZkhW$5U;rm`mYiT zOoPlTL)gv01a+xcpC7gf>XNbQ4zQ=U@7(SNd1~6!I_IT$%Dc7xn`{=z1>5gbrzpew zDl;7*CZ{_f9r$-xT=R58;vIKQAH&JO`Jjd@XEPEX+lq|dVdVNF7*RSP~vh7QBa}aD$qU0yNp&UjW|1a#YDU zDGq=0euSv%rCxqlQLYxP$o!Z-P(!p0OJ=e*QocNrU#9r3A9Lr_{bsFtU?|a%K^VU! z?~#f+d@;Xy&e z3ekSx>wyU?com{W)fvB>X7c6TjWTS=(d|5ZT2f)Arqf-lXh(h4MYvIYPp~YIIRVoU zIyVvkyWm4D%ch@3ZP@mU-^zvL!j?x%vUBWTEidM>uO>O7b70JFvO@Y1R?^_nTR&o( z<@kO)W~X!Gq5m#G-dQ?ZF1Tq#tgszj6=1J2c<<;@k!M2C5pn(H%kaikY+p*F*c|RL z!Be-REU19{sVNL!`usARz_0?VuUFCFC*D7_f9G=eVf{{$2SR^-=s6yc@MC+`XO0@rSE4jV(71rlJ(c}$m&C4uM zBUPFSABWP=F)W*Z!Gr3zQgo*tPfP=awQ3zKT~Etn|K=|cg^&2M$f?|3S2w`6;>L8+;@{<&c@k%C z$lde#kGFCJ5ndMT|G;*@_fy8&l#eDrCPWZu3lK`!9MP{3@-cCjTCL7ryPh6YT{D+^ zf^LlR!#0RPVx8nYU92%nCBH=I5Hs&wb?@c$MhE zn}Vgs@o(8jzA7|-m`O0GpeLdUPKwpqE5=@6~9J|$9MAgXUu}qIJNRzzZw%>h|2Otw zt?+9@QJmm$Rd8bsPKNBWL}R)qEr(OrJLOo*qWj4^moeG*SAF*qwzJHns=JGa3@WkL z=Ujr~y?ca05xB03zOPdmIm;0GzQ~m#&0dJx$~A7_AAlyHY7N#M;AwNJ7tb5S|M3U? z#o55Y?hNs=PySuhlQCMDKX223b9Wx*z}61sG|~L%>KpLJf93eBq*i5G%&+br8A?cU zTchz{OeT)E+DHd1zUMmW81{F*s{1Aji1-e|s$T*aeU%wfklk|gd7r%GWb@8UuO6(U z!b0X82~|#*4$rMNOAy(b-DQqm49}fPRw!(a(+B6;M$_B?<%L~CK0h0Cs>f~uuJY}T zSq-!6UN6@?G#IgYh1QC)6rBz+S*p8)!sU7)!YPRI6_==8bG_c?3Xe&kTBR}2l{TI+ zTo)nD^2YZ9kXQh^B8#@qq~yfNMso;aCqh9B54i4I*3Q4Pt_f`J2KTn5D7i9D9-w#E zCGz{Wq>Kz4aMK;Bjt!N6?l6r#^nD57Xyn8XGG4+PPo6}fG5vz6nV~*Su zF9efl(n`rl(z9`k8c;rX+aSZc>-aO6dVM>l+41y!t-^EjgsBLAwWh1$CweRRna<(I z+~v{+>2IRE7_@Ky;#09dNq(L0>@v3#lw3pR_qA)sWk!z!Chr6{HfglGPxJeSPG}2M z$n`9DsNtj&lXpCuO_XT!R~_X{%Wi49}1)Uwu(s-RGk#&sR1! z`dF(R)Il$1!=J|HyUN2uAqSfC6$*^)lyDB0<^pY>Q8i`;9KHR&-)6B46{Ra@hR;St zAs5f~E8V%mgKK9F1s_|CZmoR1{~pU4{Z6kL5NPgX9MO_$e7#O5ipB*3kMGkq0sVv) zr91u(>SfU=ZVT8kue3*v%_cuXp+#MEUP;(pWAY5T4I7skF%iDAyqOFr5)gY_|F~Yi zd6R`3(d3jK_40_w8kenvl-yA952Xw-iv|`LXd!tOs$$>yUYR9GohErjs<|4bEOknr zb?!bi!{L&*#rU(D1{30HyZW&ZL-&plJGu~n(e9%JW|qAGgBvK^manuS(d8dnA7;YD z)+PVbR=HL0oav{c@%%c1a2TwdKRvVPR$z-O> z?n%b7otXO)=XCeHS)TakT0ECbKi}|n-(K^+6-_`%PkWl3`X_oev|v)wG5w#et4Tbz zIz%i_fbW^0wpJ17y_LG2zt>1UO$7189H!l3vTjCO{FCt?P@);+)h_TQ?dvV>Ro|3{ zFJQMP6ZvT|aILwO-!q8#@uo{zNJzXKl(KeCgYkPE`6nC5l)=^!#U#VNk zxJKBl{>pg=66YuA53A@=qLm%47Sp zzi6Rteo!kp+mKocX4*a6zuXGK$VGvP78`fm&Gl0ggD4KLM1Dh*zvJ~v76D0;k=ViK zyTnHY+W`)i^RYpYDH`i{U5&~MPP>)n+TrSk;w4}>%LvozUYL(lFG|yX*XL&hqziTw zWKj`kEPUSrb*SN9%G9iW3$&Y5k*oqhd2hklRy3OLVE4voG_Azdv7tb(9>NW0<=?4_ zR~Ia$LX+D^8suzDGhD_+1+&(S+e{@V555dH3-2i{j;#0xUH1d5pvcn7@VO7osWpQf z$MAd_Q`I0F({y?^_av|LxRG$1tTb@Aa2QpZ0& z-i7^laj1M`kIDS#?8!p{$hqUj$x~&*l_$-@(vP6BriY8w5@sG6vZT1CBG7h1gxsN+ z7;vuEL0cDKc3-q%N>c0xecy^RxMZL2dFLCpV0vR?()U{x+dufMl7y0V zX?n&Po&zsO_IFYurj&o)9tTeN4zk2=F>`Z0KKNRLz9q3?g0Hn(0&0(!2<`rCAVyfg zlKCY@9Y)Id(!VwNy|VwMJ7Ey?y5gcLUiql?V(!|#TBn!v_88uM_-w^yB$V(LAWL(MDdGvJ+~@j^84@ddiu3k>6Y%td#?Ba8*0;5UQoZRWeP!3RZhzd}f}6gQsHtC{dXgrYg;0&Pxxl zj1j`~7pG~VeVH%)8;~8fn>S@Ji%30|E*JJf|6S{{jwZ0aVb8{}Tyl#VRC8yWe0XSN zwMIReu6lHs!6quNbb4%PIMFURQN6-&vCRCw*T{s*D%>VBTxikhk-IPR*}mv(%jQx( zatlT6rPAz39Mc00lfo533#lh&*dB@KsOe_?&MRxbc9!#Zj+&adIFSEToiufh9zvHv zh(YQLKPRcxH5ktBs5Yo3qW9^5P7XI^0=F2^VDR9co=`2CVD?zOMotWwu)#}DMT`T} zR?i-jhe9EDOHmeg0K@0tDUYvh2l=3SwXAdqsf88`cNMO>M9Y*-m(nd`)T+9HcyOTFk&K1SE3jqw`a2|l2^_cPobU{wV267f^pJ|+mw&<0uLEmGB*hy{$D2WQi zseQx93<&&0&DutR*HTc(lv+t=69%h6!}lA6Ta4MOb403US^xwLbkp<`Qj3lk_P)U5 zLA%nJsDRPN45fpeN>cZ;Q68Cze-$|}4rSjn6r#tbu4M{7-#X#{QM{*7t=gY>DZThRr=Bk*cyLVZ756PL`1eaOk$uygc^JD7V8*ZG9OZM%$wyb zO4F)pL){6zld6*3vZdQ1 z8u>Pl0NW9T_<4)YLtm=7p2qZ!Y{_oR{z1xB zT-_e;2%@f=;4Bhj2mRl8LWH~D)x;U-aZ1R+MFPdlDqbLK9Q5DNx;c0YAW`w;Watd zOF2rVN>N$PM4K+35C{57NGJS;r?;x(gq1b+mLPe>IFlgl_(eQJ*(gQjVD%ms{;>9W zM9XdCdiGBSUB4mLo4-%E@VRdF7}$Ml3ezxd>X+fLTm{RuiPnaJxsF4YvJANCZPCz^ z|G6gVze9GJlmB=H1yKG2=VvUDvZ){-F{kP$t*TllO zw^Uf{nF$V%i4lty6QA3~p_HoNhN>VnVk%qGJ?R1q`+kLya3Kv)3fAn{dYt(Mz}0h6 zs>F4iJXJj%agurVokVaka=#edQ}-Rb%6{ZSGgD3k7+IP|(AFMB2wVw0Lr*4%JS;ku zjH~Evd+gVmRq7UMX73vp>&|ZSd@{%z;Q(n7625uX^nuF6YoHRX?O!7dqW@gqPbBi~ zWq*GC^>)fG_6 zonfmUE}?wltkNAiP-Q^qv|tQO??gDmY8e%{V5;AO zDd0gr|D@pRv@V7i`}9{@mF9c4F?^qf@46>BP6{lkGB6X&|IU8)-@f z7%C!bFy)LxaWRhTz)_6}M2maZ7O;(c>6ENh0Ov~tT5No4WG91rc@v}<7kNVg-&qUO z5coco6hIz9SPL%mxei6Aq*W*4sqEdDd+| z<oHS56Qg|i!@G;n?)r@mBaWkTeF_OL5%W2DiD zNx@*9y`Op=vcSp(ik&&ZL8L5TJm+_uujXhF=Qu5B5@4SNSW`%#SV%;md1o~0YT z_(gsy1mbh@)GW8bW<0fvhJUkj{~<1|tEu9-<+%WpYu^39YbTN1%@bVj`MbP5tRl}_ zohNs``7jM-y%|u(r`hiGQRk?Ix^uRn=x=2SgU^;vWHRvXMjIJ?Am!+Jr&Ne zIuQvCAc5XmxA*9D3}Eh}7MZx%&gE2SX(63=t6RUG$nG^OEvCGgT*o@TZmx!MR~tp3 z?yNGy+Z?Box>NjQg!XLrSzyd`Nu?gTQRT+fk)tm-PRhmY3XDs%<}{4qnW^Kov$fn^7HnQL<+4@e=U5ZLDc;lkb#S?efiloQ-Z)$yl`V^f zv*m+ier_Fy+zM`_qCOBd%;wWrTWi*i6V+LEzRjn>uiQtl6)cgFw?#5>b2a6W!I3Ok zAFTSd&%PdDPTF230qkjn6~%>K>jcC^OU1vn|(S1YMv2HMGt$_Kqfi^!Suo`5@< zY#Dcq;o}M{kTa7eiXhESDighi{dcw(^KHB)pQ0#Xh)9+vf>#kqgn^pF#gZp+iAp%z z{YO*#RW>3kF>GT5$Z{@hpSAcQ-8CT!1Rrdk#Cu z`T#K-ms%j_f+009jB?p-!fgkj6rlVfL3H{|n);&sFKy|# zPr`NiC9}eIf31sMy8o@Zw@7yRNHg%u@7iTBsV-a5Z7pjq#AzdB zW|;$57sW{2S*b*xq|SO?JN6QOKY#Z+#12(<5i!vICAiReB13i7wJt)(2D$TSqH)3! zwlwQ#<$M&$63NX*v%27k<`*W2WwbopY|Fsp`eMV%_Lr?0tOVF;__|A@@rd393J+A| z+_2r$5TJO%w;Q)C3JNPSNW8_pC%)=kG4S(iMDb8|naf7#2xv27yHmaW7!Gvw5`LYD znY%~3ZW8MAqxbpscg}q5&2hd1v&_!mpZ!X~kq6gsdg^Y(EY`@EDu5N9^Z!;fL@8&t zC#hpMW5NGY@l0AmswbWFb3RWTcYdEatx^r+-;3C;6#r45-DY*3eg)~M-4+J^ce<=3 zX*+cHoDcK+SvI1VYiLU0AK@i+=8jb~T=F}PUp=IySw~|uco`F7f zr(A0uJU9A5Ell}$sm;yh9B199_lO4iqwYg@+uo=QIZmxh5=)slVy{t=UVhLSo29Wr*o!jUEpN%PV^Q%&sfks$^HB)7`moMKf zd;=UrUr4WJ|96zgeGpd$k~iCfQ#?d53i^1BKZ7HK0*isydBM=;>#vQ()}vyOyU8DI zW462=T>n@50sK+N48=oU-QJ*F{7R=@?MNPuxU3 zf=Gz1!e5Jc!Ru*nA?X3D>B#@q6T3lrAqAMO8evAv@b0SdJVq(&gGdQ8Av3Bfn0vmq zpyni$aAH$Kk)Hlt)^i50CGB?9(@fs|#b9#n)dJ~@(~ju%i19HNt5D2I-s$=_08JUe zZ~jjz1akok=Fl%M^@Hf&rkhWJ42@7Wr58gnv)EZ0so6apn)ju~!2iBJ=scxCy{XNo z8_WHt2F-Zb9~wV;54iP`ioFRThk<4qb8By zM8>xksJ|oql@htlvB{L%OF55cJpGWAe@ZKD^;lDpY!*o9nd53=5@*51>|}#QxFJwWv?Byq5G~eeAmm-_qGi^4X_)dlq9d%9r-vob zd6g%(#Fdb#9I=4=J8R{;po5^ z= z+lP@%N(W5u+{!WFHA84fHluQpG9k^5_3tGpjGf!yS@cc601mQuQN zCo&E&sIqOQeJ$T|Qj4-u2sB8VChlUB9u$(-WYc|xranOTmjyKl<_;i()JCAmb6|=} zZ=7ROPV{P-%@lZY5uAF@RbWqX$L-( zGr0>v%Ag=Cqw63|>Q~e%c}^%(uw|pSj~gbztE5(ZP{u^eYks0~5@bA(%oa?(-)?#? z>GZI_<5?i{%4@EES7k2|&<*Mt6`!}TESC!>;mrl-U7a)e5+D-*=rUD$2qTSe&u^>;O*cXFZvgQ?^9QtqvnOp8%%BO^`VtKt%^8G5 z)u(k^6KvezQud&vmIhoiS#_gJl^J%3R%|LCdV#K>hp7(Y{_vEj)k8RUOPXx`yU(m> zG(}1D^->}N7~Jg(&$#CH-p2y(KF%KgGGQ~j4}{$dQLXICwVg8E6Kh}-jZb{Hx9*5o zvM8RP>g11?{J?O#`%6Lh)gXV9i;5ETnQYPZKtc8! zmyX^;bRz-2RK_}PMG-1iu&qqMO|_{xj$^2;pFI{_rWx3$8?6~Zf?OX_3LD&B*IJ-- z_DkOGK>Nh8?QJ0ka!NP5R&!Et+>Y8W|ICT)Jp?vp{c7)$OQ!cPw=UJs38 zgCLn1;fcWY4CcFz`>oJJm0MV%?cvseVzr2AIum3^)v!xFOy|8<20703aEE@@jIGF7 zAZt<6DdfqOyoQ7KH}z~G5qq;<2vzrh6Z?-a!zn~ep^%dlg7GwGT=S8nPM@WA_oZ)e z&Z1_r%z>0c^Ch>R4+7^`)qSTw zdS#alUln`cjQcD!?n$vPkn#93J5rf?{Jz}6*q@*in8gUV_%%i_p%?g9I1F=v2O-rZ z2J61M-(=q#nqi?%VSi`z8zw-agp;f{F@g&D5V!KH<`Hh*={AaTI6 z>&0Z}#fXEe=!r1%yKa-ZLnt0det&fGR7Ra|gOr>7<*wz0{{Z?0x9W7IbhL4;UUTe` zn7bqQ6BCt37ID1U&b@~~0`9~>_(0a{7k-h01g7DcW?t1h{Ablxvbdxe1?Nl-Xyj{y z(!Ytc+H57qfAG4JfiGfI^S*;!1Fjr%dk)rpvl2$lc5=G4A(?5J^|_zT&`abvRDr73 z6{=rXf|)l!ol=Wq|7sZOX+{9cYALGRSUYeDvX`RqXM1|lyA1g z?93N#ZK-^>LOXS6da&73;BHH@&8QE8Q(9^VS=v*m?1yZi01jJs{Li{g_T7^qM%!_h z8TOpDJiOmB;ubF@Y*6h{Gk2wM?q~1(Z{W}-k{KuaRo_0LLww8=!gHI^r?_t8=bh1) z3N~0M3#g#$LMJUD+;aP@>hl*t&~Yt(NXXgcXn6&+br58YOMCM$i;61wj>}*R*bT>2 z#wY(EAN!IxpAGaN4R+>_<`hxT zBe(jM-B9*aX*hB#*fTN>$jnaCPQf{&;g+9Z+g^edJ3s06?H^X!e_XVtZ3RZB%9IX; zW=iEnIf7a(2I}}USSjoC6GO;9HrXl3DcU37^sClfm0M7IcSgC~D9NYfo1KZAnA9-uJKVV+~n#L3X z8LD>@^2SE?MaJl@PkVBygBWj7so6da&=*0ps#y=Pe%+Wz+UtR8K=;z#MK^D-^cZLy z-dfziF_t970P~WyhY?A8Hr}Jnk5r1>1kw%$6 z+1xIqAD&W4-z;du#)#f+4f^-p2HHPzE%fxwKRk>wyiEk5_GiPGQ}%1G1{<<@@hrB5 zA^6P_5W}HSw{@0#&UW#2c?F+KbyUkiv=X zQ-Gaiwyw}P=*Wx6z=apDB#2$Ir(msZn{4L`s|(Kn8{F9O_&FuVvFJ`AQz6n8Q z5dNi(&x)(t&MoRevch_qf$C-Myp;VBIa|c|1G;dZW#~0`i^mE4XYz@`ajK`B_aCS% zy#7~z9L0`^GaC61xRU);!{_==!jqPe@0B=%S%w+fCb16Y8TsD*OD=dl_b?5P$#kTBD6J4*RR{ZoqCcD*}|ES)kC93GcNX#vTB4BW&7Y%kGaoW z&f~1}ezEht)++vcF96p5-%+pVF3pzZqPZ49g2a!RzKmh8oMBS4)0C4M^$=dHoZQzH ze4!F7hrj4=6e-thtT|Oa!Zk8h3W_U5R>TkzORSa&uy}itNgC<~mr-L-B}b_YAbXiD zAVUG9+qujQgN6J7$z$IEURPu!lNz+F2iBuFTsdI4#V-4jjXDv!HGLuMQLhBokbQ#X zI{(gCsYE>gSR*Jb!J^Fq0N{Jqyx3$rsSph3Tm-XVQP(Jo_Rt6=9?n4 zAu^%}T^>Vy=1m|mPfAv=a?_rPsQ>o?y!)+? zwF%MFS7NNyyGUWi|!2O-f`Z$ zMc<6wKa|;a6lyVWwG+Lnc7|TE`!w8Sy13FOP4@{GaF0dD&>9)+ez2boACf29Xeau# zyb?o6WabElUHsg6@|V)7PQqwQ#gZF|GR0BZ<$DTb;#;f8JF$Z_iUt^G_V)^S{Si>C zlo4z*rkV=X zh&eda<4{zI2F6>zqnaJ{71AkMPEsP*6JvmrCGX;tYoLyO3cIHK2zk7BXZVxHK;G;- z$etWd+9C^#VF!LV!XMo%OfgYlo?AZh+(Ymf=kJrr)t7&7X!t6KH1T-t$oa>CKBpiNs`@_sKR*maG6#S@SPRVvWS1||M${bn`?X)@{O zzb@)sW4KiyXqR5`P@Bn?DYL*-YAOoF1SO+}MX7pdL`9LCkjC*47x}Z7+l|#asQP>t zouR}FTC3naerVf~OnEnIVk7upl*XIOgbp$s zlMn$3yAqkO2d^8#w~s)fG`i|%oEieYqY+Wm`C7AEo$viXdY71D(RMB&QCHP@wOuOy zq5sxGkW>VglEE*ODQ+sI?H7y*N!kF%WaR6N>`uWq^?A1$z&!xDydXl))_9AbQGRpC zg}4-4#5^Ap`1(nmk^Ks7Qk$30zC%7dzLw5g&UECkLTdUn%uNiB8^eX0xUmD|x^L>? z-rC(4botFK)?L^iX?0KlYS*v^Mt<*w{FYz z$MiP1O3gV&@jGIj!x`ii@6~+JQ+(mG8_?qZD{o6~6k*Ke0mf%hL3CM5Ec4=)bUTwm z8bivaZU=M#g)f5_3D4CW#(vab5PDr-i9 zI#O(Co?nK7xNqJvXd;Z|_8)e8&9cFIW;g0{cXk1FJzku;{uHKd?HQM;A2c!1?bRxZ zlgf(Cs}4bY_uz?WB_XBec>lr*_`bPYT%W1WYGH%&oh$0faV~$>lk~-$R{)y;RbFM# z{f2ish`1c6&j%!hth{_y`ssG%QKcIf2Q_JXo#<-2Y&Fts4(rjlN59D0 zAn|+L-ff1;wDDaEdNm-cN(FuSgXYH)_^|SPn<{`0dft;B@${sDTxq#rPH*LJFk8~q z*&>rVHF7-)m|QNAbhC7U>f6{EK3XqpkFC{`2n5)(9{V_P99j5ahtCH8c=XvMWz^p< zCXeG-GRfAwSJv#sb1`5}yHc(@u@~b7a@(9^J&UoJf93GLauS*mu_dbruY`J>kCb>k?WE5JRU z4b%O#0t*FK&-=GBKzove-}h1+>dGC=ZKf_W!`ba`qOtP$*0wK3%qpW&KF3}15*|Iw znfwSlAld#lVTr5XMUAral~!{Mc*mgYzo6@G-%s?D`c$!Ei& z!}2L2$(%#DH6{U0*8rKklc?C9XTI7hiwn5xEiARI%=-&{YqcPry6$p@MDoD@WTUXA ztuy;)=mK6+!~TjWpml<+l6Z(D zoO^sSR;T#=J7oB)ZDT$v;LEVDazfOyxP=i)y&H-nl170>EEdM)C+;j~?OHDUCVD~$+`=kW_ zY(4brF`O=Rk7RLP*Mx~k_4oVlV46%E`DQ=C*SK*vI&KgBJ&YoG@tJoPc#&dCMV-mQ>w-gpY`E zQ=^<06D)Q)s1$QuSk9*5_~cFY`v4Iph~Jeb)dMfFhv{Ww(1DPIgKO4(N7`1?BKTY& z@mtex%U{W7lbB0IO8R8|N!MD4p$v+Uk6MrRz*dBAaCEx`^uz2?SkrwVA?G@6Q#0rB z!}xkXS1E;QfN7Sa$;#U@{!~bmx}$!+Xs0~q(3~6jL8Uy|PkVQF1bk@9H9K&x7VK)N zAXQ5jU6~4C_fB5;{N+}mrM|{$*jExkxMhMMELhE#q{tljTL7koyVu&`h<>Qz^J?6s zt$;Pfq`oZvFpjE;YUF>nWnv|A=126iE0ez}0zyhI^UHwN#@Qek?XG(wqJhpd7v`w- z^!~^6Nh$t6|9mR|28TA|^N43gOKA#Snaj=zl$Io^56&1QxMg3$A1wyK+fJGTn6p>M z0%7JHhE~Up2%N8bS^(2xCG7{-h*gl`_%9SkMr^3xp3|4qv(ma6su68HO|s}ug@I;K zm?nc}?_z^(oanzW{9#O{$?mrX0>@I|T;x(?zvvVg~w#x1`BCSI+c>t)uTtC<2wU(nIUYHD4x z@bU24AJ5JYyO~uP)u2xU2#LB~ws<}54CBpl2Ksn!e@5svk}~!C94&Q0&06`p0g2u_ z@vl3a150vAjs(36{qkII__aF{hLo1^6hR$XfH^m&7&%~G-hEpdfZo(noBB-zlx`cN z*VI0siW@G;4%7*@2E(6Nd21)#`(l3pROX8q4A~Wxr*)m|fOl!15ePsfd^pQp;9kG6 zUZ7~Z&&o?fT1WSLJ;;Z{8|{RrWM1t%$uk*x7(XuRq;Xro!j>Gut{)+o7es;$XCb#|`Q|47g!m<@s|ts;Fe-JBtt6S4IdM#! zJ&b6&3+Pj_zZo^yz!+T2Hj=P&&d_`=yQ%P|7Cv zdP+4@FZX~8yXIzw0yFmDD5z0dXc9Ogp(ve%B2Aj*oTErn0g*%R1PEPd z04eb2_ujm>b2Bq*uQl_0_ukLv@%%tNGa+=Y0o0lqtIMx3DgQ%?ovASRnHrP%pBlTu z*aXg>^nhu@J_a<~GjRnxA=RAXo5^Z!&09P4u`Q*OC>ty@1a@j$19qG1WZjtlJUyTO zA%v`dinnHtxg9mQg)D%NFkK;cmndl3w`G?5shIN_L$QPJ_&b)u-X(Jifo{&R6kRU3 ztR#VK@nQXTIZWFA100kUs=k$>$Z}lj9F;8f%{Gb6ZdVqz`Wz^W2n$LD_e3+S0Qk|6 z^oSL?^M%a@Sp3tHLIDy>Yx}d}$pr{jXEHVI3)fJ8s>BM~MJCqV8j(79Z{JWS9T`iz zxqZ)m20->}NwRrkgDQ)Vf2R5~TJsnGgV~--w_iMZ0|xc5eZ0QW4h<0F-FUTjJIUtv zK5>^0`Jm(MTs>1!?h}eG(-woTUjbGjTYx@dybtU7Me8=%YO*gTlscVN@Ci49$@f5e zL~2Lx66TzeOwTB{P}}70!n66=o4|6pHnd}8-kTXuf7-w`GRuAb4#pD(>SDF)zK~QvHf=<~p8g^0pp&!p2ef5V?CfpouU?1wTYxV~Z0aFDIcD)zb#KB`-+s>6 z+cxTFJbOHm^vm+za&6ZMZye|~ub|BWnA>dM;kbUUl5BDK=6&!ASX z*W|Xw*1bEewidt5{4vi)_@kjKM-NA|>Tu0!cIS`d_f$ZpnY>eKF8(6Add*qb74h{W z=vaB~6&u@1XFL842g%{(+Yi5Hj zCv3ft4!CQZ@f4EfV)3v4m(AhAMGf-SDavdfU72n-)U*i2JO+`QK$31#kkWg{AGwm* z;j6#B?y{xeimn&VoM-|xq~db!+3Ro^A9s8Nl-aj2%rCfeK~-JUMi+~LDMif4)GEJ0 zuQTgApQy|ruGEzIX8w=jKBUMbm1XrOB#7{;dqyCw>J{+rk1g^!q>2ygQYBYf!I^V9 zR6hCFe2h;2aL`^xV6+$GukpHw_EEQY#N5J4!b|IgywydAz60z>@9l`7;g64+CJL-c zvDVms+nJ%1Pyna!wu$SQSLymQ!`J%6LS3~Yo1zd_1W~-^>mj<(X&Dek<`WeQu$=b* zwsnnbU=E#5*Evi6smB>MS&}r&_^>+Mw~CXxR*?MIO!5gyazOA`w>8%N=1qe1cDV&J=7 z&XYZ8faX{YB^2U8{|?ZVw79kCkua?2+?Fzb-#v!y@iDgE)+^;JlG_ zpAy0_#LVJd z7Y;lv#}q=3b-0LEwjkaDR8{*zj{P5SUrk;GFi+uUGk!~67NmyO3u4t3uZv!;!27qG zUP=ey2PdtoU^$~yN|V<(RLcbOSDw=1-UzC?^9O_IXv4VDpk@K^LHE4jYpdb*1`*mV$J7VJ zP~D?Un338rN(#ECQ!doQt%57SS^RdIPm0%B)2ga;;-zEpRrmKVdiXm%Jyp~0)_Z?% zl0jV;SG+uIGvy`<$g70Kp&87V{hQG^lPBLja2jWjPx|TL+&qh0O|E_J0=I|?v5}Z_ z{;i~AVRs&jLWIJS{!`weTUDx}6QNTHRTJEQS5=MqGGcB&(Jh#GU&UI?^XkQ(ZARK~ ziWKa^H9pw~S2-mPG=1#GuJMJJw`%LK5lI@v^V$TO)gW!l>lBZeJIoPY`n_vSvEG>q z{1rG$vOc6uIF&Y`nZ;OH;_raA#$&%dqab-^M6*F998dT|G;EpcdIdTW&LX3%H>)m> z!x_)>m=`GPM*HD0Hwe*%HAutDcTw;@?pSE*49c44VN0zJ7;3fyzxmls9xyS;+MRsR z1Ro7C--qwE*xUR;6>s5j(2ZvRTi=Zv8|+1yrs~JVmxYmu#ko)6vZrILz8dK+!TZMi zW97um?jE&b$&i}5^~M{w(>g4u+)GE7j+T>(%`|)*pPr3pds#=VDHG}Pod=w;jDLi> zE-YgZpQBH@rgBfFDC*36&fv>8`TN1~ym)@xvx7n$IvW_l*84g*NPcl^1#Xk4_bldl=IO=hK~X20%AH&DQ3ibWT@lv_TUh ztp2d)Kxd?_#H<~Y8;_mR3JT8yx|`mYKp?VwV7?smu1IVFA4LFEp;^*Ona^F5UkJA6Sa(P=u!=XbX0Z&p^H-^vpdbvP}} z?E~hdhJlJg)QRxCWYYOU>lwD@dwXLJ)PI6nt0TcH9XXg=HkE|T8}RzBuJt>;Urjiq z=Ba=KeaV>O(n*IfCg;$0rOh<-6@BcI-w1vJJzdbJv>L59R_{fL59%~i*uY~ zhweal^Z%~yx2R#apn@UWfv$%~*m(vZv6N{A4xH(|zZVWx!_rHjk065p#>C#?sf}Bl z-MH3a^U{$En(=;l{PsGNn|Y1`JXuiSaaJbJuG?egpVGRC(Q%0=^lZ38Ppp%K)kj=_R?T4mLMU zzq@&E{EL-X_WDir8McYpn=RX1jm}FxNM)QEBtN0s(?A?J_jxDyLJDkQuPPova zebntAIU%O+vj?yOf`UY@oev&t-;~l`QC5>dnMZu$dmXHb&TFLN+1NfuB@;=&6(S*& zIJc`49%V>;Q_ru!VQ&*^{uq>q=-L*=3 zF*eB+PZLAXlTq$#!Urg3Vf)E@xcGo?)SpcCasKE>>;?fH=*b+e&r4lwQ;uHD8?D$F zE-&NRG9Xn;Qa-}usm$Lf+C@3NK(l5@6&G=$#6*lMU{;nZ!&eMi|EIb4Edo_IvaI?x zjDc&$g@iV$CCq#1$Pf=cPx%)KA{biuNsV?LnCQ5z_hkE8WWK);w1I zm*xI1a!*CY^$rA+%IBK7QVFZHZdq3A4B)`QFs+ zTYgQVR)9C{wO%4#Lqj~Zk($U#q!dayXoKyxq2f3nbH8nv6c?ThdLMLit9GjzLJM$- z2_^(7&RM(}nY1H1{W>vdQvnH+7&CQJE4K|x04KkfF*&{->ZsOqsioOcwU72QTSq`ot`5KH;TH%NyaW>qGl>V`A-`+ZAFhLpSSdAnxg zIakYK{hfUSWNBYWC1eD}WW-RW=s zLAg2_5?MvG1XXdTWFt7jDDBbKqyyfs*aLoVgjKR8@+qWD`sFP`c7U<1jK8G)*;MNH zX!&&-`v$Hdr9c$-v|qtmhbTw7sJ)tY+xsWMoq1>sE2&{}8W+IV2zeR)cu2C>c52^Q zvU=fRLFLc!gmYxHZ!LByz%(;eP^>)R7{k2d9P*<6hq0APB=zITyU-P%c+*q1L`Pdy z^ZqRgH+`scCDQ7OGBEi(Q2vfH`lSGqikF2MdrBWKz_I-Q%>Pf8)? zN(9}%%(4s5VCBg15`Bb1 zyg8~|bVaZJN0Rx$;I=31#Xp@NlNwrAmnXh(FLn=C{)$`+?|3YnP>(bq9HJmR?&j(uLZ=2p|+Ysw;Ek}okyC3*;d%SH+N`qrl! zrt11EfKv)|E_iH6T^@0f_`I{ki-9}3@}My=G4f@J{*#$HjAPV44kW9lKGPGiu^S7u z*If8<`U3a|)L;=>BWTR+ed@SxPq|kDCH&G0Ya%Xrh*q`L?#TN#TOWO`MMn#xLw&BKrnE?5Umtr#!(^RW>rb*P5Pu_j3e{D1E}(U-otW0N7w# zLK#p}LvqcoI2`kgMPF6iakPkG9{711uBdh`?atX;Mr^ZvaajjOHYL4PU3>^ggDO{r zc#iD%tb>LS5RL=>F8yxHk>vXc%kp~)+fgBS6`$`-W1PrXwiUV zLF`T?pH9^gIoJB)*$Hm1Ik6GZ7JNSjv?L2sQ>fJj9m~pB-*uyZGa3Xb@vZB6C zIZxX=M;oi89fuz;Ob$L4xDs$zd9wI$}?+QDwd3SN9B5coGjO-f=mpS!+*=k22Ma$oz?nU zWFBSSc2hg!$$qiTs!AXXE)J+q=-YklD(Uf0(8gz?4vf5i&+S`BAkz@<=x`#4 zw9vE?E3kZyc6~XMxwzde{rcZ<{w>zQqh$FUej^6zNYpX@+xFc^W_gf-Dx$!pFd?#1 zXv$;UG5KD8BayZ?b$tIXu{T+(l73tY1Gf8{$GN2!S7nyViGfH6A(_o zdRAw)7{QnG6oWD4al?Ky`#R`Py8RAOdUf-7#duU=voU@9IMO2!5q@C)i~_|H6kxU- zbM5!liJW7V$ekz~7SBWLd~9^!(Q#+o9RJVdz}olviEbz1@F2$C4&i8gFZyK4Mm=~( zU+LANOE-#Hj~8-V+xwB&d@P9eV!RguHqz;d&=W2j560a@a7=%VWeNh`N@}K9B;nsd zGI}7bn@^re&>UW&JX$-V%Cd*TJ3nU^pHm4j+!S@0@~qLl=`m`(aN)0l49+{U`|ifa zuK(?*T4`!6o=bg{t3CZjBh+If&;BJpm1kQsk!A+RDJ!jTyi+u;{pPGv$;G1jW$4he z$SUIak1gZha#DC;B{hreO0;RTzA7<4N*=Nk#Q2w${{OuM3nzyqh)GzxB zuiSj;U}N`E$K#`swa~?~x+g`6YuE0w5sq}ne5$1WQqIlR2X#lT8H)0ARe~4V=7Pj( zTJ#K+GTJQ4xBhjO;2tBatx2rCZwCgMlt3Y!Hpm#IE*3@7or?G+&W%SUUbIJGZ|%fX zJ>~Ml1g{gLcXRxK1*ZA58qrhDx2SJ|DrQ$_b9Ub;Y4MjY>P)L2{C%{tDlnlpmSU?p zWb$ckp%uq_2J5oW|qvPFawp!RM5jF|}YBM(kpJBZJ3G3Xti{yYHl$1*skD`$)z z4dHSd`ma1%g@qaj(Jp7NRj~{2)IH9rMGCcbSG67}bkj6L%&tHo>hq)OXb&&0iegq= zwe6Xqn&lmSq=^|ubGY?)Ea)qOg|Z!g3h~-{V+!hD1=<+e1Ck!;ZRrr)13j|y-`nP13IWKAsCdy)|a^WHgWD4M4Z-8fsZn=dae z(4UT^gyX#jsx(R!2Ld)}zPSo#Xlz7T_d2|V@5*28IqN7d`tI$M<*;~VrH*JEY%C$j zCXb;0H+Wyw#_654L;bO!JO&}_p@yJ`z78YTx_acou4?@9JRwC?_YBq*xbWWUC1$A_ z!-!nka?G#rlH8rI0 z1U3)ZA=i@2@MdW(VUy!WC;wi0mD?_`seb2eB}Au$bfUS{xDCmpIfdcgx^x{n9NUZ3!LSqjYtmbuYb^7)(AoSta6a$c}!&tvsG!biW9_&i;Y zHaG!&d2F2);4PS1g&6p3&g@lni81EpY&${Nk}W^Im@od6B=;&?3RvbsJO47tX#scV z+CB18L=)G>owk)%o5szt&@Xx`lvqP{!d>nq*eQ4-?ripJH9f-jZ34BD!mY(_j=Wg8b> zn?RaOQWJ2FMmEz4 z=+W$wAaUaBLKQb{G#;wZHJ+LRu^KG*uX??uYlcBjSVQW1pV2Gg~${L!|``%msN`gTebsx zyHF+izSAYFw>DcSU>+v;L!%1+Ps?QSzad~+an&bYnbL9LBXkUzEs zM^hk4fozsW?8{-G+B)uwcC+*~kJ_5t371`6F>);7i)+eqUTE{Z@%yU7-?{-Ec_7=- ze=nSLomRCw8);fh&a-$XS9j?cM#MkW{Ff9qmZS{@|7@k4){DhdyUsPYH08u*>PzcwHf>mG>L!$hua=9Z(keOOdMx>fj? zE~`&3Zg%$!Nf3cAZ#;iC0=-xc;=dmjlm^Fh7y6)8d|&RvF8mygcbie&fz9kr&V~jv zwIv1g$JYO)5q?z_&|*m%&La-Gw6@#69uH|_sCzWEMGof&0DA})#&17#xTu2rK$v@7 zYGEjLEgl@ypYb36yV0o1c4$7T*;GsIbJ5^^J=KaFoFq-u{t0|D^hWFRg?A=vwZc7) zrA6J+tg*6GA`@2%A1&XYvzap2K_+-imhcimj~LVFm^X^bCzIAx+@G+24%c>8c^ zXZHbF)~_Ese&1vQ%-QvZ3dd16DaMGw`XbE{9vZo5H~1AzsQI!E8G3ky;z<2l|>#C>}!YKGLwC*clswHG=6Z1NA!1;X>2 zD}6QSFIJQz)Bcoex1F>74L-d{vqe*MlVRuXvLWNS#yt+Cmf1a48sxgp4Xzgpg2m7X zi8TFmRh~;DRQV~TArt1sX!YH!J%4Ye9f7R`9u6u7KjbUW1R@iXJ*?>es$y!u-1D|Z zhwnwZhiokeuypSrUp0Ikf1qS}ShdhAI!+S3T<5wNMAfC`UZaMzQMV!!mB?OZa;Nny z=HI;1XHfJ%y004gF$GwNMzgq88F};uGi+BCu-3j6`Du$Ev&92{|AO6;0gZW*xU7O^ zVXQVKd$pxaA}H(IrHe8W8HCJ6|8Mw=mmBd@!a;h5GDDx8eKn*!~F)F*&Bu{!Kx~v!nMI&Mp`K=VqW`^uj$Ka^>1S|QJ z^yFxCPY$ik+(xrS&q!%RbUJ$>(pl77OsgQ-wzk5WT(mVIE`sJ~bN=eR@4u$3bVeK2 zc{TZ5&1)v1BytFP{`hvuWlA6FbyV|fFJ=XQda=+hbx9b{jbUl3A!&x76H3zUX>e^C{)Oq4c59uw+{cQo4 zMq*=(kQ?m+`(&={mg@Tz6B`m&yJ!D4()b3Vuu-0o$(k7e6&FZ`GP4Dh&qyV>b`_*P zB=PpiH)Ssx4mOV}9VAf|YL|r9r-r$B3@t}4PKt-PZIU@}rnNqk%DXfOP2&aMI3xwd!=>o2pf{gIA5vNaUl@s*vMR-XT=J|+@O`^4j2yQR*r zdAQ~x-z}TxJ#zh&y=!#CW*MZN5i;0V2x{5_t8|$;KWtJX21ykvii;->+_PSCNPOSW zu&8^H8E|*y<_BxkZ8Q4Ct+W`--3yUbT(2su2p#OCM!X|t)O4kIaLmI5D4bOApk`~~ zSlk1XQs3GCL%kaopSxFNG8WaLwqsj~G^G2>#iEut5-R5&X{59MR6Damsw}>eIp~|Of?cR%i?o;$;;f9QT8lYlY#>314Yqgr_=oghtsPLZ z7c+ia1rHe;xKB99bYbxmR+t`9MAL-3ld*$@a%h(3K}BqToa5gqps!Mw^h}T}h(~*W zllR&$o*1id`lK4aVn#|+22}8Ggn}rmzgn#iMY;>1N_#8=KE`-E4y3;g_?3~tEo%@5 z#fDwNAP#x(S;dWo1Y=4cR0pW!A+Nfx;Zxny@Xn==oAg+mV}_B>!=;I@9zdZ|zz_dg zBpZerlR$aQ-4B*GR9b+@tD@d6GoVE=v-xd&v5vLGDyQ4p_kOY)9wbsfT4g`2UQy!Z zNF>Cb2;BGuaZE9Kf`5NvP(kYIaBS8a1)TLnb6k8eI=EuAR%Mn_4%7VHhM&z89;IIJ z{bJvmBQiC*x>aRI;#Yr2da23SV^;DwV1r|ilbKIS(IrI3KFDRBL;ICnx^E2k*g%>n zuwOS{&+$%(8T7iGLV@Y|ayxe!1?(Wku9I!HOdAjX9^;**JjT&&pOdwEt&e+}XCD7c zd@rs(4MpsNiHTB(Ugx2+_2V+;n`)H&hL^LNsff!$d*JjXTT+bx^(bd;=-10*u(wc}kgbIYmVJb23hM{v{{s~;J#H^!drGQWL>^9j0pdrm2!G3NAEd;i@PKj})sqEI&KKqzocSqLeM-*U&g&jJNxznB~JHo*K{KxJBb)lPDb)^tWzBR9PW2F zEjhXIqYZWR@JZ(gc8wB6uP@1tn9?K2iV}k}#j!}COfG`U$vecHCp3Dn?aXi<<|Ald z1^@E0|3~avkIG*B^%AgEd-PG!;pYOUK;}OUDrVNpA}-N80dW7vHuJ+WRf5D(hqP%A z)Rm^5@TlWKlIkJn)>+VXtXzkN2xb;tRkA$%(b=W+iy6O~jLyM7h_3^yBX^sC4nhCv zG>AdxLB}h% zJGtRyhX?P2=z^b5{%A3ZuHJboM6SRrw%<03WYWBs=pP*qiktm@m95mz#azbr$bNNo zDRCVUU4AZsD>rVW=X_9U41UK+b)sLnR%CL_VecSRB4SyrMUhbV8C*`tKV;`;_eFg} z`3?{6Y0$Th0IHZNLP{qwmrX}|r;^9=j11;9(^H+`nRxma{|G3+EjuzN{lJlS{kk@s zbf5BJ4kq-8KLdDfWh(lH1-b*h6~KYR5RT$4o%cu?^)RO#;mVOashY@vq$ZW~*G0_Q z#vzG8ZfhD(h!tx-Cs8YT_HuC&SKnFLWqL2<$7 zsJ8g%1_9ZURo!Pht2)$!^X3!$+f20z4g-RcAw$K7+9IHK=PmrL1!VrG1=Cd3IAHos z`MUVOTH%on^VkO;#oH&J9b^`ATNVeJTncpK{}BD3u}acjgzZ>utdj@L)IA>e?a*{$ zR3lp9G``^m(D~V5r!l%PZ~S@ywy!nT$?++wfIdIba2oR>JI$xmW8+}r$o!d{z4WxQ z-2PX#zZC4tf8oPk5!3YH=hMYZ_67XiUY>k|1`W6|5a`(KB# zV9Mh&Rfq&0?(W9~+T;hDs^dXL=x)$gG^(Etus*#z@7cKBe7b`-UwB}uEJY~K?=uA5 z1J|LDs4!m!>Jf(XqKIt8K7dF&~SmA0n9;E zyM@^fW)nT1KZ4=!wQ;Nt7Yk}y6|ph2N6T4bz>__dxnWp8Ugu!syU>aPpKsW;&}&xz z+~IOJozHTaFAs@X{L%I#np%gn%=eeD91mFZDu;w^x5lKPX)E$(Ff zD0e8EWgIU)=)09)IMt-tcr*Cl(=o?e3GYMl5o=C|`gy3Y4aZ5%(J+EH(XX{W6u{R1 zTm9M!Ya)VY)``no=%w?1r)>{sD?>O+#Y(sj)O(Q~e{Y;q-C+5h6FG<1|A6-F&U3Y7 zmwOf@J^lf#FYTqfHiG%-GFCho49*Fh7r~va9M~P{#A)6AwEN96f*BCK5Nvn)zT1nn zp=dxozxF!+EAaQ*D+Pn+sZ|ld1j`@^WgT~ylkDJ585g!fpSg#1 zy~A8bw0k7JPqaraYxyq6A_5{?10B8+#Fl7@@TDApe=T|BT1z{)RrPmtWjJi!XM~K$ zQcFw<9#gKXYLk~7O3>kNR^u8Oj<35LDYrG@t2y@K6{PIlZ)*s7%>Ex^Ey1HOHt3a0 zALt|hX?vSBdu^(_v;9z~&8C`J(+cvfgz-6m55T<1&q+VqZ@<$e;}xlU!~JLVxUFIw zg?W}p*Vg(9{C=nVOnyJxTvZ?rxjN9_T`B;~RtmPhE#6oJdhDNm^>5d`<4~2><9@90%_Phpf$YS8><*C^ z#&0z~&^;X;q+PdAU_Z!9v(;3i@7|KtKWzPJ5Con}tY-@fliuf0d=1ZFP6j9b@;b@( zVLjVrN%l+3l7EUi8wH+?0s7U&bqH4Ug@h9f?i*;>%bJAe1(^vKJCpwd3Kw!$3Qdg2 zWn=YnTx81pYBE74jK^QP&sAFz)#mk3Tf)l3PE&>y!KaUWUNI%4#@yyFwJqLWPTZ~U z;53?6^j+8v>V*!0El8a?g9>?qo9TNwLzgdgywQDhnh%lL1lDODP=qAv{TKI!qZ3c; zCA9Le!YV=b^IbQJ%!7qpM<2~!o2Rg@dU9bT-7#8{s(w)qJfJN}7R6@krQ43NPDq0Z z=$k+(Gn-)9iXayhmTL_)2IhGu_-OaZt+VFb`;#Hp9}>yLdmIM*gI70C-u6rM;xW$;ye!d9Y>wL#d%8ceL6cxz*o00ztomx>ek{ zc`^IaI)c3>2={>tVc1#dMCVPktxdiKzr>hHJ@!hvNmJ+SCi?_S@xZ?SpsmJ2?!nd; zLCz5q{nFarRqR@$c#qAvNFjV0#TrdV0+Fb_mOKHnm0Jg_RWrRAcL1KYsr?9wJJAK=v5yRJF&x)z$b2 z*%3hJ?7&!x;s54kUT8c!W*v#X8p|PF>}6ls0fp)$vhK4&3lt!J!S8n)FSr|I##GKn z2jYT5oymg~BscW1S_B^K6!my;+pz8N1%&Y9++saddpva5cGl^s_Y(k7*4h%ZW0=jn zM=@N>QFxU@$sbgZP)omi$YVKl4jO$fP;74KKW^Udfr+3Bg-vsXDs+}(D>5i;xAW!6 z6Tx~`#QL2_-~}+_UMVNSMfT{4_{8mR#OM5mBz*xMQ@DkU(>rQw!yx>UNP#%4D;{t5-fEpw!Ex9BZ;$6|%;b zW)?(5$?03N!Ggt25oyQLp8c;HC1rNuUL1?uoBP3f^sm!q`T#Ep%IjaDgYRIzGHful zf;{sVAANJFvuU$Tk7aEiS@xRwlrqiS=isaFPbgWEx}|u@QuYn@gVA7vmlFUgi4Cz@ zy{D*C2KM60@fc*M49XYfS$%~594%@K){0^DM@%K&_mBPWOtq3I;v7f%%D@Wj^?qB+ zQpO_riW{P2Q8~|X!4=7s++7|BQFhZ@`L)vlLl5~$r6yOcvylUA`u1UY&v3-xjH$rJ zzIBeiuci9O_o72SO1VmAq#kSiKK}fmPP2IxiWoqGr)I0?=9I#aJoVVC)Lag4LxRIL z(JXUq4sS4qa?rm;%dPyn3>&;hFXL<;k=b&{(O)pe$yr7HC5k^M4PV%Op_Uh*?%Mmo z<{r;JPpus=*NNPTP>P4nM($U(-H2a<6q)-Erkn8KnR&dPjv2Bw9n4S0yYg#paS&ArX zVws(|{LcPU9Q`)+Z{nQ6E=~#SAvoK9f9B|1^+{Lp=;2E@i(O9R?fYoP@Bgo_ppW2? zIp3gTx1g;(l-HJ8qM0goW1yMjzgnvYD@A>trx2D8L&o`&c2)4$9-sz#^w{# z70Ntgpqte8AD|p?cwJMIWF}43aB>k23L4lJD zZ0Eesb6klTJu+Ys+j1Kk-0eWkbfV-c4%m{ua^ZU+x$O7O;}3odu633$->~-wDeP1$ zZ=K~MWScp^=tptZUiD@R1t5^M>5uy5eH&V=VWLcJ=~un46|%UjhX=lmdAWLeKb5Xn zv41K=l~8`!9vSVBY;v(>z|}@Rc81q+v|H!IyII%?d@;(|uKbp&anQdFEOx)qEdUL;-O#j_E4Rp~y06yrLDuuiTRxlecxS6w$L6n#2X$ zka~lR+`qACt-pD|sW4@{VDx?L8xZ^~7ZUT?x@vgld}j8;{A_U%5z6wNu~C3}q5tOi z8I~&p)jsKO`}7TLx8)>QuZp2L+0TAN;P7O;?GOKtQN19B02hq&m{K8bM|on<*oK#Yj~ zB~8#PQR+`RCzx7!`W8Qv7GuDSaofAjJTwQ2l_?d@_k+H294iDtW4WmJUuIUKFLF;O zEu7oJgKlWIskkka`oVLn(pZD)3>JV=jjqWkr&_2h%M#&2&w16N=8l6e86J4@1g;7Q z{rtG7MX2O%}zBG3lISYM$uj-CV>E(6I_28l=4tC-b4!ND))A|y1X%6pc&OMv;0R8EfW4~J|Q$^r>2s{*QNM>##ynEvUubX-=`>F zu#9pa8pbl!NRL)kPTWEtw4X>ydv2v#XdFMh9%8EASMjuzm!EdT+YlTJUQpc)_Vc+5X%#{tOUl9I6eCGj zdy~Tol)XA+^VzR9$7SV4;rFUGk4&A3tF8Q`ha*o8`H>uYSH0Lt6U^2SIv?P(>{1!q z{O3_cmY-73lPY0_HlMxl_+1{$-lAWx?~qg5Q9*4{-z{wFNWgA1h54$#d{m+v)Cim^}^F2EQH5)nxvqCMn<-&q^>4dQJOzwvj1| zG@IUfRnml}#^>yJZ-yL&?qj^{94!2V9?sheT^&V@cgw2~R_%pG%z+zS_ai_VDcL^f zCz?yyYj>79C7iop+vT3mU!wP?M)xMM5)Tex#R}*_pCf6`?Bra$Br;&2nYW=-g$S^Q zCSkFfO(W%}1=E=|+8dRFS8=mmChe#sCfSLUeQ&?)!f|qU;xhcAqnRdO=T%tN@g79M z43^FaFPH5;-y%cc<5MshM@gOCt(R@Mlfn^re8#%2U8DWgw$BcpDt9r=>u7&$$%HY# z?JQOY=bs)b3WJg9sGmZYt?<=u67WsD=w~-;ok=AGq6AX&bu;`BnatQa{h^Ng(^_6; zN*zF|S2ritc6%{Wzb$VS`nYJptKvKMbXYD@X;U`EHfulTbT%C|=gow@AR*svyVT%= z9wNz=zjh*>5G5b)mURAz@XUd*Q`#{qxY*^KD+uy8kX7=%gH2jmwy&g_0V9vVck5O` z{7H`eTBReZ?58>SWnH0#l9u4}VxISarBtkD?v?)6YsFThcDO?HIRYC#>a0@yOG&D~LM0RUA&by_t%ECYkVHa=i{CXa51R@}D&2o;a_X zr$X?9E6~JdnC#XrE5~|vyuMb5Pmt&3o19IDm(4B6^56G`HGevN?{n0GyF*zTCUx@G z6JsmmWj6*v8~#GFXHmJXq7M$;2hE?YaIl`Vy4gn_-sgdO^AOMB0KG5=X@o` z$AwoWC7sB5m^S?>8s-`%G=PZeTz1fbTazo4y_WZUF=@)ZB@ylOUL-rRu7^GxS9$fh& zQu$aHANUPG;aS^antRKh9QE;+6zr;nXvD$#I18XgSVU4n>G2|Abh#sg?TWY+!GoSo7z#e@1q zjSgqL6P~{`A&unoU--TTcRtFKkfCR)@iI|&NTbO8Bs7OR@v_Sxqkq3iMXyyl4@*?N z`^kO>4$1)g@1Y-ggQd2nlZ3=wU`kig%XR%+i_indlRmdGvZei`;rp@@Rhhx2#|Npg zlg~7XHOZbs8gxEA)i(wX>cV$oKF{-9vb()^pnttWDL@St&eSs0oF_Fs>48aqCouZ) z#fS@?)rJ$#@?GH5^R>53jmW4z{v!fU6P>sh1-*Z*`aGAk*P@_29>YYTA zArjNuq8@Ufol9f*tu#eV{`;rNdzRxU|FC2|d(Bt<(g+2Gz20Hd&`mhWI=0)m+RuUG zdYyDnjw@p-waO-1n#Jf z8;1b>y7UFWlsovvJ&pk8GIEjZ4zfmK|Ck zhhEJk%lIp}dz8#*_mRfHTN6vKO$0Ya{~gIE`iV~T5pwSNY(5f7-d^&sdGOF@z!T#4 z9JC;}h?^x4Q!nKG2zsf$*dL;#F^=+{O3?jLwY9SX0S%}27|#ZpKLtIA78f+m9)PHz z<#+BBY2dxDD)mJ)ust%G&E4 zafvW*Z!5ZNS|59P^4>b=sXTU8QY^1=PTlLX1#{C*o*FzML?=UJKPkEyiFr)ewEg()IAwg=8h z9euZw)UmHW7i7zbpuClMdULv~Qth(Kgs#A!HXC|ZncWujtvr{=NG+NM1twaa+&NTN zDYkYNAHI;hTuaOx0FkA@OLrI(fP2YU#U3_kn_#GzQ4cEE!0)L!W;?whW7No|_*Xm3 z{kdIZfVv^`4ZnxghmKTJYotg(#sQ%gPXVx=C zVHYZ)J_@ocwNTaKq=UHfxPx0lU0U7oD-7QeaMG_2(4Mm2F4LI74(bQxktd1#jz_O~ zo`W3&L!BxLO`1)Pn`RF_%MW?7$iw(nm+U^!|&60o9Lbf}#(rs~o0u z8PXA6WN+L6NA^M*yNVmR$1RKcXuDC*!xVM~TInfQg}m5)Se#^v_TYY_QQoQEpdLJi zaXgIN!(SZI_{L1_U?Uq(Z+A7h4cH!h-Ou`oiFNWd2`oPSvW_n!0eU_F!3scXK)8#D zq8tu!vor32dfCcgo{=?6km|~9%}Fq;u0Ar|wyOdU>{52RA>^tI-4!mgdD;d@6TF4L zo~+)lq8^jhq^OIH%PwU7E@2@PpiPj+)&_aPfyhVk(4L+96uaKFEa_G4DN+`cJy_?A zoG?VW!!FAmcqZ%`S0Mw8O7$g) z+Y0Y((+R+`Jh2MmJ0CkvaxDzCcH_yz$8=J!XWX0mhUd6s{WC=7FPZ+3s@w3QPa5T= zUZ3Lox0Qr0?(e=Yh41Usbcxj%%>RUg>hf;)Aq0O6@<7C%SRl-=zHVNQpb6_C%_PEo zNjkMThpc#EXsNs}HQ;50*LmA%`YM7eYxf#>%f%gMCUPOq>0E~LM77pR(BvmlWMK{N z)hDyAmA-cT1myU!qz!C&@s5)!IH;G_Eh}DvyhmP<@=Ex))^ZBL&@O$l4;xT%od1;5 znXb_rU3K>allwi|eHhS&ymf<+p^SW1xAHM9Hw4u5s{5xg0((t93Ay)$Tm%f5P41cO z5(M)bLcquip6c}8YWcD+PVWoF0%-Xv;Q~hI+CMC}67=zUOaJNHZKisiWT>{NH|yn_ zGMD6PQ$w~Re^f+HpxP7nBg^n#(w391t{u+Q7@UgVvt6;n(U;eg_pLvpfCuftu4mr` z{I$|MsS^+3RUz_GxB3JJbGm(}U(+t1>&>K9vkEKF% z6x5&_`(3J`o_&Q5CAWsV_r%Nccw{kw=$puXqY8YhJ$`dJKBVjZ|1otQPEBrYv_}CE z5hJ1^QX+zYH5BO~K@btCibq8t0TGZx?=^`?RWP9_y^4Y!>AfZ*Na$Tc4-go?#&Uz`ZUh&VhPYQfrAV-FC-!@XTuJ z?)ZbGWD{6>Y=e5i>D-U2?H)^6=R=xEFVdWc!6%f7NJx<2>VyW{UvPD#v?TI~Q_$-J z52rABrpm(TM!qabxk^x_zb)>)AOCBl6xQb!B8bwTsmyl-AV~LSfIa)I&`nO+*91g; z7BtAWFKN7%^31;FV?8Mh3L{}+MsHS-Q(;>N_!nSG^|JL+FrQ6FQVRD%z1k;i(Ne<` zl;^!_!IS?wo!s?K6Nz837C%lHmJ=2c$pY~=ETy|(#9olcdi}yM&mO{bQ403mm?#}s z-3+0M9IVvlzZ!{hk7u^?QG2z$iN>%sq}5shW`ZgghIoFe>q}N2tI7}EA*iiU3OqL- zF0tI?g~EF+G%fwvE(v+<_E4tALXLI3s>H4K>pk>6czXd_BOB{XG#vBh14+z#Pf@PV zY4+iqm@23ASVo59V`UwFsi9Mai)F!D?i;$4U$LERA(yT(L%5b<_NP2S=5MSis|xcC zzGHA{#bCpM-o06PZg2StS-wExlD*pQOKBW=1kT`%R&!c7ACmg(qkmDJPO?9f55=W2FUW^)t!GS7SNfG)r->g9xSIxKVZ^n5zf z_{s(anQiZet{00l?rAz0xV5Y8Qqma|d$g-{;~wHq;6JvwZ!g7UwmG^dtdUb^UrZ-u zd7S9SM9RQXJ@IIHMuL!++N$Jq^RtLPy<*mlTAFxt98Ihv=tJ-*nCo(Xn36bO6@X>7 zrk54+_+jWwr z@(bW|+8Yhb{@X9o*?pO?C)9+mzU@C|N;o;`GNCc~^xvC0pxq7^hwCAQ-~j2| z9=7E1Nk<7sjklzzGwj1j5p0lP#)KhqZh6hHxFeMFW-J+WgF63{5e>kQ_e z)jOYb1b*VoH#@X2)Pwd?P0l`$)kIQ8(tlzO*Gn5WpCd-e5~u|$&fjwlT9T|VDj0iU zgk9b*&e;j+JIL9rhx;DTN`vXN(SX}|BA55yZdB~_9cbfA+0(RE3a5|O3*FQ$?$BO4 znpaPa(zLDrue-ydwNZa>mHz->W8VZiH5nEO1Iul)j7dpui4H^CgX}(9kCEt|RFmfqGSp?=QYytsCAS-7i=d%! zI|%*UD(<~=%2rnp*1~#NjUwP=}m?{D{O*iQCp1lJqF1!NpBKR7Q zr$yTz-7{%A&vIUxy)W9eR9#qH;Ym4&{oUjmaZk0AOD*&L2I{YgIQebF1>&$*5#rr) z>TvUfd&xP`Ofl}cpd|3v*N7?k#z9d1FqH>qLbW}>qSmuwM6PreAKl4*Q zMlz46wbfbP8?d1{0r}DO%e;6+a+;t$+HO81{cx2O(KOQfyy&gi(mN94sv@Hg`PqK^ zujBTeCudgwLv?;|SN#K6&{l(RDcL3VL;gwf?vX`MdKt&vejDBU3}37z-fAA3}$nztHd^ zFI(~Kt${7p*4?-;pP6gDTT*3!qz6I5tK5H&nnaB{6xWA7mMl|GJi99Fx5C%q`R)o$ zdaeD{r-4J(yl=+?wwdC^u`2jN?5$9hUH=8faB6&0vBAhczbXxg608rQXVH&wSNm7mFy4{5AFpr zpE#A?Jf`n0IAO*{j0kjU%I6cbvs94#8Dnxi*Cg9Rdozqe0}?|e9Q|*BPVl%x0@B7NpjYGOfs9 z!23$=`26XDIL1VcfK&D-ec+YM+)~f1tl;?QiL%0-QZDo8ulerh14fk%ubH3m6?e;| z&zUMvlrev@O(DOtY+=y9P=vC>A4xpzQzU|RTtZ{RPu9VloSD2US87p7J&u2ls2=(+ zdRzWVGo)XUxs9n&#`HxuC02E&jjA|&8h4by+mZDjhIV%;V1-}q0t5{fanLdPVbe}bzFEL% zXXwg@0k-PvWr40iv(0a8M3iT8OF7SbP1I|n=9u=^GVdHAg`CC>>Zx?KwW3S;|P8(*d#S}M3ldFMr6b+9MA1@mgm;)}AX*r8NT9p|Jp zgxU~Q^;YE^sUSqAY3%dXTK~cKD*BTMM#9)fTy8>L$?c(9ttj2TX%{;fjagwVf5}3^ zULfwd-~KB{vaIWAvN&IPtO#*m5$qq-tLxs!TS2+!YNh(_{spw(R(T5FcWzZnxi0RQ z|AcKXE(U!3aV8X~9Wge;;MO+cJBG*Jibk&{Xe0>NFy4RFswKfEK2eS>{$^^st*da4 z%KF~Y<{|I2Y{|>v9H1Y0ORTEUiw#jT=dMaC3!x=k6lr=N$_ot*@{d%jskET5L zu_|}b_3NPp%6Fp-qidd3KFB$f=NngKUYw?sLWGIi5WTi@tsDC6CmSBQ$nh1iimH1p{fwn_sJnP6fHA3Qaq!l+4tp#3-UNL2)Hs4moZ)Z5%GKH(JpXYiu*CObU9g$vcWABK?XYorrD89hPW$Ak8`lTWsOgIj`bxLaogCpj0wYAp z!UM2Rep>7V+>=L^9nx}dO3}D~oCY+&GFXRi>rTLbGfM5pXyKAwMje+nCB@G<5!ET; z4e&vRd&jo8UNVF}8K5nT;3Xf}EWAB%>+W{OG(tZsjms?>&@yj&*05gvH&&yya~7uq zrf7^ZON8^>eBBV-YoJxVXY~_*Ue~WaV65r;LP+W|B{g5&G2o>|4kD{%yP?`b%*IZI4c9=}S}1>r3lr;5Ax&71p0{Oc`H;nu*za*H)jDl7HFL z1^P-qD|bH;*{LlqSs`6Y4=4y@i%Zm~DS$v4mHqEcRud-feV^Xtb%uo9y05mfOpaZQ zEoH>@zj(LjDd-V|*Xj~W3X5nWL7Dp`K4PiegIwS_7-U@`(+rGVHZLMGoc<9W3@OKYF{b>Vq%#$!;}04)R+QaR7mZ&m6_t9uGQ+iN_eVIuf8KnG-=>e~AEmGm zU3ivlTW(j=(!rd$rMA+&qq1J&fxLzs2Eda0oaJC!%P4@%7lQnI_E)&&9g*z7+x=Ar zyDct5ww!AulXE>{DEH+MZrnh|-bbw}!T4(Nt!C$s(@WZF!tySiePZ@%cevCBrw_Vr z{6Hn%!ME9ws_NDHq#Wc{w>}sDx%=na#;cVR6U}b)S1 z2Ngp6d3>_>{2NwNL>7WG!Ry{*RL4Zd?`C{N{Y#;>2+s9x>NpjVA#D5UlCmLG=81wt#fvL37&dKd@mfH<*jXUV?d~H|M_ALdQRnb@fdR&WAs2#tx z3}@|}HE3=|F3U`)UA1#IYW)eVzZa6hZwORLKHs($tD&=@J28~n}{vj}UkZKJ22Z7o658#`*zNmk`*w%WA! zoN2_Vz*H52GD5v3#uzwqZb@81Ep;Dz>#S9`xO517DA4myYYtYS`BFkGkk46!$*|CH zBw_sWUV{}NvNUN+8XxB#ymT&BroFd1T*1*gR4v9h(d@9gSpB^M$QYXH@?)VNi%w^K=?Ph{<%z#2h6EH18F`DE%5oNSV$ z(hrg?>Ajc^$*P9=oNHfZt!#~Oa+-3d;x)ed&rzgj4an7R!}EBR$8$N zR}nuVfZ^D?Y09_Ew#X~2f0&uSSl&|_2{mU};RS7m*wE4Fy@Z5qKBgkwpp@Sb+8NX} z$60uZSh46MIidPA2AnG46A$`!yt~5F9)KCkNr{lIR%>iioLk2N+;Slo;ntQDXG*>9 z5l0%7-C|0Sjhl5UhrS__HqmvCa*oRCJbawATDDdtW+dkWVnA=tq^*GmK1dD z%2Vq0^5LOV5%sZOZU?|HhN zewoa+PporE-CdtL$|J3RrUIG`%;rAYKSCVVXba!my`e<*9SV#lV$jstEI2AV(J{crqgz-#V^?m zmG>$-D1z#iNSES0W^TS}bjw4$vv}i|zbguiBUvc40g86YQ{)$9=$9z^C4Yx-?SZh? zagh`avSz-U(|GsH(>%hzrIhBH!dxCVwOuVsfv*CYO(6eivuyp1fWS1r8R`C@3)$N z0Qrzp)57I&t^1?OS?tv_qaH#-a%`_BzJYGne;5tD^dA%1=VK)J6HLm(nbn7jQ!Ftz zNSY5tjVecd@Va3}_xV`)xo{~>N_a;Wp<}?WGj=#&M)(L}>&)cLj0hg8pU9FPFx2>k ze1NL^3iOC88ul1!=YA5Qt4+dp?P1nwVM zBgM{fAx=?f6I%QeOV^_*y-1tA24xMe+u5X4?;r3kbwa{>N;ZBA@EQ<}9jr)lM;(2P z@lqw!fLaf&9*@RtPP)S15Wi%R5%>K{IlWWH#B9MqE(HI#hOXso5?76fdzG1|v8WSb z=vkmePS$XQ&BNBi^q1Z+zwYq%;vSx7f7~{l z=W_EY1|6H|69Fj0ErlAyncpw)0Xu&$yqoTi zS3kK6CM=Y88rne!b3SJ(zz(}U3$jj3nZ-H262%!SZ!kjbJ+M^B9PRV1Mwb$DJEv)h zdo5#D+-7-(;(B>;9h+Vu93shjE90&!5g)wuXC(!9AWNNdiXPtxXa(J^7rB(p$@9?W zbWr!dkj#+7jm+f*r|3z%)#0iL5Vdb5X-N+FZ6@Inye=YvI?&2C+K9y9v810EBJ(qG z&ttCgD7@s?{|zsZb_WvaM0PnT03is^J0rQjOcKD&Vh}^K69I5v)_Yc=Cvq4PodY+JE}2W(UQj{8pOHegG3m3K_Re z5oxy>F2oe{jwX|RU{|kc-EaJCxqOtPaeYj z4S7Mun%-UQ-GM=LxUfEv0<)zJBz66WCX%*D2ZCaTns6r7tCW^L#qqDH${t)Q z3zXiK<7%~>v=H~B2J5elhF9zC{3~-o;$MqRsJ#Ise6P~J%pWDVv7o!x5VP7%@X z7mWP;K&zsh(A#;zkZGat9y^8Zc-l43doRotexoTo%LINtdr~s$mzP;!VUv%0 zI^;^Pps`o+X(ohlg{jDXwJWI0s?2S`-ZEj0Mz_jVXo3bd78k3e;KqC1=Xp;J=6JJ) z9?TmMmZLIIzn^S=`(!oPYCTMQhkAB-vD)TK(o(IUTuGL+8lt*;ihsdN^6Yx}^&EfU z{U^A2x`xMD%q^L07s>OkRr`8Z?!ne)>@1V{z}VyyC4WqobF>%^{ZvL={tT@DeGaES zDoq3z4>)yjx^$(*l<=H+648|rklaE8^99i9DlghgtS+ey7kIqKC1dWc$-0d`pY&&q z1oZlEnMn-GvcW86pW_J3X2fn3;@5q|^Cw?4-JNf=Yk2oZA{kIk{Ee3(qj=e;Sqn6d=|r8ghmbDQ8r0Z1TM+foB4vJ zLf>uvbsr&;#v#9JYPEmGRc28a`qKb`5RwyX$bdX`W>=}h1!aePkZHb|n*=;h^Uema z-S|S=b8I4+9~t8!QCS_!~%2)`B1@KNxlKocD9wme78Dj7kKYCBja(-10);Q}&d8e`aLl~SC4IA{zZcyxNtm#u^ z@IoiNwPE-1&faI@BPVo(IPd*_y?k9?G`skrPtQJcuzgHmJ!91#NxG*wtL?R^NScQC=Y%Rqo7vBm(|UE68dy9MtgaRbI$1Dd=x7S!Vq( zFg`q4B4y(vxAAA?Iq<9!it9hI6u;HkqY3lAoXxDV#=XHAQjd%LzwC**8&@MEM-(f@ z{$hg+>!n=*x~`d9BN-aUG;?OPyn6YR`&3hrsy6YCR_8E>Z{+SB?i#u1W(jFSZdIHm z9v|feg&e5EIBknlA{r4P0A(~w5P7oe(zRfjztKGo)<6kzl~6?$U+`{qq`mEX5phyO z4X};xCcxR3x1&1A55&1RGucbg=6GkPFh!va8yRlOtmgCRm6edm*!mo3As~&;MZXO4 zR3aQJ5!&_JyaKxaO)!vVsDSa#nPHp{x|$-m|I_XB-QF*!kpt*ZM5Yf5x;&MpL_Qd% zyc!cRupsVECfr%;HaFj!<{N%K9H8YW?tPY+=d#KjFcfy1!z;bT?YqybjIO?yn^7Ze z5|0-5b6V?R$uF#lDPwYbzm4^`#Oc*C!xk-oU1RvWV-yd`-!6-fMYhw-L?4Pi>G5gj zpK{BTsz4uGh)0!R6BeJM%1}4Akl=TmlL|QKEanVZkhv&a^kX<#Tn+i{So_&MRXYAI z`a1KF)XCQ=Am6H}lbv!OSrWZ3bPFXBr+uM?i2=IgesTG3&eGZW=+hOvJsN3C%%G%S z*AxtC8XBl1{!~fOy!Tp^dZ|*!CZ2%F)s$EB>Z@&S6K>aEzurGJ2Y)C$w*0aO_&&X! zeI_KzsQzx){(fFuA)oi1h8YuZ-sVg6VQ}+%i9Q?aexMoDwm3Nd_K$$I0sTt! zI^T7mSYO*U9Ss{O0QUkzcgdS;ik?k}-^tJ+8~^TJ(Z?UhH%H$me<(De;NoeWfb{*J z+VkAX_)yzbMi@zFlt3y`+Bg z%iiDugSH@dzV_Ty+vjWO)JSDQ+1GstcI=xft=ze*qsAvHMeu>1}%ONqD;voik^|y7pJ6 zhSaL5k74^wTr1hZSrFs*f(`d?Wn7mg|Gk%OnfA8)QI-8g-)u7()x2Tc=yyP&$mS_9|BEjCcr;g_B~#z_=|pi z#x||hP0W8TIe`}fe;;UV7Oty0jHu;FBv%%itu?q(_;-T9b`x^ae0zuvESr4$(V3#QP01sXKsQw#~obPxvVqlt_OLP=6c zT@(SgV$$E_;izQ-Oh8pc+OGt$}o)u z+wsDKIPq3&6EbbX038rYtrdqK?81?uf62%-eRn({bcc2ww`YX`Zgd_AFq{%-;K52i zvyLR~)5w#}NvM^8AF5%u_Fuuvkh8+*Qf50bph+pE6t(yNJM8eR9AWAQAmk=;cK`EH zlwCLhyShIhd%B5Sh{hwg*YRq-!Qw{?yA=Xzj^+%kFs07%Mu!}c9B?qBhSZIux?t1} zy8R@<2S(71{T?$$8OZ>)w?tC=J^PY~dJvoFIr z{~Ib;KyF{D6$YC9u8LfLf^OaT%jB$@h>DL8?`}ml^^a$=ipZOY#xob6`P}O( zw^j6alb+F^FNv)~*kR%Xp1kd;GMg;G$_!I=~- zN+X#(6&i7z6`upqNy#8K-d>pAi7$cs2fdYy0lS?lJl(L%e3%PU9F9;eyVofo;99f@ zfBg7p;7}k>r*`mXYHG}os>0rW6#4#0)tdP&&eQ$W$@#j@X|>Z+9kL#9tmVqs(vlor zS0cu5_}{PP8tpmn*Pj3LrnUIvcET_6%-A5`Zp!)6d)lu&qS@k)krKVEORh&7KpyOs zt7Ao>Tb$VGY4J;bU$WUuhtPcZ*sZzxJ7OEPMACLkwydK#Hr}@1hxu=$mLtp-*+msU%3iU#5G20>KKKWYuJturU)rI|6r`P2vZ-l-;&Ag?F`$7OptT_n*winu4sGwZ5ks?tf^YT}f=m z!$!~6l6;oaPg_yDO|&`WpQ>`tm}Z5XKAU;Y`Tetut3)V0^LLe~RqpPo^e`n$+)kqXw(RSH{55ZUwxtg!SkInB4-2v=i*eSBh=m)i3+J%w+{=;8oSzLA1DFX-8& z`L0|Y_-Q`JWIL04V3H;|Gf+!GXM)6iwX-4Ju^-?0af2?=j{6acwuirkM+dVIrAxy-UfGL~L$-iM;{^@jkgjkx^%RLl)pj#|?V)$&yCvB`*dZ&)hRpmfMcCWJW5n zxW_j0KJ8TOX9CF|O1g#33-Nhl#_MqZxACT^FXnEGpjLlDQrKw77 zQ8B6YGEzE#<7O*nil`Fs5naFi#-JmV=^gr>nA~eE220LZOCe&PhBx$9^Kqu|jC|3I zLm$~jyt2o>gPDo?-h)@+SQ)5Wi#ndz2+73VH`_ky>D?;9twrzGL!(aSpa-f|#6bgn zY{7%D)0{zIC7jCs>!Z%9dP6ihY6Em@A-b)}7yd)*E9xq#=~R43GF8O98*zg$@K2kdISSvDThb?_i_+k0 z;b#@;Wc%j{9;M5W_8(pWMdBA07gr`%8k57_eS4~BvQtzuyheMOLKCAMd3=4|3E^#2 z`-$MQr?zyul+O2m1Ej*^;Wiz=oryAKGoy$ufyJFaJvaZv>G|jQylI{0V+(Lefy`Nn zU+8N38YnG=<<=rONq$j-BD)uI{7aW`Rb5T*nr8RqfRAPd0)5LI8}0mV2?J&0eL^!iz3dI4%DX9xppaQ%DxGQ4eKqf`BKDO zsIYK(__Z*?gRXYTRp|PLxOks8+fIC|=kIVzhtIkUhG0$hKfY8WMmHYAVLx$i+?G7e zXerB`eiL1PQD3g@`6q3+rPP{;3H?N@+jQ#+bpD61(pRImGbI77D=9VlfxU%0_Nx!& zha><6F0h)Zmbzt3aS}e{;mBaNH7@&+PJMh^5uwW@D<)};^d&8^HPzJzLh z$j`)bgm!VeE1T_@tH&{ee`yy_`Oc--!2L>sd$GqRk~QFe>$a;MlpO{F3VJ`r!cX#6 z)CitBDZ2*hD1ln9_BLw_5uCyuX3~`e^Z|zh!>XW7D2CI#sR?GX>n#DCSlYn<) zCVvd)O99vIntN2bX#%VHZCNG#_gFH>&g+zCy9l0sc%A>*Q(X(``Y`|s{xhF;Pi)*u zrFQ@CFCm@%tQNFZs-BzBSU0>fpRIACqY4nYkgsjRT{LW|ckYzyE90}8fT|px1;1%a zu_q9Rlk6kYK+1ui2}EH4b0@MOKSi@o$vm2PJ(euJW;W;2g2kZHo)4Va5y9`LGw(F6 z!6Ta6WvB0Y6$7s(eZlYvqi*s&M%|ki#YiL>0q9=j5BmukwnS2k*+>xc8{%ezR$;_` z@Q>InBer2{QDsx)l5|rh%)G@Y)Y=+7|B{O6(HV_q9tn=R^Se#9dua_?Pq6w?c$)d&sSUmIJOrh{J$1FTN38W{@%ElD61#9h14IIe}&Aq{6=o zT*g2S1T>Ph9H&&WgxgF+w_cI6y6PN<+l(i@OyHY+&^_|#ptg0Zz!LAjo5wLBy&n65 zpj?sfM88nFNN5WUkJIwe_av5bdPpvZZBF8)m#oPB0H|LmnS$)6v2Zl+T|?AbHyXFS z0`%8N`=1_M$`Xcq9(4XQBX{^7=h?*h2MUA-9%=-Ky=)@GB~TOqvW52NaNC=?S{m3& z3&O2=hXO$0rhPMB%D&`AR7&U=%>}Z93J9IuJH%nA47C&iS|f3%6jO^`jP3&&1MwIM zB72Dn#ju4p=CsQXZlU+DcI_;X8X#>Ff%||T4v1%%Rgyq$MF;9xnXvBCwxo~HBT5xHk0kX zyHORrB~3|DqL*f9y8r9%bHg`3x=E;1{JhNYnFrZ!)f4Yc&Q3mQEY258@pQjv1)of$ zyFU^dKW@>_15w`qb(GtUhh0MchY}gT)OIGubiiAeMP4~v&Xe33*WZ3pB*(8oJ#juR z6mfRmC`N}JcW_}$a?C{i9%PA&e2n~VoY3PmQ)zSCv$IFTaVh8-QJhE8Ow_ktgX=$v z_Y2g$gE>V+6G$#f!wtUb81xWl4gz3@c<;c6V`tg?L1iN;lX??p{7FLEQW;?m^BoxE z^>YXgLVU@%sH3~}3Si;srpe%=~1AXd#?(C|^Sh@CuH{KoO-IeY!v7(5mwvPeF z{s#6=^@`|(oDO5`9uVe>h*d&s-h|aF3HeaPXFX~TYc9VIy3!uVn^;_gh!os$W>kW& z7r1ZrE8>JLch+^tnKy57k6U8BmRt7R(WZ$f;>lASvg3br9S1{rP^$EG-Q#+Ta+eyx zO?FMn$w%)J{mQ$b@bd1Rh0Ks}pX^RAKQfdYxD*3ZJ9j%_r=@o#+_9@>2c?KjF25eQ&Vyc#*{bWJg9+Yeye&t#xkKBK2jtK`%eu|BNEI%WTq!Bfle_|PH| z78&95yCGr6)1(JAW~G7lnGODq1=RD+nc3zSlGN-7rm+jo$qOmV??zgpUC{k8BGn;z zey87)U}1c-Y8xWSuIpC#+c%j7rAMi=ojz#fI;qb4reIo)g|BBH_h^Zmy&gGM++HAP zlB_!s8|)Q2p(7EEoH!+Bwbzz6xplVu&TJGyBgdKRkWfld|Mw2*>Q@QYyDLG@Gcy(X zT-tbo>QD6Yy?$%ItU_+zv0r)I?sY6oDMA}iERBVdciS@XNn)DMJDQYAlUQJT%gP>! zuR$hHO+Wk)_IA(Ao3(C~v5iYeaWQ~%VXP-(yq`%AWpm_zV-;EVBpxvGR$$%#MeoN` zEb-lmQpJED3H;t;SnpM7?@TpxsFdm?+)PUsHbnjdd)u?2)#oIhifl?MJtA%935LVB zW3e5r6UfIP=d;rz&`!3LI)&RDceeg*9OS%pf5XL-gNr#y{%(n==8YXZXdisP2Kgv` zbz3Zme87_>c2>p=?>XOhqYky;-i7W|6q8Br9V4LatS+4AF zeJ$SZKmQ6S1kgFuDjwMT6X3mZX;efqLlJAg#Zh-TtsIGp9d=Fpg;@nu^u;X;tVqZmzoRnb}nKP?vHYeaj}6cEgxl_<1)nJHZzB=Htnaob=mv2v?H@)aj& z9;?6zn!7PyjRA*>&S*qcWJPzh0){My)%$&jQDA6bmc60UQcOUTVsg3&a3R$tnJKmS znY3>#Fb&mwkN)QjlBC&@E-~$JB(8SSZt;B)w|d!eYILr*p|q)O=V&u~HoZk7_IsBK zNng!}ALaZJ_q8<|xc^ulg!6Acr%j$Q`n@Vk)GR1w^3I;s?z4I8U6k*i(69On*s(zT zCV3NpA5abZ`}6dQ&@#fR3wQrk#l|FyiXCD9o}P^Rhx)!u#(&Qo7|DWcQ)QsXt&;Qh#|GGEkG;G&J=c*aONH|oAa7^ zTXC@v@k>dLmr>AnTy*{6a+8$$wq~pLxRLPS4!k3l;mqldP3XA8?h)xbHrBp#UfVin zIofAkufD^M3@e=}m5~9h41@ZN%yGwj6<|Bv+k#5dd@mTw2H!2(X(79W3-BzBsMlBE zsF-AX*aS)`ILBBV-a~Dw-PT(JvsNn-avdUo{P4ZZ)|__*a^Q-CEg`%<@ZC)H}pS|iGcsKG$lN` z63|nc>nNwJbHB$A8=#GWjxQbl&Wzc@zxJNi&USViUT7SoCR-1mQv!ao3^pF>JP7dq zGsj)JxW5!9XM7p|ApOL5p#4lu8OPyEo!PGRllU9Hx6eomWblobp{DQ3ZCrS`Q1bV4 z`KfKeD}6gZSC$lWq!eImA3;r$cJwc$>jLkz`+La2z%_bL74Unj=Y-6X;;i)-Gqx~c z>kYXrj^OBLI(eIFni`zzBbB;$=`2DkjH!|1U}mi44>v(5=d1`f&hQV(TZM?g>DO~A zcsAxP&upOs#61`-Kx?NxPqol_1H=f8e@@_-8Hy@~A<|H+l&oY7oSBAK3mre2@@9j# zu=CR%+B5r+hpjY>26FZvd`jq`oFp)Nj&UpWS2!NT?wG_AIR&*q%+j_5h=IZMv#WvQ zL=wk}L_1>0$%MndBphR?R1-T33T4woh?|0VvBQ}FiNk$3ZhwCha}ZCGo7q|-Q4deP z`+v-ce?ot?;zKxv9_m=^1qd2W%V8&z2nS!f zY1&Pjo>bn|Jzfwaon5Wm=@jv<>1U}U39J5Fc6uFhOq;h_>S-22=-ON%~qkFpBAo-6duF9vJ z`-Szr*KfCedFSd-ORUyZ!_rJOZe2u-|M4#5{0Mjwh!zZJRhcYSQ%x@@abZ53^y50( z1}5oh6(V<>!!c-JQ_aDl8fI=#ehUaMR#l zQe+?ullj7@mmf|9wbtpbL|s!W5~2!xjEFCq3j8S+gz%mjeDFO(+9*oQ&ON3+ZN1>1 z^9`LJ1od^*PMbeh`IHkH@h5Sm`=sT)dRk<5vH?u#0VKLm+cjeUAKRfLXf_`oAxWA< z_DUW7Y#mNpo>fp;Z31mKwnh(40qMT$n9YE^zVZ%iNBN{QJ2lJAGwo|B*VY*J_8|7$ zOOc_jm`8aguIIM(y|%7p`v*vqLI*A#X<^s7@2_7&O6W}pXsoSAL6LxRL4@nA@$A2! z1Bc#NNOo-UJ_5=nnLeJ@F*=z)9~uu#aPQevIh%R_d7Kp8HtQ*{^sX%#U(X6nNeUn&gVax$~E5#IruQMf@;46GJ$gW z^yHK+nlWkTuC0$o-_wX*&;y7yV`ZYwT#iE0Z`q1C^XpU00yUc7*6FiP{sGs_{0`mc zx$+Yfp#92hvb%cSmD1cJVIi`WWYMqUpQO!{9^wd!>P+8X*guo1`nU$kwVO3w+Lq;- zrMimIE_Ha(2R7K9sD6gXoWz7NrSO%ddY-)jwi7Zj7KQkM(Cqw>thi-3ab{}}OP9Q769Vhz zjW`O$LLj7aUokK$_ezVqpJ!o2G)fND(RDRe7mL!D%Wo+R%f<{tTAayspTccmAx$NF z6N&zLr9x&6go`E0WrRchu36q?xi{Tk`Q0kOuG$2<*cke`Kf^07J*8YBG;N;Mgt1nU z=K4D`B9{BM^X`8jOjnjRTaEM$bxda4zyK|W{=xk#vJo>Oc@xcbmEa|@-efW1(!6l5(S=Z{A1ITnQV5wtO@C);^v|1J?_DGwXcq~v zqZ#)Omx$MH^RfSX`cTumNW&RAl)(K-udx;ovCeG>ofK#>4>~%wj~*TmzP9pL#LCiQ z>)VQ)yUp6$uNEoD3m(-M0I=dDH&sIRZLl4pd|oA{wa+b&&C6O*uCiRW@_x%qn&Dfd zTteJ_wX*D&Q%3S(OGzDk=JHJTGW1>GB<8;E*LJI z<`Z%|b{!4S-I%-rs@&%5P|yr4%S4G}eJWoTpW)!p*8z$w57s5}Lcby?jBc)VXo~A_ zK~^B%Dh1FB%iO5Gf=>Z$cn7qESgv2E7lBW-^89!(x*|cb#6G4<;c-eSvpDFdz0zw} z5_}^lNGL&t2PylJk*T;*-L6P&Qa~C12hU$sBFip_dmCRU6M$Oc>Z3?Uxiy!(OZwvo z)Wo|7-Q^C(xUMul^KH&?l{OyTwGBzLP}0jhNDS)ajxx3d)TBP4V*dgKg3ei>DOy7@ zdS-9H-b;VTZbqv@TDcs96#BJYEz}a+EziCAnQYQR)1wnN3?^dK+zY&#e3)bEbTd!% z>53lyHQHuM`vTt(hjtru4d$YJ)XDyiZ7-QoVq@{V+f>vO)atWk`W@rK7XtKYc5Prd z!Z07BcWvrY)E2+i++*#GDAK(k2+!L*;`so1579B6La>iI^h1d4&U2=G=QfCWjsC}i z0{IGxi0qmBx&yLobBgEuiz~nkM_Zyc3G113eii}lEj|d7hJWJTqU+ve^lN|_QUt+m zbBMnlRqsJj0tsFHnirROoMvO%_6;}?A2?Z?JFvb!(L z6vP=Hl6^k3Vll95Vu}7)d7HnLDd&9+Zv@c%cX;dP{rKHBP`~b064kZ)!gHCmhEq>Y z(4<;|vJ5X9@6~OyJ`r%5LN=Ugp0VKjG1{k>084_d`8l`fpc=U|Pt2AsGl7fKb-Tsh z>PNMQFXcx-%kDD+$hR?sNpx@g!H&t0R;h#g7x2d9ruNF%@;(Jz@kV?li(7YF!F2y| z$GSN5;tr-zGCt@`Gu1GCFER^%j;Q+a*5YH3A2+MmD|1iZW6PZQi6lO|e{AfyHXlq) z?igF#(}b4YNr@$#ED@0a7$x5=m68zFxRYdxn#Dh1y~OzDO47@g);SM-=glUfUghqz ztF>2~CQ#{Z%he@?z<52!Us#EMQV@-ql<@zg5)O<+3Y~!6hTRc7?}ufVzE4isNB1R7 z)xMp{Ia*fz(IuNxO zhI^N6_s@Logz-{jOjYyEBw^&N7UdD!Jx+034t7IsGmo{$XRB|TAO~{<*lsTVv(4eV z&+oc^|L?l?*Y&4=O# z#cXV4XA#|Y34TaCVUS%RA=%&GfcJl5tq;MN?F01rZ-h862@Dg4SR<#q%b$3VyB5ip zvAfJJBq6xV?wCrJNv+V94yMa|PYpUGu!oJu?r^p>M!e0SfNvViibE0))&WZg1onkJ zH;C*?Ut#DUwk@$^yt|5^rJL9|_#l>zMne%Z;{BpAr0`z5GgIoNeN>Vu#ggy|Nq0z?h2g%u&nO zf6gxT(8He?fP}6n3Hn&*>~t;uBPl&$82C{^swCg9fbzN*&g+C>a~<(-s{OQg*Ode; z!pKXJYFpf$Y5nBWy6FGziR=sKac!8QK#r7;STn5Gj;5kcLjyBvQY3d|Xrl-CT(W|n zufFE!D^NFG4m*{glBYp5H-7QNWdnN9pl@E74A8vkZadcc!z{$yI^dhX#vFqR z79^3xilAJ)B=>#WaKpmJhr{p()7gGTFL+eX<;mAsF!cV8_+}U1?zQsVT+_Ben?bJ0 z``lY^Ei~EEn+_br2w{SD9%>L1%RZi-ErQ?huLu=*CAQJPIri@b(Vq4^ZSf$B_ejyl z^D1hv<3&SlmObZt@LnCtV5Q*uv%+50vWsBo-xq1Va0h^2+pw;{<0}+P=*T%nf(_#6^AgyijcG>n5iv<=iT* zZOLOXx{m#a_T6Bx%`1sMN8p*#ysD`$E7+a&DN60nxX%yD=|Bx{wa%w9sZRb2rjn9sZCfjCp5dv3?-Q@gdxA5dS~;YUo{!kkucV~Gpl(mX~hB;a&x&Q zHacYoa{d-L*Z*B0qPD`C)%QW;RjOYWu`351|JSj?_Z*~z^)P2z)8kmmL>!oRORuBL z8x0BEo*zZ&;J7_ksVz8O;)XTtt#B0>E+yB(JS9UjOfMOTN{`muk@gOzx)dJb-Ho>f zyF?_L7(Sd~_I6MH9WXD1S=^ieGw{^Qd6f3yNx^oAB|U6p|8=h7}jH89xg^b*K(z^kQ8}zUli{l8B9L)k-{JN zcwPDnDT?;An(nJg63V9+KVNC_N(8P)J*ook-%Dv;4<V;>eYsTBj6?;aasr>ZdX4b=2t=Mr{LiZpb{Vn+=6m~Ql*VP9M<4;tfLl(YDS?fU^ z36P}Y39UU-AYG@3o>P3(4oBv99qM9lJ7J$0Jph=9gpLxZ4?>6TM8~Y*nz+Ji>EO+P z=R!;B;a^Uy?te%AD*d?%?#TmNaTLJbem}juALBbD@`w&GHX=&y*90!b%@?qwt;Dxc zaq5~{aw_;{$t`o=L2@zW{?T6x?@-Tq75Jc0GZ$#bw=@Qhb7J&*KVT0TRrbD~nqx*x z5q!hC14GxzrYxWCQpw}%nZ}$59N7F>y4ntAJb@JhZnPlI9E>3pa!x*j(QYU{GVyQ^ zT6J;McG1KNvu!%1Cz&C+_1H6_H#gh;megjBe^xpnh5fU%2g`MvrfKc%Uy~MI4tVHe zFN-Ez_x+6MV)CslRx`MP_vwqgEOpNjs>5DDa?KR5MLDiU`-bxTkisIwpraLIzWY_Z<+08LnCUWl3b+2YES6JyWdJ z8q>HrlW%i?wB1KMTuDR@{wg5!<@qypwiDtC+oEX>4^Yk(fA+5CZ~LrYhunEC4zs=w za1{s@)e(yOy_I@?r(Mwf){F)@E$n;TW98Kt3rNRHJsn$ZK)`K3i;y1^d=iPn+BaVt z$JS???3zCs<~GsPpsZYWUpzjgxmgJt*0X(L!h^XWjTFk=@D*??eAk0KNCpHhnW{?} zAN79pZddke54%MJy}Jv5qG-(FfpL17QbD3_EbM%klGU?aT^Vj+xI&bUpLj^;08&Kk zl{Xxx8tC&)6G;7xOdC>F>&6c|sl%Q@iy-hJof?D>03~RBr;sudQ0^Xzrz+(;Z;2$( z7`|5rZpY0_8RzXiRfk|FDFeoGUR zpJ_~;g}7cP51}~6Zj#q@z%pKvv{Rz9g@JXy$J`a1BLU@9#V=BX7LujISm8d`YzDx7 zpXOXE2FlRXV&ywDiybilgoUbU>o=GOZp0~cKKR&u<+TsKaPFbMKlJvix-|@(kD`@!}5a=+dGtSeH3$i?^ z0*!IIL6>UC!nkXkDlQ|7xgv8E_Wr_&LLxz;bZGlo6EAO+Tpzx8&M5^`7TC$BR}25 zKd)HFm;}UX@BM~taqd49+__#y9zpQ>J(+)JrvKS`R_37(w{O$sFHu@d6kgV8cFJ3~ z?DmD-nS1i%8ok;$She>D7v;B;+ZPZJhHUJXF!TKM0!|ra=`+lck5Bp?%f+AqTJj1iqpycK%5NP)uU~+ap zEZAw~-Y!2|TcLU*DC8Clojy7J+JWtiNW8Ip`la&U_6BLVpQCr>)u~dg+j-a- zwbq8vB;&$+LVQ{(E|Gi^Mx)@1ExpqD_u78GZATW~ZF^bgvb*+*-oV`P?Ks?M6fXwQ z^*XsqLehS5;}4PFB(t2f)d7Ct0p0hMY-0UJ8n)HpGlSY17t4ko16u5tUT<=aeX5=- zcn;>CI;D_@IK?HH%HA>qYdja3qgpy9f^2r{cdv~&6@)BD#=TrO)Hj<057mkXZ5Foc z2%k$dJ`BJ3S(W3Bg7bm`jC0_nsMze^?P8Z?3Y?;j?}nfAPMA*m!{_Nya>}cvbu$L1 z{7^|m?18f|R^+`2$xe-xto_`p!wK~2NsNfyT#5EYj{d-Lj(sV83-P?`sjXO!}| zJLd%Fi#E^ponnq+Q3V7X?z3Rtl>FNAIqa#Yn)|(ko;Mrjb_!7<-=pDC)gUN2f)*^_ zs4vdGyHN8JAZG)=pPS{^=k=NZ5(`*wX_cW{-0VnH>-t1a^|?ZAw}xt&CdkWeJ7)x?I}>IW8>CjAmQEO3aLL_#mcp>80q6=hiRgH*(i}Z^yv+N3M9v z7HTK%6`1pEs#goTK70B|+4217mH8WdZ1-@&$@HHR{vGv_X5TM!Pf<&A`SyDe+QnkK zqXfRF8GBt-WjBu!Dj#PT+6(e{u{gDPrV1JYuR}XBP1u!@;c4b&c`!wEvP@x|QAl}u ztOrVOVW41llp^~boI`Bs)Ns_6PzX?fA`e<=@`e&x= ze24L0Mygc}mDo~;8F$v8jvL@oZywh9M~(Aj@V;eUpXPv^q?oJdYMB6R=c_j}LW`6$ z#p14=?9w~^bk=V@Pv_l5@j@8$v{&7^@NaLc5asM(cG}Oj{;pj?@og!H)$;qEP{V4e z;kJ$(H2frnD9#}>!0FG@qxmSU4S2Sl=|O#3xAr@?9yqCFFLMt%6;0-*2uX!T;Fmxb zQb3i~;;0AD0M9EP+brG}TxN{?x8(XfZ!_WrB)T2Is0KN>6_pBvarE6mIm6;bj(N87 zcjF8If5+7+@xAzltIn-ZWju9nAI5C((h*Td=*$>a$P?AK?t-#kQb&N@K5es;s&7&* z;>>xH1o0DL(138By+slIk-Hp%(Od!Fy%}lQIy_rrh?@Rou1M35e10T1Y#iT2?y;4; zeC77~#zF2BKaSmY*#Gl9gX(cXtU3zO_dd~AdPk9@X%wNZ<@i9WRl+gAnc7Sqr&Ora;8Iln@GVHMS>#f7l*uW4mz z4K0Gf_kP}IoDyBX>i_5UE5HiyBQLW^T`fg@2BJN7sCe_WGn3Pe*wykbwv!UMo^X1j zG@SKrEvho|gEtK$t+w$>Qrw?^Cf^^5Saab(H}#}mxVPQ775~M-0ecW%aZp=FS4`~O z9z_TaJj+CE2mCso3z1t}+?-i$cm<&hBTzm#bzkSf5`pTF?|;$Ia;u?w#hyXW>;@Z@ zt{+*^{Joyd8A^uNR=J(=ZAGR999{pTx-GI}6o_9t6ss8s@F;yu)8IK$KLDOjQk-cde1Rc$gs|Opl3*m&mMHbPgI$7!>E6(Edl8-V=!W z59QmSz#u_e7cFLIzrn9Bch#_#Gb24CYEJgBse~va56ZpshW5?F96${DIk#WiQY-ZF zaN<(G$MZlMQSaTDFvsB2c5A2O${i(Fe-6Zz@2Ye%>I2N-Johka1GZinrU%rgoe=KNQ(xp= z0@}^=@2`=d8)XGNT)?{n zlur_bb8j%x-uAY0iW}uKV8<k(RfYhqn*o`@ zS8}FwNt_>NaHj(sPAVz=p?+Ky9IaQxUDB|=;SgKf;sbiw%6L$j=ZbQo>C3a9Uhi>w^;@`2-s1%w&job+HP*{k>e@z0 zdiGWxpoBLRIWDp%Qf|izUui-ZW4Xx(%RM?iX|#KRO`q0$zpXA5gdH(B^Jh$FRY1xQ z|Cw;^TC(69`IQ}2wwwOWB<p6|OfySJDjVKsqdzd5>urIUJ-{`(_ulOxv;#AE4FU z_sf^U&z5}u7B^IW?+RJYt@V$E)pMkZFovf`8@%!YU6eo1J;+|b59T$?qg!Og-1fcp zZD`K!F$%;dN}4%(SE6pqOI^x_rOJimU4d_4af7Z6ut9eccb9BO=(aCA^pghkksH|L zWL^WV7#lJ+B1p!|6LCs)L#GIDFyfumJhTGG^XisRA9dh{y>7o_xYjYs>ZphJ1PxA?-b3?;`7LFCz%ym>&plw#MKAj?IY8k;-&W^4Uo=u%ZG`$S&i)SVZLK| zj;@N``3Pv}w*)Wd!$cb?7ui?M+rcX{&oa@tCMlCLXU?LN89kGuzfy!XV`qP!q?06< zjaZNROP~dyt3Byn@9A}~586||L^X!Uql0sfo5wCR%n$o!JrFdlk;_Nv;%{%*t%gZh zi5_qds+H>kf2Ml*EOZH-`&(VIeCF{R;?sto55eGTj#v8EfDa4~m#;nE;5^)T^2<6p zWqz|Y7ep|ey`Ar3(PY&yf15KwG)`~3Y&z@tjFgtfNz(U0-A``WDg`4tZtBHH1A4v7 zW!e}8!6{+#G%urQQ+@Zg$W|2GI8;9686|Xw{h4MeNMUlS{Y{Q?(pke^W zr9d6f8jk*pKo~!sfa;<5@$*Oj?0iS8u?ceWuWW)X@~2n|j^&a~po{LZO_D4yJsBIc zXN+E2PCc0*n4gSz>p>WaP{dre!b&jCS|au60HbrfNk=md_JAkDgm3S{evvgX1Xv36 z$MTsLkYbA#VvQ(%veZzeQ%E)ZE$0mYAJW*v-2QAhl^k%QW?lq6nr1H^sG~x|Z@A2N z@m--qiqLU%-v7bo$o1EaQI&T@jFznC2ZEK)P@bzSe{kLMF+9zM-SSnH?NyXpAKFG& z8wOT!@4+K=5>x3Z=YMeq_!Rz0*JdMf(x?i2LhiXOB@?ior+Qny?NxUY9rC?RBgCOKou zPgZVuh99kY;_*^Hy-6+(4*#4Nnxc~)mj~U`%Lo0j(elp6S*Bio1PV0JXppo9v3bf!I)pU9hDjQzm)-ZZJZdLNw^^fbQ!`0U%A2a}zYUYkm>;MYvL zp4&W+!=9!2T-0YiWJ^IZSA_N4An`}gmkCQR^7xxzy2i_w&|>e}X73Yc2y^M+qThLW zR5A}F0-G%;Ypt1e<-)iZV12_~BbGt=FBJ>)GI%Jc(G`zYQBZSrxk;|t`+ee%E-I4uLvELXML zPh)8f${ErKjfYO|)B0$+9)2rr`ygr1!uik`qcUnK5pcf}WL1ADhp!ZyCSqRE zZA$#-RNC{Sj)C1yk+fczXPcWa-tGnOJ$SWzX7)H_n66eYdJ9Z(6j>YA`5ff~1eDu3 zw1T!&s82!Rpq#*&;X3d*HXqC->t_Y2q+6$-yq!PjCco`~j7z$4(2M z9Nuco_5^l$x1AqAnGv1-O+U1+tHH~sgg7Mt4pbH&RzbS1NF%x+5lT~&?n^qA_7Sh3 z7M5pxZ>IC2rp87)A?dGkDV9cAXKH23Nv@UR>&>#bvqYf97*cBs|eS1Akbk62iJJB6Fn;vGiDSYP8COJN(UU zf2*I?6?a2y%pvIens^yfVjmdGEm$9{mGJ>r6+5K;ey1*_plbBuSeb)4pGURe&e3}J z2=-b8`OmAZKH+b!?MnsD6F8A_H|+5r<(3e};jxXFs>JjWa}Ffw2Nt=;#I%-jisd2`O3C_IzD40a(DUIge6JGu*R-2q{tDSm%Gmj61 z_$VWsD%hw)cp4$mo}&pdaq<1Fecun_W@J=*BKyk`&HDX5r}V zrpRjP@l)&7tFUo&h(6{eC*!M32{Nf!Gvn79q{xC==` zSGi4e!B@F&9u`IWhWwZ!9A9J$KwWz3-@N+u7Wq%jQen18S}+Gcbg=#W)}VP@MO4y9 zk`A`)LpO=?H+1Kdee$`S)^OkV!B7E?Gpj_V?{H+70kKG%yJ_7>#8VU50rA+&51VHr zjWbsDa|iB!6Y{sqWtet7LN+Pk2h;BPKHg3cZn7w_U&|F&D<2hhGLNI0$75)X9?fAV zA5*l;QtCNE>c1Xo6Rl0Sx6L3RxMR}yI{rAP!{!6ik&Lu3*MuMoDeEJhMd*ifv*xp< zaH8O_sc0Q;9M5vzes~{h!Aqrj*w+4K2!4e*F9sIUwrIcsesBx~*^?;Oriel>*6zxC z7b<8H%~YwXBE#B7`hy%>oR7h@VYO3k-6WX6QZU#ww$?3b9z-mDdfer^!u<)icN#YP zqNKRR`M>T_$qH4bh|*hE=f^yru4-#?<(6OVr6&jnd9cTnx8Ai1BKvE1!(ZO$ z@3o%hWfA^bxiTXt3`SNP*{NoarnJjFfPWK4c(dZ_3QyUUe*}Kx+ZtiDR#O(_6JhH* z<-1?w?s%AsmizraTW<=sQCVRUl6h*aHuxsYU`bk&>j78u3Gsh~0zM!mq@`d=+goDz z)Q#E{ak04e2`u8}wIaz!BN$QRXxGAbvH7h0b;BU2hM*|29%oN!MVO+FC(j(5hUEu%KobO~_!`a+>Op&;z9xPTB=!m6%b5YE09T~WeEp(XbgScu5qChD zJu9;)SsZp6H5I48{XUMV68n^1L|LwA|MTYhqL(_gCwra`0vais>W1s!eU6L_rmIOt zOfO2UU3K<6CPy@6opyB1<`*Lsq!i=#7`;tQ3*WJX;ndbD=jlEY2&JvGpn!exH zXWso?Qg8(HJ@Vxy$h#q$pIyK*l0$F5mQ1ZpFnKRfU7#Pb^&>oXUekl^K(D&?N9e9| z1Pz2`+|(M#dX2b;xqhi0c*LnTsZ*sS_JDt4o>cE9`Cygblsm$1QLIIn?cY{%GN)qgQ5H+&a#w|bGmMI6x%1$Vuu1Rq(Gjfp(#_RPcvYI-5eP!JD z(gf|EVCgcPU%mf^8euF1edw(eDE<3$5k%x`G{1s7^X!GVD&kd}Sf58ruy`m}=U3Lhk3cWsl- z`TsGcWo>fScTD@v^B-JYdRJ_(@M$_StvWj6xe|2f{wogM&G9oLM*X-LK5Rz!XLqdf zfOP!Ne?*@25tG$d*CV-YJ=Ayy>XX{VQ$EX_nNe2_u&|rpc5T5vm&EP8D^m`7I(NAT zcPC{CJZ}H@u)j!Je~!jLeg)E&*}#12y;Uo`)A9}#B3tUE?W7Y(I(}4^7BCg!feKXqrhhcP#D)y?B-reboxKSlZlXD9#V{$hcNPhuA{`UvI| zUdln_%SubLGH>S~%=0+@^oGI|E<#SKgKksEbDi?ScgkEXMIr2m@L82AeCB7qr~Wy^ zcSqgzeSalZ_WnEHZ$5uc*eX&z`0Sew*M}j_DQ6GdXZRX$dzMwrlUq=^udP;WbJ}h{25^QzsuJNR&@azOf=3`VynVt$iJWPKd z2K9f&kf>wewG9{h>h#}E9!g==%J`EVkGC5lC#!HUCJBO7Rq{U>b4j;8t&M>^7sX1vPY#) z6E0jo#}lv+qiw5kOPSbn^KCfIc1O73-9hxsZ=K0~Go}Ktiemh=GVV>H{jAQ~4aTFF z0;P-P7PIoC(YVRp^|s@r9}dPzOerLZA@?FLi zurA)d@7=$xXKCl%9e6Z*T(iOFxu2?r)w3x@2Uf556Z6cV{pOW&+gZKZ zgBqsL2N*Z-t&M58DSAuw36Yk{)UB<|u=RT?p-=?(+pOOel8z$fylQ=?2sTj?d_cA) z#P>!bOa!-$W+wJObC>g7Q8cvM;FgnqF>gY-4)095^_Nn4ky`AuPu>SO3>idhj;!z90 z0_U^$O9#zZ?(q=nS3%vGDq-0c4}C}f*~QYu(o|}drqf7ZA;g0mjKtoH$SyR-x=MyeeyDc;7Vr!c%e*>?+KTtu z$*)d1HJw%0TSFa1n2;M_Yx%<8_&~Yj28BqFE{S*4tW2iQPkSAFI0!kr{iyQuLYN<^ z$m6hkU>s6+Q)fMdt}C4?UZz$<7Mg%Wi6s$4;$iNutAw}tR6hd zO|2?9sWp2U zi9{vmOi>DutZ3ORYFnvAI!dg5r~WX*XA{lU5cg=-k5}haa|c_n@os%b7@m=s!6dZ(kW1faB(MpI{Gjl0}Bs zul^nQx<%tW-SGC%Q$VSe$2}dZFY+Zz|)5ZW%$ho^4`Q_vcCIs z?hzCrlOK_4Sw$K}Wk)JfAv=N_#tT|6df6|4*<~S4P0m^5%U|&1o*Ixr5cQt*wpf^r z{k&an)@OQHgPpZ{m7zBj}6sevC=2;(u;7j6jt;5~~X*>1&dbXxV+ z`0DrkcF`ps;scGXJ58X4TyGmk&=;m$cg!7-(X=wNWxew;OxYdIRTsfZfXxH##=N4+ zF?XwNz!TRe&=QNc!w2~zwBGSbPw&-ETFl??n`@2}!cA~tE^riORYg@RNy}5z+9+ee=jy@sSeoO_wjh2v$ye{rQv5(uyq%F zrW+TIU%$~+(7nqfGA4YJ)eHQz&xRG|$_|=qPkAvMCtbH9jYKKzwW7fhX0X?LmHB%2 zIkvGIh+cmTroIgnv?XT&4u9;WmmZDtW{ya{!zDp=XXhuHt$B|H-uu6=y@WZGLBF$8Q8U*z5WdiYNp z(Gx3%UeZnZ{+!N<@(J%lvfQvI31Pp!Ho@CSvy1+RM}Xyn%UD-5GaCR{IEb7D`-fBT z;U~U~6dH^`6NI0THPK|G7Gfm|#5{Ocbx?#jS(k+5G|{=X!h%tMnBJ^L-4p3}Glz36 z*?ebJ*Gg|26#kSFD=it~61bX}Dt!ADG5ZwCJNy3c_wcOEPVS})ThcmiUbi{?cQikZ zzw`n*{5iM%KpYyilBk*Z&fV?xsq&XVC{&?vd#Ar2qr1tHab16%6N<-Yo$lS_+# zxn@KF#mVokrEo-wsT^({YPbl%@ytaJ`g9eC!;Z@+r)`j8OM1>oHhQY)!Xy`%mZ)Jy zw?3&I{gHk9;BB%PBhzRZ5`N(5vCM~B z{fg^r^GW2M3cslYALJLG<)6}2=D#H2qzM&@Q)U$u6@*Nu+Ef=Wh%kiSBFi!LcE{TT zzq895IsC2m?6s-_yb^1-?El&x*D4lEQ52+Znq$+6hWwcKt}=fQ)m z<@;pqq0+NG+;H-n63XejKv})30^bYZrq!zK1j2_Pi;cDSZ5|w%L}R9K_m5S$@7|B` z&u@rQ!bvmC2usK1Iensc&l&u6qjiUJK)EK_r;&eCbH;V!t7qbAunygvnvMrr}W}+khwQpnj$AP+~p#8dZ zD{%&`P29Z5(r@c@W-98>^cjZhLay~uH`M*R=xI;YMRDEyU3izDg!Q^GzP|xn9+oAT zc2hvV{~YrR(1ve4;rI!!{%WgTO2PL5mk*{m6}^ofvW(a! zpL+ag_q^4CNhj>QjcfqgxV7O#Za$EUO~#;a^SIj@G~0`O#!%FcDPI#DQGCtH)a|1# z`p`Ae@Slly26xwgh%kdEAD1JuB9&H+(WBa$)3rQ9#_^VV!Mn^GtJjpZUP#QyAG3Gc z0dFm#TbkJZo!uaDKvLb>_Vmf7;=b+FvE-5~Ak7K9ofbkW1qZ;dwkX$l698jwWpx-+ zQ@otHHDLXG-cvxPObYi-1!ss`zsRVvKxGTX#oe%Z#-z|4`pcc2u;Xn=^@F>GHU_YK zIxE*YAKItRDrb*(Y8c&P!L~AyT%pSqGHZ{yw>tj}tL(zr8waGAxo@jcTgJ%&7ugoA z8wO#kZ7z_v=Vme*KX{&53zAH@zAbsE0=I$sR$m&mLQqB7Va(t+KQNF-fU4k#bF;|L ziZ4UL3f-$0Hdekiq=Ni6p{2jLm$gejrtQgN0|Pzzna17!q=K%BYvi~>cgJWc<}*C! zR`T&@@J}ZnL?_|I@OhaebO(ZTdczHR{--#LB_5HF|HrfX{G@?6{hF`YEp}%fo25T~ z%H{XkBk%q-W)L{w8uf-QsKWkL`x)Z6tHDuskR%@$b&A-6_*T%eKBb)mk~&P}tPcY0 zr6M{~BM#gzXrfPJW)f@wuhdH!wL7;zF4-@h2aI~-wl|ERfBHJ;lD=P_hf@o+JWkA4 zZ18|F_Q*HD@?h*=eEg^xDi48YU+(;9UeNu$9eb(dTBdvbvfMH`!K#slIerj=gr06j_S}O*_z2+f(Z7>&B1;I z27D1j27zBw(|mb1QE0~+-BMB`<0;tp==hDD)A}o->(*?8doQG`Ysc=UUd<+V_}Xu| zaj)p?yy~CV{|ikWgkEEd&7+}zWZacN|M@$oa<5}PeJI-1&HfEL_jG$P)0o@@YpOpD zlRT5+yO(~4#YMRd4vv*!_Sj<&W{EnUm&C)++2G>2%;IC#q5C`sG%Kn!Bio%jKQur4 z&G>yMh!OF!VSd}$fgBgI$fe)b4Em_xmEhcIz`rWU5fQgAgD~>*n_#q~$Elev2G_6s zbnUaEdEp$_9QIk-3nQi=^oz|yOGl*ZdH>-WnX~0D?E`jh7iBcRZgz*-`GnIl( zrAWQqhR~likfmLlE_x4c2L|uRfmKGf-~GKig#&roNre^wEM-#s+^QPg_Jz;QBp`mY zo0%vF{MUce;vt-4cZXiQeG6%^ejsGNe?~d3?GHkipUy5OO(lJEcOD_QyWf~JqL*2C zkyw7d`78Zv1tekhvYm`C<(#?hE=7YX7OF`8eHm+oa6rM-GxeB#|<>PpCY^t z+zfAB<4WNtqCvaEESVJBSA?R|`+k)WODH)pfE6NgjC>2ZJg&eUfb%WsJ6xWeGO z2k|>5BnjUsJdMY75$t<2#a#vOI+>Tr*^sNokWxT?J99Eby|H1tJB_iH-{;jCu3EqX zR^H>pPb2`#n{^SeNfDS5`(7~=srt8ugnxbsgcdLY5H=yUm0lMZ9c}R33QhSQO+yme zlrMfrY&e{dTMw2Ntp(Oiv==)OH&<-RVZXg)={uW z4o()5MW#!+!Hk$L*rnPkbSh$|AFYaymH?&~c+NLkKe)J0qPcs%OFR%ucRGEz$%lZuR#Aux%TsFTFS%agB-l&zBVWj zdHV1(l#4OzHKDqeCt`Ef#V94lh4snBsJI|HQ+?ocRvD=O!*HfKTVk{Ry7fm(ao8mO z&cNN2+WP4|Vq0fT+gYlGytQ^%tEHH11*PzQ+jh2FRNzPJa{(Rhn^|{@hnQhA;%yW~ zjGx3jn_ps`rc$t!lhf4M6d)_0N`Ikx7(rv()~%64B9bVE)3*QeH-h2_b^yF`P``Nm z8M}K3MjVn81TnwXjLEAcLfqnU0T#;Og9e4q&#Gr7rs|{j#lR;A_1RV9j$6zS_7}`z zmKS-{yfBN>&;Gsan0A(6I(wz=z(bqMb_#8I9n6bOf_iJNhgr>wH}h5Z-(`FeA0T z_kmXhJg3L9Nl?86`Oh!rgaO~{_|6kCa*Y%pv2iw3Yk?D;$2aFG> zK(mO-a-}yP&L1YDHsd^7?*RfwfYos#FPOhlsSyby*#}a9#uxTlW`lKi2S+aTCOzh^OM7uY87X=S8903{9F?H&?O|XEfm(L0-9+N}yet9QjrY z2GTiEpzG)&{SC#s#im@@bfU|GT*j4bDB|#5{hvdBNK*ro5^!Tf^46p%RiUc!cezPQA(49jv8Yy})OTylp~RQg_p!o>hY?Y6 zI?N*X(qx#jqReEipTW~X(}s)dPiCPBfGpr#6V|KJ^yu1e>FvZ>UVzxXp%U_bBXnb7 z<9!KKFi|Po&_XRJ@YrI;Y&heJ`W6ue5vWOamkA7#sC%Hxyh#SNT{EFYu6{gX81ggo zb+0`Vjgn;U*Nxte{nEjyaKQH$-1Q;N{80z#D3P99zfxOrQM zd)5^83QEm)M{Fkm{ff6x_K)uDMk(>WZ80 zN_80}e9M2B=)@ZP0$9ywL;cl&mNmv>87nu zl?uSVbq42AW7l_|n4BGZnK)#MNWnK_+cD1q3z8g|s4#$MhEjIDVT7LCaL`*&N5k7} ztDE?%GjHR3qC2*eN&M^N?gf0{X^Ii^I$;K2JzP^*6k^Y3{I_Ew-gx8g*!HnS)Huy= zvjDH(uhZOrpN;0`3T+50jI<62$5o1j{41(j1?vsb=WWJp41j{J!~T5RXnWW8wkjYL zfSvP0_g?!_hg4WOmy6E}ss_(kK#4f0x&Mj~@rKbf+EhQ|dvYd>dD3TcZ;e41Q%lz? z5A^i!0vCJgnCW#?4QlSB_f-}PFE%<{`epV&J3ZI=T$nCqZBF}?4t`KI`8>XdaxGWw z6XhuX#s{_FWc_qXC}Y)}Hl#1g~{gx^bhO)ml?Gs7im^nnH^z!SJjHm$GGR9wqG~ z<~ndQHCa(q_y}k1$>5U)6b%%ucE#@U4x5g8`E21Oc5>D5PV1s*sDsGTvvTME=}jZh4f^H`a>;io-T9jGsDvWhM(Z0b&~nRO!NlD>3-O&}A(BS3N5W^h(RbzM7$`AC zw70>z(!E{d+#aa|Mf|B<@q43_#?y3cfP9A zsGogmKGXDKop(LpJ}&Wtou9CQp5u-`ScRIM5BpYZIRp4iktXWe?Upp4?gdqG)`va7 z6ggZqb=Cc-d1sNWTQy`^eTciOaMXVU!0rs_gWUt<=JUtuU$vF5AEEf97_i8emd6)9+X>xHmz6}TnY^)+t_Y5iM@ zD^_DZ8Lnk#d*rofOhs*!n()kbXM8&fTKDv|Zl5*ymSS4^>qGpWkm<}_%r#BkUR@MG zl_;bcFr@9ZHOE`;{%Dqdha@}4I>(gHVBni=7rH1|4>4ch@6b8EGgZecKyCDX9a~m8 z1=WKTo)w(a0qteOx5#DeC`u}L-`sYNEj`aevmCY$7G)$`;UOV92PL+LaoZb2o~pxq z0w5eKmV)$4_CEfKwL`CCw2#MjSxp3I7$1)$D@9WhN!vxA3ilJV_1$HoMtopf%+#r% zgLj=QUdYL}#n86jvuMu(rNNk=1wP;MhJMBy497^3l`YQj0Ys8di;5_&H|XuP6wOfO zjnQsVZqcu~(lvj?`>88Th3}bXc$ruhnV%E!>uz3BL(we4BFR%Oh{%dd{ZZ{8$5Jtn zNJSJ$jk2lf^75MRlrDQF3+*aQ5zsunU*N*A^CNYf8?QoP8#V8>Ph5mY<9)uNTZal~ zHCk~tLs6?@_e_9C<$}oUomxSe-#?vDmE;&z^pNBAA6L3>N_l@nTNzK@m@x?(2JdGANWmv&ud zYh?S%pUp&3loXZx(|y#k(C66UHY9QERyD$A_-C31h1 zV=7|#Yro)nDKF;qKI1JH5CE18ft{4}oB&D0@GpjE^X9^(+afnwCht!n zNFpa*_SJ4DPsV~D?wFkOI)Us(X#9uli7lZIG$?*6YI`T}M+SPHkZ4ns=Q)n6!2soN z?v$F93yzrE3Ax&>xbBo$7x5wM$TAOX@8?66n|436sAZSL!sTmHI2v)=ZwU~8WnQ<| zVbM2r=r=8g|3}kVzcu;3Z=4VYA|VDMF**bRK|xwV5Q(9vh{RO-O?PesK|+w0iNru! zknY$hX=xeV-3&HZu`iz=zW>2<9MADw&v{?>>pV}h!=pXe051V(dz=s84P?N`QU)8D z=Dn;$ZuTluhCJ~^8Io8>r24s0&HM;ZR>z;Z^WL&Pux4A~R7pKILw$T`z?0@dfA~-7 z)I5Wk8W$UCY9GIhW8*fc(4M`Z{^sDg^v#s6#C0>Z5fEVy|Ad_KuaeEu?kNDf(WDWi znyJ>VA{@0z=SKLnMJwt3(|%fTM48bJ>}^qtWJ0f?pe$HI3o#UU8KhZL2$4^}U++0peaT3LT8AXmq?NJeKxm87 zgI|7!?G(GM`lGMOF((*h)D04R} zpn4NjQ6mg8IW8QSZ<1Euad$^{HN8Dl?SpaDGb8A~M_tMQDlqrP-SaAo6B0W!-x~iP z(wOIFQm-8R2+NOD`y2LQ*~iDKzNrx*oAw`XJW}*$eB=xjkSM6OGwsygJ9~V6jDrsS zpVhg}AbhBXwKC4@)Z*vWnJb>qFKZ zjW@qo5e4<1HEZq*p7L)57&0oEexA6Yv(}~9{W4-#cJ|v*-;unp`Lidmu=6yL&WIbM zort;u2%QK#aWhh}f=6-dZA|cH!E1UPp)EG@@zlfe`I`HASrhO_q1dN?khiG_*+L)l zu+@kl{ORNf$cdoiVRfFoGg3o4%6_(k!vChr$aWbW{BF01dNvRzw? zU1-1VqJ`UgP@2kXRatlBtbq`6=dQT?K7=+%Olzp}2`|iM+T%__!CrCtCs9w=<3CD; z@kh45xCkBNmpDvaCOqbg0X6x#;Qn?@_ZIbef?|BlIQ7)qepxHG1H z$1mh9W=k)GRlQPLcL6WOxJBpTWS{U;=wb^lJu4t@=@PT!9;1 zjveK{Iwuha;7n!DWoL`voav3z*JZn><{Hr8Ve)uno*Wrqq3dB30w%w>zZyb}4j5h_ zYy`)h#2M~zoYNp&!qlu%R>~b7`|-~J&L-rVaFEc2&Mwy#y8S2I$h|oR(|46am7Pw* zapEwmT!DBVud-(PnWU=wut>tjkBG*4bk5cRYx3%D^{|fay4INTVjT1z@R}s}>dvr! z*g0M6$ny_LSpPQ`YfYxtGc!v#HU@Zqo*i#XmrCFz>_?Pxq&Ixyib4qOV_mv-BBqar|crmT=LVd2;Zf;8^=|(G4GD{vJ6nm$iJFE><*; zTO5byE;{@Hxhx{2-uU^TfRlCbQA=Boe}3yKNq1$gz%9 zPvq(x{;S%eBKPcdi;B{+>$mq-d;LfS!O7c!Lr$rq0fM$qx;1wj;MeKKjWR==_n9(> z6AqhHy;;7W-2QlJ^QsMy@Doyi4#B<3a)=!!FY z!U2>gYgagK9&z(~B)5+0-`dBoM2}Oisc#V6XBghL(m zN3NN)-BjeP1k9btpscZz-VrdT{?v*J-^gKYfplqs7dxOLx#}M3X3_)(&fFY-=dwpq zJvvercw7s~vNuj8P;c&Kdd>f#fAyDe8aXhS+$TXO6_tMh-7GV{(fh^4%ayOlU`y$9 z@F!x$fuL~46H`vQ>bOVo4Oc8!iJhNPM4=*3$#IS=eO6qFw$6i2U25GMKH=x&yYj@) zC%QeRQvorn)Yumnt|yWp_n`)%%T;E^s_FM0r4&Vb9u2W6)Q90Oz-R`wV2pA9lG!U* zX~g0i&WXQ4{N2nM5HwN|{o!{IjrVzrGp-O9CQSRRO8N!}DelJEa!2~;J{b_mlR-#` zoQL)K{~#((bwaN1YA&B}5^| zSZSvut%FIA(c}GQdCK3_c@du{GUNAyF5A>0x2@CvVvW}p@MsD_sWH;2;h1h`+Bay{ z!l@qo-m@H^0t(0iXJ7cmT+)u}j zVc7EyQ#&aX(*nAxe7Og?9up5H&eWfsC#zBZm+Q_|4{}~?Bc9X!XO#`zFNtGy>Bu}j zrCj=a+{j^WY76ask+7ZP+W)z7P-&rQ=wkoq%c>lh zJP^+cwm)?9ADCT)wyXnS?wNE3Ym(d+4KisU8e4|UbH6n5od&+?lV9-<8G1Wc!qwe6 zIyHFNn?|%IKeKy!jjCYXuj%=@)b7*-(XMp#GXNO}t+A@1*lqqc)YTS12Ktg8*v0Vg0on<{MqpylpM)2^&9e zz07LzGYZh$KjG#)eHqU)eko9l`RwQQ#-%rwH_%*53mOrx;v*9t~-p^+YXs8 za;K|PegV^+ZX=`KyUoG(=eh*Y9G}@Y4V4tK=R=-xr!&~DBpycm6DF>|uhba($Jki> z6hsmFPqTmDPPaEAoIpj;v$rmn=3Z+^hZoDFOU!p^t9R&6{(bFT6@C163?>jPxeW@h zPmD$)h72j7YR1YnVV{lRkE$Bqz0O_NI?qazjh_~4xzy>Sa4UT94UCJ zoxaWxIP}@M;D{|ziCuU8h~GA`o~w}Gr`B!CEt^~vD5wkU*mIo_8bU5J$=wM%5JK2~ zFy9yS{Lt;ECCKlg|I{|xX;yLtu<~Ef)%BS1TH#V=wpLkBh{unn4+d{%-|+tfWSHt&ib(&6lV@K6}-Oq(IdW}9-JSl4ECa|}v;XLa*vrFU9at6$7z zH$lC=4=w0udi5!2R=Q`z*M)1HWY%J%9L;(D{i2&m?)2|A(@gtrnR*oFM?M%Kov=xF zYTg$F^FF#U3y&Z-eH=6Awat&m3rbn7eYn=eBRXr+J1MPhWLHok>QV(NP|cu=&dQHBDK31 z$o}K27sfCtvPmGE+pL)yDC>&nzv8_xj6$kpd{jEb*gJE=y@obJ=~v0efcVwX3NME# zxYl@i(0z-wWg3EUY#D1`U#tSb;A#|^(AD#jx=a`1PEP~m zs6G1@-;=v34-pA`|D}YtOh2ytja}#?1S@qG!)UwyKmv9Eq)Q2Und)>Gi6PsZVx`rE zE>s8qFq)y?hj|sDHR6;Ddqif!fZ`DMb4<gq@R%hd$w z6K3$U&qHV8m{RMiOs_|PaFSTzeusy^M~s{`UypFpOTPX0+-NbPRJQBBbe}%Yto-t{ zkvo3S={3;d1KTrR$mb05G)axraXUDa63A@6cSo;f6LQXhufyJ>1;31BPqT%U*Ykgz zWSURWQfA9?LWK8j8BBg-gVi24p8qUN<>lF9luCEmC&b*w|CIQ*=0dh+K zE&G$z%%({`-nBnJGp*C#alvG`hzLgoERa6BoH2ZGF!1x{TQ`f1>!_GtTh=-G* z=hMCp2`vc%=90%T6m{GMz1{47(=M%BPv!7gWai^5y=;Boqd$q|jXx9Gc}ROTRGU9m z``sfgQTA7I0zAwHxjD&>|5D?1o&~=eN)e}HeDN@anmPP>xY!U}>2Fb(hK6=XRKa7G z+X+8CR?g2e&Vm~%RVj;<1r%hmdXcDFM|;_$0BhZyN7tUsIF+~JW`JlU4x(z$(;jQ0 z?zoW_j8lCQgvn?{=zD^q%4G`N#quGl6Y5^Pf%2yYV|>t%T`=oWq|u;BdK9RL;`VMe z0y*$#ZOSOHN7(tt>Cp0V%+BMYllzVXi_x<_j87-jx^kGEP0A|APvsnD+{YY;<#-HW z)UlPI?o`sh*ti&pxMS*-tP7oVKAN8{4uG9X;vN3zBW*SE_rW|L3r)35HY<$C!&WZ? z=PR}Gk+>PVuaAs39ro`0A}3Tw1?>&adYQ)&s~weScxky`)Bfz^T+ z(CzEW0BRIg%TH(tz8T=U59I*Lc9!-zk-N!T!*xIGcgvH zX7QC5`!f$cNKZvB?p;-aTCL%F+$|#a0M%d_*Tb;qjI%lx(j!23^(6v@yFOd_t?V7S z+i)CPqYRfsq9*pXv2?|dFhQHIlO^(!InrA<)zNp(tZQ`gzl>O ze0m4^Cu?}Qc>M`=B#U6-?%&sOWTsE(2a)MRZjBFl6z5T9>ssfjPS&T{gK>~GP)OWq zVn1JCpJ(ga@KITulIQ0&1?G{+CO2L3OI}FFgYOvq#)CVzHP!ot)d^4L1mO?zeA;=f zM0t5M0vcIf=yq$M{|lO9e&M&$V0XVGKIG%ZLE@SIPz-9H27I&EmZI4uC!V}1qK0ep zXBgceOR$G!SaTx2^p2#8?X~Yt>ZfaaN#gT~^dUoI@z|kti0`p`$(@4?f@c;SdMt#fL zZ)k}Xws@`c@)ASs?3ohldQ)Uf+JM)7mIl$%MxgUSr<#%3RM@FiBs@5{m>VU@UalTC zbFXS7tn#xzrd^kF>$mz&*!d$T&U2A}^x~{5cdwf7|5bZFEAYXwPl$)eHiIfpL}U1Z zH8aH{6O;ttsJo5CmqqAZa^Qw&}NzxN@@n#sZmirDXkEqqB2%y^L zKl@;Mil!gIrsr%iWABN0!Du0;v~Q9+-Zl1QJ&ZK?I3te zwSrV0NBQp>Z8&ZQfKqVVK1F!I2Yu%VSnExZOL8CFPwJa9Y;7_c@cGm~jfob#zb{AZ z$s2zo`ay1%CS!Z;Da*;aINbZefQAUh8QjBk^0V+TnP4P-wy{2gpC*J5dN1?oB?p=e zc=+CDuBmG9QX_m`Dm)tuvQb3PnOwhJh&3Lj_Rl3C0aNuN)Lk6?}R~sfVj$Daign zA`0^ezIZ;6wS#qOamRDPj#c4662Jnri%F;Kmp76y3Ljxt7Dzd$ApEMj_a!+DzZiy* zMa56n2jVFstX3Dhur93NkS~&y3_m2Fz;?&1m%x}3DU{2^;fr$;_$Y25{bGj|3|+JL zJQ-WZNFa|lP2oYL>Zdw{pkU9IbxfReP|x~+x@90bd0vhxzP0llH0h(((-tDt*!CUp ze4}Gah+}v2)0GM;MGgh_<75kl#wVEkY;BeAm_>&AeyYjC368`BLS_h}$*7qRU@)DW zP|}jz#lxdnc&-2OKr-5Cpy_F$%BuZ>+`dr1EwvuG5g}hIWuGPP$L<&s+@I}|FYY(< z-v+{QL_BggZL=%w@U~$lpZqMOQGbEa`y*{cdCGJ0Yh}mf^&=s4vJCCV;PcJEFTx1c z#{86lh$rG_g(|-o{{{_Ett~Irh8v79%NAcp*SK2cT~>QO+p2h5R)Z;4r|kb_>kna9 zz`D&f+0ix@v z-Zm-XAShWB?YATNbfe7lT>emuX+l8&ejzvt$F3twS-`Lt%)eD?UHqRn7D(>M&T9SK za}^0^Wpgi=`t8X!Yoz- z&ak?ozP&Z9BMUpg2!dLSg8%jVhR+op6!;t*|DEQYto1e5=A3Ai{-o*Weor}soX>dR zsKClGr^Ik=AEV`Z8!PNK7F<02H{1APp4yYsEz|41*I4W-lb<&(^#*h%m1B;bE5cc% z`q+T@Px1ChqBnA{8~!c(LVUnf8op`O%u8DO!J(h*&-mDp!a18leWXhih1>=%NH4ejXm_Eac2x-^jaXmGX0jp0InRKF>$a>*bYiNt{1c)zgkF394KPUQ&Fm zw%2CJLXN#U+HVy;?2?+bvIE{A^_-D!BEx5UOjQCZw9xdG{HK-1sDjLMA&zl7bCgDZ zdwiQD%18LxFmC$D7_MC(Ytw2%KNY}X7H>YK^f{7k3yt094`NS15R(`E$M1N7`)^1B zs2bE2mNr^FOhmC6N|U(b^<)b{LxW6$ZN}O@x?EFL`!-E=Eb{^DJ@DGdBs&?QHZ+ic zPh$MJI1UePtk|4(Uz-P=S=?FS&CC#0G7X2t{bBPF zO9C{XRd{!wlh?PmCX^zjCH)9DCYo3SCT>{DR;UnZi}g!7@95s4WBs6!m|S zQomK~Hru4IX_A{GK2@Nbx;d6LE<;N!Oz6G%$=N4982zc7k0*--bA?j{eq^?3uiyVQ zLK2@f>UY;YQlJfTj!b%^I+*T+sa<&Ky#XzANtECR6I}(M{PljXrpS;Z+S4Lfw`sH5 z`^<_c|1pjAr`@>BF6*!jx#6l9tcD+?7|ZFCC^ zbDfI{$2|y)i{}y4THEJ#Pw+~+GSv9S^FUx&=m`lI#uXsO!ZY^wfLk(lx(we7{6!IB zrmQ|y2K*O{KVb6TVCnuCU0H}VxVvgF5XBt@1ZxK;=9K`~)mNJ6`3GAefS+H3c+!H4 zf8hPp>>DGp^2ilEHGj%r4m7IVyKZ0SPj9fiBN#9v!o^OT$A?B4f$kYNX~n$<%EyJ} zwX8zY;luO%D{yA{^{n$aX8yez;@f*F08<{p~q?vtslF&dgH#LiM|*uQA82q z`A3U!KgAHzN^^?*w2BY`YIus^{QzjOj0pd7lGuKak+@*Ll? z%`YAmW+a_g%KBM%C2Mm+EnVc2@?qIAO*Y|;lxv3eUDY;kDr^&^7#0`)*e?(<+y(DE=Kvrhb?`>5y;y ztRaOWlC!CJK|RJT`diSW4au~YxOP32)-cF0tvc8z#Lg;O)~NB5)5-I0Ed?wSzbE^y zJAohY=UER*Wh4?c>Kjt?vVRn@J5b4Lop{B;sr$$% zzoz%C`c(T`0NC{Cp8XCZaJVRTo6Nt{uh0i=%h2iZgyt?{g4@sA;%7+}dOw>k7kf|4 z;(aXZqHwsj=C0P^SALV8{J4jl;pY-wq(1^tVRKvLf{C*xJO|`wOgN3D{yO`k@^1|^ z;QaWCh_oQ4Sf5fjiJvP+`+@k!^3iNkiG}vK=%uZe_dxk;7crNqtWUuMCmy1L+f7U6 zy&Myd*+)%2wg?Nc?$;rtHEWn$7P0*TJ^p+BkQ3>h+N+YMSrpCl*c|PY)%)o2@_rzn z=`U$|0#9I*?+83?k^JIj7a;_ge-^o|x2uxc!v1&@wEKx=-z)dpfjGrZtuwzQ1%__Q zSLx8Z#H)rAV;t-W|G^CEy>Iq*;>z?vGsAYviT~BJ1=eR4k7w8UMLjHn2$~f!RV8e{ zRVE^W#@TE;oic${8doM47>5a(LnwCQ9iTZmMv(?s?>1t(6^To*qsPN_YS{`s}U)ETMAlN3pu z9!h`|tgl0dd-!q8k0tk6EyJc;N>)(rSLwEGwh!P@Cbg}BNLcxF|9OhQLFyrB@{kK3*`(S$vm0mhA8 z^uYkVzp~k?oQj@`m)itJQ5gf>XF`Kq^kAx+#w*8{rUw4~Z?THf$aAGiT-|+<|AyIQ zC3W##xiK!KRx2-D6!4;dTb5FMBzTl;d(Vn$6a;nyXI#g+em~S&dr^kXl>c!>OqYlV zpmH3)uva#iyLTouCdvsytVoWjoU_cYetj_ep3uRy41R?KeLj;5ktVHxYs#eHK%y?t z!qhD!Uai3(zI9}?+$xZaSs+!Yr0qDvuftNCIj9J%RAj29+$}sVmaxkVAu6`nl#A0qC zR=qa-S~peUelW^ec{3e{q@>bYho<+`QUVO0nZ(``7;Teu#N16ez@i4}>k?sfv7Uqa z{w3G2Cb}{l+DD$M>y1Y*6$YrJ#tN*qI%%#3bZKp9l(EX1NSEc9W7^i}daGHa7Mua& zDLKv$um~Beph1;>85X=+FqcGN{HNLy6%;^OH)d#&rEmAcl>=ek)xy z3!uQV7F9exC|c7e8Mgb&aqig(sJ1!aWhp6t4ij=OYPUd`(Kv*~_2A`@`3ZQOqiMNf zXIgzY^RYtr69xUzp!v?j5BGRO0&==_BHkw_{iPoJoPIMLExM0xx9gT;l_HPVJM&WU zhBsI8B5b^3gPju$Pjgh(b7}L2oaa=cK*yhTt+uH54wl6sAM2>qXbl&S{sPjKK#^}1 zifOpGNont*oSwXxqMi>}?knFN1!r5cz80D{r18;-;EJjfb#!IJ*yaMgc>%@FhB)qf^R8*2m;Gyr!NU#l|~T9L<5e2C+ML{4zRrzOHt-=Et_*!I{lnC z!q+1=y=uEb}#>^8ph!%W^{NUL><5LOxejnf@A&?>fh`mEo0XaMX9nym}C@ zC|-w?_0i+Wwh~Yh8Y)ci{8Y#3TjzRnaB67-_&y^>uc@;1PEu()SBF>Z)(6B$@B?j6 zv!q6_`CnTi!;9rzCWUh?2%`e#cFdXfw1EFi)PU=|a;K31{yd|?hPv6Sp98T}+I!Im zqvoT{*O#G|%ggKY?qLPQ&(0bP$=Xx(^9{GRI#tOL@bDIyoAEysxDF^*fc1IqaSkK1 zr5A)RaxBx_SsQFLknO(njoe9^Pk|%#ZvO!IsfAju<%vuzr!{fz?Km*UTz2@;E!zfY z=%K-;`(3c3(9M}J=s=7p(rEDQM2&F|s`rTRo^^2>SjAm1n7Tc*tp1NLo3-Q~!{OAW!>FHK5I#vUjx1&)M&5y$JQvp?F@R7cmk5+juc@kJhqqw;UJT5A2xA~T#`j0n83fC#Fv zy_njFb1SXOvqD+R{>w4i88xB@{6qaL_LL z5;#d+dSkmeD3&3>|B1P2a9N`p@$178;ATXy5sg>I2kuWBkJq^WJmND%#wql%GIr<1 zftF7yLhrH39vJ`O(QP~jMg0nldh0&@s0Uk@Z4}4+o#EZi>x$KKkCa*;ez$`{%hN|Y z#~)Kd3cePx;%k^jc=JBQDBhk`FR;8*uD`4ghxpH@QHlUwQtI+H3%8~U0Ms%gm;8Mo zj9ESq6nI#M%?B;X4bHP&NF~feBiNaaI>)shU!I{mk-P`B!v@ZaZwb_^43+COoR|9* z^&H?z$xrBQo4|gXP|6yGqTUWE`O&?{|bI; zF$WdxVWxf%=rCW;EZ|U<`0R9=A*c%Zr%<5?D9`&z0k%V|E9J>;fQ z)>pF>?^Lx`aHtKkzOLT~xK3x4?r$RxWvoV=ie>EQa7;ZxT12dQU~LX5<@+xVTx#Rq`QT@kc&eu`e> zPoL}zHqSxPA~_WtkN?Om0iYAV{}pGyNmJ^;nPK7af92Nw_rmbQ@e+Iq@)-PW;{xn^ z^{>a{HZvCNkhte~P@zRPpR-C2{|rNB1tQz%8*rXM+=Tp=NHQQ%X_|%{E}xD3ZUsyU z{N(p3`>V$=@=uitdvNmp`}C^g^<1@Vr;@G72Qcc?SGhT4k23`Uty<-pC*MjyQd`P6 zvoL;UiYoClP%)mRH99pVj19BKW(QSmKDnZwYv z%KbslV8p#m7vjPE`-gH+}4q$~15p+}(A#_-N$9{R0~Et7hN0@nRg(9)7gA zGhU4{26w||Vmz^s<(4mpS1;FEIWG0z>^Rvx3JnN;lwWSoyzg^<`V9!xn#o3{SBWnM zQjLjo@DxcaF=heoNJsWJXF9;m_Y2BBTw1>4ubg!!#*+wg-_apE-jaH}Gf7H#6{?~E z#~_#D_z|>CXuY~nKJD5&wb2KWvJuzMN8v=<;A=6!l_DB1E0{q-gDrue4%`3Y$9-Q= zKFdjyC}{(+Z(UblF;^Tu&I&oBD{cQ{Viu#CZa-9*cFvLzNjnM6pyT6eM%4N3KcAaU zH32zH0<0FWgC5Vs^x6Brdlp#i=MFtVy%@UBS$%DMsreiF!R8gmoAHO$`@Cg6E4%-eE)^-^dPQ54Jp@H}+)@BQY*p8WH>s1j<-a@ccm`~1K@MHMNd42%hHT=dIs5ChaCgTz?>A!BAzG>TUJ0p zsfd_Slm~tYOwpBsrS6I%aTxoH{(39q%8RNC)aCw+3rY-jDQiepkUk@gDF5VVF3Pc`L>!r{^0QZOp0<0UR5HHQ9r?}0JS>-lA*ND3`)^?F8w298e6#I-c@nzzzQmG26P72zwc-F-JFGA;Ul)>@Pyi@xn{<=;F;? z8CUiesrMEkny!-_f(=SQi&@Qm*zD8 zLf5U|e~*Bgwu34rL$L_k_vrh|jysn*=Z|bPEVLdzIf+EfK3w*(mhI9Km&NK*18c_Z zK9)hguiJ75OAwxu6xy`PBBOd0z%yDZQ<&^M5pJ8iRX0x6HKQVzTz%USLFXg+>2;0v zt08}{D|}PU?E4hATUE#W!HMNgMa~56THox~o8B6BD>=pB0dwEV zIA?(;UG1Ip4A}H5xtOJrL1P8|-sHzS<9~lYJ)OrV0R9F}f|GP*16>c=BrszS}ty?Ze@p`j*6i86jtZk3=eYG;GdvoCDw$dbuF z6EV9H%~Mc*nNpx#F*@2ek1AF9-rYh_hG!d6wPyDm~1N9}A}H6Oa# zeX6H1J8HGI`~69vCZsabKyzy(Fam`7b?3r7Ae+!5pfT;$f`Cw;TQjcI@l~;z{c8it-6oFV_uehxWLTkUEr)08~ICJK14go zZ?*=u)`8Ueg!d~974>``Q{KW9jjS_`a_Wt#Gk4%X>`n^9dF)Mj?6_{uv0~U0Y;7ex zz8buq32yv;q1Dk6fqFeydnM{HP{{Y6yf#ikb7KG&ZWH?M&6xSZ7m3AwP}=zqHSqJm zp9kl6m+m5b_FitLR@&?ZUg?eGxZ}rU-yEH$+n7Sl`%TwaU0z}OjxcK^n}1^8`R<*; zyUFfJw(l0gcddJozj)VP?xg%ZwrfuA@E>XDusy_GV$Q< ze=tyn^>yvVojV%y>@Ptqa!)4Vn7WKa4#h#oyqJRPAPZMJlm=*nrO2z@0DM-fftiu7 zV{O{zuwa5%W76&G#B(0b-Wd$$9tpVbdl3KM%laXv(X$(uyf~~c{vb6*m8Z}=k`3$2 z)AknBD*m$BPgTd#GkJ}`h8C`hEGM*a?I1dhdfyqUF0VdqR6nZbQGO%EBhug!l&G#S z)pSuGrG-49f=!jFF$%{iDHya9qKc_pc-M(j9WDW@-ve^oT1zRK+7>)3v-Y6-(1q`$q z(LnbG;`xZ|sVXlIBoOD{=&zezPejXG)P=s>^C@G#e1lt$6EHxfqRi92YP{wGV)dms zi92q)oovy=Q)Yd|QwM*9w|HU3Px_*ge>7PTc8~V?yUnVUS)f1}sn&LEc7ZSWKG#LK zHrfbKDFVIE2{xRSv&R9%qD5(&3>|Lls_yf*MAm$*6V@(sNfuCc%>nF3XU%Rd(J_9l z20b@Cci}d)~b8mKbkvJ&xg96Wnqdy5Jiaz;=T2Y~oAO8hET3ON} zzFXn;)a(57UQFFd#{;QSLBng$AYk>VxHDiH7qHUaG!6{ z0|_um9pdqe0iy;~z%AVlB>oa zG{3KT8NA?FeP`6~eJ$6(CW)Ruy`j5PDLY8p{PSll5A0rwj*Zr?&Iyzq zKL~cMldu-Vb;jMJldf|D_xUg<`_HsqPzy_A_L#7nY>s%-UT_+tb9ujoW7nCk!)U0} z`YNn<5?nZB;k6YHEn!*LYHVg3kymej`c?h5>g$HU~tX#A4&)%Vj64@Mr!tG`!7QL9&ou19y zf@*e855+U`JBNs2N9|JzW6SWJ43^(41J@UP;6lS?t1E!(jffy3JbA?W*o2qVI|q6H z&C)WtrwOg2FB<$W*myu+bs;5iM2gLYUTH|gjd6j^@#wL=_F>PPup=Xt`nC`g)cRAXRAXEVdStO)4a-Ubzua5$_TWPEq*K6UBCTy{Yhe zm2?ui?xZyh>q4MG8p84qm0;T^L$;W7DSR2#$JVQ(^rWL`JaJ98K;8St?(3Psv#ZTK zsabi89cyV7+*{!-8_B2T=IgXROAFroKpSY8+qPlL(M-!&xQ7XF`?j<0juG!^T1y_N zxkQjZIR009mBHDM+D7v2o9&uukr_Dn-_fWzed#kTCiyYx|E9` zDfRO+FY*{sN}Vt&-5h*kip(7#MjrJqHjy?_XF<~H-C*rzl>q#G%Iu}mT~`snZ){2f z$$-V6fML)EVe?Xxj)PCjt)Q!v(_*KYuAcvCU_VOq0GI$kdmQXupce!2V5Hnh?=S$Q z0u4AWzc^agg^Hko!IbqA*uU~tQVA-7ZiqSf$PIk4f*_9$EEZoJwgjKJkzd25T|3$a z)C2Gf>XdpZ;1WR}`ft4+GOuhhuF$PcLaGPiEf*;{uKz5d_;M7f3`Vvj56!EpHM>*j zc7~~-Bnl4IOxlHE)-53Tb=Hgg!-n8hFZB8F(^C$OO^zbVkcLq`v9}CWAvWzYIkSy? zjkQPLneKYTAiTFaQ`x9XL%RM7;lq@@`;`1kGJ zoKo@OKhvc>6Sh0Fk~c0c%tZS$0<@wK(pHJWW(!=Qvb8ZjKM0{_OHjExG$z#vrt^^5+LL@&mhWc%keX4YQJK2A?n3qB5d)ck;9~)C`*7! zHjZih+-vMH_cHte)v@#74cG8;)}ltCH4TEc0{`u2zR4Yc54_)>0y}gq{`@Ar!v3?+ zQWd*7F*JaBE@AW@jCv(r$D>&qzroQl6~3*Jn2=5z4q?3W%aSE?`t;<_FX_A*Ip+)U z|JD;1zOIE6={84Lw}3P#iF{{oo55EEMnaz5&Z ztq?P;Yd9**e)75jgsSRHM9NlJI*{fq@#O=KY8M9y22>}&4ZBQm93ymi=Xv!OyVR`- z$yY)8 zs4BqVgU>bj5E{=gr#M=|Sj{7ql+acpM%o7P37GkK>gyewY5EWqUU|0DX5OpM9A*dQ zXG9s^SSTb2Zk`lz1za{6{2Tf@GFE&iP{?W9C{uIpBWe=1_FF2a9qN*P>v?jhO6w!3 zYZgZ4*KnAVKaGloO8_ig)cFY88KIlZY|OeNGtl|w5|=vi*{uKiI)cy1=h?GH7a;rX z2KkHIbr-a_dOghxx%e|t^~ZR(DJJW0lSHDZXIctz>MK;E}EcT2G-?JZE3kL$Hs93!5ewE>)Mv$J3!!uDxmcb1^v8 zrb1>~*+h}5U-uU(29&OBn$ zbZ4JESGKrJvgE(edS&6fwRIWF=OnIgMW9bQ8EIaKpZlDfj=mV@2) z@>Pd?sJaE zhAsN&Z8m>19qAr!^{&6>KOKK0Gnrvp;$&#awHp9U5a= zI4)a`oBj(`+tFZiFX4{zCf2%Veld7(qI~d+*0H`jRPn-aK6G6xdAO$Tx(*MYrIp@$ z&<2%e`&YSOVH_yebfW+JDjoPzwf`Y`=D z51dYK)nyJ6O>5Lg0TG#sgMCxlD%Q4WPzf7B6a6|meb{Y3Y`O68MIHHuJ1b~hbE|mh zsVjX@&+G21xI`*)|0AL7#U@tK^U;gyVy?RF>UOaZ%z*k{EH8I8i-v86UXa>FllO#MLJa+nAuQO@Qe;Vmi7U^KJQL3oxI9sQhmd)tXN>5js z(ib=m1V=$bmAa}~T^Z91fP2bCBkZ#y(nBj8*yiw`yBC+2D_U6_AkNtKUNrst0*=O< z``=9xpDGX8ClNfyD)y(<9fo`0hfQiB2;^D@?dYNQX0BivflUXuX?sCviRDrYZpS(I z2c%Y&zd$!WP&zL4D2a816YkcGi5bAsJOmq7IkK(ClSC^Rm5jk-{3pwDypn~|8S?qu z{`QK!A9%GyhIMeSLt5&)&HOKF%ah@Ob!CbB7vJ2uXCMOa7ab{&zD!;Fv27FC^rm}( ze^gN&voSS+qT%Gt;vyZZL9ZRDqP&C3=#<>9i{2jz_ehsIyyAkce27j7ldR@*J9J}X z9Un<^u*q7@^-a{lWFl#1;Nx*4Y4lkJbC(=+rSSy#rc~c&*q(lI?Fr-EDxE zW#mPE$|zne?~sp>LEGTW11~kP>aiyY3oXriO9VVR&&(1*hV>b$nh(vD84 zo9iuI*lFL1`P!@t*SF~r8%^+sh!2der%|=786R6is{X8wskk4kmVjFNVPVt_fTfOa?rO@1C7(5vqdbj0p*b=!7JINX#qW6_4 zwQfzM$VD78y!?Dcl*r(T-(rHFQMS%3kteJzn;5iJ14ac`yXcE|a}9n(s6~+rrBT~{ zq$BLW7`)yBibau?rBH{9=ilJcW?DN=l&v0V*fEM=4L>9yg}0*1n@D}AQx`b+@4KDN zX#DHFfg6{K^5pPxxG&;s51WGdWlt=yt=nK|TTy)8Fk7zoIr-!52&Acy6_a1oe+|!0ZbHzOX*G-uE3;MOJn8pnFstw-NxL%?&Yt(NLJ^lX_(i@sNkTe*jfgv6cac<%czxPJIt z*Kxf+@AEugXVn)Uf}2e9Q?3mw%Vh{=KF*d(o4fJEVPS5K0vE_p+82k!Vj8T$9h__T z%LE|`x36zg0b_m0e3=1)vn)&9&rL3iYonFRGU(8=VX_rGwWyk&))x-_X8|~ChsT13 zDwGrKNv1vQ5x%~b8g-hvRiIhLxBZykRiyN)LdQ^IW3)N$QTIzkXk{Px=+O#ADGW*d z^lqC6teA94_t=qo5?ubidk|cq$daNa@OJvx%eWpVEw!|q`at0QRr@1B11sNG+wVkj zgE_!}F1KrKixAA;_0>KRh;?}OM-PGc^8+CAMMx^m9hZB<^79L^ z>ZgXrmbLxUB<3GR_M;_7Z(<8i0m6Hg6PBQK3 z_HF-m;w@Q|TY01)YDk*xG%bZb-n^jU*dyDhoCEIqbB)4R!_aY#gkhSLnfT-qchw{% zSaW{t*3ghn8m4Z1n|I1+_&0BW>sgAtqL2;x;Yc&{KGl>s=2GWorqv;E5}N2ruktct zsqnJg(@g+B&Y0y?H(i?iu9lb76OJj&sz6^R2KaT{L5JK=yH6^StlO$kwnb5-O!l8U zQC39jUj z8|l{rPrQO3X-T}IFIQHE2@F6OOUn%420#qW=oZjY&$DGkb5${u>MvI+tNF@cM0$*vJR#i~PH=4CfD*UaRQ5u9>d8gTk4_H<2Ymb!w zEAvM5rIAtg%u{|8!llaWXpPuC^2ZRqz6dn#OW!>DWq#>=-?ed0GPC=&GSG4I{w?}Gu+kO$Ay z+mFpI;vM)%NkqR3Rww#Oa5lEyhcpMuWo-SdEiq!B(7K$Z!a3h?H_TqBleuRS^d`sC zvNv^U(|csvuwYly)i>hXNz{AG5&D**3}ofi+wu3mueK+4*t_>~s=S~+R%ZRBIdqNzE<{b?iAwu9iDn?+|}QgR^ZU2*XIqJtL_VjEbKN zECY(}lYZNphwL4Qj0LzD9sX5(7I>GVmN(!zogL4+8T-E#0{9+d6CA<5beXuCG!1P}2^1-S;NDSN8( zhN$+;{#WYgh`Nv#(VZ$^vm$QXwd<=O{#(`-M1b>x%_d0p{skk5YZ9t}MJuHRGRB(%@M z8ZA(p9gMKx9}~5{&AA5UXKqn8#`myySW{#G$|Nr*tz+t98eskqU?n)dZt5^*6K}_0 z-hg5!eQ@;0du6xXuF)$UbJg1p1$wZ3D&rp|Z-zak=JzLO4L>^;+qyYKwp;7~MxXIO zJ!BXW(LtTV8=`jH-Q0beoLYa5PzoDgyY+-N4(2r7a<*|-`tOiX?^!)2y@<7*Bs_vlU-oZfUPDx-zrPx zaqG({mD?JAXHVY`;UTM(@b~Gfy0z`V_WM2ch_BMJ5@%~0pZ$-k7k}n_J?nAMw{Fhm zBT{4)hhcz2iMGU48L>UVt~l7^ix?FS{n9Bzwbrb0DtM#$Z|2`W;@Or0!}aYpg=2u@ z8yXz9BOF0ps;3XG(jPfCO{W~Nb*FQ^_`UZzCVL}v$P}PO{zj$1h36VZCqIKc%1Zfd zi5YwIeOL1w+V`4SdG@2%RNZ<`;HB zb^g@C6be*XjsTio8;&|PDI22EshJ<=Xg=)fKAx0+^;ng5DnfX=`}@Z^diG@9hU$OQ zT;<<)7oqD^3R`NNviYvG*vqj?wJUw-b^?|v(bgaxgJaU7I4@%lYDr$x;4D8|b(v^I z3WOzmya5?$D7LtFB!nkU%td-mt5bIsIC1r1G`zY$Gkm=mzY6JA*kK=Q3ynNuO+4IJZN8DOEzrrs1bvS))Q&Wp;0f1~0>X-xKh!lT7u z4W=EN=ZN&W3+=mYlPA8y|DGiR!_Yz0S@4HK*Q=l9M2gUm*7+h{opMaALT@(?J3OA` zJ(gckW}E@S9^O55C8Z*(++Ksvl%j?kvVc%E9s#X?4(HW3b`xNfp`Z82#JU`^dlEG1 zQv4%wRW48CY4=dXfP=9B)oGS3=O>~%=~JTug6jOU!tRdJH^V^%kyZ#_r0z8JOOnC8 zl;^q&z!nkj8xPJ@RLGw^zd(8LV&up3{{pu|K>rjOt_He+y6+aBWj~tX+(P3;HEw)Z zH5L4}?VPwYPZf2(p&CI9mR+V#(7m~)_UZ*E1lv<{&W;x!eo!@EZj5g3cv&qpeD!$4 zHTCAODwY-2D22fYLKTXZ%Ed#lK*aZewNCs6cuVrj*!NC-#Wfg1S~AG7cl-9 zxhKBV`bD=fQf@)zIT(}a_p;2C6=sFA3Is{Kjy<9=J+Rk699aiKtUQ90@0xeKS`=#fGj5+O8+lHL`7b*Mo z7m@DgIK4NWfk8J{23y5nq0jIRk%h3Ppe4i0lm5kCj3Es953_i29lT7Q{%}TaX?+LZ z4?bILLE+PAR64anb*N*nawXgq#85e)7)OV6J_Jd-iQczo-~YC?W=wY>{r1%X6_;5R zGeO~*3AP!(9{OrmC@yNe!%JGv!#&MSJMF%66#uW0%D23@Iqo8w_Cj?{2(`h(u?65c7tc5I_;A~p% zx5#ks^G|*%t{*j|#+Hk}j;4pTBR+zS@J~8RjI#b9msn~toqaH+nlapVA*GH-uZO72jwfMl3sNqyd*M)`RrcmlwuiUBhbU0u43{vnM)=&A+9sRHmO! zn$Lz#!r6Hn5IwwP+Bf9W4W0iID|v*UeEK)|KGFB@6#_ai`Xf+LIY97GI`%TfV!Lhq zVXF#%IxlQ{Rq0pjV}mGncE{5T^y$;JxmQ=_Hy`OVQr+05<7gCX;eDC>skyr3WQ<(< z*y+b^7$a1w-t9x8z^2ruUDioipQR^}8Ts4{)7D+^lh3l}e$p++Q{$zCGY656~gE|r~21U_*zzqcD_F!NMsLzBoIvyqxn zA>wr48dzG6W)RIuo~<>M_-2)(Yr-t%Bn3^q zzcT@X@_kqrd-f}Uw5+o|p={S%z!#L|jOeZu#u2roxy(U*PZ?_6s1DJw=v8qcN{iTH zdzp6ax_lP?>WVwN#{08vn&xf+V+VU^wIo5PbVL0Ce1jz3v36vZUdbrFmUgc+Iq=*a z6X&02$?(`gKV7!LrL{NGmLCy=d>CA}IGUi>ux`W*8gvrvii+pzrSW7qOG6Xm#=uxQ zWsvZ)E%T3k)f~a$)K?aYEb1b&hqn+TSJm_SqVFaOE*!>;+|Ry<)0;R<)E06#lsXR=huMjBYB1(A%2*hvaLN03P|3gL?lF(`_e1LkWX0WULFA zenGdF2DLB)b{l4s{YyIrY~&`t#CgZTFYaAee;eNU<1K>SfI+2I+%h9YoS@pecI(b0 zi^^9AE6yS20jHC{6s&TtUPBZS)0q74{Fsv%hk7e;k;)ZC^!)q$W-`vtRH*NbOv7wk zppRMdH@}OTe_Uy`(Mm4XjS8QxD3p~xFvKHiKVjW3gZ{)7w_%p`$T@)gog8Q1Bg&dRdB4+_u|?FM z&X+&rf(_$Std|}C?m1rI>aj4${+_szl`qq{L)Y{|BHX;&0@`_!t|nzb*k&}U!f{7&$}112It{|6U|ha8a~RH(|b3YOZ>e=uje( zLv)f_3KgEY@p>Rg#>prL0X?NEijwB|JV}!#)TPP#tU42)LaJqG)$C{e2UPm{H}vYP zPD}l}(p=;mXBp|-1gPbjk*`Yj3TcA$g)7?eAFj^GW1MXn1Q*Ngb>e+W#}r^|loE=- z&n>GDwYtZsO(mgOf57!uy^Ct|lSFs?Q<^7pPLFl_dbA(za#*pBe=b{n=@`>A^Y{Z_ zbi`?>1&5)0ZP|vIswZV~AI^&p?ql$!^s(eQ`{u|T*t*t#G1Cr7=s$a?L07v$$P4}} zbW-T1!C&#+SJVJe!E4K#XIpogk5IWQ-dTV+WfGz}e|@<}(|<^GlP6r{D;K2%M-{^1VyBl5_O z11{DaF?k%H6|2!7!~91b^TnbPR3;Y^Cv1n_%&y^)rvB6 z+Nm7kg~v~KZx$GUsOKCcyg=t?&~>sWA_ceNY6wABnv7$&sL-d3`zQ7*y}^YEVlAY5 zcDIo8_p}i_QcKuZ?62LvwTf_BniWR0u-a^tM!mFJ`_DlFolLXio)fK~y&B!kB{UNd zrhrcPrH`xV&Im@!3Y)8%oE9Ew;!k~I(ty2ntm4K0UBbAsQOmv9!{!u-WpEW&+Yy# z1i%PW1AhnY{bND&fDHHQhNyzbSK7&%!c^LRefwr!?4Rsc7jPU@p|u^OdD^!;g?vKF zVh>3WnkbBw!GiK*A^qsGzie$%64fzRD91(1`%t1vnWI8d{ZK4fhSb{Hbe4{QA zpfUhMwSKd7UexDOW#%n5z8nl@&M#EgxZwk#S7p&^oY4&-Og@-)Z z#C}4+7y9e|lLbvKqwUmiKsA7IX4vP|fhKN>tRj87A>tUs_vijiFoR&Fvx*3`kMh0e zgd`-eR%dy;j#>dc=c5nuk>eFAC5_I&oDPQ^*NmvQ-x+H6xmHnr`U_5Sf=#E>)82pN z8x<`)ck6E1UETi0Z`rCj(@sFaIiBPX`pSMw+P$MR@(|aA@-=wIqo?3QNt(L-SZuts z`+Ct<8S0dX2;5d)ZOA^z9+7XMz5IR;a|`^7`S=)ay)DDts&+Ygb|I82&@Su##UT@I zowDjpbNujLD^6muN&){z;%qi}zRWyr&y#7N6q8fme1^d4wVnAx|IdivK)(mT1+6YV)+{~diSC0sC1YC zi`8emJR9t0H0nQ#0C~~xX(GRQ9fdA*=Nf>AAu1k42}bqH=zAB&t<=09qltGegg(z? zi_9YpXLD93Wpcmqs=34mj94i>)X=)@Ry@ww8hcg(cDbJMA&5T$q;c?~2Gtom80lBw zMmE*i8L2iRNj^Al$T)IK@s`=7Tw5rcaa~r~#!zmaTFyM)(tM~ZHqtEu#1Zt5q#5lo z$?qsfY!QrSx!+|*l+Hj$Q1kB5OftP&dkC~b>hGYafz>W_N@{}^1`^}FrxDWOAs+{# zx;`eGekiRb@S&$3VfIBo>2B)P01t&GM0aAV#UQEg))`oBGlSFli^Mx?H1x3*YmADg zO^5#Z#^PgFJx_0x3TdWIF^6@RxFDNFni~Hn;wWviuN}&s}qCpjFiC) zpk0+rjc50)O8e9C(?eM~&M0=$VQql>+Q*QbG-*ZBFi<0CiSTk6l+naj>RE z7*7cPgX1;EyHdPMqBqS&7cexmq0xOQF=A46k+z32OMPmC?OJ;$cQQiy}f< zaR6u$9uGZuU%vpx)0Mk&2WJ~B59=@z+1u!l%h#1y8Hfe8zn9pqdg43f0HuT)UL3da zIv4)XwpG9(ILAKIk9z8h{EgkFS>&OO2$2c5)r1W75J6ATaU_Qd6!pTwtS#@MK?y&= z#en0~U9`|eFW0aZp^EuJAZKG_^QfZtr~(SmqD?kv`N$|X(%s)jQz@Y;PN-#%wuU5y)AzFgFzF&oH{1CmNl4 z;BEJt#%qKnT^3VUoYnrY5;p?AMq6MFKm!*(;($eMG{$#z}1r-IW`-vs3I5VjLHI8>WIG#)cj@%q

2@%d*EAwb#fO#O{(yByB+X%}JMeURKvC#)_zJi;vm;2Zd#SVmir3rCeNN@v zZQ>2&Jfr6@#I!fpFx3{$mp=Ql3>$^Q*0!QTz++wy`Bulfg`0!|BKR_jN~73hxGV{u z&&DKf&|O5JZadQK{nSOT3e7T{FYE1Ww9_+~J&eYgN{RQ=?REl?8&*_}M(!HH*@*O0 z@0~T%MhG1@+!R*Hx|9_$a`|c2_k0xQf!F~5H~W5DHE%ac6VyA_B*mxKv<}_4pZ(2h zQ7+Q)d)2Ucj&h;4wxsZH^Q4yoeSg)aJh#j3IV5Ec(Ch>$GjDf%3`4NW?q9C==50OU z0C-z#;2%kky;dW6ACc=MycYgn5@H^C-L}_u&O19BtG)hYePGWtaZ!a9|2jDF-Yy5S z8#3#9qv9Oygc&QN+QKnV7&GdVX%4-pRo>tFJK_6PUD`Q}RZJUtK~R1L;cm~5m8xgj zfKazh)uT4-9KCz@&=>G--oj>|x0)@f#50`i(#od(z>xcOLciaQK+?mxQ5`nm7XdTX z707Pg@;*SZfc0^Bl#j+NgmV@b*DJ4OGJ0c;pFnkrUEr?#{L*|t_IZJA(Cl&mL1pi{ z2Sy%H>p4dgQLVX3IUG}9yQB8|f=4^0&FVMH9(3L&HWoh7)-XGJ;QdFAE7&s9Xe4Lo zNGx7v>J##+)0lZks&B7FouLFka3fiMR=>WsAm?0PFj=vGWkwz^19zwO@1g!j{v0^;K7yl(uZ4c9eiHdg@3E0aX%<$>D_r;ZyGs+|8 z^H^@us(Dms_z3w)a|oD4<2Aa3w=B5Z^;8~k32@fk)Ebq6ZwP7|5NcriE%NSA!;xZjNug6o~$NPdhUaran}CWOJpc5I!+o zIn+3;f>5ddF-B|uoj0#MNXteY?vaYM!bQkt`3v=TMzHB4PRGzaKi zPy?qf=Ir^{0!MqxwaO7N|m4(cOA znYZRaZ5`fITGd&3o(YB{Lx^W|7^?%^H`uEu659aDa29z*NmoS|E4bdnS=T9M^Q86I z`v+d5FlP4b)BL?-OGh_q@0dBl2_Te(2go39)InA}7c6&w4pzts@X2E1W&1#++ihr1 ziz;9J?@^W{FEC7LXYiFAV)gI<{6&T1+6&Dr>%g<2UbI+fb^6800ncwZkzkYk}UeCwudGC7Be7YYRLcA-ni-ULyiQH`3~MTZd}!G^nuQk$1|1 zZJJb?;MP}g`cHYI-(n{Al`N)Vt&f~lL?micsWE9z$cxda`ZWetF<^!Ath*bH6HlT522V> zI|23mu+w-#zf~RxODQ)n>n|hIb0@5|04#nv*+^K{J>iaSof?sZL)WFQ}7c zls750d{e?+63%^`YhU)`7o-wG0Q|37M-{oFw&=r-s|0Gyqsu|u(3DWaW)2c8M!LH- z1684w_zO17@E&-6esN_aRmnvb`TZ^b$yyBj;uYB5lmJ1gDi^>=%hPl z4=s%g-rQp{=FgVzld4$$edvjn;vCo?`3rryh?8i zw6l0Kc=q26?{>fy?RT>yiR6&|s#1q++A9B*pcGCDi=dmks zifNuH_o~K>hQg747Z0t_cbw=+oZzlE$j&7`r{Em!iK!sGctn<~ z;&Hx#MAH2h+l_Kbmnl1NM>R0=0B!P}m)^6SDP+H5{P1w|5%6YuA^~p^YsJ)H^`W#5 zI`DUjc5w#zrG8R`cIPPUr1OX;c7y6I>qp#0@7F!5yXW+p=k|}(B|8wJJA=2pP5~>} zs*aag4l83lw@Jx`LnQVm(Y0L1RLBUq9FtE}t>98r?rw?-v`HW(bgol*k8!ekoT}w2 zp@JS9lIf&-@r(XgtGM53)f{0{YrnDg*BgAsw!|^=;m-BmBORyBkm4!}qBJ>_ne|h1 z*rg2rK?7-y($c+qJ24z(EO4gw?pb`L4gw+@T_@nMFqSi6nvN0bIGiJErfX-4%F1^($`6(Ll)fI_5Myl#dUL#_{~_ z1uaQM8VU{{W>xm8YO3s{^w%H~gT{v+Xdu^>eMAO{G^Lim^_$Ay*hpVV_^gP2uswcw zH=x?EOf4c1=+^mD4gpBpK`^fHz@83sMZKZ7VKS^4bP#gz@l;pGLq&MR<^gAwV z-W_P){8f1!3JK&7M;$QTO$GS}+TCsXC$Qmt&GC!z!}C}E{IgV1F&zu{DUzeyvGIvs zG_q-sdM4H{^p`UZkTm)5WP*LVrMYKa&}z|HLy862EqlRgMD}h72456?X#Vowc#bik zuN!m#aQ(oah206yS57I{?e2d2*_Gy~Mc%VxfWPd(q^r0u7BWPx4KC-##g>G%tk(sv zH6q!D#!hU7A4bju8;cVU;-B(ip3zeT6rgpwN+?c9T-zM#8k_6aOOpC2?K!|WB-7^k zN8!p8Dk_TeS9nNCp!ZtC!y2nBU9Ue?FE)fZX(nAjRet8SLjDTGX7y7s(aRm)I6yO3 zI1z)JVoPgR83<5HU{^d-Fj$>GoztZrO4~%#{vbonHM)1$5XHMUM~9jK1=*d-NT!QK z&$bHo+-yROZdY~qHuvXFJcYs{iBYeH@JMhTL$%Td82PYyZr8~h=NuQfV{w;=I47w!%_?B@3m+SzbSvCM;=n!VW^j3y!TVHsYZ9Ds zpD5;sP$2guh?Xb#(j~)D;-}x$rn)N)TO_JgqTZw{Wc$@FRLk26RAb&(e}DVw!A6=8 zN&~jDi1?I`7La0DAfF8RvOM|@TwyJS1MT!}_t=Z!TgDNuPj!il)9!|ChQW3pZCW#B z>rYXu$=5)co)*Tp?M0FZhm*vBc&ZettRr^M($M;w@w|1Ds|Pulr~JdR<2>KuoS53c zN`4TCV9zv{maj>xB-(k5!J)Cu3gw`J)${Lvv(4xUx@@OMp6y$ioYhC3(~Re+fSmzG zi>m^cB7ZZ24a-X@zygLc(k2XbQ3@nRS=w5nc7pu~u8YU^sde%gZ@`6e?O{XBAN#%?Zyp<;wr>%{Hr#&AE0m5MGyvi9zzsYI+51dcUdjN!#W!ngqWLKX zG9))c#VaQuDUSB`C zMZNu0=?E&f7_r5c7&Q`*5uEZ9v@l9D;BUjTq)#(99CYC9y;oBbw0=J`zvU@ObZl)^ zCurJ>$BJqK)EWLNn(9qpxVS z{(UU~h06ycV+p!K1l*17K& zM6{EF>#h!WBba@|Qbtz9P0O8d{1wmf*+F|8n_-}bK~Ii&E#;OzpSYs3HS;mZ#Vp`n zWwjND{QezubG7$wy4ML4BDRtW9S`~OsdRs;6i; z-jf>sMY%5}HiTcH@E z*Q4}WfZ;2ks9)dxy4Ot`x|wLy7=>geY*~r?*Ptj=u&(iHBf5Gv8z@NJzXKR?-|CL< zZ|3&M^ewgzx(8aNP-Dck;{%@EjVMN0Fi3{u<8^z>1hT$!=-vVef2HyNg!SM5Dtl56 zp+ev46tNqcAM2WpU%t=JR<=uV)PV1iw0pk0YvJZsxDJ-bwyBm}fuiw2v2V@o#3OPj zbFtP4@XxaZ3-s-L5K<#?t-qhJujvmbNWHQA*Ky8+uJkT*Hw5OKtW|9*2-%FoYjPAG( zW#!Lawv98b*sH+OF*}*CcNm6_*#(*9^fn09-3E$2OGOQ&H?H! zG4p|&0VN`X;-NpqF@q1Z0b%ico$dhN}zF#tD;?L;Q38-C)I3;Xt13oIz!4m=JMu}`+0;T(}vWma`CSh z)-%(7p-bN#XXIB(T@AJOcodZ~J8D*oh?QWtV5 zCIqEq=irEZpl>rvj!^CFFmGNdRO|HJij*P&9*+%>fhUz{0A1Z?e*>|MJ8f0+K_|db zYhi$*Ihkh*sZMbUU`hobrG1hd$!X zw09K25ttbUo%_Qx&j+vx(LyuPOO+X77db*)M`aZp`m+hV=LSXkMFuB|;lcoW2T2Jz#*H(Zl$zhwn(0D+EVhoGucP z9KGhPkD~W07TyL6e#Gm{atq;O#bVEgAmd_Z$(r!E*f_EA!p6H9C&(>ZBtyk6l<|`e z|1VqNqB^4K%X62}-VtO}xdyzXg(vhu0C}u3Uyy;^mC#2)4hM3>FCFIe1k%s zw@ykq)$ES4v`8?iNB>@Ecwdx2kFBm6X6`fvxM+Y+rO&@t9C*A+_k9V77LPv`xE3!^ zrUN*qWf^VE1qDQX=zLL;TWf}4`>YN5`Lt6g@& z+e1myYBo&*2MX%!7q6njjolwJKr8ElT!z)`ND^hImbJz6oVseX5*f+~BtUfKY)amA z7aN?&%t4KJ-`M#JBQeAzQ4o95ji*=SZR}pGzZl1^K98muBrBQ0l6GkDt)98QPv~5j z3Z7y_WYq|0=OC)rmJicJ9l5ZPGHizAN!y92mQEim8gsa)Md`kp`_7-vEerBewli%R zd2HrcGj_*BIQvu@aF+MMfNx5+o)v(e3aPb{E=h7OE7eKzC^Q_dMAz(_O8f?Mro|vF zZ?73#$ss4`?-3Gkg0rbW05SZ#_^R#&%exJp+($n1fekVFz+vTthS-MP%*9NAP&w(& z1uoQkVPJRCxElO8103(_!s*i7y}_oE^oI9dyl>`^e8lF=ZCZCHj9A51FQ~rI;FM44 zxSY?fo~|lEg!2{M)~1uPjQ0=Cp3p=m^c0lmRcaC~SO zSl#zOLyf?mGL($sIN(Qw!}g1Lt%FQ#;})a^)+tX=;kvEb$<|F~S#{I4#Axb4eEu%% zIK6nc!`5Dl5sMhez!LSM2~ET4jJ^BdyQdEU_(72xL`PYfCi8vN?36DL=F7To-vWWY zwYxpA|7q}F&P2))$Aoof(@V6Ozs)KOAff@_*d-RHeh`VgnG?v8%%PAewb{2Z)J zNN_ppsotzbQj`yd%Gcw<2z-_(E2+Ei7#9E<5Rs%8z=zsS1)=5aCA_!o;nZpG9e5%f z2yH$w=jMXQe|48LuqNSsPbPKuQ%;Cy%fIXy-Z=`(>;G3G+-U4p-#bkELs?k{cljS8 z7QG1&WH-QSVOZ;~{|**8hPk}>a#`IfcbP^LRk(Pb1R)TGBXuIs%-gI75mw>mNmstc zCMHFld*`*cN9X{2obz5cByO=W<)__Vrzx=42pPdGZ-srmch(R@3Kd1)=+(hx+F#js zNUvUF+>D@G|`)hW(EjPI3Z8i^(*3t+BgRL4=Ttq(>%o=1zcTD?mL{whRs; zFTh2Og0_CxbNd?acMFsCC#n9AIw6SAop9@KrP_$HmF<4D9vqvV)rh}c`+#~Q+g;(- z3?`Sv!}d0Vk3Y{Bf}S*Q85nm7FVVQ}CY^t6?DSRK6z;AS^syLucf0!jY3fX2o`s0q zpM~pA2+qmu#}7b4m5oju!o$_xWO)dB69N#bwzTFRK^tVyG6S_%0@(zwm2ch2Gp49t z<_zX%=w-IUSeFF1wazyPp@c*W;n$wP_<1sa?2f8qTSQ1yT zmNuLbn!MkCdvs_}sC3%SrXzyorq#VKvgBQw@n%u8Lv;;)oX&Mz;%dQD-$!X~VVa#4 zPGcI$t~81}IcI&u({-D%bS5lcpPc=lKS( zPtl49;m5N>L?!fOT40FlyrXC-==^yh@!6f;0!8ghH>*)Dp+a8k6Y zwiSf)bB0!ye8*4_ty%Q6@VU0}yWY@`J|_?x^{3py1;a?yv7!xlJ(W?d_szVM7py{u zxJN@`8T3e8NuUil_io>YA6BBI8UGm25J{ZaGSaT0T*UAA|62snp;GEalb^HNioZ_Q zg)Hzc<)K^*GfC-4^vNILQq{}Om(guy|0tz&$Syb5C$hmB$Mi=}Hp5+H53fp)E2&rC zojZNwhm40mS`qTscMsAcF=yB|OG5kpFJvIv$mE@E>?Xt-rt?C9)%9gR-vRykCd2Wd1kMWX-{JrVb|axx2(t?Vqtkw zo-KP+)0PREmKg==6D)LHw37kq)#WY{_irETZ42RiSekIp3&$u;K9%tSjx4@KcvNw;;+f;mb)n5Nsb&z&!ef z?`$gKaE2g|V=Zvh?>O}P^xa0llDA{@{P>E?b0*rfY=NM}~2hUow;UXav?=>LYgMuG-o>IJG|B zDI)e3S6JaL_vm`^u-QL(;CO|w*V){4L93Q6dZKnW7p_=#{KtveTI2Zr9%W2?Ji1tH z?LO=~=e-157Jb*FL_(p3y#yN~2<#wmVpQfV(E}FR>+a{qB9JyvaFGu*k`NRDcCOuj?||ic%>q?}|JI|%U7wR4eaYR9 ziu=H!AW3m=AKuex9%@>V3_sLV)uMQ9ei_fIrd8X#(C0hKQ+S&NJwAzdW~}kvxU-^F zW7rckAQF^D_;GL$E{HbYi9v*&Cm+4t8GxBrmF511WIuBt{~nZ-v+3`tS-q>q7VxB& zU2RV&ddB6G-%PJXgxOGHWXtwqMHX3dqOP5DQoSti()Q3`A-F}JJpW!(K@-2_ooH{I zFx0x`fak#cqNjxgQ;h4`j~0Ib>R31(RNE7z8Q?*1-jxMhAMh8T1k2C$Yp*97Wyz@% zZ_Dm@ADiu2jY?%BC3nbc2T#D#pT4mZ1<*!ks2I79J}SW5AxH?OPd2%3FO$^ z)=|DoV4KfGF=xBRQqDEoxsJQW0`QuW-4<+WIjS7LR-=Y@jK!4(u1!L`O8C~=6M}0Y zEG@^%zns$6Yl=(ryjl_X^cwgqD6wucGj&NPxT}FeRz#fU4H%teejD2;+@0fngS6Rw z2>;Sxccv0bUzGNHw?74|Mz7pWMbOv{XAQ3%mQg;C-C*C9%TuwY2oW_9FTSSo!CH`0 z??T0$tB;`&AJ_Z;w0c#(M`OM*t|-66K<@rXEx)bkCqN!TV$OLDqSBeiJy`ULvDo4Ah#b(3k$v z0f6i1_qRt-HOKRFcqRt?Nw7G%nqrFx-KqkwWi@Kb@n_v0UJDZZ(EOAW)P z=!{sNwyjJ(#r4obAvy|C%7MAwy;=65x?8lx z8!;3<(3j;@ zmt$abX^JKte(^RW%R>dg)``E!Nh{~X@_=L0G z4L=+)B_#4zsnvgIkbEd$$FMyb&RtlB$v)Lwhx!fq0)uqz$v~$AM?&k5& z;d2*Vgj2{x&Cv(({~_u;`{CD?7jCM5yX@K^SpT8=4I~tlbqLieZR+nw)sBDCL%f&!>F#NJT%Ik z$wUy_F?fhROK!++$$(WxVEA(&1!-dU43MES4|AfOpAW{|>UyF$9?T%#)cz5iq6N29 z@kW>S>XJEjO~Df^6R4okfA+NV74z5o;{m1l439)AGArDH{#G3W64&2uXsrB#EyL6m z0;oJjy!y`GxCWe)_CeMZ+dQX) zC2_pcVGV`)Gu|^Al|U+i&tLC1tAEt?-o6~fho!j(%gj`;O4v-`4uP)>#zMV*tKz&Q z_C*zgYnIIEpAx;qS1nnR$@!i0Sh3Lft%x78pI7vl`e|0o-2=-}MW0+vhiR%NB5GqV z_?svBtcg1hNUiG!&DP?$&+VV3`HQpn&K=gKe6+2P9oBMHMulu4_Na~YkA5*OsH+>u=#M50OFtAm2=)65qd08V`CH{oC?M`53kd^nu+{9Y5vE0 zCM@%v+j>a!>rVLi27sb8`h~O_!kJ5hUg9*OJcBMlZY_-ho&8-_<{~%x`{$F}C2AS$ z&rDn(J2a~jOPx_hc)=W^mC#O06Hb9b>1RIn*#Kxh1+M^bQ!1jOiu<09qc`YOvg=nP z$I4!`9mjiBzxcVA$Efldc6iHL0O)-CQY+nsb^IqlBewySw9o`>Gh{mwa{kh{C8iH~ zWC!KGw#{7bNQe_D-dJAJ(dma&TZSZasqhmhwpdml2Nj=|G}i*~L(ccoN&@VJDmr3X zPln#*5EXs%q`xG`%kPt#rPPZSuvc-Xxg1oBTf^Y6Aq$1fn{%?AckHZm4-L%dy4LU5 zCaGPY2&FkcA;kJlMWuAJUu~0qh_h@Mk)`}LF~|ZS!X}-PM=%_cLo&gTYIc}pFMKxVT=KPgy^y+5#>>R9#Xb~DPP>X#g*C-M7+yg_eNj? zd38IK?S+7GnU#jmjE(%er!9foc-V@`uACp`6*`#>S~n2n(f$0WZ!#C{U=cElo}ErOx(^)5 zD_!F@NN|{Yd!>yoQ9$C=$ZSf9xFF2dGtoH1s};3gUdG3v_q}#_siBQ`d`<^XS8^rj zZ6DSA-W9WTok0ruy$3@US~FYN&AkQX8#LVtRuu`2~S1ym4;^p=b~*capk;zR2A$tF@XQty#8H><*a?hHexTH zvVb~ZO7`MB)%I6SzC(Dj3nstW5P^5t4?-zHD4g8WKy2-+&&9Z4i0Vpz(0$;P<* z!t5c41-3K~tC`Z<$DC=kB84iksKPm4Nzcn7eM4VP@OX%I?Cne6>w`|gTX-Bg@TVv} z30L=EQ)Y8RXj3YnXKj5K7M^wfY267Vlj+gfmcqBGGs!gOy~g>$a2`MqQtAugw1i@vhidhsc~-~i_KxKOFK3e1x&18WU$A+)ugut7lms2p zD*Uc6AB~IuC&$NNW&}O*3V8UbiZ%ME_#1ENSKKYdZMx@cBZD&cfnC%a&q0``&steo zOGoBuP5l=lO)E8L;nO0dnjsvA4r@{H$kH-V-vx>NF@7{Gi zgx%=MKvJI_KW=|D`m-Ez-Vf;{VM1K9__YIUc>0MnIe`tQv^DIuoJrllWV~>HuzA2a%RMRHRD8TM($s_v3YL4U%X_7GiFnRr?W*aa1Yh-=GK9um7gireG z*HbZ1*|2x^`xlA5`u{vu*xiGF2RrcVlav63_i_IlEkpiyq0aLE8%Bt;qZTts_z@4u zaR5iPtnH5FH~Cx*04-*(LSWUq6zl>hz4*4~B~yGkEptb3&O3f}U&)7oXQ7gi)?BtH zB+6ZwDUGDTMCh`IhtMNg^w(NVM)2EOK8u6>zsXvn4eKyaV9?2Dr4mQPL3r=0KwJWm zg7eR@Af^k@`OD(voquKVpDvk?!sWyC`Jyy9#+zgY*Z%ADmBTewO7UEjNo9Duo$IK) zU9tll2iezRD22g}JnWIkfbh;w!hIK{Mv}aehwf~2Im+YkjGw`OWwMwT|86(rJR>H> z{7AhQu$Wi;K-EvwmcHURP$&JD*IN*8AZg^(U}a_<&nBC ziXL&h0{FGfKGg7Q`u8$03^0US8xL%?I{$H#mneyBq8Z50+p#UU%8!3RW8}i(ZH#WM z`IiUkV-TCnChD7}I*Yoyf1z?fj>n}?qwi%oyA1kCmN56K@v1lF87P<<)7bcxO_P7! z!<+ajS$@CS5vC}Q5QJ`oUcL2QP6K7Up8F18Qn%GHnB3k5;e`Rm2L^+f^!Nf^+s6fa zeDrfm*&j^f^e2?1LU{6Gj@O*lC($ol4&AuzD&_>)pENrr%M1aO?R8!vcx8}A z*EhC4;S1(yGJ) z%BytmWnBkDILoqS17!x#WbQV~<8)#jLrUw4$t{Z?g5H%wT#L*rk=$A*oW}E2?|sh zgg2VN^*eoAyGzSs>}g>~7IdagvN$3*$>CfTL<8|s&65>A>ki}ZaOiR{-!@4L=We1xqrKy=MPaZ zdQ!z#Pt;ub7<V+SH;yxuTDsK?8KpfLL{mbxqQwXuB)D;qJX_pb=nZ9+`dA(AbkxGeFJ21R z*WJ+d7Z<-DeE1LgQ}qrcHX%AK8u=9oyo&FA=+4u`bM;K}>P@~-0(3SdGU1A@ebq>N z1w7lwFd+J_yJOHrf{g6?__3zib5s7K>t8u0>iFz{udl0D9iGn67K@L6cTPpjL8~__ zu7t9|gR{{deU$3{dS-N*1No~!E1qt?_Tr)iEMyUFDptTXlZ0!D^XI32mO>0vI9ZQc zIKFqxKE-{X$*SR5kx%WTyNK_^KSQY9G@Fd8kTU8Gg2mOniYWXQ)x($I3aaU%A%LD=V1>QwV*C!phYv(n&Klt^Z>QpC z9GnRSWd_st!qc>(_jI4D)r@c<%deuoDdy>2-4|&pj5-^qK$nDVEVmUgd5~-?WH#WV zJ2~0#W`hZTbF)KQ9)LZ!jF|G+bQ;b67%#W3X#C%fsF&F<#3FKM{2w9C!@S6|Z+0*Z z*0QpzTRMFwKb$i)7W#W?;rUMiF}fStT!rmY8v1xeX!{r1bC6+{PoZEK@aR1BFb!L+ zH&)Q>Jo>rlK(nKEy1z8GQsjad9o6bnZ|3wV>~dXo`bYWU>QNej*!9_4dJn6n`^phpH)V>F~9R%o#NNY$|~XaB3%!p2xq zuZrd!tC$}ACdU-9Vo3Ge2CL|nV{$^r47(6NizZ+5-IV3|YV$>TNzkLSkVj|Y%_jXm z7IScWY6SOnD1Vw;byGo0x+hZ@>h($2Y=s;_mxUYSxYk7z9d;Qtndy-aM#~H48-?ad>m1!G|T}Q>- ze{IR~M^8sUUZYX;O@qRG>W?F<_ny1Kah`)gXV$<8zIqJ8@?o4}N@WlARFC5GP6N_q z!H;Q*CEkEi+t`3;{{Q60j)N3+^xi`rz8_WK5OE_{{EldlUQS%SxHZ{cnNec!3^&hf z;W#&}Ks(b-O3C}emIg{a9+z8GkYmcnd~yZ;-ZX%5Bsfr>#!vxPCYJbb&BW0SnxqQW zzT`OcW8>#HvgLXlqZ3z9*_7U{Gf(pQqB8$UFq#&B=e=B^KvQ}_04u!gxw!HSWoSO5 zmx_MC3TL3SE*ITjk$rn)aGve+HC|>rjD~SHo1V?k!~Plbv|M z{mwJ42d{~TQw@h+7yA$JMIhorcbx{8xBxGtnkDKXBSkqG^UdQmt38U){ilg@VJ!T2 zU$tg5d=BZ?y0MF@t&kx-cLwG?0sW^}RLK7T7&e>WLx?6Rg44Xk+0jIPXxJy)Z!T#7 zyDI6?X;RY9G`rk@ zw^i9Ri5c$etW+Tg^;gLGeJI~8pG}qv;$G^ncc(gU`Ypp}tHIiug@4~gt&+~W*gsh6 zG#i7r6Xa#QEepDZ+-Ro60X%iiM1Ojz%iHR!)ZQ!K9=X_m_wMjVJQsH|kTB1KX{K{K zDJ4vul=}p}TE*Rx?fSIZks^ceU&MF8Y@*vo!M$Ui@pZ1@>y?~BC{=#Ic&1AM zPU6x%&f@DSPh)c)IhR^!aPQA^p~zux2ktg615(3#d#RnJF&6cL-fWiqM3)y8$sqLW z3AZa?Ve0>X&53tnbi7a-!P5bdLT=VWN7swes_+E(o zXLNWW4`t0O&q>~Uxi;`crPWxO2#49P*9T#GI7J$&}@!i8G+k5DFmZUS?UMoS2&kam+%>o3i`8lA@IpJ(Cv^jMr~5I3^y^rlg7`Q zu2k+s@I=j%z{LBjnAL6LJ{Cii>Wo@FMMiVH{IGj8UY_4y!CPp(g+l42RwTgJN| z_H<_+i9v9*ljsNU>Y2**&ClMwE?9cED*=j+jiJ@b3VWlA`f^Tns3inOoy$fQFV{p@ zD$Way9VJ|&@K9!@hPUB+NKui078=ouMT9sd@99nzgeGIHf${}K^I_1I|8g15J-|%c z>L~`|q@s$B`T3WFy;P|Ei##Rw{e2;O;N#`jbqjD6)r|T{o~wj5zqRCgGd{2;`owrD z=;4~0wX!iA=3fw-dJygwknnwPV5At3q%l02k*hw=VcLTY2HjAJuncXMCi9$@QY=*A zIPjIMhB6~0Q#ZM8j51tu1cMn%?LT7^=#(VC&Afc>+FBh5vvS{Tc_{E1+lTx_m;i3f zp)4?yC+UE#fQ2>~36Hz)a+l@hWg=KZz0V_Qrg#KKVu64282Ct;V*W?+m$>SL88&jd z#SH#>jO>E6mr1z&SP4x{ct={;t=9Yspmk{-k6@_iKbEuAPa{LTnTDV>ERx9Md#fKu z^d!75=WVOi5t)3RM(#Tp6i;}wXYTeOBkJ})j+V>)z$$$x@u^$@r{?nprW`|q_xph% zJF0i;kC068%`ZwAopXHqu^ho@jgzL<%1&%~jZbkb*dx01gJ}CtMfTzTJ_HX0J@I9W zw|Xc)xa$#TbXYX`RnD9Dx7WcLeC}8Gokst3p4993!0(5|J{Cmdde{n?(?s4+aw02~ zA>7&eKAUPsF`eyRnY?`1 zu^c`^Bm);3(1TOW$ll{B0}xLpv3+ zM96TxM@taZm;i)p6>2;7a{72e*3)~2WpuCf@v@qizDI+76&Pp0xwDp3x=gtl9m9WU zb>>95bCYhf7oF8@k|ud_KZ{_4Y29h|#$ zys?(6L2fx)(?)DagN%E>{HcHROJtbRt0W%MYOVcFii4kmeZr1;F3(Hl+LdXRfOsD0 z3>EFy!CQ-v|YxZBR zjZ<5Y0Fl!ty0m8RK}u!EJ`|g=_}l*xM;!V_7%Zk>dN(_N#r_#sH`3|wCB!3XFSN{E zK1w|XqNS)*Xzw{kOxX#VSlu8{!j9EmhR5;BXMXkuj2Fv4h4`uN${800to(cP)5{k> z2^q@=ZnlJK#(kSLgb{+QVpo0*_hfZ$z%98qvT?BERUh;vN94fCfTZZbh!H%q(Y^wP zlUgHliDu~3$ROAdKjn%0Qh6#VgvULw-N34Xw#T8W(2;MbIDz8k=4~W^6M@Q(;hFpEa7#gBU(L4!6>uSO56(lopB!*?~oL?%-MvY zd+E8=0YP^6MWC22RENhN7S4foEOToOEGB=q-P>_J8p8^M zF=rgZ?#m|dG3G%3c7S6$<&ct_=BW7GS!-zUF%HyM2@@>?zVW)?f^OA`EO79_8k4`9 z|Iu?mt6TgDtETB(FNYUw+|z}#blvirEeqHLE$?)^Uu4Zsj}gROu<&ns7ugKnzV;Jh z?Z`CwI9e*LsaW{_K#ZZ|65AE z`aTlU@NkWg0Al>>%8c=uOu}jNtm2=->`-?#gMP3nl~o141rqw=&$P2GIFxgg5hs3O z5xE8>?z)-(ZYULp(+XWg6JcvF_<$Q9`7Buy_nuOomKrm@i%}jcE(iWRqOxh<{?qAs zrO$o7`g(%!^zVGwBd_1Eop-;cjr)@FC6j@@gxQY@J2FV}G7BJ`UA%X)8U&l~&Xb+z zwp@x6c^Xp4T65d59S&0iF@^XOeyxy3`PQQW78=fT> z$Mdk09I4YN`;GGCCfy~6;r)K$K5vaYuu~N-mkFq9ZG$RI%NFGE?;+SMxlM-8F+7%s zhH+(+JYo}6!@yd_FID#C&V=f;SFPooz1nF71*N2DR!%FgKnF@vIX5-V)@#{iX zXv-Mw`d)CitC^cNXQkKsG%Oii-FZ)uIlit`@vx#NG@8>N(zw_uGs^Q;I1ZXwxK zSZ!fcjtuK5>B~uUDvl+m2_cK1G{!l%(`^+-}Y^-ODZpz%IPY_v!#Y!rqqIz;|}(OFF(suk`E@_;C85 zb{PL^oZDCM{MNCPUPOvTl4ug*b(*kp*miM=gsXG*&zrP>kSnnQm{m2`{+N# z6_0|wzVVWRC2h&PUhx)11}29rEqTAyvUi!`eGjBNs2Z&~3SeE2@7$&LfU#d(ns4{W zSuu24Yej&yvbMFJ3`5(6S);}(1>i_)pQI{?6 zs^QA1aaROtlv`{w)`I(&680TPCPRi}m;;_b89!K>SZ$u=t$%!?<4Jk~n8B1pTDTNY z#&NjnN;KCM^yaEFMcY*O#&&nTo++V23LiC5PjH=x(4eSBRNa(JAa@i`L# z6+Z?P;tiBfRj1;y;5XnQytME#M{v%pGL0PeTb&!Z0_;fg6#4FQC zIYXd8jE#!L*^KX=g*P$zFtDmw#LJ;6X?#}z$AHmk+(?G}Z_Ez`Lhk_$v;ga%Q6GA1 z#Y}#iAXc%(Wd-z&7Fh1aFulPKz4+o3QcGe=WdG%RpX+iwASe38lfV1B{?W=+!IPjE zNJ*7z$>CQqFFHFtE-A_EXA_5W88s*3eA#Z%JnJc&Nh8Sq2D(&}b(0ZOzR4?2wanP= zn%!!)FWzk0Im$baEJ{|8ugC*BV9MSS4>Q&CVS@c@5@VxBzs}6R_K!p&bP>Yl9uyY` zxi1+VUmN(ITSGOqxKw0n_3z%=U68s~$*6FU={r`GZxqSIocm=b9L#eon~g2+_@RUR zeeWfMp7(f!loIGItIcsznlS1SpW>`UI@7gRudaDctjv!M!{y~N;xYZ@4{%$)d|k;h z{Z%HH6Ey3Z89Bc-)H`zQA+|wfeZEJ+eWjD0qPbgt)?;vm{G2wLXI?BF{Le~(x!^-Y*4S`n1=!J*5^-Htq2>qq#dA z4ty6Pu9DMS{9v0`*D~Qts*80{x*vCNe}HOWkSv3t{8Ew)XCsJ*RA(&OO8DV5hIn>d zDc<-{OED`2!VL}cr6I%f!;&_EXD>NNdQa{mOUJh9GvbmhDR@eBoi^&WY8HP}Hrie` zGQF(}S8BMKq@o@#NWLhfb_b*W_tjR3k1R0#S-#hFK|QTgR+o@oN%te}2U&j##>7e` z{NqQyL&O-iF;5lg_=o9~y*)CRnD$RdC+3EyTs5ISWW$R92ncc;GfJE^e>YbuZ=0N4 zx7m9qF(jlfA=^(9-7im(N9TJidzpET=-RS09a{DMz*1?lJa2%nmFHtfbx=uHsD>go z;lsfqGB`f;oiF`CW~Vm>=PEf*oN6KD2y1X6^zK0Ul}yeSRe2Be?}h4+8E|({=zO&` z415X>*P;dNtAqkOhfW%5sUfl+fnO8>4IW@mo0W`+T9qC;F4#{y?uwnaAyTjM&Ais% z%&dEPZZ~^*UL~Hsa$0|?ETEfluf-$eAo+ymjJ3{{^uFMR5U!zWqD1u4V%(9{PY90-ATv!I7Xv5qBy<5JUpHUod zX7w~+nV3cj&1o)iIqXZjbb*wAso+q)t!^Pj)#196a}_bpZ9^4yO+ zz_!mG{ejUnSzdCC&{sbR3Y(CluWc8ldWr1E$n%RzO%-C@Vd0#wz{c^ z_rnL+ z!6YhH$|xpwN3XAB;x2tHxWtaIBpFa;gtP_b5nozuj~`!%QV&3Dg}=Lv%_E79&ZQYV zLrdBUINnKJYo<>>q1m7LNjd+T#oP>hm?5(g2B_2LvI^LIB3hx6<{hVXjnP8<$7=M+ zE6JU6`RaKW$tnc6%Zn%M$6bC`D61%cK*DA^`ICcO8%@r8LR3m%uF^-4Cp6i_3PD8b z4j^8~a@|FwQ~tA)?Fv!fqh@U(0qe%wc)^tEtcp@#w2>_e1E#rj9rtg=J^%?w%L0!+ zeXk!Ndd|uHaIwlxvlje-eZbNH;sGq31DC0>&R-op{s(rH{UJFy9_%VSs{eg-p2ZZ=FJ|Qr+J2fH3-l6 zAu5**9FDs3xmi#CPA>~sm6M%Mdf{%;`%kS-ll=k;z1L8C*RR`!BxAh5UACUINuP8S zjlbs8F%xihd-e>b5bkZJU9_VH;Zk#XL$4tGBSqER_0xkLiFgxGTwfJEWIjc>N7j1c_fi7p7jL7C z-XHG6*9NZAE2WHYR6HD1D!QY((jJB?joroXrRQ=OylOE9GD7+^;u@j8o2q{wDR=On zgiu}0$#J(YFOT4T;Yf#qVl0aW}C?2)L7Jd<#D@mh_`4k3^m1%Zh+H)t zv$A!ch58rKqN|n+CW9%3k963~hiC-fc2B<1wl2(t>%#(=4g-bdQ8KR0a0RtLXy4_= znmmsy;``0B_nU9c`b!hfV=F28n<*{^iSgNUMh2*P*DdE^f&hAz2ZZ}*Lnl+csz`m! z2P57$L{usB@dUH`%e<_Fg9q%Ft+}%$hkYX53AI_-9KJu|mhRRc^F+wY#g?gb+VKv` zG}F&T#yXb*5b~VRZQX!H>B;>ljB~&$uYG9fP zuWgN2+ZWRs*?m`MZBFOaMA~1RP$q?`6e#l(HI-?Hb|@=PKCtV75+o?$x{4!MxtlUt z7dkF)&nYIxDPZZi*!9!O<-xwtlkc5UZq(FUToLu|x*!zPCKOR?+&+}{aI-YB^Aion zH8NjnjBnSyx(m6Sb6TY@NA}d82_EQq zzE8f%HBYwK&EK`=Txk&2Nnb!o5;tdjFnC({Rl&0J^<{n*j`$+``BvZ2Ps|`xcJZR0wmw450wwJr|eMR&(iFc5!bhq8a_?Yd0ivmK}alhj^dik+4C^@o*mSl z%7VX(x?09bY1ND<<-U33jI#GoKGuC)o1oO_voEwf2(3ump>eFcj&lh7T*TJTBx^XdyLWiF zDk8FP?xtza-9c^v{wZ8h^YEQgSw{3ixzkdyfgoMA4;!)$hezyk=iQGCLbHHPktWZs z0i3!e)cr|b*Rw>Ki`{=t@^o_p8R~xn zrAJ)9`0oE$L&MEJSMxyVCH32lQU1?nz*m8Es$h-JQJ3A zCHjoGZ0x|U8PCUfE*l%hA;WvZx3L&0Gh$IP*b~e#MT-cY|K7*i8C(ePv?vG}ws-hz zP>>>DLYz-#5Y=V*_KOt=8mMq$-`#rs+43B#=bYb}Rkb*j^6uWxG@7n&<~v_;`4F^2 zFls*oD7^07txz!>&6>2+Ja?KHSAwWDf{y6L3TEh*^^1?BU?1_4usoaXlLc$P0hew` zLbDq8&<8bv-H&EOBg7M#{c-W_M1${7BlMyU(`ecDQ2V!CVzaxaZwiAwvp4vl;w`Ho zCG%>jen&E~&Ji&Q0-Uvx31xYV=2>Y!C??jz@6;aiKAF8oKjGqChE!A_tIoUW+k1a{ zdZCSmI0&Yepy{%vjO~4l$R>{Sy!Fr1HwG+DCU5bsrxYyH`;{BQfUVw3lB#fd_z%EJ zSGn}4X{^H0s67z-2hK^-)1 zFH6;W!~cz>mVIX>kl7U+73yp?BOZ0a|FS(SXwtrqrP^)?E>wA+7RA4+WGOK#YtVW^ z@AUaQK&shAMt-gFR)CVx?ME#%o8dTP2g@ga+1?yovh{gH=;A1%`Z+8DOwl)aj-3XJ zd9yW&vLfanoI}L})Nt%-5Wjr8Be=)_IWwU9cgu#pf*Y}HQ5OZ;1jy9_cH5-<={Z1gEOh_|J{pA)dbyAbAF8rnuR=M+v z6U#uLKF;|ypIqZ6oa5C%VQ?W*2FGwHd6i@oGqc=4b0}R5^8!+$Q)!fl!hJQCo%!ar z5#=|n6gxd;_+L5q$Z_(`ltp62LmrMY4w$!)EUF_1$qbFA0IBmn$S4=fG3VMxoNojM zPsP`mg^V08*3TW8QuzmR z?CM4&<5F15aJ&~O4GFg7bcY<@>(t3Ai_NytI`rw$Bc3)<<5#QYr7zl^P7Vsrgn&D( zdc=P}z;hUw|A|>F<^#%eg*85bzv^^5IE-*iJDj78;x)ufomlX|8f{ zRj(s?$l>lRyR9&k0bA8&+SZqqCdTL6JrLq6u2AJ9M4fQ_Gf_$5aUC|DTje>+bH7e& zrnuz3&IHT*XDezxQZt6GK_$vlK^APUzgw<0ZnZ0C#m3DAzMzwrE|HWMEN8yr2( zIDa-<>K+?VXz&VT7M0G{)`VQ`#&l-jo>9z!8cSr%P&G(pX+a;ZB>elqa@B0^O&OA$MX$l}y0MgPA53fPL0jE__m`^eNb)!ziA2l$ zC3zs=fO1H}0RNOO?C({_@`v7lqvBda@Mski9PG7y8>I1aTT3ND;bW1!F0vvmoWE$v zY;nDO?RBG~UtimfEdSa>$Sg$B+Dsp#bkI&l(5?&wtJN9Pn)b`83>;Nd>J4Y!1Fa7NMYqZ9d5TXYm2Q8 zeD~J)D`oerSJ@bctUU3q{B5ET{pLq+cJ~|CYeF%USW@{*sB@3_6n~GEub*-Rf5&@? zzMcZZxW{^<%R8eTfiNYYW%$x$98J_-PFj5^x!L}V;B|%k?h%JG?6`d?ardq9bY9*PnKi$bHxxeGSoY;>-74LXin5j(O&>te)4 zjrT6E`9EKp%MeH1a(R2^Ds>jKYqYIFX>mq9S1ycnzOPhgQ?btNy6ulLZ?7I$keaoR-6-kzwqLYoQGP z#n*YyGm-mD@BW#DmS5_s6SYRU$2vpk2HRZ3oQH*jHgpRml;F=cs8>F3X?;n!&P@&s7^=rdhhvk5Ob? ze9RUP%&dwz)yaxQ@J}A{XC&e}QgaKN?WQZMv^1V>?RiObNsuT-jajtlI*AI@4k)mJU0*zQti{W8S2g&kzE|-ly z56$VX0yZ1#@d<^!v}Uv7;*H7U&$B@oIz_kM6ArXjc%w?n>7Pyq^rvktgh5)pQ;b}3 zE1M6ap$=o~9ph})t@~L^GZ%me4GVSJ>~eIl=YdA14He?_Z}7YHppQG7V`JYa{sJyC zoX>?})q<=!^yadFL)@1K3z^?`l-2I+sjm4i#_A^gCv_&5i)3B1>$ri!;AvckE5}Q& z(moRN_79{3-9BpQe8<-MY)1#A_iz8_x*@_XM%(|uuns%WPm~x)IY=@rk+eg1)$jPt zNMp%(?&&=D#;^bCpn3h49N1gzO$l2vL9dUar3Q$Z$nruvNxhC z`$gxVk1qImXMPJBUPeq_hK_{!={fo@5B#wwxESQ_vU9wZI)Vd z3Pq2ObNW3`)sV(IzWptYt6KSHhkeq)4@j6YRI#+3FOAJ;jPDBlUhgk-tCK@luK98^ z{XNRr$BQvt^Rr%RoiF71vgD0voJJTZ+JUHfAhGFxEOwHH=K|MVN8+(>^|~l~kVKe% zflB|sR&$20AnhyH*bCO)*hoGji{fBo@;Ydp4{(0Qlvhf|KWF~RC>CJoMsDgg7$VLt z?Nypvw0R|p3~pnQp>6tcZT{|A-&2tt$gxCR6r>Zf-lDOMiWlmIZ<3#|m+J>Zk|;C0 zsaDn8clbs~%aZYvCzgn`&qm2{H+idk1M7}hSkk9*vXBBm1gg=zZ(0! zL~+Rk6yn9u?B|%BC?5uzd9b=CnUJv0eje{!pd|^F4>p%ul-`9j0SJE;nU+k&Nqff! zW%oK-au0$pZkchS-|38g)Oj;Sp7*H~*uKv76(wJ=O2e`7(eV_~Z%>{^GivP)G2FZT zCjsL2_8-vKv@u+Wiy87jL%8K)pqp~hSoqBBcMcqc)9@Om;5rS0YO4ImMX0iG4y446 z6(nzsrS}5@1~mRSQ8xc|DwoOihbM;>0)TZy#d|J|dBo{)kqf3$qXxZB?JG!p% zzQwk~`UJz&_=jUR7m>JqYF_WuQ}9Ra5tlXPuDc0Ssc|uPLoY(WJ-xfg!XT7q{b~3H0f@T|G1ewA9Jm-IZc^QN4+w0=bFsOO*l0==7611 zr|!p#EQ?0$H(N2fs}Ct$<6PTSH_4B)cEVAF@ylkWl?ywWX;2FO#On%S|HRj0=gBuVEEq*7-nPtUlQ zxS?wqOaDCb0#PnA@x}e_nIEb8-U?to^o&Reii<;#JI-Dz*h%5W;|8#PGmqm?w4iU$ z(BQJYXmWC}D?YJ0^hD8-E;NNiqwnUs&=DMiP4(-h{JBZ(yYOW4Qmt`YJ7S49Yo`rf*Z!*Yka6j@xjaG)-lV zG25u(g2V>QkEALFmm(*>d->oGtS34B3QEX7e3%fU-%KHh1Qh)cK^1Xs7vIwLSGQLS z04^J55vB&>ieDTaMu1!C4;@~wvxh1H`{W~{3EG!|TkT;bbcmI1pPt0az^77i2O9kC zbcn&R&S}5AbfF?8+$~OUxSyzu$I*%`?AwCS?VRho z$Ln6tAEkC;*}o7q|Hem&XX?>Xqw~S1*uFy9N#0Jr%x2+OKl*X}f@OoR!r^=FCl>Kh zDhJFi)Ia|ZO=lg|^#6u^6_pZ(q9Otth=PhR1Ox0SB=SdKrR0KdLyef<;Q(AJk<@`;7{~(+)LxG;LpQ+ZUKVF zDGsW=Y(w(Y0(EbqNqvglV_tvwH3IXqGj zKsmXgweCh2f1q0Kz`=sD>cnbTh9Dm?N38u4R5fWUifM4p#weeI+n!ooW7e*3t$2sp z=jWL9!|o-78$OXaRa_WFN%hG9(}~<_{n9fawe4v&?61WKW8{rq(SzuWV(a1%PUplc zbE=HQ_jJ_d+siDS>p<U#!CCnPM{~K z5!EmE_wFfmGWEq<5n7b%C1EA0lNclI$vz8t?)Vx%UHGLBwAgifFCO$A`t-`sb1%96t(_Lp-k4Pt9J zf2bX&@!OtV>;jY1@+<>;^a9o_la49BLxBzd|ESL{yVPH1ov^LYNEtV`p;sbVK#f=QeU5+`xAAq>)31?DA> zJ15zX-W3On6O=TJ9D93=M(Zk`M?5)Gw)-o^oF1g@;~TbiF9%* zZm!h0 zyxaSEiU7W>UUci72{Yvk^Ke_j2c})|#(GkcnjM)c2?=Vmy^;?=bZ2Bf)qrcVYNt=R zq`{=`Q3?8PdTm_xABSOS-FLJvU&CVyg!hAXiK@q$QBuF>|0yqASLTr%)nRN6rq4;I zeCP{w4AdESAcY$UERdK7O>cFKQ82s==N9Gq0DO$jr~TteEH6)$O|}Yu-G(j2U7lGF zZnQb^r_I?io{Wnc^lt{I+CA-51KPX;aO2l(&U?#guktedd89zEybLuTy&TENOyuml zJy|!}D9;arw|%R)obK^0z^OO<{vAN7(cl2#U9Hed!URJlq@2ZE;R0&o4_&xdV*Zu1 zIHDdn3<7rgS)dmBB-Al4(xp%A&{6ox7$k00h)y!!TVo% zLy|8mv&u6RUqas%0xFe4SHFeq&pTlRK)@9Hq*e=PP1G#cR|sTD=<^oaW9DPqbDDAS zM3ARTTG+w#esXu04slC!z$o^&>TIsk_VuF$`cvS){rc9Y&117w%v_(n+ldjH9>aws zxMzx7Jparyw!#M&V8;q}rnlBttOl7Pbx+!rFR$~Z){F{|u*SW(TO+ zy9gul?8$;?mSGP##FP_1ckLcM4Q`D#Ht;)lUe-nTu|T{U2UwjCWLY`LD|uKEM@1Rr zgIkpeg6IKLr$=>gF3W!$japlaU+iZ^F&&O$#D7uywHHMvrX&47B# zT!O{<*QryaKNcvHzUAHNYN~kdSZQ13gE=YNN=2QQXWlejbLI)=8WRUN8cT9;eXk;+ zm#yVk%KPqf4YqBxvF`S_)yKKArdKBwgapYUo+-@Egx`#Lyj*X_-Ki_Rf6W2f#=N08 zTe%W<+?}RrzvlH5vGC4>Y6|4o(vNF(?mn=Qw~Z2X?QE|Ti7W^Nksy3=eczJ0OBvVa z(h}F&5~Dd6oNFyn?2qXO1zbG&t19%Tj6;~rx&zjiOJ=yfr?f~V^`_IQwh>W&6WIRy zqTU0}QQi@JFA{Y6o$Ga!vcEUY~;a#T;Y-8((d(UM3&iulB3ev z<}T(AiCbOn6K$sFY>V2uc6G|i28DcNO*IIqGSE~FfMm;`9*t3duY`8=R@&3 zA79|}biYMwJlF6meZBZNe}FAJvqT4F)y$&?{G{Vn+`TEs8=2S?g_(N5S+5tD(%Tn2 z$5`wz&23W&SD6|HU6X>I1>dIDkeB_(-+8^V-zsU$-T!ZA`MV@@qvfq&LRa>6e7?Ri zlMB`1TfOT7Zcil7`P245B3FOdJ;OQt3 z@pa=MiU7zUCID!JiGa1e`fGM;t&%JQcLDlEjao(x+l6y0E@ODzUTmEIJSifur3@VV zA__njupPfMxi|@5&kn8-M#egdlHa4~X4A`U5i~~|C8mS^H-V3Ts^g|hD?ij*7lR4J18Q2&@RF0%6H@Yao&E*ol&xjx83C|kn3}R zw-z?n$m&wmSqR?g?}XFOJFBd}K>RM>2pt@*{&Tt!c8k0W25n(=DU-s@0`qOrj0^Rb z%GzQLT_w&!b&nZzV(P_m;`EJ(u@@rB|KTMP+rE-j7@1&ZYz+zJNH!Kw&ZJGOlJy6`o1~vLzmWB(X@~$W=G)YVi3%WxTxEBdQjUy3>!1qwjWv#6u8Hr)8;bR9YnqB`OH%bl?tJ zZ^#=?^ZJvbvg5RR_}K31t9yg|#6oHDLyMH&^X>lN5V;;m%1@quJ8D^IQx0I8)L+`Q zq+u>6*pH+AiAxJ}=e;IBHR;+gni>@7JdfUwo3-j=b`?*CmH7Aj5II$nLgGH;f(-NU?1s_i<3W1A2I9 zDNu~RJN<9Ia5%0Df`9J9@XLB4oWGGofeNaO+Kp6Si2+e^eSTg zoDn1lqzF^L&6riVxF}#d0l@f^Z;1t9_k63Ivuo3V$*o!f>ue*iCJm2O4IYknha5q> zS(1k(PxqOAq`_S^lMDm*Qp*4hNd;Bx%PJ&ez@(pR zx@H1^k8@x`qJ86xAgK&NwYX1O4*nPeT`7{r7_Ru7h06g#On<$<1u+eGWtX;)%lAOVU0YpyNR#} zJXya%%VUo?SPhvSPas=Y4{ALK_q6AWxPc4DUbPQVf?%7hw?v|EH1MfHX_Jh5d@jM4!`M@rj@R3 z(!i1%>MXHh{FY(e^{KN@(p8~*YqL_EabGYzT%}cHSlX%Z72({0Mit7mRum@WIU^=; zA!M{EQ(z@l2D}Xa+xJpOLZRKler+1ZWSUt04!Hj~Rxp2A6x!cKZS%fZ>}=d+d~v1L zS-`W`ok`r{Bt?wiLVy#LTlZ;Pfe+-w(Pw=i`!|F01AzWG)KZ0_SJ`ZELG@yNsjoHm zV)ug@;l*R0x>4(?zQ@5FcjAi3DcbFr2vwv| zAzU3enwdx1z*edOkrS1;Kz?c?gb&=9Usp1%;Of(}!NW{qXuNhsBz!~e{-)mPogP_7 z7!!Q6&Gni++7JB3_$Jmd*~}&ow_KqVbz+$+5p~&)TLd^xII&H#*}i9YDc>$!6DgFT z{V-EXfw9wI@0ue`=WSkLfRulrARA2Wvec}U@zQObsv8cx6+_Y&wlfTo?+nP&`9HjV zK0Y}x+Si&WHu`WTeBQ(=0MW>m2EP(FSs|OxotqUAWj?Vr%{_HTxx8nA%oXKg5zDi8 z&Vxt?=SmTGX9*l#Q9crX9t~Zz?p&nANbdKRy$U1!x|maJ>DiAyi(CJLcUi7%(>$ZE z?}*GaOx&!O`gOz=vXhOT09SjzT?PKn#CiGunK~rOpy)IK;5H(G>xLOmV z{rHnwLRdLEE`{-j1u(N-|5OzCn^imi62v*>E;Axt)@zmPj^{P)b0d<&Q};9~i+LaK zj5zxi1v$T3ZOS3(z_v%Y_=ifY8IFa9&nu~YFnR1zBOTKRnRFQ)BW4Zu<(Ia?FGm1KO53`V=r>zp5ZQwVpv?!oP@P6C{VxmmD)fLizy>D%c< zRp9Z74__suo>&jak8iLKBNpJ6?}9wen_9QOLq)0(tAa{Nfg19=Ii1?FRW&+ ziE4v>r-2F}2a5TlX3IB_?pl?*5v`Z4q$QPXm5vrtc-GrZ{BuO*syLNO&c{#7ACzZR z3Bf!GWu8|tq7N7&#;TM$@#MSd2^`DSFVsCC5t+BW7@}*uhVGO|tG#{)B0IA&pE20q zz~5U>hI7bQeT^ao%_7OF~(8$2%eXDWx*C^ zn-|`$y$Zn}biEs5WiHj($i7HeKS)*%e`}1(3vD2ZQztIKeTu^6%H-Dkm9E zhPJCiokCGZtJ6B!I3nhsWYsBfGE78fNt7Avw)9FT(J3#lsJ^+t`@Cp*|U4S6d!mxT}AG0KT?YTj!$)#b>hUOkPK z8h@tm$vLCKDn^P)sbWv2J|}J8=ObzUW>w( zV!hAC>WW0+d`v;{DDmSU48_u?Nu#>IPj*|ij$+WcXycxrdMd!fVgtXfyo5ROy#^Ov zT81I7!WoXv5#<$1;P?I2{qn)zC86SC&(Qp4b&t}{^7eKSV(i!U8dGQwt>BrwE}85> z*jJR<^qE30*VwUcztQ0(vp|n{iKEZ_{>U@>%-tt&6P2Yz z6o1g@Q-6h4cR=Go<(=a=-IZUjK)w}PvPE$Kj~6OD?;jtOXwF9;-aTR}d@A)t^wmk4 z+F+z{wU|i*f@ZGcp)`48@Q<8>Ql9V#bS$~~S9tI0f~hPQP) zb*0Gh_sA-@D=@9?7TNy>hm3fv1KRZrL}FG2H8t8HBbDOIin;L4bZDN4S153Phc_Z* zvRqb`zxn+otj}h2j2<6nY*(te?(@dUdyX7?9AyM z>#5`Jj-#MN)=qR}w7t=S8rQV$sd2vl@Qw3%+5_DD#UzDyw&PFFdqkgWDDbt*F4IFKa`KMstoY=$T_c`Hl?$aPz8Gt}sj=l-#~)i{WfN%QzN!&omZLrIcOUN;ZoK~} zOKn+nhGUT5{56Qi4V{WQ5YeTJ{zu+$$5u7z)^#JA(zm?tNC#DwNuP?|&p)|S307tI zC=JIA5Tm&!VtP!O+oh6c&OkN6`PgEujpELKT!^vWYV8Q&1;KxPZUoACYX(T!- zo>~I3zDP4QYs}N`c4o_y;OspfvRROWrr{SXZ5M)lk*Kqg)r;#@Tp#lc9gpm>9$b4j z#8F1|^Y6%N(}IOp5LbsgaNsPSq6cYEwQswotXqL5F>11J5~DCSb|!FECb{0bVIbkC z{4GA2jC9Vj&{znq(>+g)o_92h`4dw1Hp|&)!DsD^4m9yIx$MPRXO3OkiA{Y}Pv7An zJ4pb`g?#sk?JIUzFCyMMW{Yl83kD75rfL zjuF1n&Eq}iU*`ocm1`YcLN(Jvm(5No2I`4>X<<9e1MwUt3hG`m(2tz08c~rWg@}ps zUJB`@xoNS`-dTkq&O3mj&=Iy_6P>(`_>{2l{z0xHO#!4He>N_@zw#fYKGte|k|5;H zsb?5?dkmrsp*ihn=}@F!{E- z`5l)W|1ko#6X;tT8)M2XX%}9-f%-@c`kU#s)`~~~%(>OF#ntx7GiO3ZtwXksN^lL( z%VwgE=T2KQ1*iuB!r)jyfJun<2^Z8#9rTO);%TP=zZEVFU=Nb7mU2j)YUk+b^E$O$5->_gr{TxOqqr5fB; zO&#SfSDtUv?)nagQ#f8-)4%d{#gMxDg&*+WPkD!o$qcCS(uL1B4kiuK#`*Pe)1Qho z(}cdkaV&(YCUG~)rSxrk890#DB4Mlkx9`)-$WSjk+8H;^upwLQ+46zjl9}9rgK;2S zVt(WH9sk?$?_^zFa`EEBuD4Qb=CizJL=2W)ZLc8s%JL#vm*Gwo1Q}#&uw+w`h!1YxYhsN%^LxmAU!Fnx~cAEhMl~xa-pnvHrFhR-hmhd1)GE` zcbw`6;-()n1zbQzl1i#n>4gjsgSv!%0cvT-r z_g+sqaS%8yJT7}Zs35`6|D}ssUuW=z-nMr-Oh@O+a`@G5viUY&U=;zH+2{m**_3fXXKr&( zMQ@aESGnd}q7SEr*qyrk@ESXwHaq{`X1~jQj~FlAm<6Cmzo~l>xr>2Xyh2VSE~-^)Mbng%rP19h+6#ta#z$gFowqyf@{f0NPWvD-W)9v1`!swA?X7@K%LB`S=WWV%6J(z*aDecPe9Vq66{EmI{!m8=4NEzW)EP{p zkd!a%Z8-#XQySW}jkW^YZ48YOd7;kvI~yAXcFqHluiE?Qf^vr)D8=Kc%NfRaOUI1u z@bbFyzNVFE_#);sDU8Yccfp+T(-WNZ2TM7sL^XC#Q)Z)Uh&QTbmcR zOAMwr!uFS)&;FiM=NwMAz%Y)gdSn&-qEBhDv3)JReVrohWr4-X0w*R=lVdj^AaB2GinIJXmNCx5C+y`|0m+8D8hC z*QJ4QWcA*wK*3mtGB#G%xE`!I7f$7JltVf9{b*b+Ve$zLzb^PNO@YtWcZ$g-ezUCd(9!BdlV@gdEsK{rW+aRDaVE znI`M<5}(yO5)9l4Xv22vxsmY;)D8z^e~Kk#koJi$L{{z&zgg;Sv5=66f-F(-{Z~AZ zcGYFH64mYN7J;W!$$I8ahwvZGj?_IkdNnWN?B=ot>ffz#ww(S@D~1#dqFaj z?RUU7h4bVr1yHmf?pcxl> z?OT28-vW|Gwd7YBR>DBxFJo4}a;fa7puw}vGi{doLfi#B#KGFJmbdom@GoENyY@e7 zpKk59`Sc1bKfBoXTr^s9Mb&K6p!&s5xbbj!&wI6gpzUbsZ$DOB=2i?~0Rw8CO$;vY z6~sWp)1@14Ny1HEs$W57OLo&VnP@HY@tHTqsl{R6`zhO!>i@uh9SE_$-Wy>+->=*} zd*4=}t}@mUSt-7GS)TZj6gVQGDf)pn=v+g3cAMb(*CsU9!N&wgFCH_RY+p5kqm@m8@II~Vl_$>}*T$?)nD-$-Iz&wJEJYzVn$RM}uXaJUfc$cjvTQ;;u1 zdkd3Ij&=I%#vv_njVxm>_z%i{QW@55$ACyI9efDtd&;i5ngp6_T0J%6w&8suVo?)v z#eA>MLrl(Nm2AqQR-JU+ZECNKarpzgS+m|z0;Dy~w-*^#OOnDQ8yE(3=LX0J_dSQh zEJPqM9C|VW6bc3=s%;Kvb5D9rQAH|Gl^?+MBWQ8stw#N{Kk_?n*j(otGEHga^)O+Q zjTT_v=-U@xweVNdt;ICkEK^1{@<1&TolZa(`ok!$WiC$aa=uicvxQ>_{#@2dHV(UeO zYWXPl`{!Fsl=Y`$E0ecoWJ7zc{rc8H2Z7KNj}iBjnwh>7b0Wd`-B?`KMo`1KJq#E(57%5*mZniOK#(LpR_HyG+V9+_3vkI%R%i5Ksl4mM zuE_`^gt?@vXgYGONlkywbWx_?sq-IX<)aPKFQFQ;hQD&?m@R7{xJh;k<-I^cIGDbw zE_PE~2}xuAJL$+y&Dzc`6qEqgU`gY0e|1x2UMK1?zMvSTZM~nR$;_eZ+Kw!(4n_P<_uV{_S-)gE8y5P}=dBx9&hexb#Nk8Egu_%ymiuu#N?Zy-U+cGBENhT=LpaI4D+5irqB)HO7LozB0&#I@kw;VZ;Co zTJyb2oL^Z=7wnoVJ>YF^!-3y;t;F2z=(Vl* zR6Y6e##@7vgR%FG z8klT_xXN3wU31FqHuo(&nK>JzHzdYR#B0bH!{fp!f)z7#Qc&c*j~yEcok?yqg``{t zc+t&adXlgO{PPb|!1x{^y^kq)av)*7ZDi#{zI@1X<6gm^eFn>Y+d5v{tErN@w=jYD zQ8%9*ntP|p5aac-^+3DUxVEk2#p0^t|EdX83sb|z?}esQ1{14i&6361b&KP- zUI%9T#vckCFw$3-PFOi9Ms4@M7(6TyJY9*VUKl}-8J*=nyi>Ib< z=&&xS>enKf*AZ*!&j;QNZOtXb{hjkOnxJbB6q*w&0ep^WAjC?X?MIW?(<@1atJd3_ zUIcm9(wxxTGak=DSN^QdcClmYFH`SL`p`YWUnE^`>mBo~#geyTv*Fu2ZKKuT-5*GR zU6X-jW|&v642*e_gR-qT0pZ_SJG@ zchoFRqD-rELtn@)_WVe0MEU-EykCFXFIv=U|6XR1;_Q0CtEqDDqTtSo4WE4Cc7646 zifqZ1gDY;;rS!(cQKv+0ig@3jlNqhurqfNBSKjOyBzU)+`ZE^9#P+$%l8odzB+}}r zv31mcaB|lQMRaySl-|6!b$;D}xsI@WrbwKgg)_Nr)0^kPUdNX7&^p>O7q%M4z2|p2 zSw|)^oKosg+xBz+85dmdyD4?~R7`4{+J7R(a;OxPQ(XhSzToUbsXYWjT9RyisP?N$ zh>41gB}ET<4P2=veuiNa;X`>;v3-o~06W;dnX{9ZuHr{tCZ=yWb%=)cV$Q)4<8P)( z0f`_oq6;spUaqj+q(rZ6}A+?n^p22 zTF3Scz8a8H5Y6A!LBjgi8YV5$Fzpk&G8chB`8hX1&XooUCwZgZ)_0q0U+Y%=gx9gR zrvWL$+=-y_e1%?HsYf1M_`$f%^%Ci3MT0|4yI)lqVKd`gH^+nwmt36Feua)4F@1&< zN-4-!yDED-{5!gLq$XfG{~Acff>*vxvQK_sxAk|OD(PJ}(|xY*KCo-Xja~^*c5xrU zMuFe*ettXt5vP9L(^Y&v?sP=YPQ6zkFh&>uq0h#d-aMhR-7x$>_)ufo%natiEA*jQ zG=J-xYc*o=+PL*SO>Vd9ajGlK!>RVy=pL`)sv8dx!_HU=uErfsgy&xJd$UbbvM^Z(TgAN%Dz4<>Dd<7^w_?6lO}1l zpV`iGESR8GT={c14__v4=zcyRM7k3%+im(i;!A7l?o&BXuRJ+8(HS&Hg%bTzL=*nt~YN|2@upAAOx& z>tynKzTiw3rqFKbzUv@pfB|uuq+-kSOO5v;#~{fB1iSglf~HB~9cSuM%u2^^46#jq z-0;9=x_KB^*W7jh;J-lxz;Di-MtW)~e|foaTQ1r^FqfQ2IBiUDv$ozFeB3PeDB%+V5C0 zCjt7?3zCxOI2xh^_Mt>yp6sFvY5fRf+VCf{1zunFv*@c;&H%@x8F=VnM~FF6z3zD>ZD!7T&G@EmaSIDBTJ%GhspB+lVjYanXwR5N;@wd|NFf62eWd zDd+mc$Dnl;;E(PDY>#YZDou8WBfU*aez^ueGLx2(%kPR~P|C%)fO{ikJ@&HmT6j@s z6lv|pu0dBwBQI!Q7?fTH=@86!8*de_a}2Qc;b%LB!X$L)8uJ-DK{ zY|O8xnOWJ&Ug4DY-VaEByWO0@3!REZuNznitE|*mh0#lkYxeJrv`@>H7%lH=B1C2L z?9lVUR3)g>H?7}aMio1Tp54bUuJkMFThi|G8Y`Ixtnr9x0jvJSmZfNrz>qQIJ=el_ zBCkucwc`v;~a|akR{X3G>*sSZlAXnv>h@lC%dd-`(3g(5*{(mvl^R z=>`wX`a&liR!TVFzsn#OCejglQ>BrNW>?9Qbnp%@Pi_}2h?ta${<8jpSPyDD_`OLb_q0}v$QM7f)+Or39HdE4V zH~$j6MW2op3qh>wmonJ)*{4uq=E+hByAQqlXLdBBQ?ciS7{N#Fir)U%4h{CelLf|b zzbe~HXVG$NT@RXgQ}A5tPf9xb_14nB8#aUWmM;8%AqT!DP8+oiLwrN3NvC z;x|e0+RjFO@5svBiKlk~t9%584GO|5B85KG$#7g9guzZv*4j(-XXmvJc4jzy(?=-}PQd~@P ziZ2Vckv?SbXz(T7y!kzQy056IQ^aIKlE4d0d8}Le135N<82eh<_v7$6f5Ow(O3=qB zr=$5IjjaB>NgHUVV^*K}#ZF1H0qNAdLK}+3owAvKSQoQNpzsLoJq-KIBj2*rsH?77 z-i2M0a(*HZ&{I>^N{CAfY1woo2I@LM-N(3gBf+TFlkrN*`NZe+2Y&jnE2`wBU(Vsm z*l>B;xq0V8^MNwqsqhjc32E!Da8QLTF=rumpRqr>vWe@TwZ<=E^@=szS235&u;;5B)+lsM62 zrf2@0Iw{!JQ*OVWNpo)dNg1aJGw)9skuxAe1Lr=9+?!R#Ly&HeB3l+Jle~a*Znivo1dtKG#@WYqT{c#hdXH za@^+jIt=Q($9Kys)R;LRPW z@eM21qiiyjvdm(rwLiU4*<}kI_mKXV=_bqmYR65k0dQIc+so`k2`z>)X1U4L+Xur` zk7t3&sNnJ=^1}apF`h}9T(F~js>uJ8$`AbI9P7UQG~l!sI^3q6HoN58chki9AUQQy z@QcEw87>K)BT)<9*_OjiJ-liLb(Bk>AFXV9uS-v`G238M7f*p`)PGv0Ytkw*SE-bF7!x>Cs2U?eVX$1d0 zJLCqYeAqP?;$6BgDbph9;h;3+%3TeQVd;_MxhvAU@{94MKu)^HcuC4?Lm?03g37lZ zW**PR3s^?ycq4YTpWD)td zRL5tE1KojK^UXj6Ko2VFGk#FX0bu$tU<*>pvh4`q`#^DR2Cya>w?BhF5sa5xYzPTku4Pe6sUm`=3K{IPS_UM&}0C9_OGT z=O$F=^wIn9(EzQy;62QeDVkI??>Z5lqa3jQ?B&1HebVu@qlafUhU&h9OXdBS<^CCz zv=tY=m`av`csBaNqVjWB?max=;~N?KdMEySX>GcRT>q+gG=!^B96oGFYKGx{iwm6$ zcg>uk)?RoEzueEX3P&A0N)PW<%kS{KNaO*3J%}V1>zVV>N6&lKF7meTE^~n2gm9m1 zFeK-0I7{6;6w2^oOd?x|7`L_Qw({yQ+2M6+^}vkv$j*V-%-RW3vf0Il>jBd^J{4waLKZ18nnfu8v|kG1G$$j_kBSTg6*-AA_LX!4ns zzQv>ThTO_EZEy8M5xtyt@~oxJTQw6V#lUk4y9$3yFa#V$r5-3vD63tLFsLMMKD`|X zp4oeZ+lR&V;p+L3wrC=Aw(?2!#u*y&`}%`C>W|Dv)}y=&KLRqXJPaM2+OL1dTNjWR z4}11=@2q#vtFM$^-;c^_VQLc_7`nbtUjXYddN%BN8kGa>hfY_fB31AwpSNM^rnyzI zKVfnk^*f;s?us9~@r$*4GhKy9{Z@B@-e6_fckr{Rm5AE_3#u&T+)Rv&+45J%3^0N) z_b#hLlAb=BwfxdB)o8<#oI&%K}Hl}Or1 zlJh(*p-4-h)!BKizii7P0y7TzLHdJeyn#F&B%Bzd1=z~RFp6tHuqh&1I4+=RM_1bqbpQvZOP5+#OeQKH| zj`x_a0gP#T^^1%Z|71B$Qno-bojxF&68wkYF)f*#H_!NlwzJ3oR;&K?v(s*G=Fpt$ z#`Gpv>Aqe`0%tD>yj=$_2>7`$D&p8*qx)+>6F_BOkhl$J_Fcz6B2pwt`{v23k5ZPK z+BK5OZXDdBkeozI_KiBBUtO`5fBXYVgPsP&5{)HIST1+Yy6WA;>g1scu?-4mQcNn8 zQII%n_K8_|`Mjet!K6A$JFGNZIrgLlCbP(cX_eOcUDJu1YI(Xo=~ee3Mr|q^?bxAd zfc*BiMx}@1UtI;f8wz)+`7Kp_4df^}doO3!jCC&s8eDnVI#gt9Z=#|7L~(56IQ{x1 z!^`a`m{C9K0I{#KDjZwGZ5d^KA5xwZ4KV%>^Of4+mI@6pY@}A)Clb`Y?Ci);P9{&SvgZw+o+J>pV&z3dgd0XuyG5WkNGmKhor@Q{!$Shi}~0f9mk03TfzSBOn&s8GIL{`(%7}5oQgASI>CyTlO}%HnF5N z>eJA}sPfN$(O8iqzfynM8|$v6B*l#`cH3gC<58}16*hS0wwisN!j?@0YJ6GkT+18b znv-*?Cy%{yR~;0VUfe?5jCOnp$1fIFx{YQrpBNPlAj}Exq&8-!59|)qZx`(JS7HjC z+j-}bSG^~w;sp~&DxcP|l3|7~fmVLtXKxY<=3;Fdg)^bHS7nmr*U@@YcN5B3@(bso zuDA0;NsYd?D%&|bXT6lCcRe~&PRVS{W}H_T7r{Zpr?1c4oL!-I!!Xk7@8>#vC9$nEw7@c*7SjrTsPY4Xl>1_P#ueN)AXwf!(?&Yy9|H99h%*?Q8vAJDTr~ zTW>D&(KJ%@bNF2F8Yd+Z+B8c|7k}3Sc-Q+YU=p^A08X1#AFJ@fN2S~ETX;j?gutS? z|6y+qRsla(y7y#^Hn``;z7jyLBb5$&vQaM88@5*jnn=4qRKMNCPYE9=vxk@lKigmS&6l(eR-;a^xb8er+YdSQNi0$7B&Ai#R z%HF_86_ZYiMs^=_@QZW0iGK6pS_>9o`X1d~sOH5s#!Jwm<8Hk{H!|RCS3S4MC!ZE7 zTan#H65)?{x^V_X)*ZWKyDG-_Jhv7}69$6!;4dG0ed3BjfxKi*22>|QbcHonYgM|P zdipwl6FNBt)~oF-LiUWZ``qy#LjIw|W2O0;|4x;>Ih{>2vG2$$pA~t@P zv@ifMXQGAd4+ng6{|k8B&YM@u>e~B7!ZnF-)^#Y@z*k9Y-p9Qu(ULEje zh*GfQ!!nO=GbV?`skRe)v$0GP-jTQs4YrJh(_FbbbBtHL#wu&rGDhIic)p_@gy&60 z(%AyUI;}S8sG-4p*u~m*E}^5=X!*L~q49HsjmaunwbSB;G6F-aJ z+;@PwIqdc9lFyM0Yg)>=@T6=%XWC7NW^Ei*?Ud|*KITKWlicd4R2adsjyk>LwX;m1 zmK@B0;ir-LFevYFZ#5XbeO8=nyGzjw!03VeBULbr>lB-QMBJgDEu$Zv(i|R5KH^9Y z<}uB$Zm(!+Ol6I(Rj6$G=trGOUDS0lwC4)&I{&8RrAksu4A=hB6F3)a(95UF<4?$L zcdG7027gC%<}l<^T&YHvLM{eUYQA5tHJBpdCKIoa)cHuUN$z2BP0y*&qy$#emFR4em|y7Mx$o$Oy%G=mUB*^vGI)aFh5O zQp%Qocg#JGpYYtkK)NTh;x+qjXeascuq%&$>e_>gpWFiUV!oN`!4r+uV;G9Bb}ObHA{jMbudo)=fk-cAXT&OvPHgT=UL&k`P*Ia$PEL3xF zMN>wN93v>3@{C7&CZ^6?uo*TH38a3t7v9MJqRu_9W_miz#n~xsKDf*=qdUAT?B%^W zZf-Q;eBJ9cLH0fnm5!UyNe6>cyf)<5j+O-Ob720Bks6;bnBK-eyUS8XYzsT$9L47| z+{)9QK2Y;`jakFm#&}&ELj7&GO|{WO3f@hk?TH)}P5m7k&pX6eP+wGZgtPG`)88wB zBWJr3UWTuWlVr-?W=^v7j3lbAS@Kke2%>97iNE>Iv=3dWaKPEEZqjtmLRZ z;GBG4nsj1au4_NFle!z;n=%cJU>yqt9ZN>AKdXKo4fIg1B%A&06)9FsI$969E&=uE zj37UhPY#anm0t`O@OGS;aL=K?SxuPsSi5mAF_$zS+?>)Qyzl`P5e+G2p4jIS9&BC6 z$-qgzsUAR_JoF`JkEY=aOS)TkT+YaeGsqE2qimW)SKadY*+DHvh#c&|gsIlv+oMDB z+Z)hbyGck@DNP!^mPh!B-*~+ov%PlDu7#_{<%|Bu69y{)JPRdkTD9?X497`B3Uqio zJW?=?L*)a0bDk)r@B4ARGP%45H+NTD&`6};t*Lx*Dv*wwUp~Y`SCK%6cMyUVq(@QwCqP$Dw zKg#mrs*h;u=&rlzh8pL}!{MS|E9}eV4l=7+fT9(Td#*%MCbwTSzJjzao1UZ&!n}HL zYRxz%Il9uQ$PWHSI{mnwQ~=J2@M^Z*CraOCjoS9Xo%xerBZF1o8xaHpie+~#gF{2iC9KE>JEp3)9$oeP$ zuKX!bf(Y0DgYHfdL*4p(I)@%HrHWH+jb4v-cVV)`Ny*s}>@I1GDQX#YUp>~`mzMGA zZea;k0kUo;F((_`{4U2EDM1?jvXNV;C1@1<#{hu^Wr7DRB%-+SCI*CndJ4a}9EgDa$g)$*5_ks{vw2Ko8Q&_Expk&d-#c4e2D&+_!3{ z&3>N0q-QlJL-uTM5eL25^#TU;c1s+)vD5`(Ey5W1Fe+|`*GjWwkh+OeQ<;rhArHkIq z`6O`1UmF$Mgh3stM@6cE3EY0{Yi2`SjTj;N(f$pts@Cy{*1MJzhjz$Dz7kvCJQjSj zDvXZ$b-$)D-)g;BmTg4<>LUfTPubJa_h zszs5J8spWOwzb=pmf0S!a{GhN+H9zEjB9h#MZx2qT>zC(siP{R(AuU0rl482N6u7! zc~x|{#;1~eDc+dO>>`5&70)(6VAw;6Km<@P&nm!SJo1N@MGbjk6{yW7$={ciOiqdQCq_oxGb1Gm&M!6mheJl8jh! zC|?7UBS%6??));S=lyIf1_d%~?_9L?hclGztk-q_#a=D|#2($1+`H+$)W%D!{wWI| z*Niv8WRo~SCoU!Qdt{x4AYOX08o`_3PfF5i*V<7XUh%i(vZpc|eMsaS6_z~tsj%eWyW z2l~!oJ1wOSy>pJPfR|@S;tsn$_qk}qd0kRWoa%iv9^~YD$Ed)i)!H7P#uATJEi}SU zB;|kK;e7;7dFyeu#>js|b2kNZISk0?&IDauqZ;6iAE!kj#^e=nIzOlJe4S_sx>k)0 z+X75b%cQwJ=HE5>=<*}u%VstAm`b(}ExeF83|qUdffgOr;CE6>$zlbpO*ZNW9zLye zUb^U-L+sV3m8HDg7 zgDjeo@LYBwF5Y}F$)FK?{Rw+jQl#NTqhVTvT08gT*UcRf(v!ufY-8RDTxCdoOl*u% z=s{bb^ZH8gH}L9{=)!3XIk* z0?Vy*oL)5#&+|wC+^k}MsM2;rPn~m{9xxH-Y$s*(*2=*VPZ%P(+Pxo(8GY*AqTQ9H|M#L|d;hp@eO3u4*jjHO2<{swa zagQerOQ$DKD;bpzEzPhxVkAr7nQEdorvf>-=ybScEM?lw810CsQ$9n?4Pgr=M~9G* zCdza7EzLm2k2Ct@$P9A}dSIN$G-*=$q$X**CJN$#ULscb3p+)W9+t2)ro2{|N53#@ zEzGM%JBvg*6M|-GgMG-e^J#O*><`dwioTY|&Q*_{&6X*kF-mg(6Ol@ZWeXi`_m(n^ zybk$}YL6?9ijH!UaT?E%*I5g_TL>CuxC%r?cJ&5K!D++ygYJV2c$aiH2f z0vN%Ary@TfY4se>8VLW8tNEmGgQq%$C>HRSp_h{|z5mEHJYH?hbDB^~2LhIZr?ftj zmHZ>61O4jPUVLa|p+~c+LIGK;l7Q zf-DC8ocV{lk1L~%5qEjvbDnHqd* zra#aA0i^S<#?=*)Jn}Y9@TIjqfwhi*C3tNRkZ-r8jc7;$^S$#n%Q?3iyQaqE7lMuh=DNbF`ux*z_o$;k|t&g`vp7DM6 zzHSie_*)+i&BUEvXxV?{#I&5_N`^A}dW*ocS$0cS2^f&V)Z^-ZG*eOeK&|~;0j3cfh0SmY6+f!eNt{x+TEO$SbY3=Cb&COkIyud#*Lk zanT*N=%Mi)Kei}cS|b_7hbHgak$Eyeu_U!1wvX7LfY-vavQ6e_&vxkwA8YQDF{XnpS-`+ihc}Ssq9o-S!&X5 zg*1>=_zBqxkAvkw%flytC>@=bKK-?bTv}4?X2s{a;qH4^_7m}*Tv62r6v2R}6HNYA z^=jB-Bg>uuRK7p#Z;%Pt=b`gEkVd*v#mY%i>*N_RM>j$`}9%lG-ffaUj}`Q*+- zmbYYo$Y^?Zdn#Eceuq~q;*up zPlgmDd}|e}0D6AS(%U)LG736bpD!tcgl4Kt=3L^4%(0b&A?@03f1mWGZe?$_=-c6Z zRA>|*y}CkCBx{0QYW46jUR-Fso!$TK^?k#$?9Pt}cnCK+1x$}P3yRqkQLM8XP{sUE5>c%T1sVC{S zCyj%VsEDiN;Qk$GNVnhka5ONN6zY#L$x~<#pGercJe+S7cDA9Q!dPw7^Le`LBTF;K zj{a$3xqQSL*Jw8inwz5AU&)=AN}Y{1q!}$T4yty39bi&1+hMOjRT_k+pm2XRqtCX$ zn)Ut8rIBQ9MEp(l9j z($*1{Z@`lW2n#(p(MaB%OnFKg*jpYLD!9QV+uQj`w^%GoJ|C9nc2Ub-6!96|dUGi2 z6$W&7r%ur9r3{N<)D`{d)qLLh@E48!aN$dSGxgcU%9!~#pC^neg{e*M(H4CTieXzC zi6!7Lx|{=>6LY`e_yNkI{UY0@)cs+`&{CWq;zKDV^pu5V_@%Dewj9c$^K2__8t$2pz?G5q0Sg_F$FVU zw$!u=SeZTvI_&zk@=uOqo{KcM2UC~2!kgLImtVS+8nX5ey=hk*wHI*g+;Rl?k-Yax zxhUi?AE7+($d&WZ@2<8yzl5=3E^wI4XOGF#{0U1-KSpq`rs@W365C_Q(Xq6SH%vEK z7wOArm;>aX(4UST{pq>n;_{ypEX=cAFc-l%uR8y+mdd`uSCOY}8$jRw!!{ZCMHTqnIZf=ek10FTakRdo7yv%= zoFn*dF0bNiFNGjLJn&uv_>Lgdlsy!j-gtfmhu@V%x=l~pI(8OD$7lyxy`9eBd)C3Y zDC;!{8~5!!&6=K-5V+?5JEQiSTbt&kXtje%T6Rdsp3hmd!@XzuT(0fHckr=V8zXrC zBptxRrHyRUgYRsNuY z={3d~Ln!@5Kat(+m)^El7_Q>Qe)4+QKd7H=zf#h<9bv?-k(c1!1a%2=62-I4sGcts z%4WAsLf9Q#Lz3&Z}_C|~az}?9gPNXl*oC}-BR9gfT`nd8)YI;TekupqK6}Kt3 z9hVInwZ036D_<;19YK!YI{^EzFm2y7+!}{z21+xwpB$QzKPVA_KZ)Ftd3fomJOuE& z;i6=hrfa4BytZ{4+4mmPN5godsRxVcZCK~3MohWYp68#uIy1%j3#tiH>7r!-$aHhH zeBmB#$_f6T=jD`eLb&+{@b!9FV)WhGiWb_;UcjosBi~utucm*A1Kzs57v}4!@y&~k z*wX2q*~L>}mJ71KJ}}a8zlC`GeIWlHyEi)x+=6OVnxcc?!K%B*L+4eZaMR(xwA%MP z?5(5SUeuN{yQQ9Oc~o*l?uG6++Rd}RZd(Jvbj*H!GmC)P_rS2oU)p-Dx(HB(>S?Z_n(ZrW-55F z^@mq5&TF1N?b>A5FSj4gHw?X%FA{iFS%2xv$4>q9B8~2|28UaTyXEJtxfvd<4+O@< z-VT&twY0T-);wqGQ>xZY>P)b)l>^0?M8Q+J#G zBE@}5hGNAxd43Xa;2%#YVK7^{;oJ-OWNcQV5j%U+1)wt!8!zA`fr#MNP2Pc3EoO^) zvy^{$s6EXER4}S$=92xfo$X22@_+;H5nRde$k^`EsA73cX4}_tZ$tq)q-5`jinkDq z`>pH4aGNz>vi{glZ(?R=HXIJ97e?_sN3IVBR$(sh@5VBo zak00f+_V{V2~r+DFM5WaSQiZs9e!+Zhk4x1J*X*V~Os;||>C?_YlVbn{y9Qb!6a{J_in zXp5^TMVWUk=(uRAj{!(JiikX7Uu2%hjEzeDS)^ujK{D;RijR?x!qjaN-&b(qNZg;aZrXW7Q0G?6 z(SsU`(_9$ln8%>NH>DZfrn-kvVUV(tuwHyIDEpwON~JF8b6@1f_R|^O*k6)$B^YN* zI^2d^HviCC)X&byHv@K4K{Yg@@!}Y-+ayrei>deEwr?T9Jz6L^`v27##K~2-{ z5Q{ju<~To2`=wr=e?@YRs(dLV8gzZ)-NEoM|BUC@+=A`$D5Xfe;^Q8LZ}a3S?`z6%@u|@?i0oJ|M>pM8c0*T$qp-MT_0NDQ z@q+AzY|R;iEJO4czmcP2$-MV}hpSoH2TcK+?R)YiifKoNplcclpu}}y!9l;tGM6`U z_AOu~75j=$CxZ|r@%gkr`k7^{5kGOnxP`8to=8uj>uA*wY1^FJM=G10q^pa-@i_JI zWN@e^pG&+l?63R42_1D+4J8Hp7Rc+L>baR{-Q2)Vt+_v{K-z}iiHFQ<_rzxraVNrq zvd%>AeUmdp*o}aCQg&`A>^;x_5xudkv(QH05#`r?ZFg&$MBj%PH*R?TqS|$WVY*pA zqTP6vH~A3NL+ZA-3=vTr<2`t&fu7Z2z`nLnZQ%p*V7!#q`Hb;dO4pBn0 z$0y~cGs+)5R@;B_3UM~tFkZ!baj3jOqEt2dOXQ^E&UB%ljx~>AmfqExB#+t?=Z*sq zJF*;b6Sl$7LLdIJw(C%-LnB(EFHO4n3$YhTx=-}NY(A>FPaA`5v~;%j6L^Icz|YPb zfNaUxv$Z8!Kcdd4IR8QAZSvLhKdBB`KUgrFQcwGfJ{nx^DL>NuwMY2+#44*8C=j~l za#KwDXzVLq@CmuR(X*r`eV5nIb+htNjCrDY2{)Ms{+b)B-XnpV_DIP#cb>aq1bxk| z&WRN_%rLeeNz>?quHN9Z~Ilam`rg)=F1UzgOt=lO8zPz1V zqVoM3sOfQ|o-)rh-AS+&9gUo1=WXq7`{JuO9Ry?F$cNwB3d=njU7S|kSdCZx@)5K-Z&iR`neRx z84A9cD!Yl1(>SYEtdD9Fum5~JBL&4c0YUtDh@`%duKqm)`ouFph_4&ELwm4>M=bON zo9{)&O6U7Swd#n1fLx-Mu?JV~~=59&?xoT$I|SgB_oI zY^^}pJ>0(ajjbBg**)b|R^Iuy%Y{i(xe|L|h|;fHj@1v3(`df~Oa0KDm{vW-7ErJ7rT$2CuGfk~tN>RPv>fivR8QHC$POHpY5Nq3!n-~Nzs1r!ygGdm>W zIV#RHv*rAvevR?zhX*ygTxWrdR9XLrCC7V9da)n>jdy_OX#(hQt!%$^v+fKQN%^P> zs7O(Lsk@sZ$Q+N2We9-$~%KX(=pNg=b8DCMn6t{NH1Y!QQ zkJ$0xbq%}-TO_t783fWk3f(Nq^&bYRMdsQLClv!%YY#2hX*aH}#<_nQ;1Ik-q)zD^?okT~k66Za*+Ozo9B>kbabe zS`68e%525w6Oq9OmTkv6>Hp>5k9`A1ky&s?E&J!uVXwyls-9g5WiMfOP z+Zm>_#{NcKrn(Jt+t$j*c8#k~Gp|<&8TM z@%Yq_i9{V%hB@K>st(oNLWiO3h9Rhi1gM|CI4V83Pf;MpNb%B)O4TA%^twmF*U?YC z!A7ebWBqx-{aU-9Z#$QWOWFAH@_FL(boJo98z&L*3m&dYf}eY0`$gk9DtE%Z5Viwf za>paeB_)46U0AF)co8nLczgYq{9P}^*y7-d)KjlJ{c>|cHjPUB*?#}QmSlJ=!W}0m zD;jCQYdq&9yRgm(zjgbzThFh1_k^#g2-udyZn-w(R;)ZtZdQ@K%&!Donfsp7*3fhR zcWgyMWEy0qTAD>t;oQTq1$Kgp7KJ0MvK}ukF9_zt&Pv+_r+Pwv$ zRPGk{l#xF@F{p0Fe~j~^D1G93PR!`^wKoEAm1mTSsctt+WqW-tgzm?e`yY7B-+b#t zFLeLC6FZdl{(+S{z)L&VvVg<6Y8C$JwjI??>2D%mD)?t4U%i-w51uy>FQ-XyW!?5t zI{pKm@4Y0v7(-V6()D6QSOQN=m?%h8hTnGkCESy$y^{@em}N~sgJ2A;B?tSa`Q*i} zr4aAeAAw84jO+O!FAjU29;V~U;saN`XE=3yt~1>wfX=P~V}}!-5w!tT=F=dcq( zYj{heovtOsNd9kuE4cZkzmBI1CYmmPTv|LFYPnA+FY{bFXwIfb{YYNmSbTvii61@r zYWb@LLk%79BEJXmyf&?AJhwn7tyJ#92CKl=8v(4OH(DE0HA$bPD(#cPk8Gn;mR>*Z z4*sEX<2vN<3%C|KaG#%j4^fIayW{y^K+9qnVc(+Qu&0>sEq67U?+Eg6#hkK&cS0{* zP6d)bCgRHn2y++wjuKf--@Tj3Vc5bUd4{9wD+L5~MbY+i-31}jjv@@t5O7Wmer5^m zJvJ&@s~ztsR&D1ndJH3?)BF=^(tKYRggr&% zK3MNREo4-xqKJ2^mDKPp7vs&(L|FWkUMT8KOb+tY9#S+hHC!G`IW7P?05rf4L%Wq| z_o5WN2}*c7twjsskCbI&@=7|h5G8Fg)!#qLTyW0lAf+(2Mn3_`J7{NC0$aun5ddxG z)cz!oTO{U^dq7GL;eqH|2-jEE7nnR>99@NH4?j3VNmV z5wI#^wx;xGJZt<)$#Fl|IR?`!h!fn*J>-uZOx$PeI6MyOpHyi#2l09?Iadr4z}$1+ zKUNUlu~o6z^n@j@eY{OO@2kqQL1o$ag|fqax9|N}zP~FWuV9*Z)f|qSddWkG^>fT3hDGOae4eLZuw)#?Kd^Tb0}# zP0}v;_ABBANw2itFJI5PnP{b_aT%~Df?wj6`?Y0E4r3_)XOPCebcqOB38d&cZ9Z$& zKcU(e8`dTtUTSnu#by7&VmWNVMnCYemXLCA|I!3dB*=Gm+B=Zp4~lysQ0s+NLJZy? z+j)!CI>?K~MJ^aKaaGRyeZ|yM^uem6s_lNBQ{D)ZE#6;8gc~fD4Y$-o`XM}=@Zdmj z!N^gtr+PPr%%2?fGF}wXpgVZ1U#7hGm zG^{@*l zCVscCj%kdtgV8oZ#5^eHZXcet=Zw(lF&DnOUB;D>=IDAMwOsngzLYn%+PG7(Rb1+5 z$V0+&tdwqD>g(#t2E{(0z6Yr?c!(<(?i!JTW@OtnHmdrkd@2%8sJZiQsOylFo^xMr0$mI0$LA3d#+~yFPhk!jn+KM? zD&9Q;Soprv7*`=<4!#h+G77lGa4}PXgi#Mn2A9RnPuh-~z@<+Z3zqF)-N65g%OYC#h zFb+ONeRq_VozSn+gIvaACUQlWjC?`U&a$1G6*=bNik(E>#!X1!A#>lRQI;Rmc0iy`A==cvRA7d~0^9!R{%5vD=2%G3j)}eM8ve z=1~vOv&+Xo>a)+G_IU2nCGj1jL0}QC;U-<;t@>W^&*K%*AcMD}cMO#PT0Fh`&1W=d zt{(MKqth2!vDH>8r=_#*J0>*>&zLgdGE-^>qHgGCYLh2|B;?}MdlDhUYXa$26aG&a z^WMxAf%>eS`F5zY_=2R6M-5N??Be`Zo%~{{*CYHw_vVk3+#d!FGCMe92pU;@QM;!I z(D-N&=IRPm_n8=PuF~Glt17XcgbePzP1B?%FT_Kj1%d_BUzlpoSNR)X%${d|H?ntv zM+szG=n4*t9RMgTvzgjjz`RM0xOGctNA|#@KFm%nhBg1`i1Y`wTZ(2GpgKJQc4n4vEGZPR z_lRW9u8-Z%3O?3c_XUnMSLmTR&ib`x8Bg9cpAJ2&UC6pg(HbJ>&K1oSv~w(()4jUb zE4du?rvuSUa&K?Ymd398Y_zplqAm*}aiSi8+`plYe)rhjWVTo!O(j4&5hJHeR#g!4 zpkD4-*W7!PY$Li{`1esN-8JKn)&rkhR zj&msgGP3s=bY4FvMHl|C&eW>AL6SC7J&u;`6YP$KT%J;;SL$XSG9r^hNeQla{famH zxg5x~yXdz##5MKNT0x$l`x<3_)Zs^(vXn%6olqjc^>j`K$1Ab8_1l8aW?f%|odt%t zU7mW7S9ZSR>sFiDVm?-7*+5GfsA?aA~LjhQ9*fYYJ^8dr_$YE-g| zoBq;n=a1_J9mqvTV{4?!OWd@g@5SrSR&k}oP6hw2oJ)+07RLquR!TPR=o5S98u%0I8wfj8X~7XbznEK$FUr|@LAF|-CWjB{c` zn&5x%vIJoek22>7UdwjKK5F`HACfqd4CruWbzEFtf5|Z-{9owGFJRrNr2=r{X;ok9 zEEWyCKCugY3*B>1Grz$<6Ll}qTCH~~8FA_mQ9Q=Qo@*A;;lUMN78jk~0+W>bzLb>JBa z4Y#}P2fB2X1nn`p&k{!mi0Sf^QF6#VUgs^O$qCl$g7xeii^cjH>4Bz44ic{ItKPR&QlFQOb< z=VNtHBr3pmFa+j&HKR)yRs@pq6tQjIyLk2G;*`bq=WA1OFwSj+*lOXhGG&3C%4`)U zB)x4`^GoB}Q-2~<8!b10<3fZz{O0v&=_6&}c7Z8o@*%{&b%6$5q3m41q$gu-$ohM& zP|elkXpFehR#xSy;D+tuaodfwL4pSDR^?g24b_wAo)o^GZZ#$KIykkxd*DhFtGpy7 zyAR6nfUPX+D&@{96Ka)$`hKA&?$uPWj}X&8Mhxe>(^|zTH0|0`f^u{VTiU zx{XNb&L_hyF$LT#v+LuU!z&c4+r~@OWvY+Ga^IzBN3>cM0hrXGo>aj3bcJ7i_^eCi zoAarJ61Ba+cAIA$V?Pl@b0`FPY!+|ZKfxwc1jZ|}uVkVhAjVG%Aj);W`Yu2$In^F* z$aO6mVa1?pS!{2aRgrArQwNs+ctv(lgEb=Yk+%tI%)&>w7ts2Iv-K=*pS0UeOqKA`U;dKmq+~$ z!12Rl5f?3qo9eg#@#%y5tTxaYu8Lx*`&+v8YzdpRmTa`YvEA=`-P>hpUXFrXS4z2) zghr(^!_k+)2XDH*o%az&jEs+^8JtCS#&E}99oNpVT(*!k6S&iB_4<4TsqcJ%3+X4N zs<=AS*Q&+P&AW+S!$0+LseWq(Dbgg0TFmA`bjR~x8cx=1a_}aXRnYiJF|eF(zQV6Q zl6g)95@5{eUgy%#`C{uRYaPV-D~Exi8U;E_CLUPjAR+DszuzQY>b-Z@9Q#nW&Ie*h z4(O{W&g*MT#8qCrDql%-v6?&f^E3&y*LMpUiyDqn6iWD6%gSNYrq2(6l_Jnd_=77s ziX=VZrZm-kkvfg@NSAxfaAgLga{23K2wW$KGQ~5C2-TVTk`8m|xj*iAJH%Bz$x$#( z_Vz;2FcfxFj+R)la}_ULxv$MZt=Xwqa?V;B@kc$vqQL(y;7=*Jx4i&KQ1uRi5L4>A z9ot9|9}S~n>%bMtvR=S@h!a@SfDx}*%CDS59n-xuyQ#J8GBfJMCuYqrISrS>==_OF zmQHMQ@TR`^{Y7KW%I9ne_MAhUy?F2Ft1PXqQwp9Qi27E;3LGYWA~vP%Wn$obWzFb5 zvZW*F9vY24oJe;@mU&o232AQx)PB+@DNf-Bw9sQ3?UNNN0V<%M8kaJEi#*k4j;Jgc?m@sbFMAW{%PP%xCF^XWF2@o6Y%^T=IBQ!QohsBjx5?at$MrwzpY$d zc1~N>uRTydDRdFQknkQ0U#(nIeGHMyN>U4_@p>3;9Q>C@?#AhANCtu;A~bWBtp92F ze4mvdzB68s!Sw)EiA-j^-$)_t{G8cS<8a*rhhOqXVI2gvu5T#w!L<& zYmG_Ryfwi$ClB4gwzYFxdW);7>iWU$0+J@mA%7bRvJAX3?|ZBcX~o}^avS~WAB>L-JW}nR?j>=8^mv%p^r0G^O&};FEzyVI5%&3 z^3}cbw*!(#{Vxky8 z6ytgJ@$7jViT}IFSAcrOYDqqt0<+biNW9h2F=uH9b6ioxsP{hX45nk)lr{{TD9DdG zwy2Pg&*87226~f)?|@0$|KDQD!TzIs_2f_H{0jR1s#Z?qCx~U}%ebabn2I1C>!!=m zsM8ggui>;QwOv`RjjqLEdjjO^cE$_rqY;ycqNj|P)>9yAERV55=Z2o zB$=osnzIf3EnV4=WJlpfG>V?RBedJ6`mO66+Ohre>r@6$bc8W#gSKU_Kt_{P)!@qr#IzA^qsCl)!s9QICc zl0}a;e(|61q@%p}#Y&sh`#f7pLWvr%4_^Ue4!Pp}sv?)1F(Tuy*aVqsef`pw4q>Y;gb-e&a9?uG zGG-5c!n3Kv;x@k2;nxr{Qmi5;ckidm6wh}5>G61RE#?{jnJKZ6@lPvUQ+Ca+snIu|0D9Xze1g-EjHb}_h9hlph4Uu z#&;b-s)7;#X`N?y4{z-0ahlSnqcZ+&*$-V0)vhOhoUAjux%9y5IAuMfaO%E{cQl`# z(KyEH*+=(9ZHKP3R1nC#!z zmhME(Ygf07yRhv9E$Xw9x#vZk?V!+EPsDJzI34~o&6u-KmUB&)@3#9&m+*7mC1MDR zPvOv$x0TTMPHV_ul7O_%dX&L4bOp8lO7Q97)w^6*u=m4V(R;M2EZWO8^|S(UA=gW| zUd%(k*=o;4V8lyIc8O@0pHxYjWkd<2VQQM#V7^4~jj!u*wh|#?n++`u3+)q)9ve=v zDo8hvc@<8uM&W3e*;#G3!CkEO=BLj+G9RxwMgcYc$O6~4%Zy5z`%?H?&cwGBdA}B4 zxB!sLq#%IFl&!V!%}DHjK*?Pd&x4;J=ib!5DtlvweJh-fp%w&gbmC$4b2j{F5l^f33<`mvlzuh!YmP-}XXJo?4=3E9q z_x3S=VO8Dx=lV%FRV%))J$&(|>qxCO9OGsNmKk{ZYX3=cbl98_f)^@RRo1dQ7AiwC zm`4o2b@UQI>Ki%2pYk!Z;E)s6oqhND&aT^XTO^`*G7@SjeMMCJhAvrm!{)1FvFnu| zU?SoJ2=;nY$S{jav5e?E@&4d4yZp}VO2jC>cSxm4FcZeOj#(9y-OPj^pVj=zs#~i4 znF5Z53}emzr5tj;2RnzV7^9pHjO9`q9b)dA2@Lt~bN4rdo`V@b9EkPfzEW)=a_8-Qrf_C?;9ElFzzvBRgNA@SJZ+>u_^wn&${Bg^5jFy1ea+!vTyMlslHgk_GR#) zAN+ncd%2NJ$RvKx5*Lk_9B&a=x!vpk_@W*}pbj9Hf;er-Jc(eAATJHt*&%vtM;%H5 zo3V5I)vj$pCwIpRN*@w>6oiw?1}#W5{_;B1y`2lD!(5 z9Na-g;*?w?h3+}i&cdK|l}I{nOPc#-V~)vB!s zT~kAHXQ|y=?0cgMJo~Ps&qm4=E8K{v$S(6lMN9*Ylb3o&bdwL&g9#aZF}4{{)p6fU zt@*;pzBVT;di$ET<9UAArse)fACT=ezoGfvO0x3!s16_4b!bo2o^Mq>QhE4cLFks} z25$rW*4(~<)7m?q(q@Jw=D&&32Mv!Zm*afAmiT2>_t!oCrInH&!!jfVI#GydzLbQI zt){K0Fuh!J->*ct!k(c@ar=VZe> z3dC)sPMhJsia$<}%HRl@y>o4sxA|;m#)Dm1*fEhnv2;+%diFvQdl0mW%+DV3O+0+0 zQrx!h0@o(U{z1^!cdmJ4uj1Z&EQ-LU7Y&StPs&+Ffuj{mngc15a0Cmb&d{qyqceO^<^K5w;q*E8=O;ZM#){ z13Xa!5Fh_rd%*|p8C!bDYcT7L7-Lu&p}2Nd&x7)81JHDG2TyR+;XGQ6MzI<=qigsW zvGkAKuIQ7!FO-e*wH`5s5_F%HhCwPMf?;aq2?(ouHpx6ZD>LOgC4vyY=b%``x^%0gfzQ;&RRaOs3(iw#m+0 z(H#;;q3Qa!sT3mZxr+p~dig4QMw_%Mi@0+PCf=E?MCKY}UmtC$eH%v{EGMX)UZaUK$#KEX~zLvc;&@gr= zf+qNKU*wAycx&C>d{@#;7}WZ8_F_S#24{s@jh~f{yqIv#$nP_k!0Rzq$|bh#zq7`I zg~OMcpY)`{r0}H1Ps(5?N$SV?w@cSn&t!W)Sxy=d!QMl-f7J5QB6*0=fIF2Xi!;ka zB{d=2_hcZX`6uwCXq_1m_( zX3=GmZZe^L0y^lwWPQS7C0>Ex=VHNn%)FcLJfG+rU7fv?PfC!Y{%327dx^aF-@#p> z-oIWwR=55xPr~+dy_fGgW4DFBi$QOp2d+?mCzbhWH@i-?)WD|7k3;q|{^KvKN2(CV z_@)uW+Z{{fi1?;SpKX)67j#GuD9sd4cib4oA3U?>ZDL&(05tXyGN%q`RnYlPC2{U! z0${Vt`Uh_RD)bEmzK}J%zV5H4NqVyXosvhcU61aWl#2|y{^h6ydgj%OxrR}Nxr~)! z%+!>Vb-PDUA}&xcYkyO~Joki8x%{=va;U=5jk%bjP>-)Cp1 z?>t?r_|Ftalh*7oG|MVv_ZVX}K&Nb}`tO8nzqnfG7ceREmLYfz3soR~Ere8C z_Lg#M9qa`QE);9LrfS=7$tB*w#Y`1M)wI+&Q_pgFP4|*ycpGPF+F^Cl>D}ZHl@dqN zxdC~VUP<8%@2_0lApbFQGpovMmbNN7`L@Z6xo+v{-}t!l#J#4IN0ok(@fH(d>QebP z8U!R~+Ev%izYQt&R%Vq%hutns<1c_o8vCFwN&^FoGYqB%)qhAM%O+$voL=x#A3Q~B zS*(~z*rM~&*A)WG zM!T=JN4tJ|E;x$rhycSHy5$8lIM#^3k*i7BmeWwxVSh9wsllrprdRFrv5}j+yy#s5 z9wS~5C}MVtyL0=8t*Elgd%md;YgGncJ}O4KF6x~7HFIm?AI*~dU*Ul5=nV0>;31X3 z{yb5Yl^hC|wdkfFt7;{hUyie+JIS1Lr^43X^_~z) z-+L~Gz#RH9eV9Y;fJ0$~7;EccX4$vsD$^{Ljkv1j6AEc--Ii0Pvy1yxQ_s2kPMa=l z*T3P8e;5;8sOAv$Iynu~hebFk?Tq;@E^d$8D&Z?H@NM-dQRdTkY}7EK zZ|^q!)`*MgI&MEKl{4;jnmq1>v+v}a&+G`bm7aRB>4Ktr0{x4vUYL6jb`|o6~YE92Gf!UhdDA^*6tR`eD!;0tT+k_zh_&N{52!DYh8WxIHqz{9vu4OB1uwy{I(## zr0YaRM`5yyafw`XOS1ISzEk1??)PN@j- z{E}BeKR!5)*3@U+G5*NNc&yg0Z#8Li=++aU2!4H~wnv_q9M%M3~B zWxSgwYS)*{B+`CIXioJlaD_{FdXc#zDM)v2v!}Rj@7hl;G>4t@wI8&@Kv@-NQ?@3RkPSt-$%d+9E=J)BOqw)#iwEZ^0sIx|$<3-Vz9M4VD>R3A0X89wN z)f)_EYPsw4fc$(Jx9ZkB$sFP_8>=HlQH*){Cl>y%sk!G!?ZSYm*gSAg+IGz3#oddf z_}g9n?MKD}TC*yHm#+&w;Xp?0n)Gbb{``AHxIfCCxcfZ0I6)Nyz~aL8y?CfsHq>z& z#}~Y0xnE_33K&(1>JNI*K~S=uJqOZos%fj9GOr@v-avU}e( z%m8gBYiQ5W9;xwppb}GM>~_O-+Stbh70z!;Ruva==5t>vwHb50xKk(_6p#S5ge-zS z1XETl`DFsbMmM>#)Sa-lk6F9au3O@@rT@L!LaY@f+zDFCQl~187*7?Gs2eBJ<+?71 z<0|E#e%5iFN^8&ee{IELjyPR%f9Yg4NVs5IS1_Aavy&WF!zL_(iciXWgee-J1U|Rj z)hk`FF6wV@_9RiKq)q+KP38Gy+GiFUOPsOf(JMp2RZurPvk- zzZ5lVmi0%^J$-&Y^o4wx@mH}vf`2U!Pt<`9&rK-@qv+v$2hmI^oNC8GHb@P9HDfnl zB_K@!_b9BIoBzOgXh-Me5ys~}e(I>$`M0_BlUarnHh9M*i^eB{_WK{6-aVe_#{c8K zx?H7FRFV)&DwPn5oTf;U96Cx4O9(M?Hq25E$zgIxh!HvDl$>(f%3;n%4r2~;nz5O& znH}tK@B6#&$Nl&I+-Hx^d++z_^?a6wg9CnDhc49?aB6=~#^accN7F51Z~sBea^sF-^B;NhOo%wcz3*O1Vv&m|at!X8%|S z`lAhTd1uYD@k;)~^%!Rv0?qe85sWanhh&qMF&-lQ^m+T)9upm(7Kf0$ws2OyzK;7ehQ3!Kb)tO*CjRaf_h8GdBl&9q1L4HX&mrA?A*q! zf$$`gkQriSWo=z?3v3jq@*pIDHrFWS>od1oQ40tv!myY{Gc`B5>-#I-^B_30z^g9#kk4)NdWom*8X8FWZGtS{?>_gU~R zo~1MAAb51?df?w`M!=nPmSbZj?51Hu<{#M|Wb!vbRk+(h9jTn^9Z$|G)YZqJA2idC zT5&9-9J8eUFxhF+- zKaM2igGF0?e@4m_EOI>g%(ny?XT`a83*DGqv|YY;B*8Y$ zaP6v9-rw7FsnC|t!ljAXdfM*uCi+cEt+cf&s?}b>(V#R~L}s(bR5~OCIve6_>%BW0 z6pJ38vp+w3H^wU{#hq^ex&u6dH(Aq{aJ)}>80ldT=96w^Iu#lld^d1*b{1^3z<*3? zKEu5I;&bw9o*F4C+kHC5@EhdUOxPaeZj|?FNk&0>qH$ihki?x`UFA%l-@szRMdqC( z%<0NH*3*->rX+9=BmWl5FDDIVuP=-`$1qKxJqXMAbp7w1Q~yC|OVW5>Yi@VxIM!0UVb120(H7e$u*yl>k8{jbo7)?C_V6?Q zM3gXqOToZ*&c}rf*d8`kb^4-x8`?Xa`R9f-bN!mSX0qX%$jEcm@(%CL2EVNKc}Z

tK6hm!b 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

w-4k!3PIbgH9Wp&7P&rL#GduB`4w-RuDYbl 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

b(zyMKyp6nQts|2>h`?)bpJP41Sf^ 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%0AvIu7Af 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


BYJ$w(Vi*g}7+Vmm%P?gaQ^~U| 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 literal 0 HcmV?d00001 diff --git a/tts/NeMo/tools/text_processing_deployment/Dockerfile b/tts/NeMo/tools/text_processing_deployment/Dockerfile new file mode 100644 index 0000000..9b2a4ae --- /dev/null +++ b/tts/NeMo/tools/text_processing_deployment/Dockerfile @@ -0,0 +1,38 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +# Dockerfile for C++ (inverse) text normalization backend Sparrowhawk https://github.com/google/sparrowhawk + +# set base image (host OS) +FROM conda/miniconda3 + +# set the working directory in the container +WORKDIR /workspace + +# install dependencies +RUN conda update -n base -c defaults conda -y +RUN conda install conda-build -y +RUN apt-get update && apt-get install -y --reinstall build-essential && apt-get upgrade -y && apt-get install -y git && apt-get install make +RUN git clone https://github.com/google/re2 +RUN cd re2 && make && make install +RUN apt-get install build-essential -y && apt-get install wget -y +RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v2.5.0/protobuf-2.5.0.tar.gz +RUN tar xzvf protobuf-2.5.0.tar.gz +RUN cd protobuf-2.5.0 && ./configure && make && make install && ldconfig +RUN conda install -c conda-forge thrax=1.3.4 -y +RUN git clone https://github.com/yzhang123/sparrowhawk.git +RUN cd sparrowhawk && git checkout test && apt-get install -y autoconf && bash autoreconf && ./configure && make && make install && ldconfig +RUN git clone https://github.com/kward/shunit2.git +RUN echo "DONE" diff --git a/tts/NeMo/tools/text_processing_deployment/README.rst b/tts/NeMo/tools/text_processing_deployment/README.rst new file mode 100644 index 0000000..5c1df01 --- /dev/null +++ b/tts/NeMo/tools/text_processing_deployment/README.rst @@ -0,0 +1,10 @@ +**Text Processing Deployment** +========================================= + +Introduction +------------ + +This folder provides scripts to deploy WFST-based grammars in `NeMo Text Processing `_ for +for production. + +See `documentation `_ for details. \ No newline at end of file diff --git a/tts/NeMo/tools/text_processing_deployment/docker/build.sh b/tts/NeMo/tools/text_processing_deployment/docker/build.sh new file mode 100644 index 0000000..fbca672 --- /dev/null +++ b/tts/NeMo/tools/text_processing_deployment/docker/build.sh @@ -0,0 +1,18 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + + +#!/bin/bash + +docker build . --rm -t sparrowhawk \ No newline at end of file diff --git a/tts/NeMo/tools/text_processing_deployment/docker/launch.sh b/tts/NeMo/tools/text_processing_deployment/docker/launch.sh new file mode 100644 index 0000000..ddc35ca --- /dev/null +++ b/tts/NeMo/tools/text_processing_deployment/docker/launch.sh @@ -0,0 +1,44 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. 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. + +#!/bin/bash + +MODE=${1:-"export"} +SCRIPT_DIR=$(cd $(dirname $0); pwd) +: ${CLASSIFY_DIR:="$SCRIPT_DIR/../classify"} +: ${VERBALIZE_DIR:="$SCRIPT_DIR/../verbalize"} +: ${CMD:=${2:-"/bin/bash"}} + +MOUNTS="" +MOUNTS+=" -v $CLASSIFY_DIR:/workspace/sparrowhawk/documentation/grammars/en_toy/classify" +MOUNTS+=" -v $VERBALIZE_DIR:/workspace/sparrowhawk/documentation/grammars/en_toy/verbalize" + +WORK_DIR="/workspace/sparrowhawk/documentation/grammars" +if [[ $MODE == "test_tn_grammars" ]]; then + CMD="bash test_sparrowhawk_normalization.sh" + WORK_DIR="/workspace/tests" +elif [[ $MODE == "test_itn_grammars" ]]; then + CMD="bash test_sparrowhawk_inverse_text_normalization.sh" + WORK_DIR="/workspace/tests" +fi + +echo $MOUNTS +docker run -it --rm \ + --shm-size=4g \ + --ulimit memlock=-1 \ + --ulimit stack=67108864 \ + $MOUNTS \ + -v $SCRIPT_DIR/../../../tests/nemo_text_processing/:/workspace/tests \ + -w $WORK_DIR \ + sparrowhawk:latest $CMD \ No newline at end of file diff --git a/tts/NeMo/tools/text_processing_deployment/export_grammars.sh b/tts/NeMo/tools/text_processing_deployment/export_grammars.sh new file mode 100644 index 0000000..393fca3 --- /dev/null +++ b/tts/NeMo/tools/text_processing_deployment/export_grammars.sh @@ -0,0 +1,59 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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. + +#!/bin/bash + +# This script compiles and exports WFST-grammars from nemo_text_processing, builds C++ production backend Sparrowhawk (https://github.com/google/sparrowhawk) in docker, +# plugs grammars into Sparrowhawk and returns prompt inside docker. +# For inverse text normalization run: +# bash export_grammars.sh --GRAMMARS=itn_grammars +# echo "two dollars fifty" | ../../src/bin/normalizer_main --config=sparrowhawk_configuration.ascii_proto +# For text normalization run: +# bash export_grammars.sh --GRAMMARS=tn_grammars +# echo "\$2.5" | ../../src/bin/normalizer_main --config=sparrowhawk_configuration.ascii_proto +# +# To test TN grammars, run: +# bash export_grammars.sh --GRAMMARS=tn_grammars --MODE=test +# +# To test ITN grammars, run: +# bash export_grammars.sh --GRAMMARS=itn_grammars --MODE=test + +GRAMMARS="itn_grammars" # tn_grammars +INPUT_CASE="cased" # lower_cased, only for tn_grammars +MODE="" + +for ARG in "$@" +do + key=$(echo $ARG | cut -f1 -d=) + value=$(echo $ARG | cut -f2 -d=) + + if [[ $key == *"--"* ]]; then + v="${key/--/}" + declare $v="${value}" + fi +done + +echo "GRAMMARS = $GRAMMARS" +echo "MODE = $MODE" + +python pynini_export.py --output_dir=. --grammars=${GRAMMARS} --input_case=${INPUT_CASE} || exit 1 +find . -name "Makefile" -type f -delete +bash docker/build.sh + +if [[ $MODE == "test" ]]; then + MODE=${MODE}_${GRAMMARS} +fi + +bash docker/launch.sh $MODE \ No newline at end of file diff --git a/tts/NeMo/tools/text_processing_deployment/pynini_export.py b/tts/NeMo/tools/text_processing_deployment/pynini_export.py new file mode 100644 index 0000000..80ccace --- /dev/null +++ b/tts/NeMo/tools/text_processing_deployment/pynini_export.py @@ -0,0 +1,111 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# 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 os +import time +from argparse import ArgumentParser +from typing import Dict + +from nemo_text_processing.inverse_text_normalization.taggers.tokenize_and_classify import ClassifyFst as ITNClassifyFst +from nemo_text_processing.inverse_text_normalization.verbalizers.verbalize import VerbalizeFst as ITNVerbalizeFst +from nemo_text_processing.text_normalization.taggers.tokenize_and_classify import ClassifyFst as TNClassifyFst +from nemo_text_processing.text_normalization.verbalizers.verbalize import VerbalizeFst as TNVerbalizeFst + +from nemo.utils import logging + +try: + import pynini + from pynini.export import export + + PYNINI_AVAILABLE = True +except (ModuleNotFoundError, ImportError): + + logging.warning( + "`pynini` is not installed ! \n" + "Please run the `nemo_text_processing/setup.sh` script" + "prior to usage of this toolkit." + ) + + PYNINI_AVAILABLE = False + + +# This script exports compiled grammars inside nemo_text_processing into OpenFst finite state archive files tokenize_and_classify.far and verbalize.far for production purposes + + +def _generator_main(file_name: str, graphs: Dict[str, pynini.FstLike]): + """ + Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. + + Args: + file_name: exported file name + graph: Pynini WFST graph to be exported + rule_name: rule name for graph in created FAR file + + """ + exporter = export.Exporter(file_name) + for rule, graph in graphs.items(): + exporter[rule] = graph.optimize() + exporter.close() + print(f'Created {file_name}') + + +def itn_grammars(**kwargs): + d = {} + d['classify'] = {'TOKENIZE_AND_CLASSIFY': ITNClassifyFst().fst} + d['verbalize'] = {'ALL': ITNVerbalizeFst().fst, 'REDUP': pynini.accep("REDUP")} + return d + + +def tn_grammars(**kwargs): + d = {} + d['classify'] = {'TOKENIZE_AND_CLASSIFY': TNClassifyFst(input_case=kwargs["input_case"], deterministic=True).fst} + d['verbalize'] = {'ALL': TNVerbalizeFst(deterministic=True).fst, 'REDUP': pynini.accep("REDUP")} + return d + + +def export_grammars(output_dir, grammars): + """ + Exports tokenizer_and_classify and verbalize Fsts as OpenFst finite state archive (FAR) files. + + Args: + output_dir: directory to export FAR files to. Subdirectories will be created for tagger and verbalizer respectively. + """ + + for category, graphs in grammars.items(): + out_dir = os.path.join(output_dir, category) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + time.sleep(1) + if category == "classify": + category = "tokenize_and_classify" + _generator_main(f"{out_dir}/{category}.far", graphs) + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument("--output_dir", help="output directory for grammars", required=True, type=str) + parser.add_argument( + "--grammars", help="grammars to be exported", choices=["tn_grammars", "itn_grammars"], type=str, required=True + ) + parser.add_argument( + "--input_case", help="input capitalization", choices=["lower_cased", "cased"], default="cased", type=str + ) + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + export_grammars(output_dir=args.output_dir, grammars=locals()[args.grammars](input_case=args.input_case)) diff --git a/tts/NeMo/tutorials/00_NeMo_Primer.ipynb b/tts/NeMo/tutorials/00_NeMo_Primer.ipynb new file mode 100644 index 0000000..db3bdfa --- /dev/null +++ b/tts/NeMo/tutorials/00_NeMo_Primer.ipynb @@ -0,0 +1,1281 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "name": "00_NeMo_Primer.ipynb", + "provenance": [], + "collapsed_sections": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "7LfkL2r2Q1tr" + }, + "source": [ + "# Getting Started: Exploring Nemo Fundamentals\n", + "\n", + "NeMo is a toolkit for creating [Conversational AI](https://developer.nvidia.com/conversational-ai#started) applications.\n", + "\n", + "NeMo toolkit makes it possible for researchers to easily compose complex neural network architectures for conversational AI using reusable components - Neural Modules. Neural Modules are conceptual blocks of neural networks that take typed inputs and produce typed outputs. Such modules typically represent data layers, encoders, decoders, language models, loss functions, or methods of combining activations.\n", + "\n", + "The toolkit comes with extendable collections of pre-built modules and ready-to-use models for automatic speech recognition (ASR), natural language processing (NLP) and text synthesis (TTS). Built for speed, NeMo can utilize NVIDIA's Tensor Cores and scale out training to multiple GPUs and multiple nodes.\n", + "\n", + "For more information, please visit https://docs.nvidia.com/deeplearning/nemo/user-guide/docs/en/main/#" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "zLSy94NEQi-e" + }, + "source": [ + "\"\"\"\n", + "You can run either this notebook locally (if you have all the dependencies and a GPU) or on Google Colab.\n", + "\n", + "Instructions for setting up Colab are as follows:\n", + "1. Open a new Python 3 notebook.\n", + "2. Import this notebook from GitHub (File -> Upload Notebook -> \"GITHUB\" tab -> copy/paste GitHub URL)\n", + "3. Connect to an instance with a GPU (Runtime -> Change runtime type -> select \"GPU\" for hardware accelerator)\n", + "4. Run this cell to set up dependencies.\n", + "\"\"\"\n", + "# If you're using Google Colab and not running locally, run this cell.\n", + "\n", + "## Install dependencies\n", + "!pip install wget\n", + "!apt-get install sox libsndfile1 ffmpeg\n", + "!pip install unidecode\n", + "\n", + "# ## Install NeMo\n", + "BRANCH = 'v1.0.2'\n", + "!python -m pip install git+https://github.com/NVIDIA/NeMo.git@$BRANCH#egg=nemo_toolkit[all]\n", + "\n", + "## Install TorchAudio\n", + "!pip install torchaudio>=0.6.0 -f https://download.pytorch.org/whl/torch_stable.html\n", + "\n", + "## Grab the config we'll use in this example\n", + "!mkdir configs" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6G2TZkaxcM0e" + }, + "source": [ + "## Foundations of NeMo\n", + "---------\n", + "\n", + "NeMo models leverage [PyTorch Lightning](https://github.com/PyTorchLightning/pytorch-lightning) Module, and are compatible with the entire PyTorch ecosystem. This means that users have the full flexibility of using the higher level APIs provided by PyTorch Lightning (via Trainer), or write their own training and evaluation loops in PyTorch directly (by simply calling the model and the individual components of the model).\n", + "\n", + "For NeMo developers, a \"Model\" is the neural network(s) as well as all the infrastructure supporting those network(s), wrapped into a singular, cohesive unit. As such, all NeMo models are constructed to contain the following out of the box (at the bare minimum, some models support additional functionality too!) - \n", + "\n", + " - Neural Network architecture - all of the modules that are required for the model.\n", + "\n", + " - Dataset + Data Loaders - all of the components that prepare the data for consumption during training or evaluation.\n", + "\n", + " - Preprocessing + Postprocessing - all of the components that process the datasets so they can easily be consumed by the modules.\n", + "\n", + " - Optimizer + Schedulers - basic defaults that work out of the box, and allow further experimentation with ease.\n", + "\n", + " - Any other supporting infrastructure - tokenizers, language model configuration, data augmentation etc.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "XxAwtqWBQrNk" + }, + "source": [ + "import nemo\n", + "nemo.__version__" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "H01SHfKQh-gV" + }, + "source": [ + "## NeMo Collections\n", + "\n", + "NeMo is sub-divided into a few fundamental collections based on their domains - `asr`, `nlp`, `tts`. When you performed the `import nemo` statement above, none of the above collections were imported. This is because you might not need all of the collections at once, so NeMo allows partial imports of just one or more collection, as and when you require them.\n", + "\n", + "-------\n", + "Let's import the above three collections - " + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "J09NNa8fhth7" + }, + "source": [ + "import nemo.collections.asr as nemo_asr\n", + "import nemo.collections.nlp as nemo_nlp\n", + "import nemo.collections.tts as nemo_tts" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bSvYoeBrjPza" + }, + "source": [ + "## NeMo Models in Collections\n", + "\n", + "NeMo contains several models for each of its collections, pertaining to certain common tasks involved in conversational AI. At a brief glance, let's look at all the Models that NeMo offers for the above 3 collections." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "9LbbC_92i41f" + }, + "source": [ + "asr_models = [model for model in dir(nemo_asr.models) if model.endswith(\"Model\")]\n", + "asr_models" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "t5_ax9Z8j9FC" + }, + "source": [ + "nlp_models = [model for model in dir(nemo_nlp.models) if model.endswith(\"Model\")]\n", + "nlp_models" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "bQdR6RJdkezq" + }, + "source": [ + "tts_models = [model for model in dir(nemo_tts.models) if model.endswith(\"Model\")]\n", + "tts_models" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iWKxKQnSkj9Z" + }, + "source": [ + "## The NeMo Model\n", + "\n", + "Let's dive deeper into what a NeMo model really is. There are many ways we can create these models - we can use the constructor and pass in a config, we can instantiate the model from a pre-trained checkpoint, or simply pass a pre-trained model name and instantiate a model directly from the cloud !\n", + "\n", + "---------\n", + "For now, let's try to work with an ASR model - [Citrinet](https://arxiv.org/abs/2104.01721)" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "n-XOQaW1kh3v" + }, + "source": [ + "citrinet = nemo_asr.models.EncDecCTCModelBPE.from_pretrained('stt_en_citrinet_512')" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "YP4X7KVPli6g" + }, + "source": [ + "citrinet.summarize();" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MB91Swu0pIKr" + }, + "source": [ + "## Model Configuration using OmegaConf\n", + "--------\n", + "\n", + "So we could download, instantiate and analyse the high level structure of the `Citrinet` model in a few lines! Now let's delve deeper into the configuration file that makes the model work.\n", + "\n", + "First, we import [OmegaConf](https://omegaconf.readthedocs.io/en/latest/). OmegaConf is an excellent library that is used throughout NeMo in order to enable us to perform yaml configuration management more easily. Additionally, it plays well with another library, [Hydra](https://hydra.cc/docs/intro/), that is used by NeMo to perform on the fly config edits from the command line, dramatically boosting ease of use of our config files !" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "RkgrDJvumFER" + }, + "source": [ + "from omegaconf import OmegaConf" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CktakfBluA56" + }, + "source": [ + "All NeMo models come packaged with their model configuration inside the `cfg` attribute. While technically it is meant to be config declaration of the model as it has been currently constructed, `cfg` is an essential tool to modify the behaviour of the Model after it has been constructed. It can be safely used to make it easier to perform many essential tasks inside Models. \n", + "\n", + "To be doubly sure, we generally work on a copy of the config until we are ready to edit it inside the model" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "ISd6z7sXt9Mm" + }, + "source": [ + "import copy" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "N2_SiLHRve8A" + }, + "source": [ + "cfg = copy.deepcopy(citrinet.cfg)\n", + "print(OmegaConf.to_yaml(cfg))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W_V3e3W7vqOb" + }, + "source": [ + "## Analysing the contents of the Model config\n", + "----------\n", + "\n", + "Above we see a configuration for the Citrinet model. As discussed in the beginning, NeMo models contain the entire definition of the neural network(s) as well as most of the surrounding infrastructure to support that model within themselves. Here, we see a perfect example of this behaviour.\n", + "\n", + "Citrinet contains within its config - \n", + "\n", + "- `preprocessor` - MelSpectrogram preprocessing layer\n", + "- `encoder` - The acoustic encoder model.\n", + "- `decoder` - The CTC decoder layer.\n", + "- `optim` (and potentially `sched`) - Optimizer configuration. Can optionally include Scheduler information.\n", + "- `spec_augment` - Spectrogram Augmentation support.\n", + "- `train_ds`, `validation_ds` and `test_ds` - Dataset and data loader construction information." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sIwhdXkwxn6R" + }, + "source": [ + "## Modifying the contents of the Model config\n", + "----------\n", + "\n", + "Say we want to experiment with a different preprocessor (we want MelSpectrogram, but with different configuration than was provided in the original configuration). Or say we want to add a scheduler to this model during training. \n", + "\n", + "OmegaConf makes this a very simple task for us!" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "WlSZ8EA4yGKo" + }, + "source": [ + "# OmegaConf won't allow you to add new config items, so we temporarily disable this safeguard.\n", + "OmegaConf.set_struct(cfg, False)\n", + "\n", + "# Let's see the old optim config\n", + "print(\"Old Config: \")\n", + "print(OmegaConf.to_yaml(cfg.optim))\n", + "\n", + "sched = {'name': 'CosineAnnealing', 'warmup_steps': 1000, 'min_lr': 1e-6}\n", + "sched = OmegaConf.create(sched) # Convert it into a DictConfig\n", + "\n", + "# Assign it to cfg.optim.sched namespace\n", + "cfg.optim.sched = sched\n", + "\n", + "# Let's see the new optim config\n", + "print(\"New Config: \")\n", + "print(OmegaConf.to_yaml(cfg.optim))\n", + "\n", + "# Here, we restore the safeguards so no more additions can be made to the config\n", + "OmegaConf.set_struct(cfg, True)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-nMDN66502kn" + }, + "source": [ + "## Updating the model from config\n", + "----------\n", + "\n", + "NeMo Models can be updated in a few ways, but we follow similar patterns within each collection so as to maintain consistency.\n", + "\n", + "Here, we will show the two most common ways to modify core components of the model - using the `from_config_dict` method, and updating a few special parts of the model.\n", + "\n", + "Remember, all NeMo models are PyTorch Lightning modules, which themselves are PyTorch modules, so we have a lot of flexibility here!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qrKzFYkZ20aa" + }, + "source": [ + "### Update model using `from_config_dict`\n", + "\n", + "In certain config files, you will notice the following pattern : \n", + "\n", + "```yaml\n", + "preprocessor:\n", + " _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor\n", + " normalize: per_feature\n", + " window_size: 0.02\n", + " sample_rate: 16000\n", + " window_stride: 0.01\n", + " window: hann\n", + " features: 64\n", + " n_fft: 512\n", + " frame_splicing: 1\n", + " dither: 1.0e-05\n", + " stft_conv: false\n", + "```\n", + "\n", + "You might ask, why are we using `_target_`? Well, it is generally rare for the preprocessor, encoder, decoder and perhaps a few other details to be changed often from the command line when experimenting. In order to stabilize these settings, we enforce that our preprocessor will always be of type `AudioToMelSpectrogramPreprocessor` for this model by setting its `_target_` attribute in the config. In order to provide its parameters in the class constructor, we simply add them after `_target_`.\n", + "\n", + "---------\n", + "Note, we can still change all of the parameters of this `AudioToMelSpectrogramPreprocessor` class from the command line using hydra, so we don't lose any flexibility once we decide what type of preprocessing class we want !\n", + "\n", + "This also gives us a flexible way to instantiate parts of the model from just the config object !" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "1Be08R4szkT3" + }, + "source": [ + "new_preprocessor_config = copy.deepcopy(cfg.preprocessor)\n", + "new_preprocessor = citrinet.from_config_dict(new_preprocessor_config)\n", + "print(new_preprocessor)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UzJQ7Y8H4S_U" + }, + "source": [ + "So how do we actually update our model's internal preprocessor with something new? Well, since NeMo Model's are just pytorch Modules, we can just replace their attribute !" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "WdtnPKX84OJ-" + }, + "source": [ + "citrinet.preprocessor = new_preprocessor" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "OMz2KR-24xTO" + }, + "source": [ + "citrinet.summarize();" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gPb_BdPN40Ro" + }, + "source": [ + "--------\n", + "This might look like nothing changed - because we didn't actually modify the config for the preprocessor at all ! But as we showed above, we can easily modify the config for the preprocessor, instantiate it from config, and then just set it to the model." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IV8WKJkD5E_Q" + }, + "source": [ + "-------\n", + "**NOTE**: Preprocessors don't generally have weights, so this was easy, but say we want to replace a part of the model which actually has trained parameters?\n", + "\n", + "Well, the above approach will still work, just remember the fact that the new module you inserted into `citrinet.encoder` or `citrinet.decoder` actually won't have pretrained weights. You can easily rectify that by loading the state dict for the module *before* you set it to the Model though!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YplQcgfG6S1U" + }, + "source": [ + "### Preserving the new config\n", + "\n", + "So we went ahead and updated the preprocessor of the model. We however also need to perform a crucial step - **preserving the updated config**!\n", + "\n", + "Why do we want to do this? NeMo has many ways of saving and restoring its models, which we will discuss a bit later. All of them depend on having an updated config that defines the model in its entirety, so if we modify anything, we should also update the corresponding part of the config to safely save and restore models." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "dsxQHBV86R4a" + }, + "source": [ + "# Update the config copy\n", + "cfg.preprocessor = new_preprocessor_config\n", + "# Update the model config\n", + "citrinet.cfg = cfg" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eXRRBnJk5tCv" + }, + "source": [ + "## Update a few special components of the Model\n", + "---------\n", + "\n", + "While the above approach is good for most major components of the model, NeMo has special utilities for a few components.\n", + "\n", + "They are - \n", + "\n", + " - `setup_training_data`\n", + " - `setup_validation_data` and `setup_multi_validation_data`\n", + " - `setup_test_data` and `setup_multi_test_data`\n", + " - `setup_optimization`\n", + "\n", + "These special utilities are meant to help you easily setup training, validation, testing once you restore a model from a checkpoint.\n", + "\n", + "------\n", + "One of the major tasks of all conversational AI models is fine-tuning onto new datasets - new languages, new corpus of text, new voices etc. It is often insufficient to have just a pre-trained model. So these setup methods are provided to enable users to adapt models *after* they have been already trained or provided to you.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "B7Y7wt2x9goJ" + }, + "source": [ + "You might remember having seen a few warning messages the moment you tried to instantiate the pre-trained model. Those warnings are in fact reminders to call the appropriate setup methods for the task you want to perform. \n", + "\n", + "Those warnings are simply displaying the old config that was used to train that model, and are a basic template that you can easily modify. You have the ability to modify the `train_ds`, `validation_ds` and `test_ds` sub-configs in their entirety in order to evaluate, fine-tune or train from scratch the model, or any further purpose as you require it.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1hXXdaup-QmG" + }, + "source": [ + "Let's discuss how to add the scheduler to the model below (which initially had just an optimizer in its config)" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "cveKWvMZ4zBo" + }, + "source": [ + "# Let's print out the current optimizer\n", + "print(OmegaConf.to_yaml(citrinet.cfg.optim))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "XVguw3k0-f6b" + }, + "source": [ + "# Now let's update the config\n", + "citrinet.setup_optimization(cfg.optim);" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1JZBCQeW-21X" + }, + "source": [ + "-------\n", + "We see a warning - \n", + "\n", + "```\n", + "Neither `max_steps` nor `iters_per_batch` were provided to `optim.sched`, cannot compute effective `max_steps` !\n", + " Scheduler will not be instantiated !\n", + "```\n", + "\n", + "We don't have a train dataset setup, nor do we have max_steps in the config. Most NeMo schedulers cannot be instantiated without computing how many train steps actually exist!\n", + "\n", + "Here, we can temporarily allow the scheduler construction by explicitly passing a max_steps value to be 100" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "mqC89hfE-tqf" + }, + "source": [ + "OmegaConf.set_struct(cfg.optim.sched, False)\n", + "\n", + "cfg.optim.sched.max_steps = 100\n", + "\n", + "OmegaConf.set_struct(cfg.optim.sched, True)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "r22IqOBK_q6l" + }, + "source": [ + "# Now let's update the config and try again\n", + "citrinet.setup_optimization(cfg.optim);" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U7Eezf_sAVS0" + }, + "source": [ + "You might wonder why we didnt explicitly set `citrinet.cfg.optim = cfg.optim`. \n", + "\n", + "This is because the `setup_optimization()` method does it for you! You can still update the config manually." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "THqhXy_lQ7i8" + }, + "source": [ + "### Optimizer & Scheduler Config\n", + "\n", + "Optimizers and schedulers are common components of models, and are essential to train the model from scratch.\n", + "\n", + "They are grouped together under a unified `optim` namespace, as schedulers often operate on a given optimizer.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6HY51nuoSJs5" + }, + "source": [ + "### Let's breakdown the general `optim` structure\n", + "```yaml\n", + "optim:\n", + " name: novograd\n", + " lr: 0.01\n", + "\n", + " # optimizer arguments\n", + " betas: [0.8, 0.25]\n", + " weight_decay: 0.001\n", + "\n", + " # scheduler setup\n", + " sched:\n", + " name: CosineAnnealing\n", + "\n", + " # Optional arguments\n", + " max_steps: null # computed at runtime or explicitly set here\n", + " monitor: val_loss\n", + " reduce_on_plateau: false\n", + "\n", + " # scheduler config override\n", + " warmup_steps: 1000\n", + " warmup_ratio: null\n", + " min_lr: 1e-9\n", + "```\n", + "\n", + "Essential Optimizer components - \n", + "\n", + " - `name`: String name of the optimizer. Generally a lower case of the class name.\n", + " - `lr`: Learning rate is a required argument to all optimizers.\n", + "\n", + "Optional Optimizer components - after the above two arguments are provided, any additional arguments added under `optim` will be passed to the constructor of that optimizer as keyword arguments\n", + "\n", + " - `betas`: List of beta values to pass to the optimizer\n", + " - `weight_decay`: Optional weight decay passed to the optimizer.\n", + "\n", + "Optional Scheduler components - `sched` is an optional setup of the scheduler for the given optimizer.\n", + "\n", + "If `sched` is provided, only one essential argument needs to be provided : \n", + "\n", + " - `name`: The name of the scheduler. Generally, it is the full class name.\n", + "\n", + "Optional Scheduler components - \n", + "\n", + " - `max_steps`: Max steps as an override from the user. If one provides `trainer.max_steps` inside the trainer configuration, that value is used instead. If neither value is set, the scheduler will attempt to compute the `effective max_steps` using the size of the train data loader. If that too fails, then the scheduler will not be created at all.\n", + "\n", + " - `monitor`: Used if you are using an adaptive scheduler such as ReduceLROnPlateau. Otherwise ignored. Defaults to `loss` - indicating train loss as monitor.\n", + "\n", + " - `reduce_on_plateau`: Required to be set to true if using an adaptive scheduler.\n", + "\n", + "Any additional arguments under `sched` will be supplied as keyword arguments to the constructor of the scheduler.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "V3pQM2aj_6WX" + }, + "source": [ + "## Difference between the data loader setup methods\n", + "----------\n", + "\n", + "You might notice, we have multiple setup methods for validation and test data sets. We also don't have an equivalent `setup_multi_train_data`. \n", + "\n", + "In general, the `multi` methods refer to multiple data sets / data loaders. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "g33nMx9WCJdj" + }, + "source": [ + "### Where's `setup_multi_train_data`?\n", + "With the above in mind, let's tackle why we don't have `setup_multi_train_data`. \n", + "\n", + "NeMo is concerned with multiple domains - `asr`, `nlp` and `tts`. The way datasets are setup and used in these domains is dramatically different. It is often unclear what it means to have multiple train datasets - do we concatenate them? Do we randomly sample (with same or different probability) from each of them? \n", + "\n", + "Therefore we leave such support for multiple datasets up to the model itself. For example, in ASR, you can concatenate multiple train manifest files by using commas when providing the `manifest_filepath` value!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BjI2Q5LECJib" + }, + "source": [ + "### What are multi methods?\n", + "\n", + "In many cases, especially true for ASR and NLP, we may have multiple validation and test datasets. The most common example for this in ASR is `Librispeech`, which has `dev_clean`, `dev_other`, `test_clean`, `test_other`.\n", + "\n", + "NeMo standardizes how to handle multiple data loaders for validation and testing, so that all of our collections have a similar look and feel, as well as ease development of our models. During evaluation, these datasets are treated independently and prepended with resolved names so that logs are separate!\n", + "\n", + "The `multi` methods are therefore generalizations of the single validation and single test data setup methods, with some additional functionality. If you provide multiple datasets, you still have to write code for just one dataset and NeMo will automatically attach the appropriate names to your logs so you can differentiate between them!\n", + "\n", + "Furthermore, they also automatically preserve the config the user passes to them when updating the validation or test data loaders.\n", + "\n", + "**In general, it is preferred to call the `setup_multi_validation_data` and `setup_multi_test_data` methods, even if you are only using single datasets, simply for the automated management they provide.**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZKURHn0jH_52" + }, + "source": [ + "## Creating Model from constructor vs restoring a model\n", + "---------\n", + "\n", + "You might notice, we discuss all of the above setup methods in the context of model after it is restored. However, NeMo scripts do not call them inside any of the example train scripts themselves.\n", + "\n", + "This is because these methods are automatically called by the constructor when the Model is created for the first time, but these methods are skipped during restoration (either from a PyTorch Lightning checkpoint using `load_from_checkpoint`, or via `restore_from` method inside NeMo Models).\n", + "\n", + "This is done as most datasets are stored on a user's local directory, and the path to these datasets is set in the config (either set by default, or set by Hydra overrides). On the other hand, the models are meant to be portable. On another user's system, the data might not be placed at exactly the same location, or even on the same drive as specified in the model's config!\n", + "\n", + "Therefore we allow the constructor some brevity and automate such dataset setup, whereas restoration warns that data loaders were not set up and provides the user with ways to set up their own datasets.\n", + "\n", + "------\n", + "\n", + "Why are optimizers not restored automatically? Well, optimizers themselves don't face an issue, but as we saw before, schedulers depend on the number of train steps in order to calculate their schedule.\n", + "\n", + "However, if you don't wish to modify the optimizer and scheduler, and prefer to leave them to their default values, that's perfectly alright. The `setup_optimization()` method is automatically called by PyTorch Lightning for you when you begin training your model!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "g91FE8mlMcnh" + }, + "source": [ + "## Saving and restoring models\n", + "----------\n", + "\n", + "NeMo provides a few ways to save and restore models. If you utilize the Experiment Manager that is part of all NeMo train scripts, PyTorch Lightning will automatically save checkpoints for you in the experiment directory.\n", + "\n", + "We can also use packaged files using the specialized `save_to` and `restore_from` methods." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NzMxga7QNYn8" + }, + "source": [ + "### Saving and Restoring from PTL Checkpoints\n", + "----------\n", + "\n", + "The PyTorch Lightning Trainer object will periodically save checkpoints when the experiment manager is being used during training.\n", + "\n", + "PyTorch Lightning checkpoints can then be loaded and evaluated / fine-tuned just as always using the class method `load_from_checkpoint`.\n", + "\n", + "For example, restore a Citrinet model from a checkpoint - \n", + "\n", + "```python\n", + "citrinet = nemo_asr.models.EncDecCTCModelBPE.load_from_checkpoint()\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W4YzAG-KOBkZ" + }, + "source": [ + "### Saving and Restoring from .nemo files\n", + "----------\n", + "\n", + "There are a few models which might require external dependencies to be packaged with them in order to restore them properly.\n", + "\n", + "One such example is an ASR model with an external BPE tokenizer. It is preferred if the model includes all of the components required to restore it, but a binary file for a tokenizer cannot be serialized into a PyTorch Lightning checkpoint.\n", + "\n", + "In such cases, we can use the `save_to` and `restore_from` method to package the entire model + its components (here, the tokenizer file(s)) into a tarfile. This can then be easily imported by the user and used to restore the model." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "P6_vMSwXNJ74" + }, + "source": [ + "# Save the model\n", + "citrinet.save_to('citrinet_512.nemo')" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "HrBhgaqyP4rU" + }, + "source": [ + "!ls -d -- *.nemo " + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "Tyht1E0DQGb_" + }, + "source": [ + "# Restore the model\n", + "temp_cn = nemo_asr.models.EncDecCTCModelBPE.restore_from('citrinet_512.nemo')" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "dqNpmYYJQS2H" + }, + "source": [ + "temp_cn.summarize();" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "A5e42EoiZYjf" + }, + "source": [ + "# Note that the preprocessor + optimizer config have been preserved after the changes we made !\n", + "print(OmegaConf.to_yaml(temp_cn.cfg))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OI3RxwpcV-UF" + }, + "source": [ + "Note, that .nemo file is a simple .tar.gz with checkpoint, configuration and, potentially, other artifacts such as tokenizer configs being used by the model" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "jFBAGcaDWLiu" + }, + "source": [ + "!cp citrinet_512.nemo citrinet_512.tar.gz\n", + "!tar -xvf citrinet_512.tar.gz" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mkau4Q9jZo1l" + }, + "source": [ + "### Extracting PyTorch checkpoints from NeMo tarfiles (Model level)\n", + "-----------\n", + "\n", + "While the .nemo tarfile is an excellent way to have a portable model, sometimes it is necessary for researchers to have access to the basic PyTorch save format. NeMo aims to be entirely compatible with PyTorch, and therefore offers a simple method to extract just the PyTorch checkpoint from the .nemo tarfile." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "qccPANeycCoq" + }, + "source": [ + "import torch" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "A4zswOKHar9q" + }, + "source": [ + "state_dict = temp_cn.extract_state_dict_from('citrinet_512.nemo', save_dir='./pt_ckpt/')\n", + "!ls ./pt_ckpt/" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ACB-0dfnbFG3" + }, + "source": [ + "As we can see below, there is now a single basic PyTorch checkpoint available inside the `pt_ckpt` directory, which we can use to load the weights of the entire model as below" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "4ZAF_A0uc5bB" + }, + "source": [ + "temp_cn.load_state_dict(torch.load('./pt_ckpt/model_weights.ckpt'))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Hkq6EM99cS6y" + }, + "source": [ + "### Extracting PyTorch checkpoints from NeMo tarfiles (Module level)\n", + "----------\n", + "\n", + "While the above method is exceptional when extracting the checkpoint of the entire model, sometimes there may be a necessity to load and save the individual modules that comprise the Model.\n", + "\n", + "The same extraction method offers a flag to extract the individual model level checkpoints into their individual files, so that users have access to per-module level checkpoints." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "LW6wve2zbT9D" + }, + "source": [ + "state_dict = temp_cn.extract_state_dict_from('citrinet_512.nemo', save_dir='./pt_module_ckpt/', split_by_module=True)\n", + "!ls ./pt_module_ckpt/" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DtV5vpb5d1ni" + }, + "source": [ + "Now, we can load and assign the weights of the individual modules of the above Citrinet Model !" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "rVHylSKFdywn" + }, + "source": [ + "temp_cn.preprocessor.load_state_dict(torch.load('./pt_module_ckpt/preprocessor.ckpt'))\n", + "temp_cn.encoder.load_state_dict(torch.load('./pt_module_ckpt/encoder.ckpt'))\n", + "temp_cn.decoder.load_state_dict(torch.load('./pt_module_ckpt/decoder.ckpt'))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "88vOGV7VYcuu" + }, + "source": [ + "# NeMo with Hydra\n", + "\n", + "[Hydra](https://hydra.cc/docs/intro/) is used throughout NeMo as a way to enable rapid prototyping using predefined config files. Hydra and OmegaConf offer great compatibility with each other, and below we show a few general helpful tips to improve productivity with Hydra when using NeMo." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DfY6Ha3qYcxG" + }, + "source": [ + "## Hydra Help\n", + "--------\n", + "\n", + "Since our scripts are written with hydra in mind, you might notice that using `python --help` returns you a config rather than the usual help format from argparse. \n", + "\n", + "Using `--help` you can see the default config attached to the script - every NeMo script has at least one default config file attached to it. This gives you a guide on how you can modify values for an experiment.\n", + "\n", + "Hydra also has a special `--hydra-help` flag, which will offer you more help with respect to hydra itself as it is set up in the script.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gEsZlnfaYc3X" + }, + "source": [ + "## Changing config paths and files\n", + "---------\n", + "\n", + "While all NeMo models come with at least 1 default config file, one might want to switch configs without changing code. This is easily achieved by the following commands : \n", + "\n", + "- `--config-path`: Path to the directory which contains the config files\n", + "- `--config-name`: Name of the config file we wish to load.\n", + "\n", + "Note that these two arguments need to be at the very beginning of your execution statement, before you provide any command line overrides to your config file." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZyNHlArpYc9A" + }, + "source": [ + "## Overriding config from the command line\n", + "----------\n", + "\n", + "Hydra allows users to provide command line overrides to any part of the config. There are three cases to consider - \n", + "\n", + " - Override existing value in config\n", + " - Add new value in config\n", + " - Remove old value in config" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "96CKbvn6Yc7f" + }, + "source": [ + "### Overriding existing values in config\n", + "\n", + "Let's take the case where we want to change the optimizer from `novograd` to `adam`. Let's also change the beta values to default adam values.\n", + "\n", + "Hydra overrides are based on the `.` syntax - each `.` representing a level in the config itself.\n", + "\n", + "```sh\n", + "$ python + + +
+ + +
+ + + +
+ + + +
+ + +
+ + +''' + + +#class Converter(): +# def __init__(self, model_dir, model_name): +# self.num_features = 24 +# self.sampling_rate = 16000 +# self.frame_period = 5.0 +# +# self.model = CycleGAN(num_features = self.num_features, mode = 'test') +# +# self.model.load(filepath = os.path.join(model_dir, model_name)) +# +# """ +# # NB: Save the graph +# definition = self.model.sess.graph_def +# directory = 'saved_model_2' +# tf.train.write_graph(definition, directory, 'saved_model_2.pb', as_text=True) +# # https://github.com/tensorflow/models/issues/3530#issuecomment-395968881 +# output_dir = './saved_model/' +# builder = tf.saved_model.builder.SavedModelBuilder(output_dir) +# builder.add_meta_graph_and_variables( +# self.model.sess, +# [tf.saved_model.tag_constants.SERVING], +# main_op=tf.tables_initializer(), +# ) +# builder.save() +# """ +# +# """ +# builder.add_meta_graph_and_variables( +# self.model.sess, +# [tf.saved_model.tag_constants.SERVING], +# signature_def_map={ +# 'predict_images': +# prediction_signature, +# signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: +# classification_signature, +# }, +# main_op=tf.tables_initializer()) +# """ +# +# self.mcep_normalization_params = np.load(os.path.join(model_dir, 'mcep_normalization.npz')) +# self.mcep_mean_A = self.mcep_normalization_params['mean_A'] +# self.mcep_std_A = self.mcep_normalization_params['std_A'] +# self.mcep_mean_B = self.mcep_normalization_params['mean_B'] +# self.mcep_std_B = self.mcep_normalization_params['std_B'] +# +# self.logf0s_normalization_params = np.load(os.path.join(model_dir, 'logf0s_normalization.npz')) +# self.logf0s_mean_A = self.logf0s_normalization_params['mean_A'] +# self.logf0s_std_A = self.logf0s_normalization_params['std_A'] +# self.logf0s_mean_B = self.logf0s_normalization_params['mean_B'] +# self.logf0s_std_B = self.logf0s_normalization_params['std_B'] +# +# def convert(self, wav, conversion_direction='A2B'): +# wav = wav_padding(wav = wav, sr = self.sampling_rate, frame_period = self.frame_period, multiple = 4) +# f0, timeaxis, sp, ap = world_decompose(wav = wav, fs = self.sampling_rate, frame_period = self.frame_period) +# coded_sp = world_encode_spectral_envelop(sp = sp, fs = self.sampling_rate, dim = self.num_features) +# coded_sp_transposed = coded_sp.T +# +# if conversion_direction == 'A2B': +# f0_converted = pitch_conversion(f0 = f0, mean_log_src = self.logf0s_mean_A, std_log_src = self.logf0s_std_A, mean_log_target = self.logf0s_mean_B, std_log_target = self.logf0s_std_B) +# coded_sp_norm = (coded_sp_transposed - self.mcep_mean_A) / self.mcep_std_A +# coded_sp_converted_norm = self.model.test(inputs = np.array([coded_sp_norm]), direction = conversion_direction)[0] +# coded_sp_converted = coded_sp_converted_norm * self.mcep_std_B + self.mcep_mean_B +# else: +# f0_converted = pitch_conversion(f0 = f0, mean_log_src = self.logf0s_mean_B, std_log_src = self.logf0s_std_B, mean_log_target = self.logf0s_mean_A, std_log_target = self.logf0s_std_A) +# coded_sp_norm = (coded_sp_transposed - self.mcep_mean_B) / self.mcep_std_B +# coded_sp_converted_norm = self.model.test(inputs = np.array([coded_sp_norm]), direction = conversion_direction)[0] +# coded_sp_converted = coded_sp_converted_norm * self.mcep_std_A + self.mcep_mean_A +# +# coded_sp_converted = coded_sp_converted.T +# coded_sp_converted = np.ascontiguousarray(coded_sp_converted) +# decoded_sp_converted = world_decode_spectral_envelop(coded_sp = coded_sp_converted, fs = self.sampling_rate) +# wav_transformed = world_speech_synthesis(f0 = f0_converted, decoded_sp = decoded_sp_converted, ap = ap, fs = self.sampling_rate, frame_period = self.frame_period) +# +# # For debugging model output, uncomment the following line: +# # librosa.output.write_wav('model_output.wav', wav_transformed, self.sampling_rate) +# +# # TODO: Perhaps ditch this. It's probably unnecessary work. +# upsampled = librosa.resample(wav_transformed, self.sampling_rate, 48000) +# pcm_data = upsampled.astype(np.float64) +# stereo_pcm_data = np.tile(pcm_data, (2,1)).T +# +# buf = io.BytesIO() +# scipy.io.wavfile.write(buf, 48000, stereo_pcm_data.astype(np.float32)) +# return buf + +## Set up model +## This should live long in memory, so we do it up front. +#model_dir_default = './model/sf1_tm1' +#model_name_default = 'sf1_tm1.ckpt' +#converter = Converter(model_dir_default, model_name_default) + +#tacotron = load_tacotron_model('/home/bt/models/tacotron2/tacotron2_uberduck_Noire.pt') +#waveglow = load_waveglow_model('/home/bt/models/waveglow/waveglow_256channels_universal_v5.pt') +pipeline = TacotronWaveglowPipeline() + +class IndexHandler(): + def on_get(self, request, response): + response.content_type = 'text/html' + response.body = INDEX_HTML + +class ApiHandler(): + def on_post(self, request, response): + raw_data = json.load(request.bounded_stream) + + # Request parameters + synthesizer_checkpoint_path = raw_data.get('synthesizer_checkpoint_path') + vocoder_type = raw_data.get('vocoder_type') + waveglow_vocoder_checkpoint_path = raw_data.get('waveglow_vocoder_checkpoint_path') + hifigan_vocoder_checkpoint_path = raw_data.get('hifigan_vocoder_checkpoint_path') + hifigan_superres_vocoder_checkpoint_path = raw_data.get('hifigan_superres_vocoder_checkpoint_path') + inference_text = raw_data.get('inference_text') + output_audio_filename = raw_data.get('output_audio_filename') + output_spectrogram_filename = raw_data.get('output_spectrogram_filename') + output_metadata_filename = raw_data.get('output_metadata_filename') + + # Optional request parameters + maybe_clear_synthesizer_checkpoint_path = \ + raw_data.get('maybe_clear_synthesizer_checkpoint_path') + + print('synthesizer_checkpoint_path: {}'.format(synthesizer_checkpoint_path)) + print('vocoder_type: {}'.format(vocoder_type)) + print('waveglow_vocoder_checkpoint_path: {}'.format(waveglow_vocoder_checkpoint_path)) + print('hifigan_vocoder_checkpoint_path: {}'.format(hifigan_vocoder_checkpoint_path)) + print('hifigan_superres_vocoder_checkpoint_path: {}'.format(hifigan_superres_vocoder_checkpoint_path)) + print('inference_text: {}'.format(inference_text)) + print('output_audio_filename: {}'.format(output_audio_filename)) + print('output_spectrogram_filename: {}'.format(output_spectrogram_filename)) + print('output_metadata_filename: {}'.format(output_metadata_filename)) + print('maybe_clear_synthesizer_checkpoint_path: {}'.format( + maybe_clear_synthesizer_checkpoint_path)) + + pipeline.maybe_load_waveglow_model(waveglow_vocoder_checkpoint_path) + pipeline.maybe_load_hifigan(hifigan_vocoder_checkpoint_path) + pipeline.maybe_load_hifigan_super_resolution(hifigan_superres_vocoder_checkpoint_path) + + if maybe_clear_synthesizer_checkpoint_path: + pipeline.uncache_tacotron_model(maybe_clear_synthesizer_checkpoint_path) + + pipeline.maybe_load_tacotron_model_to_cache(synthesizer_checkpoint_path) + + inference_args = { + 'raw_text': inference_text, + 'synthesizer_checkpoint_path': synthesizer_checkpoint_path, + 'vocoder_type': vocoder_type, + 'output_audio_filename': output_audio_filename, + 'output_spectrogram_filename': output_spectrogram_filename, + 'output_metadata_filename': output_metadata_filename, + } + + pipeline.infer(inference_args) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--port', type=int, default=8000) + args = parser.parse_args() + + api = falcon.API(middleware=[MultipartMiddleware()]) + api.add_route('/', IndexHandler()) + api.add_route('/infer', ApiHandler()) + + print('Serving on 0.0.0.0:%d' % args.port) + simple_server.make_server('0.0.0.0', args.port, api).serve_forever() + +if __name__ == '__main__': + main() diff --git a/tts/vocodes_server_talknet.py b/tts/vocodes_server_talknet.py new file mode 100755 index 0000000..32cc859 --- /dev/null +++ b/tts/vocodes_server_talknet.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python3 + +""" +Starts a demo HTTP server to capture and transform audio +as a live demonstration of the trained model. +Brandon Thomas 2019-07-29 +""" + +import argparse +import falcon +import io +import librosa +import numpy as np +import os +import scipy +import soundfile +import tensorflow as tf +import subprocess +import tempfile +import json + +from falcon_multipart.middleware import MultipartMiddleware +#from model import CycleGAN +#from preprocess import * +from wsgiref import simple_server + +from vocodes_common_talknet import TacotronWaveglowPipeline +from vocodes_common_talknet import print_gpu_info +from vocodes_common_talknet import load_tacotron_model +from vocodes_common_talknet import load_waveglow_model +from vocodes_common_talknet import load_hifigan_model + +print("TensorFlow version: {}".format(tf.version.VERSION)) + +print_gpu_info() + +INDEX_HTML = ''' + + + + + + + +

TTS Inference

+ + + +
+ + +
+ + + +
+ + + +
+ + +
+ + +''' + + +#class Converter(): +# def __init__(self, model_dir, model_name): +# self.num_features = 24 +# self.sampling_rate = 16000 +# self.frame_period = 5.0 +# +# self.model = CycleGAN(num_features = self.num_features, mode = 'test') +# +# self.model.load(filepath = os.path.join(model_dir, model_name)) +# +# """ +# # NB: Save the graph +# definition = self.model.sess.graph_def +# directory = 'saved_model_2' +# tf.train.write_graph(definition, directory, 'saved_model_2.pb', as_text=True) +# # https://github.com/tensorflow/models/issues/3530#issuecomment-395968881 +# output_dir = './saved_model/' +# builder = tf.saved_model.builder.SavedModelBuilder(output_dir) +# builder.add_meta_graph_and_variables( +# self.model.sess, +# [tf.saved_model.tag_constants.SERVING], +# main_op=tf.tables_initializer(), +# ) +# builder.save() +# """ +# +# """ +# builder.add_meta_graph_and_variables( +# self.model.sess, +# [tf.saved_model.tag_constants.SERVING], +# signature_def_map={ +# 'predict_images': +# prediction_signature, +# signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: +# classification_signature, +# }, +# main_op=tf.tables_initializer()) +# """ +# +# self.mcep_normalization_params = np.load(os.path.join(model_dir, 'mcep_normalization.npz')) +# self.mcep_mean_A = self.mcep_normalization_params['mean_A'] +# self.mcep_std_A = self.mcep_normalization_params['std_A'] +# self.mcep_mean_B = self.mcep_normalization_params['mean_B'] +# self.mcep_std_B = self.mcep_normalization_params['std_B'] +# +# self.logf0s_normalization_params = np.load(os.path.join(model_dir, 'logf0s_normalization.npz')) +# self.logf0s_mean_A = self.logf0s_normalization_params['mean_A'] +# self.logf0s_std_A = self.logf0s_normalization_params['std_A'] +# self.logf0s_mean_B = self.logf0s_normalization_params['mean_B'] +# self.logf0s_std_B = self.logf0s_normalization_params['std_B'] +# +# def convert(self, wav, conversion_direction='A2B'): +# wav = wav_padding(wav = wav, sr = self.sampling_rate, frame_period = self.frame_period, multiple = 4) +# f0, timeaxis, sp, ap = world_decompose(wav = wav, fs = self.sampling_rate, frame_period = self.frame_period) +# coded_sp = world_encode_spectral_envelop(sp = sp, fs = self.sampling_rate, dim = self.num_features) +# coded_sp_transposed = coded_sp.T +# +# if conversion_direction == 'A2B': +# f0_converted = pitch_conversion(f0 = f0, mean_log_src = self.logf0s_mean_A, std_log_src = self.logf0s_std_A, mean_log_target = self.logf0s_mean_B, std_log_target = self.logf0s_std_B) +# coded_sp_norm = (coded_sp_transposed - self.mcep_mean_A) / self.mcep_std_A +# coded_sp_converted_norm = self.model.test(inputs = np.array([coded_sp_norm]), direction = conversion_direction)[0] +# coded_sp_converted = coded_sp_converted_norm * self.mcep_std_B + self.mcep_mean_B +# else: +# f0_converted = pitch_conversion(f0 = f0, mean_log_src = self.logf0s_mean_B, std_log_src = self.logf0s_std_B, mean_log_target = self.logf0s_mean_A, std_log_target = self.logf0s_std_A) +# coded_sp_norm = (coded_sp_transposed - self.mcep_mean_B) / self.mcep_std_B +# coded_sp_converted_norm = self.model.test(inputs = np.array([coded_sp_norm]), direction = conversion_direction)[0] +# coded_sp_converted = coded_sp_converted_norm * self.mcep_std_A + self.mcep_mean_A +# +# coded_sp_converted = coded_sp_converted.T +# coded_sp_converted = np.ascontiguousarray(coded_sp_converted) +# decoded_sp_converted = world_decode_spectral_envelop(coded_sp = coded_sp_converted, fs = self.sampling_rate) +# wav_transformed = world_speech_synthesis(f0 = f0_converted, decoded_sp = decoded_sp_converted, ap = ap, fs = self.sampling_rate, frame_period = self.frame_period) +# +# # For debugging model output, uncomment the following line: +# # librosa.output.write_wav('model_output.wav', wav_transformed, self.sampling_rate) +# +# # TODO: Perhaps ditch this. It's probably unnecessary work. +# upsampled = librosa.resample(wav_transformed, self.sampling_rate, 48000) +# pcm_data = upsampled.astype(np.float64) +# stereo_pcm_data = np.tile(pcm_data, (2,1)).T +# +# buf = io.BytesIO() +# scipy.io.wavfile.write(buf, 48000, stereo_pcm_data.astype(np.float32)) +# return buf + +## Set up model +## This should live long in memory, so we do it up front. +#model_dir_default = './model/sf1_tm1' +#model_name_default = 'sf1_tm1.ckpt' +#converter = Converter(model_dir_default, model_name_default) + +#tacotron = load_tacotron_model('/home/bt/models/tacotron2/tacotron2_uberduck_Noire.pt') +#waveglow = load_waveglow_model('/home/bt/models/waveglow/waveglow_256channels_universal_v5.pt') +pipeline = TacotronWaveglowPipeline() + +class IndexHandler(): + def on_get(self, request, response): + response.content_type = 'text/html' + response.body = INDEX_HTML + +class ApiHandler(): + def on_post(self, request, response): + raw_data = json.load(request.bounded_stream) + + # Request parameters + synthesizer_checkpoint_path = raw_data.get('synthesizer_checkpoint_path') + vocoder_type = raw_data.get('vocoder_type') + waveglow_vocoder_checkpoint_path = raw_data.get('waveglow_vocoder_checkpoint_path') + hifigan_vocoder_checkpoint_path = raw_data.get('hifigan_vocoder_checkpoint_path') + hifigan_superres_vocoder_checkpoint_path = raw_data.get('hifigan_superres_vocoder_checkpoint_path') + inference_text = raw_data.get('inference_text') + output_audio_filename = raw_data.get('output_audio_filename') + output_spectrogram_filename = raw_data.get('output_spectrogram_filename') + output_metadata_filename = raw_data.get('output_metadata_filename') + + # Optional request parameters + maybe_clear_synthesizer_checkpoint_path = \ + raw_data.get('maybe_clear_synthesizer_checkpoint_path') + + print('synthesizer_checkpoint_path: {}'.format(synthesizer_checkpoint_path)) + print('vocoder_type: {}'.format(vocoder_type)) + print('waveglow_vocoder_checkpoint_path: {}'.format(waveglow_vocoder_checkpoint_path)) + print('hifigan_vocoder_checkpoint_path: {}'.format(hifigan_vocoder_checkpoint_path)) + print('hifigan_superres_vocoder_checkpoint_path: {}'.format(hifigan_superres_vocoder_checkpoint_path)) + print('inference_text: {}'.format(inference_text)) + print('output_audio_filename: {}'.format(output_audio_filename)) + print('output_spectrogram_filename: {}'.format(output_spectrogram_filename)) + print('output_metadata_filename: {}'.format(output_metadata_filename)) + print('maybe_clear_synthesizer_checkpoint_path: {}'.format( + maybe_clear_synthesizer_checkpoint_path)) + + #pipeline.maybe_load_waveglow_model(waveglow_vocoder_checkpoint_path) + #pipeline.maybe_load_hifigan(hifigan_vocoder_checkpoint_path) + #pipeline.maybe_load_hifigan_super_resolution(hifigan_superres_vocoder_checkpoint_path) + + #if maybe_clear_synthesizer_checkpoint_path: + # pipeline.uncache_tacotron_model(maybe_clear_synthesizer_checkpoint_path) + + #pipeline.maybe_load_tacotron_model_to_cache(synthesizer_checkpoint_path) + + inference_args = { + 'raw_text': inference_text, + 'synthesizer_checkpoint_path': synthesizer_checkpoint_path, + 'vocoder_type': vocoder_type, + 'output_audio_filename': output_audio_filename, + 'output_spectrogram_filename': output_spectrogram_filename, + 'output_metadata_filename': output_metadata_filename, + } + + pipeline.infer(inference_args) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--port', type=int, default=8000) + args = parser.parse_args() + + api = falcon.API(middleware=[MultipartMiddleware()]) + api.add_route('/', IndexHandler()) + api.add_route('/infer', ApiHandler()) + + print('Serving on 0.0.0.0:%d' % args.port) + simple_server.make_server('0.0.0.0', args.port, api).serve_forever() + +if __name__ == '__main__': + """ + Launching a TalkNet server: + + from ControllableTalkNet.controllable_talknet import * + + app.run_server( + mode="inline", + threaded=True, + #dev_tools_ui=True, + #dev_tools_hot_reload=True, + ) + """ + main() diff --git a/tts/vocodes_wav_images.py b/tts/vocodes_wav_images.py new file mode 100644 index 0000000..ec59498 --- /dev/null +++ b/tts/vocodes_wav_images.py @@ -0,0 +1,49 @@ +from PIL import Image, ImageDraw + +def render_histogram(wav, filename='histograms/output.png', row_index=None, col_index=None): + dimensions = wav.shape + print('>>> Tensor Image input size: {}'.format(dimensions)) + + wav_signal = None + rows = -1 + cols = -1 + if row_index is not None and col_index is not None: + rows = dimensions[row_index] + cols = dimensions[col_index] + wav_signal = wav + else: + # Remove 1-sized dimensions + wav_signal = wav.squeeze() + rows = wav_signal.shape[0] + cols = wav_signal.shape[1] + + print('>>> Generating image (rows: {} cols: {})'.format(rows, cols)) + image = Image.new('RGB', (rows, cols)) + pixels = image.load() + + minimum = wav_signal[0,0] + maximum = wav_signal[0,0] + + for x in range(0, rows): + for y in range(0, cols): + if wav_signal[x,y] > maximum: + maximum = wav_signal[x,y] + if wav_signal[x,y] < minimum: + minimum = wav_signal[x,y] + + print('Minimum: ' + str(minimum)) + print('Maximum: ' + str(maximum)) + + if maximum == minimum: + maximum = 1 # nb: to prevent division by zero below + + for x in range(0, rows): + for y in range(0, cols): + v = wav_signal[x,y] + scaled = int((v - minimum) / (maximum - minimum) * 255) + pixels[x, y] = (scaled, scaled, scaled) + + # Image Show only works on local X server: + #image.show() + image.save(filename) + diff --git a/tts/waveglow/.gitmodules b/tts/waveglow/.gitmodules new file mode 100644 index 0000000..e3bf8bf --- /dev/null +++ b/tts/waveglow/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tacotron2"] + path = tacotron2 + url = http://github.com/NVIDIA/tacotron2 diff --git a/tts/waveglow/LICENSE b/tts/waveglow/LICENSE new file mode 100644 index 0000000..2a718d6 --- /dev/null +++ b/tts/waveglow/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, NVIDIA Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tts/waveglow/README.md b/tts/waveglow/README.md new file mode 100755 index 0000000..89886f0 --- /dev/null +++ b/tts/waveglow/README.md @@ -0,0 +1,91 @@ +![WaveGlow](waveglow_logo.png "WaveGLow") + +## WaveGlow: a Flow-based Generative Network for Speech Synthesis + +### Ryan Prenger, Rafael Valle, and Bryan Catanzaro + +In our recent [paper], we propose WaveGlow: a flow-based network capable of +generating high quality speech from mel-spectrograms. WaveGlow combines insights +from [Glow] and [WaveNet] in order to provide fast, efficient and high-quality +audio synthesis, without the need for auto-regression. WaveGlow is implemented +using only a single network, trained using only a single cost function: +maximizing the likelihood of the training data, which makes the training +procedure simple and stable. + +Our [PyTorch] implementation produces audio samples at a rate of 4850 +kHz on an NVIDIA V100 GPU. Mean Opinion Scores show that it delivers audio +quality as good as the best publicly available WaveNet implementation. + +Visit our [website] for audio samples. + +## Setup + +1. Clone our repo and initialize submodule + + ```command + git clone https://github.com/NVIDIA/waveglow.git + cd waveglow + git submodule init + git submodule update + ``` + +2. Install requirements `pip3 install -r requirements.txt` + +3. Install [Apex] + + +## Generate audio with our pre-existing model + +1. Download our [published model] +2. Download [mel-spectrograms] +3. Generate audio `python3 inference.py -f <(ls mel_spectrograms/*.pt) -w waveglow_256channels.pt -o . --is_fp16 -s 0.6` + +N.b. use `convert_model.py` to convert your older models to the current model +with fused residual and skip connections. + +## Train your own model + +1. Download [LJ Speech Data]. In this example it's in `data/` + +2. Make a list of the file names to use for training/testing + + ```command + ls data/*.wav | tail -n+10 > train_files.txt + ls data/*.wav | head -n10 > test_files.txt + ``` + +3. Train your WaveGlow networks + + ```command + mkdir checkpoints + python train.py -c config.json + ``` + + For multi-GPU training replace `train.py` with `distributed.py`. Only tested with single node and NCCL. + + For mixed precision training set `"fp16_run": true` on `config.json`. + +4. Make test set mel-spectrograms + + `python mel2samp.py -f test_files.txt -o . -c config.json` + +5. Do inference with your network + + ```command + ls *.pt > mel_files.txt + python3 inference.py -f mel_files.txt -w checkpoints/waveglow_10000 -o . --is_fp16 -s 0.6 + ``` + +[//]: # (TODO) +[//]: # (PROVIDE INSTRUCTIONS FOR DOWNLOADING LJS) +[pytorch 1.0]: https://github.com/pytorch/pytorch#installation +[website]: https://nv-adlr.github.io/WaveGlow +[paper]: https://arxiv.org/abs/1811.00002 +[WaveNet implementation]: https://github.com/r9y9/wavenet_vocoder +[Glow]: https://blog.openai.com/glow/ +[WaveNet]: https://deepmind.com/blog/wavenet-generative-model-raw-audio/ +[PyTorch]: http://pytorch.org +[published model]: https://ngc.nvidia.com/catalog/models/nvidia:waveglow_ljs_256channels +[mel-spectrograms]: https://drive.google.com/file/d/1g_VXK2lpP9J25dQFhQwx7doWl_p20fXA/view?usp=sharing +[LJ Speech Data]: https://keithito.com/LJ-Speech-Dataset +[Apex]: https://github.com/nvidia/apex diff --git a/tts/waveglow/config.json b/tts/waveglow/config.json new file mode 100755 index 0000000..7160474 --- /dev/null +++ b/tts/waveglow/config.json @@ -0,0 +1,41 @@ +{ + "train_config": { + "fp16_run": true, + "output_directory": "checkpoints", + "epochs": 100000, + "learning_rate": 1e-4, + "sigma": 1.0, + "iters_per_checkpoint": 2000, + "batch_size": 12, + "seed": 1234, + "checkpoint_path": "", + "with_tensorboard": false + }, + "data_config": { + "training_files": "train_files.txt", + "segment_length": 16000, + "sampling_rate": 22050, + "filter_length": 1024, + "hop_length": 256, + "win_length": 1024, + "mel_fmin": 0.0, + "mel_fmax": 8000.0 + }, + "dist_config": { + "dist_backend": "nccl", + "dist_url": "tcp://localhost:54321" + }, + + "waveglow_config": { + "n_mel_channels": 80, + "n_flows": 12, + "n_group": 8, + "n_early_every": 4, + "n_early_size": 2, + "WN_config": { + "n_layers": 8, + "n_channels": 256, + "kernel_size": 3 + } + } +} diff --git a/tts/waveglow/convert_model.py b/tts/waveglow/convert_model.py new file mode 100644 index 0000000..32e77e2 --- /dev/null +++ b/tts/waveglow/convert_model.py @@ -0,0 +1,72 @@ +import sys +import copy +import torch + +def _check_model_old_version(model): + if hasattr(model.WN[0], 'res_layers') or hasattr(model.WN[0], 'cond_layers'): + return True + else: + return False + + +def _update_model_res_skip(old_model, new_model): + for idx in range(0, len(new_model.WN)): + wavenet = new_model.WN[idx] + n_channels = wavenet.n_channels + n_layers = wavenet.n_layers + wavenet.res_skip_layers = torch.nn.ModuleList() + for i in range(0, n_layers): + if i < n_layers - 1: + res_skip_channels = 2*n_channels + else: + res_skip_channels = n_channels + res_skip_layer = torch.nn.Conv1d(n_channels, res_skip_channels, 1) + skip_layer = torch.nn.utils.remove_weight_norm(wavenet.skip_layers[i]) + if i < n_layers - 1: + res_layer = torch.nn.utils.remove_weight_norm(wavenet.res_layers[i]) + res_skip_layer.weight = torch.nn.Parameter(torch.cat([res_layer.weight, skip_layer.weight])) + res_skip_layer.bias = torch.nn.Parameter(torch.cat([res_layer.bias, skip_layer.bias])) + else: + res_skip_layer.weight = torch.nn.Parameter(skip_layer.weight) + res_skip_layer.bias = torch.nn.Parameter(skip_layer.bias) + res_skip_layer = torch.nn.utils.weight_norm(res_skip_layer, name='weight') + wavenet.res_skip_layers.append(res_skip_layer) + del wavenet.res_layers + del wavenet.skip_layers + +def _update_model_cond(old_model, new_model): + for idx in range(0, len(new_model.WN)): + wavenet = new_model.WN[idx] + n_channels = wavenet.n_channels + n_layers = wavenet.n_layers + n_mel_channels = wavenet.cond_layers[0].weight.shape[1] + cond_layer = torch.nn.Conv1d(n_mel_channels, 2*n_channels*n_layers, 1) + cond_layer_weight = [] + cond_layer_bias = [] + for i in range(0, n_layers): + _cond_layer = torch.nn.utils.remove_weight_norm(wavenet.cond_layers[i]) + cond_layer_weight.append(_cond_layer.weight) + cond_layer_bias.append(_cond_layer.bias) + cond_layer.weight = torch.nn.Parameter(torch.cat(cond_layer_weight)) + cond_layer.bias = torch.nn.Parameter(torch.cat(cond_layer_bias)) + cond_layer = torch.nn.utils.weight_norm(cond_layer, name='weight') + wavenet.cond_layer = cond_layer + del wavenet.cond_layers + +def update_model(old_model): + if not _check_model_old_version(old_model): + return old_model + new_model = copy.deepcopy(old_model) + if hasattr(old_model.WN[0], 'res_layers'): + _update_model_res_skip(old_model, new_model) + if hasattr(old_model.WN[0], 'cond_layers'): + _update_model_cond(old_model, new_model) + return new_model + +if __name__ == '__main__': + old_model_path = sys.argv[1] + new_model_path = sys.argv[2] + model = torch.load(old_model_path) + model['model'] = update_model(model['model']) + torch.save(model, new_model_path) + diff --git a/tts/waveglow/denoiser.py b/tts/waveglow/denoiser.py new file mode 100644 index 0000000..0e73584 --- /dev/null +++ b/tts/waveglow/denoiser.py @@ -0,0 +1,40 @@ +import sys +sys.path.append('tacotron2') +import torch +from layers import STFT + + +class Denoiser(torch.nn.Module): + """ Removes model bias from audio produced with waveglow """ + + def __init__(self, waveglow, filter_length=1024, n_overlap=4, + win_length=1024, mode='zeros'): + super(Denoiser, self).__init__() + self.stft = STFT(filter_length=filter_length, + hop_length=int(filter_length/n_overlap), + win_length=win_length).cuda() + if mode == 'zeros': + mel_input = torch.zeros( + (1, 80, 88), + dtype=waveglow.upsample.weight.dtype, + device=waveglow.upsample.weight.device) + elif mode == 'normal': + mel_input = torch.randn( + (1, 80, 88), + dtype=waveglow.upsample.weight.dtype, + device=waveglow.upsample.weight.device) + else: + raise Exception("Mode {} if not supported".format(mode)) + + with torch.no_grad(): + bias_audio = waveglow.infer(mel_input, sigma=0.0).float() + bias_spec, _ = self.stft.transform(bias_audio) + + self.register_buffer('bias_spec', bias_spec[:, :, 0][:, :, None]) + + def forward(self, audio, strength=0.1): + audio_spec, audio_angles = self.stft.transform(audio.cuda().float()) + audio_spec_denoised = audio_spec - self.bias_spec * strength + audio_spec_denoised = torch.clamp(audio_spec_denoised, 0.0) + audio_denoised = self.stft.inverse(audio_spec_denoised, audio_angles) + return audio_denoised diff --git a/tts/waveglow/distributed.py b/tts/waveglow/distributed.py new file mode 100644 index 0000000..19cbfd2 --- /dev/null +++ b/tts/waveglow/distributed.py @@ -0,0 +1,184 @@ +# ***************************************************************************** +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ***************************************************************************** +import os +import sys +import time +import subprocess +import argparse + +import torch +import torch.distributed as dist +from torch.autograd import Variable + +def reduce_tensor(tensor, num_gpus): + rt = tensor.clone() + dist.all_reduce(rt, op=dist.reduce_op.SUM) + rt /= num_gpus + return rt + +def init_distributed(rank, num_gpus, group_name, dist_backend, dist_url): + assert torch.cuda.is_available(), "Distributed mode requires CUDA." + print("Initializing Distributed") + + # Set cuda device so everything is done on the right GPU. + torch.cuda.set_device(rank % torch.cuda.device_count()) + + # Initialize distributed communication + dist.init_process_group(dist_backend, init_method=dist_url, + world_size=num_gpus, rank=rank, + group_name=group_name) + +def _flatten_dense_tensors(tensors): + """Flatten dense tensors into a contiguous 1D buffer. Assume tensors are of + same dense type. + Since inputs are dense, the resulting tensor will be a concatenated 1D + buffer. Element-wise operation on this buffer will be equivalent to + operating individually. + Arguments: + tensors (Iterable[Tensor]): dense tensors to flatten. + Returns: + A contiguous 1D buffer containing input tensors. + """ + if len(tensors) == 1: + return tensors[0].contiguous().view(-1) + flat = torch.cat([t.contiguous().view(-1) for t in tensors], dim=0) + return flat + +def _unflatten_dense_tensors(flat, tensors): + """View a flat buffer using the sizes of tensors. Assume that tensors are of + same dense type, and that flat is given by _flatten_dense_tensors. + Arguments: + flat (Tensor): flattened dense tensors to unflatten. + tensors (Iterable[Tensor]): dense tensors whose sizes will be used to + unflatten flat. + Returns: + Unflattened dense tensors with sizes same as tensors and values from + flat. + """ + outputs = [] + offset = 0 + for tensor in tensors: + numel = tensor.numel() + outputs.append(flat.narrow(0, offset, numel).view_as(tensor)) + offset += numel + return tuple(outputs) + +def apply_gradient_allreduce(module): + """ + Modifies existing model to do gradient allreduce, but doesn't change class + so you don't need "module" + """ + if not hasattr(dist, '_backend'): + module.warn_on_half = True + else: + module.warn_on_half = True if dist._backend == dist.dist_backend.GLOO else False + + for p in module.state_dict().values(): + if not torch.is_tensor(p): + continue + dist.broadcast(p, 0) + + def allreduce_params(): + if(module.needs_reduction): + module.needs_reduction = False + buckets = {} + for param in module.parameters(): + if param.requires_grad and param.grad is not None: + tp = type(param.data) + if tp not in buckets: + buckets[tp] = [] + buckets[tp].append(param) + if module.warn_on_half: + if torch.cuda.HalfTensor in buckets: + print("WARNING: gloo dist backend for half parameters may be extremely slow." + + " It is recommended to use the NCCL backend in this case. This currently requires" + + "PyTorch built from top of tree master.") + module.warn_on_half = False + + for tp in buckets: + bucket = buckets[tp] + grads = [param.grad.data for param in bucket] + coalesced = _flatten_dense_tensors(grads) + dist.all_reduce(coalesced) + coalesced /= dist.get_world_size() + for buf, synced in zip(grads, _unflatten_dense_tensors(coalesced, grads)): + buf.copy_(synced) + + for param in list(module.parameters()): + def allreduce_hook(*unused): + Variable._execution_engine.queue_callback(allreduce_params) + if param.requires_grad: + param.register_hook(allreduce_hook) + dir(param) + + def set_needs_reduction(self, input, output): + self.needs_reduction = True + + module.register_forward_hook(set_needs_reduction) + return module + + +def main(config, stdout_dir, args_str): + args_list = ['train.py'] + args_list += args_str.split(' ') if len(args_str) > 0 else [] + + args_list.append('--config={}'.format(config)) + + num_gpus = torch.cuda.device_count() + args_list.append('--num_gpus={}'.format(num_gpus)) + args_list.append("--group_name=group_{}".format(time.strftime("%Y_%m_%d-%H%M%S"))) + + if not os.path.isdir(stdout_dir): + os.makedirs(stdout_dir) + os.chmod(stdout_dir, 0o775) + + workers = [] + + for i in range(num_gpus): + args_list[-2] = '--rank={}'.format(i) + stdout = None if i == 0 else open( + os.path.join(stdout_dir, "GPU_{}.log".format(i)), "w") + print(args_list) + p = subprocess.Popen([str(sys.executable)]+args_list, stdout=stdout) + workers.append(p) + + for p in workers: + p.wait() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-c', '--config', type=str, required=True, + help='JSON file for configuration') + parser.add_argument('-s', '--stdout_dir', type=str, default=".", + help='directory to save stoud logs') + parser.add_argument( + '-a', '--args_str', type=str, default='', + help='double quoted string with space separated key value pairs') + + args = parser.parse_args() + main(args.config, args.stdout_dir, args.args_str) diff --git a/tts/waveglow/glow.py b/tts/waveglow/glow.py new file mode 100644 index 0000000..7a76964 --- /dev/null +++ b/tts/waveglow/glow.py @@ -0,0 +1,311 @@ +# ***************************************************************************** +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ***************************************************************************** +import copy +import torch +from torch.autograd import Variable +import torch.nn.functional as F + + +@torch.jit.script +def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels): + n_channels_int = n_channels[0] + in_act = input_a+input_b + t_act = torch.tanh(in_act[:, :n_channels_int, :]) + s_act = torch.sigmoid(in_act[:, n_channels_int:, :]) + acts = t_act * s_act + return acts + + +class WaveGlowLoss(torch.nn.Module): + def __init__(self, sigma=1.0): + super(WaveGlowLoss, self).__init__() + self.sigma = sigma + + def forward(self, model_output): + z, log_s_list, log_det_W_list = model_output + for i, log_s in enumerate(log_s_list): + if i == 0: + log_s_total = torch.sum(log_s) + log_det_W_total = log_det_W_list[i] + else: + log_s_total = log_s_total + torch.sum(log_s) + log_det_W_total += log_det_W_list[i] + + loss = torch.sum(z*z)/(2*self.sigma*self.sigma) - log_s_total - log_det_W_total + return loss/(z.size(0)*z.size(1)*z.size(2)) + + +class Invertible1x1Conv(torch.nn.Module): + """ + The layer outputs both the convolution, and the log determinant + of its weight matrix. If reverse=True it does convolution with + inverse + """ + def __init__(self, c): + super(Invertible1x1Conv, self).__init__() + self.conv = torch.nn.Conv1d(c, c, kernel_size=1, stride=1, padding=0, + bias=False) + + # Sample a random orthonormal matrix to initialize weights + W = torch.qr(torch.FloatTensor(c, c).normal_())[0] + + # Ensure determinant is 1.0 not -1.0 + if torch.det(W) < 0: + W[:,0] = -1*W[:,0] + W = W.view(c, c, 1) + self.conv.weight.data = W + + def forward(self, z, reverse=False): + # shape + batch_size, group_size, n_of_groups = z.size() + + W = self.conv.weight.squeeze() + + if reverse: + if not hasattr(self, 'W_inverse'): + # Reverse computation + W_inverse = W.float().inverse() + W_inverse = Variable(W_inverse[..., None]) + if z.type() == 'torch.cuda.HalfTensor': + W_inverse = W_inverse.half() + self.W_inverse = W_inverse + z = F.conv1d(z, self.W_inverse, bias=None, stride=1, padding=0) + return z + else: + # Forward computation + log_det_W = batch_size * n_of_groups * torch.logdet(W) + z = self.conv(z) + return z, log_det_W + + +class WN(torch.nn.Module): + """ + This is the WaveNet like layer for the affine coupling. The primary difference + from WaveNet is the convolutions need not be causal. There is also no dilation + size reset. The dilation only doubles on each layer + """ + def __init__(self, n_in_channels, n_mel_channels, n_layers, n_channels, + kernel_size): + super(WN, self).__init__() + assert(kernel_size % 2 == 1) + assert(n_channels % 2 == 0) + self.n_layers = n_layers + self.n_channels = n_channels + self.in_layers = torch.nn.ModuleList() + self.res_skip_layers = torch.nn.ModuleList() + + start = torch.nn.Conv1d(n_in_channels, n_channels, 1) + start = torch.nn.utils.weight_norm(start, name='weight') + self.start = start + + # Initializing last layer to 0 makes the affine coupling layers + # do nothing at first. This helps with training stability + end = torch.nn.Conv1d(n_channels, 2*n_in_channels, 1) + end.weight.data.zero_() + end.bias.data.zero_() + self.end = end + + cond_layer = torch.nn.Conv1d(n_mel_channels, 2*n_channels*n_layers, 1) + self.cond_layer = torch.nn.utils.weight_norm(cond_layer, name='weight') + + for i in range(n_layers): + dilation = 2 ** i + padding = int((kernel_size*dilation - dilation)/2) + in_layer = torch.nn.Conv1d(n_channels, 2*n_channels, kernel_size, + dilation=dilation, padding=padding) + in_layer = torch.nn.utils.weight_norm(in_layer, name='weight') + self.in_layers.append(in_layer) + + + # last one is not necessary + if i < n_layers - 1: + res_skip_channels = 2*n_channels + else: + res_skip_channels = n_channels + res_skip_layer = torch.nn.Conv1d(n_channels, res_skip_channels, 1) + res_skip_layer = torch.nn.utils.weight_norm(res_skip_layer, name='weight') + self.res_skip_layers.append(res_skip_layer) + + def forward(self, forward_input): + audio, spect = forward_input + audio = self.start(audio) + output = torch.zeros_like(audio) + n_channels_tensor = torch.IntTensor([self.n_channels]) + + spect = self.cond_layer(spect) + + for i in range(self.n_layers): + spect_offset = i*2*self.n_channels + acts = fused_add_tanh_sigmoid_multiply( + self.in_layers[i](audio), + spect[:,spect_offset:spect_offset+2*self.n_channels,:], + n_channels_tensor) + + res_skip_acts = self.res_skip_layers[i](acts) + if i < self.n_layers - 1: + audio = audio + res_skip_acts[:,:self.n_channels,:] + output = output + res_skip_acts[:,self.n_channels:,:] + else: + output = output + res_skip_acts + + return self.end(output) + + +class WaveGlow(torch.nn.Module): + def __init__(self, n_mel_channels, n_flows, n_group, n_early_every, + n_early_size, WN_config): + super(WaveGlow, self).__init__() + + self.upsample = torch.nn.ConvTranspose1d(n_mel_channels, + n_mel_channels, + 1024, stride=256) + assert(n_group % 2 == 0) + self.n_flows = n_flows + self.n_group = n_group + self.n_early_every = n_early_every + self.n_early_size = n_early_size + self.WN = torch.nn.ModuleList() + self.convinv = torch.nn.ModuleList() + + n_half = int(n_group/2) + + # Set up layers with the right sizes based on how many dimensions + # have been output already + n_remaining_channels = n_group + for k in range(n_flows): + if k % self.n_early_every == 0 and k > 0: + n_half = n_half - int(self.n_early_size/2) + n_remaining_channels = n_remaining_channels - self.n_early_size + self.convinv.append(Invertible1x1Conv(n_remaining_channels)) + self.WN.append(WN(n_half, n_mel_channels*n_group, **WN_config)) + self.n_remaining_channels = n_remaining_channels # Useful during inference + + def forward(self, forward_input): + """ + forward_input[0] = mel_spectrogram: batch x n_mel_channels x frames + forward_input[1] = audio: batch x time + """ + spect, audio = forward_input + + # Upsample spectrogram to size of audio + spect = self.upsample(spect) + assert(spect.size(2) >= audio.size(1)) + if spect.size(2) > audio.size(1): + spect = spect[:, :, :audio.size(1)] + + spect = spect.unfold(2, self.n_group, self.n_group).permute(0, 2, 1, 3) + spect = spect.contiguous().view(spect.size(0), spect.size(1), -1).permute(0, 2, 1) + + audio = audio.unfold(1, self.n_group, self.n_group).permute(0, 2, 1) + output_audio = [] + log_s_list = [] + log_det_W_list = [] + + for k in range(self.n_flows): + if k % self.n_early_every == 0 and k > 0: + output_audio.append(audio[:,:self.n_early_size,:]) + audio = audio[:,self.n_early_size:,:] + + audio, log_det_W = self.convinv[k](audio) + log_det_W_list.append(log_det_W) + + n_half = int(audio.size(1)/2) + audio_0 = audio[:,:n_half,:] + audio_1 = audio[:,n_half:,:] + + output = self.WN[k]((audio_0, spect)) + log_s = output[:, n_half:, :] + b = output[:, :n_half, :] + audio_1 = torch.exp(log_s)*audio_1 + b + log_s_list.append(log_s) + + audio = torch.cat([audio_0, audio_1],1) + + output_audio.append(audio) + return torch.cat(output_audio,1), log_s_list, log_det_W_list + + def infer(self, spect, sigma=1.0): + spect = self.upsample(spect) + # trim conv artifacts. maybe pad spec to kernel multiple + time_cutoff = self.upsample.kernel_size[0] - self.upsample.stride[0] + spect = spect[:, :, :-time_cutoff] + + spect = spect.unfold(2, self.n_group, self.n_group).permute(0, 2, 1, 3) + spect = spect.contiguous().view(spect.size(0), spect.size(1), -1).permute(0, 2, 1) + + if spect.type() == 'torch.cuda.HalfTensor': + audio = torch.cuda.HalfTensor(spect.size(0), + self.n_remaining_channels, + spect.size(2)).normal_() + else: + audio = torch.cuda.FloatTensor(spect.size(0), + self.n_remaining_channels, + spect.size(2)).normal_() + + audio = torch.autograd.Variable(sigma*audio) + + for k in reversed(range(self.n_flows)): + n_half = int(audio.size(1)/2) + audio_0 = audio[:,:n_half,:] + audio_1 = audio[:,n_half:,:] + + output = self.WN[k]((audio_0, spect)) + + s = output[:, n_half:, :] + b = output[:, :n_half, :] + audio_1 = (audio_1 - b)/torch.exp(s) + audio = torch.cat([audio_0, audio_1],1) + + audio = self.convinv[k](audio, reverse=True) + + if k % self.n_early_every == 0 and k > 0: + if spect.type() == 'torch.cuda.HalfTensor': + z = torch.cuda.HalfTensor(spect.size(0), self.n_early_size, spect.size(2)).normal_() + else: + z = torch.cuda.FloatTensor(spect.size(0), self.n_early_size, spect.size(2)).normal_() + audio = torch.cat((sigma*z, audio),1) + + audio = audio.permute(0,2,1).contiguous().view(audio.size(0), -1).data + return audio + + @staticmethod + def remove_weightnorm(model): + waveglow = model + for WN in waveglow.WN: + WN.start = torch.nn.utils.remove_weight_norm(WN.start) + WN.in_layers = remove(WN.in_layers) + WN.cond_layer = torch.nn.utils.remove_weight_norm(WN.cond_layer) + WN.res_skip_layers = remove(WN.res_skip_layers) + return waveglow + + +def remove(conv_list): + new_conv_list = torch.nn.ModuleList() + for old_conv in conv_list: + old_conv = torch.nn.utils.remove_weight_norm(old_conv) + new_conv_list.append(old_conv) + return new_conv_list diff --git a/tts/waveglow/glow_old.py b/tts/waveglow/glow_old.py new file mode 100644 index 0000000..0de2375 --- /dev/null +++ b/tts/waveglow/glow_old.py @@ -0,0 +1,233 @@ +import copy +import torch +from glow import Invertible1x1Conv, remove + + +@torch.jit.script +def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels): + n_channels_int = n_channels[0] + in_act = input_a+input_b + t_act = torch.tanh(in_act[:, :n_channels_int, :]) + s_act = torch.sigmoid(in_act[:, n_channels_int:, :]) + acts = t_act * s_act + return acts + + +class WN(torch.nn.Module): + """ + This is the WaveNet like layer for the affine coupling. The primary difference + from WaveNet is the convolutions need not be causal. There is also no dilation + size reset. The dilation only doubles on each layer + """ + def __init__(self, n_in_channels, n_mel_channels, n_layers, n_channels, + kernel_size): + super(WN, self).__init__() + assert(kernel_size % 2 == 1) + assert(n_channels % 2 == 0) + self.n_layers = n_layers + self.n_channels = n_channels + self.in_layers = torch.nn.ModuleList() + self.res_skip_layers = torch.nn.ModuleList() + self.cond_layers = torch.nn.ModuleList() + + start = torch.nn.Conv1d(n_in_channels, n_channels, 1) + start = torch.nn.utils.weight_norm(start, name='weight') + self.start = start + + # Initializing last layer to 0 makes the affine coupling layers + # do nothing at first. This helps with training stability + end = torch.nn.Conv1d(n_channels, 2*n_in_channels, 1) + end.weight.data.zero_() + end.bias.data.zero_() + self.end = end + + for i in range(n_layers): + dilation = 2 ** i + padding = int((kernel_size*dilation - dilation)/2) + in_layer = torch.nn.Conv1d(n_channels, 2*n_channels, kernel_size, + dilation=dilation, padding=padding) + in_layer = torch.nn.utils.weight_norm(in_layer, name='weight') + self.in_layers.append(in_layer) + + cond_layer = torch.nn.Conv1d(n_mel_channels, 2*n_channels, 1) + cond_layer = torch.nn.utils.weight_norm(cond_layer, name='weight') + self.cond_layers.append(cond_layer) + + # last one is not necessary + if i < n_layers - 1: + res_skip_channels = 2*n_channels + else: + res_skip_channels = n_channels + res_skip_layer = torch.nn.Conv1d(n_channels, res_skip_channels, 1) + res_skip_layer = torch.nn.utils.weight_norm(res_skip_layer, name='weight') + self.res_skip_layers.append(res_skip_layer) + + def forward(self, forward_input): + audio, spect = forward_input + audio = self.start(audio) + + for i in range(self.n_layers): + acts = fused_add_tanh_sigmoid_multiply( + self.in_layers[i](audio), + self.cond_layers[i](spect), + torch.IntTensor([self.n_channels])) + + res_skip_acts = self.res_skip_layers[i](acts) + if i < self.n_layers - 1: + audio = res_skip_acts[:,:self.n_channels,:] + audio + skip_acts = res_skip_acts[:,self.n_channels:,:] + else: + skip_acts = res_skip_acts + + if i == 0: + output = skip_acts + else: + output = skip_acts + output + return self.end(output) + + +class WaveGlow(torch.nn.Module): + def __init__(self, n_mel_channels, n_flows, n_group, n_early_every, + n_early_size, WN_config): + super(WaveGlow, self).__init__() + + self.upsample = torch.nn.ConvTranspose1d(n_mel_channels, + n_mel_channels, + 1024, stride=256) + assert(n_group % 2 == 0) + self.n_flows = n_flows + self.n_group = n_group + self.n_early_every = n_early_every + self.n_early_size = n_early_size + self.WN = torch.nn.ModuleList() + self.convinv = torch.nn.ModuleList() + + n_half = int(n_group/2) + + # Set up layers with the right sizes based on how many dimensions + # have been output already + n_remaining_channels = n_group + for k in range(n_flows): + if k % self.n_early_every == 0 and k > 0: + n_half = n_half - int(self.n_early_size/2) + n_remaining_channels = n_remaining_channels - self.n_early_size + self.convinv.append(Invertible1x1Conv(n_remaining_channels)) + self.WN.append(WN(n_half, n_mel_channels*n_group, **WN_config)) + self.n_remaining_channels = n_remaining_channels # Useful during inference + + def forward(self, forward_input): + return None + """ + forward_input[0] = audio: batch x time + forward_input[1] = upsamp_spectrogram: batch x n_cond_channels x time + """ + """ + spect, audio = forward_input + + # Upsample spectrogram to size of audio + spect = self.upsample(spect) + assert(spect.size(2) >= audio.size(1)) + if spect.size(2) > audio.size(1): + spect = spect[:, :, :audio.size(1)] + + spect = spect.unfold(2, self.n_group, self.n_group).permute(0, 2, 1, 3) + spect = spect.contiguous().view(spect.size(0), spect.size(1), -1).permute(0, 2, 1) + + audio = audio.unfold(1, self.n_group, self.n_group).permute(0, 2, 1) + output_audio = [] + s_list = [] + s_conv_list = [] + + for k in range(self.n_flows): + if k%4 == 0 and k > 0: + output_audio.append(audio[:,:self.n_multi,:]) + audio = audio[:,self.n_multi:,:] + + # project to new basis + audio, s = self.convinv[k](audio) + s_conv_list.append(s) + + n_half = int(audio.size(1)/2) + if k%2 == 0: + audio_0 = audio[:,:n_half,:] + audio_1 = audio[:,n_half:,:] + else: + audio_1 = audio[:,:n_half,:] + audio_0 = audio[:,n_half:,:] + + output = self.nn[k]((audio_0, spect)) + s = output[:, n_half:, :] + b = output[:, :n_half, :] + audio_1 = torch.exp(s)*audio_1 + b + s_list.append(s) + + if k%2 == 0: + audio = torch.cat([audio[:,:n_half,:], audio_1],1) + else: + audio = torch.cat([audio_1, audio[:,n_half:,:]], 1) + output_audio.append(audio) + return torch.cat(output_audio,1), s_list, s_conv_list + """ + + def infer(self, spect, sigma=1.0): + spect = self.upsample(spect) + # trim conv artifacts. maybe pad spec to kernel multiple + time_cutoff = self.upsample.kernel_size[0] - self.upsample.stride[0] + spect = spect[:, :, :-time_cutoff] + + spect = spect.unfold(2, self.n_group, self.n_group).permute(0, 2, 1, 3) + spect = spect.contiguous().view(spect.size(0), spect.size(1), -1).permute(0, 2, 1) + + if spect.type() == 'torch.cuda.HalfTensor': + audio = torch.cuda.HalfTensor(spect.size(0), + self.n_remaining_channels, + spect.size(2)).normal_() + else: + audio = torch.cuda.FloatTensor(spect.size(0), + self.n_remaining_channels, + spect.size(2)).normal_() + + audio = torch.autograd.Variable(sigma*audio) + + for k in reversed(range(self.n_flows)): + n_half = int(audio.size(1)/2) + if k%2 == 0: + audio_0 = audio[:,:n_half,:] + audio_1 = audio[:,n_half:,:] + else: + audio_1 = audio[:,:n_half,:] + audio_0 = audio[:,n_half:,:] + + output = self.WN[k]((audio_0, spect)) + s = output[:, n_half:, :] + b = output[:, :n_half, :] + audio_1 = (audio_1 - b)/torch.exp(s) + if k%2 == 0: + audio = torch.cat([audio[:,:n_half,:], audio_1],1) + else: + audio = torch.cat([audio_1, audio[:,n_half:,:]], 1) + + audio = self.convinv[k](audio, reverse=True) + + if k%4 == 0 and k > 0: + if spect.type() == 'torch.cuda.HalfTensor': + z = torch.cuda.HalfTensor(spect.size(0), + self.n_early_size, + spect.size(2)).normal_() + else: + z = torch.cuda.FloatTensor(spect.size(0), + self.n_early_size, + spect.size(2)).normal_() + audio = torch.cat((sigma*z, audio),1) + + return audio.permute(0,2,1).contiguous().view(audio.size(0), -1).data + + @staticmethod + def remove_weightnorm(model): + waveglow = model + for WN in waveglow.WN: + WN.start = torch.nn.utils.remove_weight_norm(WN.start) + WN.in_layers = remove(WN.in_layers) + WN.cond_layers = remove(WN.cond_layers) + WN.res_skip_layers = remove(WN.res_skip_layers) + return waveglow diff --git a/tts/waveglow/inference.py b/tts/waveglow/inference.py new file mode 100644 index 0000000..39e7e22 --- /dev/null +++ b/tts/waveglow/inference.py @@ -0,0 +1,84 @@ +# ***************************************************************************** +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ***************************************************************************** +import os +from scipy.io.wavfile import write +import torch +from mel2samp import files_to_list, MAX_WAV_VALUE +from denoiser import Denoiser + + +def main(mel_files, waveglow_path, sigma, output_dir, sampling_rate, is_fp16, + denoiser_strength): + mel_files = files_to_list(mel_files) + waveglow = torch.load(waveglow_path)['model'] + waveglow = waveglow.remove_weightnorm(waveglow) + waveglow.cuda().eval() + if is_fp16: + from apex import amp + waveglow, _ = amp.initialize(waveglow, [], opt_level="O3") + + if denoiser_strength > 0: + denoiser = Denoiser(waveglow).cuda() + + for i, file_path in enumerate(mel_files): + file_name = os.path.splitext(os.path.basename(file_path))[0] + mel = torch.load(file_path) + mel = torch.autograd.Variable(mel.cuda()) + mel = torch.unsqueeze(mel, 0) + mel = mel.half() if is_fp16 else mel + with torch.no_grad(): + audio = waveglow.infer(mel, sigma=sigma) + if denoiser_strength > 0: + audio = denoiser(audio, denoiser_strength) + audio = audio * MAX_WAV_VALUE + audio = audio.squeeze() + audio = audio.cpu().numpy() + audio = audio.astype('int16') + audio_path = os.path.join( + output_dir, "{}_synthesis.wav".format(file_name)) + write(audio_path, sampling_rate, audio) + print(audio_path) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('-f', "--filelist_path", required=True) + parser.add_argument('-w', '--waveglow_path', + help='Path to waveglow decoder checkpoint with model') + parser.add_argument('-o', "--output_dir", required=True) + parser.add_argument("-s", "--sigma", default=1.0, type=float) + parser.add_argument("--sampling_rate", default=22050, type=int) + parser.add_argument("--is_fp16", action="store_true") + parser.add_argument("-d", "--denoiser_strength", default=0.0, type=float, + help='Removes model bias. Start with 0.1 and adjust') + + args = parser.parse_args() + + main(args.filelist_path, args.waveglow_path, args.sigma, args.output_dir, + args.sampling_rate, args.is_fp16, args.denoiser_strength) diff --git a/tts/waveglow/mel2samp.py b/tts/waveglow/mel2samp.py new file mode 100644 index 0000000..f13f4af --- /dev/null +++ b/tts/waveglow/mel2samp.py @@ -0,0 +1,142 @@ +# ***************************************************************************** +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# *****************************************************************************\ +import os +import random +import argparse +import json +import torch +import torch.utils.data +import sys +from scipy.io.wavfile import read + +# We're using the audio processing from TacoTron2 to make sure it matches +sys.path.insert(0, 'tacotron2') +from tacotron2.layers import TacotronSTFT + +MAX_WAV_VALUE = 32768.0 + +def files_to_list(filename): + """ + Takes a text file of filenames and makes a list of filenames + """ + with open(filename, encoding='utf-8') as f: + files = f.readlines() + + files = [f.rstrip() for f in files] + return files + +def load_wav_to_torch(full_path): + """ + Loads wavdata into torch array + """ + sampling_rate, data = read(full_path) + return torch.from_numpy(data).float(), sampling_rate + + +class Mel2Samp(torch.utils.data.Dataset): + """ + This is the main class that calculates the spectrogram and returns the + spectrogram, audio pair. + """ + def __init__(self, training_files, segment_length, filter_length, + hop_length, win_length, sampling_rate, mel_fmin, mel_fmax): + self.audio_files = files_to_list(training_files) + random.seed(1234) + random.shuffle(self.audio_files) + self.stft = TacotronSTFT(filter_length=filter_length, + hop_length=hop_length, + win_length=win_length, + sampling_rate=sampling_rate, + mel_fmin=mel_fmin, mel_fmax=mel_fmax) + self.segment_length = segment_length + self.sampling_rate = sampling_rate + + def get_mel(self, audio): + audio_norm = audio / MAX_WAV_VALUE + audio_norm = audio_norm.unsqueeze(0) + audio_norm = torch.autograd.Variable(audio_norm, requires_grad=False) + melspec = self.stft.mel_spectrogram(audio_norm) + melspec = torch.squeeze(melspec, 0) + return melspec + + def __getitem__(self, index): + # Read audio + filename = self.audio_files[index] + audio, sampling_rate = load_wav_to_torch(filename) + if sampling_rate != self.sampling_rate: + raise ValueError("{} SR doesn't match target {} SR".format( + sampling_rate, self.sampling_rate)) + + # Take segment + if audio.size(0) >= self.segment_length: + max_audio_start = audio.size(0) - self.segment_length + audio_start = random.randint(0, max_audio_start) + audio = audio[audio_start:audio_start+self.segment_length] + else: + audio = torch.nn.functional.pad(audio, (0, self.segment_length - audio.size(0)), 'constant').data + + mel = self.get_mel(audio) + audio = audio / MAX_WAV_VALUE + + return (mel, audio) + + def __len__(self): + return len(self.audio_files) + +# =================================================================== +# Takes directory of clean audio and makes directory of spectrograms +# Useful for making test sets +# =================================================================== +if __name__ == "__main__": + # Get defaults so it can work with no Sacred + parser = argparse.ArgumentParser() + parser.add_argument('-f', "--filelist_path", required=True) + parser.add_argument('-c', '--config', type=str, + help='JSON file for configuration') + parser.add_argument('-o', '--output_dir', type=str, + help='Output directory') + args = parser.parse_args() + + with open(args.config) as f: + data = f.read() + data_config = json.loads(data)["data_config"] + mel2samp = Mel2Samp(**data_config) + + filepaths = files_to_list(args.filelist_path) + + # Make directory if it doesn't exist + if not os.path.isdir(args.output_dir): + os.makedirs(args.output_dir) + os.chmod(args.output_dir, 0o775) + + for filepath in filepaths: + audio, sr = load_wav_to_torch(filepath) + melspectrogram = mel2samp.get_mel(audio) + filename = os.path.basename(filepath) + new_filepath = args.output_dir + '/' + filename + '.pt' + print(new_filepath) + torch.save(melspectrogram, new_filepath) diff --git a/tts/waveglow/requirements.txt b/tts/waveglow/requirements.txt new file mode 100644 index 0000000..20c8b3e --- /dev/null +++ b/tts/waveglow/requirements.txt @@ -0,0 +1,10 @@ +torch==1.0 +matplotlib==2.1.0 +tensorflow +numpy==1.13.3 +inflect==0.2.5 +librosa==0.6.0 +scipy==1.0.0 +tensorboardX==1.1 +Unidecode==1.0.22 +pillow diff --git a/tts/waveglow/train.py b/tts/waveglow/train.py new file mode 100644 index 0000000..e8035c1 --- /dev/null +++ b/tts/waveglow/train.py @@ -0,0 +1,188 @@ +# ***************************************************************************** +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ***************************************************************************** +import argparse +import json +import os +import torch + +#=====START: ADDED FOR DISTRIBUTED====== +from distributed import init_distributed, apply_gradient_allreduce, reduce_tensor +from torch.utils.data.distributed import DistributedSampler +#=====END: ADDED FOR DISTRIBUTED====== + +from torch.utils.data import DataLoader +from glow import WaveGlow, WaveGlowLoss +from mel2samp import Mel2Samp + +def load_checkpoint(checkpoint_path, model, optimizer): + assert os.path.isfile(checkpoint_path) + checkpoint_dict = torch.load(checkpoint_path, map_location='cpu') + iteration = checkpoint_dict['iteration'] + optimizer.load_state_dict(checkpoint_dict['optimizer']) + model_for_loading = checkpoint_dict['model'] + model.load_state_dict(model_for_loading.state_dict()) + print("Loaded checkpoint '{}' (iteration {})" .format( + checkpoint_path, iteration)) + return model, optimizer, iteration + +def save_checkpoint(model, optimizer, learning_rate, iteration, filepath): + print("Saving model and optimizer state at iteration {} to {}".format( + iteration, filepath)) + model_for_saving = WaveGlow(**waveglow_config).cuda() + model_for_saving.load_state_dict(model.state_dict()) + torch.save({'model': model_for_saving, + 'iteration': iteration, + 'optimizer': optimizer.state_dict(), + 'learning_rate': learning_rate}, filepath) + +def train(num_gpus, rank, group_name, output_directory, epochs, learning_rate, + sigma, iters_per_checkpoint, batch_size, seed, fp16_run, + checkpoint_path, with_tensorboard): + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + #=====START: ADDED FOR DISTRIBUTED====== + if num_gpus > 1: + init_distributed(rank, num_gpus, group_name, **dist_config) + #=====END: ADDED FOR DISTRIBUTED====== + + criterion = WaveGlowLoss(sigma) + model = WaveGlow(**waveglow_config).cuda() + + #=====START: ADDED FOR DISTRIBUTED====== + if num_gpus > 1: + model = apply_gradient_allreduce(model) + #=====END: ADDED FOR DISTRIBUTED====== + + optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) + + if fp16_run: + from apex import amp + model, optimizer = amp.initialize(model, optimizer, opt_level='O1') + + # Load checkpoint if one exists + iteration = 0 + if checkpoint_path != "": + model, optimizer, iteration = load_checkpoint(checkpoint_path, model, + optimizer) + iteration += 1 # next iteration is iteration + 1 + + trainset = Mel2Samp(**data_config) + # =====START: ADDED FOR DISTRIBUTED====== + train_sampler = DistributedSampler(trainset) if num_gpus > 1 else None + # =====END: ADDED FOR DISTRIBUTED====== + train_loader = DataLoader(trainset, num_workers=1, shuffle=False, + sampler=train_sampler, + batch_size=batch_size, + pin_memory=False, + drop_last=True) + + # Get shared output_directory ready + if rank == 0: + if not os.path.isdir(output_directory): + os.makedirs(output_directory) + os.chmod(output_directory, 0o775) + print("output directory", output_directory) + + if with_tensorboard and rank == 0: + from tensorboardX import SummaryWriter + logger = SummaryWriter(os.path.join(output_directory, 'logs')) + + model.train() + epoch_offset = max(0, int(iteration / len(train_loader))) + # ================ MAIN TRAINNIG LOOP! =================== + for epoch in range(epoch_offset, epochs): + print("Epoch: {}".format(epoch)) + for i, batch in enumerate(train_loader): + model.zero_grad() + + mel, audio = batch + mel = torch.autograd.Variable(mel.cuda()) + audio = torch.autograd.Variable(audio.cuda()) + outputs = model((mel, audio)) + + loss = criterion(outputs) + if num_gpus > 1: + reduced_loss = reduce_tensor(loss.data, num_gpus).item() + else: + reduced_loss = loss.item() + + if fp16_run: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + + optimizer.step() + + print("{}:\t{:.9f}".format(iteration, reduced_loss)) + if with_tensorboard and rank == 0: + logger.add_scalar('training_loss', reduced_loss, i + len(train_loader) * epoch) + + if (iteration % iters_per_checkpoint == 0): + if rank == 0: + checkpoint_path = "{}/waveglow_{}".format( + output_directory, iteration) + save_checkpoint(model, optimizer, learning_rate, iteration, + checkpoint_path) + + iteration += 1 + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-c', '--config', type=str, + help='JSON file for configuration') + parser.add_argument('-r', '--rank', type=int, default=0, + help='rank of process for distributed') + parser.add_argument('-g', '--group_name', type=str, default='', + help='name of group for distributed') + args = parser.parse_args() + + # Parse configs. Globals nicer in this case + with open(args.config) as f: + data = f.read() + config = json.loads(data) + train_config = config["train_config"] + global data_config + data_config = config["data_config"] + global dist_config + dist_config = config["dist_config"] + global waveglow_config + waveglow_config = config["waveglow_config"] + + num_gpus = torch.cuda.device_count() + if num_gpus > 1: + if args.group_name == '': + print("WARNING: Multiple GPUs detected but no distributed group set") + print("Only running 1 GPU. Use distributed.py for multiple GPUs") + num_gpus = 1 + + if num_gpus == 1 and args.rank != 0: + raise Exception("Doing single GPU training on rank > 0") + + torch.backends.cudnn.enabled = True + torch.backends.cudnn.benchmark = False + train(num_gpus, args.rank, args.group_name, **train_config)