From 9b97430a74fd5b43b5e0c0b11fddfeb38e60bd92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eren=20G=C3=B6lge?= Date: Wed, 26 Feb 2020 16:14:10 +0100 Subject: [PATCH 001/185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19d7fa24..918328b2 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Below you see Tacotron model state after 16K iterations with batch-size 32 with > "Recent research at Harvard has shown meditating for as little as 8 weeks can actually increase the grey matter in the parts of the brain responsible for emotional regulation and learning." -Audio examples: [https://soundcloud.com/user-565970875](https://soundcloud.com/user-565970875) +Audio examples: [soundcloud](https://soundcloud.com/user-565970875/pocket-article-wavernn-and-tacotron2) example_output From fab74dd5be681d5fb51080515f60e1b20c6b8d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eren=20G=C3=B6lge?= Date: Thu, 12 Mar 2020 13:23:13 +0100 Subject: [PATCH 002/185] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index ff377f69..694bb36f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,8 +6,9 @@ labels: '' assignees: '' --- +Questions will not be answered here!! -Please consider posting on [TTS Discourse](https://discourse.mozilla.org/c/tts) page, if your issue is not directly related to TTS development process. +Please consider posting on [TTS Discourse](https://discourse.mozilla.org/c/tts) page if your issue is not directly related to TTS development (Bugs, code updates etc.). You can also check https://github.com/mozilla/TTS/wiki/FAQ for common questions and answers. From 70a8210283bbbd613fcd55f17ef8ebb7bdaac32e Mon Sep 17 00:00:00 2001 From: fatihkiralioglu <38240476+fatihkiralioglu@users.noreply.github.com> Date: Sat, 25 Apr 2020 15:18:46 +0300 Subject: [PATCH 003/185] Tacotron1 + wavernn configuration fix Tacotron1 + wavernn configuration: corrected the input format for wavernn vocoder, converted spectrograms to mels --- server/synthesizer.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/synthesizer.py b/server/synthesizer.py index e9205bf1..3268be46 100644 --- a/server/synthesizer.py +++ b/server/synthesizer.py @@ -184,7 +184,12 @@ class Synthesizer(object): vocoder_input.cuda() wav = self.pwgan.inference(vocoder_input, hop_size=self.ap.hop_length) elif self.wavernn: - vocoder_input = torch.FloatTensor(postnet_output.T).unsqueeze(0) + vocoder_input = None + if self.tts_config.model == "Tacotron" : + vocoder_input = torch.FloatTensor(self.ap.out_linear_to_mel(linear_spec = postnet_output.T).T).T.unsqueeze(0) + else: + vocoder_input = torch.FloatTensor(postnet_output.T).unsqueeze(0) + if self.use_cuda: vocoder_input.cuda() wav = self.wavernn.generate(vocoder_input, batched=self.config.is_wavernn_batched, target=11000, overlap=550) From cc11be06d7efd1e9a2a1cd5a35e7f790592e5067 Mon Sep 17 00:00:00 2001 From: fatihkiralioglu <38240476+fatihkiralioglu@users.noreply.github.com> Date: Mon, 27 Apr 2020 09:53:52 +0300 Subject: [PATCH 004/185] fixing "No space allowed before..." compile errors fixing "No space allowed before..." compile errors --- server/synthesizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/synthesizer.py b/server/synthesizer.py index 3268be46..10f4fb0a 100644 --- a/server/synthesizer.py +++ b/server/synthesizer.py @@ -185,8 +185,8 @@ class Synthesizer(object): wav = self.pwgan.inference(vocoder_input, hop_size=self.ap.hop_length) elif self.wavernn: vocoder_input = None - if self.tts_config.model == "Tacotron" : - vocoder_input = torch.FloatTensor(self.ap.out_linear_to_mel(linear_spec = postnet_output.T).T).T.unsqueeze(0) + if self.tts_config.model == "Tacotron": + vocoder_input = torch.FloatTensor(self.ap.out_linear_to_mel(linear_spec=postnet_output.T).T).T.unsqueeze(0) else: vocoder_input = torch.FloatTensor(postnet_output.T).unsqueeze(0) From 5a99986e86a7b7dddeef7692cb2ca83a237cc2e3 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 20 May 2020 17:30:25 +0200 Subject: [PATCH 005/185] update numpy setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f92dac8a..a1987a60 100644 --- a/setup.py +++ b/setup.py @@ -93,7 +93,7 @@ setup( install_requires=[ "scipy>=0.19.0", "torch>=0.4.1", - "numpy==1.15.4", + "numpy>=1.16.0", "librosa==0.6.2", "unidecode==0.4.20", "attrdict", From 7931a106e234430c449a42c4e2032b9f0e5098ea Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 20 May 2020 17:41:55 +0200 Subject: [PATCH 006/185] update version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a1987a60..5e89723b 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ args, unknown_args = parser.parse_known_args() # Remove our arguments from argv so that setuptools doesn't see them sys.argv = [sys.argv[0]] + unknown_args -version = '0.0.1' +version = '0.0.2' # Adapted from https://github.com/pytorch/pytorch cwd = os.path.dirname(os.path.abspath(__file__)) From 2a071a75055b5b266fe982602585be35d2667ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eren=20G=C3=B6lge?= Date: Wed, 20 May 2020 17:51:42 +0200 Subject: [PATCH 007/185] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4adae507..6a90ffbf 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ TTS includes two different model implementations which are based on [Tacotron](h If you are new, you can also find [here](http://www.erogol.com/text-speech-deep-learning-architectures/) a brief post about TTS architectures and their comparisons. +[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/0)](https://sourcerer.io/fame/erogol/erogol/TTS/links/0)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/1)](https://sourcerer.io/fame/erogol/erogol/TTS/links/1)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/2)](https://sourcerer.io/fame/erogol/erogol/TTS/links/2)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/3)](https://sourcerer.io/fame/erogol/erogol/TTS/links/3)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/4)](https://sourcerer.io/fame/erogol/erogol/TTS/links/4)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/5)](https://sourcerer.io/fame/erogol/erogol/TTS/links/5)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/6)](https://sourcerer.io/fame/erogol/erogol/TTS/links/6)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/7)](https://sourcerer.io/fame/erogol/erogol/TTS/links/7) + ## TTS Performance

From cedc22847beff4a3f8f0b088463b37355717b36d Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 20 May 2020 18:16:24 +0200 Subject: [PATCH 008/185] fix synthesize.py --- config_template.json | 134 ------------------------------------------- synthesize.py | 3 +- 2 files changed, 2 insertions(+), 135 deletions(-) delete mode 100644 config_template.json diff --git a/config_template.json b/config_template.json deleted file mode 100644 index e525ec31..00000000 --- a/config_template.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "model": "Tacotron2", // one of the model in models/ - "run_name": "ljspeech-stft_params", - "run_description": "tacotron2 cosntant stf parameters", - - // AUDIO PARAMETERS - "audio":{ - // Audio processing parameters - "num_mels": 80, // size of the mel spec frame. - "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. - "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. - "win_length": 1024, // stft window length in ms. - "hop_length": 256, // stft window hop-lengh in ms. - "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. - "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. - "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. - "min_level_db": -100, // normalization range - "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. - "power": 1.5, // value to sharpen wav signals after GL algorithm. - "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. - // Normalization parameters - "signal_norm": true, // normalize the spec values in range [0, 1] - "symmetric_norm": true, // move normalization to range [-1, 1] - "max_norm": 1.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] - "clip_norm": true, // clip normalized values into the range. - "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! - "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! - "do_trim_silence": true, // enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) - "trim_db": 60 // threshold for timming silence. Set this according to your dataset. - }, - - // VOCABULARY PARAMETERS - // if custom character set is not defined, - // default set in symbols.py is used - "characters":{ - "pad": "_", - "eos": "~", - "bos": "^", - "characters": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!'(),-.:;? ", - "punctuations":"!'(),-.:;? ", - "phonemes":"iyɨʉɯuɪʏʊeøɘəɵɤoɛœɜɞʌɔæɐaɶɑɒᵻʘɓǀɗǃʄǂɠǁʛpbtdʈɖcɟkɡqɢʔɴŋɲɳnɱmʙrʀⱱɾɽɸβfvθðszʃʒʂʐçʝxɣχʁħʕhɦɬɮʋɹɻjɰlɭʎʟˈˌːˑʍwɥʜʢʡɕʑɺɧɚ˞ɫ" - }, - - // DISTRIBUTED TRAINING - "distributed":{ - "backend": "nccl", - "url": "tcp:\/\/localhost:54321" - }, - - "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. - - // TRAINING - "batch_size": 32, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. - "eval_batch_size":16, - "r": 7, // Number of decoder frames to predict per iteration. Set the initial values if gradual training is enabled. - "gradual_training": [[0, 7, 64], [1, 5, 64], [50000, 3, 32], [130000, 2, 32], [290000, 1, 32]], //set gradual training steps [first_step, r, batch_size]. If it is null, gradual training is disabled. For Tacotron, you might need to reduce the 'batch_size' as you proceeed. - "loss_masking": true, // enable / disable loss masking against the sequence padding. - "ga_alpha": 10.0, // weight for guided attention loss. If > 0, guided attention is enabled. - - // VALIDATION - "run_eval": true, - "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. - "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. - - // OPTIMIZER - "noam_schedule": false, // use noam warmup and lr schedule. - "grad_clip": 1.0, // upper limit for gradients for clipping. - "epochs": 1000, // total number of epochs to train. - "lr": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. - "wd": 0.000001, // Weight decay weight. - "warmup_steps": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "seq_len_norm": false, // Normalize eash sample loss with its length to alleviate imbalanced datasets. Use it if your dataset is small or has skewed distribution of sequence lengths. - - // TACOTRON PRENET - "memory_size": -1, // ONLY TACOTRON - size of the memory queue used fro storing last decoder predictions for auto-regression. If < 0, memory queue is disabled and decoder only uses the last prediction frame. - "prenet_type": "original", // "original" or "bn". - "prenet_dropout": true, // enable/disable dropout at prenet. - - // ATTENTION - "attention_type": "original", // 'original' or 'graves' - "attention_heads": 4, // number of attention heads (only for 'graves') - "attention_norm": "sigmoid", // softmax or sigmoid. Suggested to use softmax for Tacotron2 and sigmoid for Tacotron. - "windowing": false, // Enables attention windowing. Used only in eval mode. - "use_forward_attn": false, // if it uses forward attention. In general, it aligns faster. - "forward_attn_mask": false, // Additional masking forcing monotonicity only in eval mode. - "transition_agent": false, // enable/disable transition agent of forward attention. - "location_attn": true, // enable_disable location sensitive attention. It is enabled for TACOTRON by default. - "bidirectional_decoder": false, // use https://arxiv.org/abs/1907.09006. Use it, if attention does not work well with your dataset. - - // STOPNET - "stopnet": true, // Train stopnet predicting the end of synthesis. - "separate_stopnet": true, // Train stopnet seperately if 'stopnet==true'. It prevents stopnet loss to influence the rest of the model. It causes a better model, but it trains SLOWER. - - // TENSORBOARD and LOGGING - "print_step": 25, // Number of steps to log traning on console. - "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. - "checkpoint": true, // If true, it saves checkpoints per "save_step" - "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. - - // DATA LOADING - "text_cleaner": "phoneme_cleaners", - "enable_eos_bos_chars": false, // enable/disable beginning of sentence and end of sentence chars. - "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. - "num_val_loader_workers": 4, // number of evaluation data loader processes. - "batch_group_size": 0, //Number of batches to shuffle after bucketing. - "min_seq_len": 6, // DATASET-RELATED: minimum text length to use in training - "max_seq_len": 153, // DATASET-RELATED: maximum text length - - // PATHS - "output_path": "/data4/rw/home/Trainings/", - - // PHONEMES - "phoneme_cache_path": "mozilla_us_phonemes_3", // phoneme computation is slow, therefore, it caches results in the given folder. - "use_phonemes": true, // use phonemes instead of raw characters. It is suggested for better pronounciation. - "phoneme_language": "en-us", // depending on your target language, pick one from https://github.com/bootphon/phonemizer#languages - - // MULTI-SPEAKER and GST - "use_speaker_embedding": false, // use speaker embedding to enable multi-speaker learning. - "style_wav_for_test": null, // path to style wav file to be used in TacotronGST inference. - "use_gst": false, // TACOTRON ONLY: use global style tokens - - // DATASETS - "datasets": // List of datasets. They all merged and they get different speaker_ids. - [ - { - "name": "ljspeech", - "path": "/root/LJSpeech-1.1/", - "meta_file_train": "metadata.csv", - "meta_file_val": null - } - ] - -} - diff --git a/synthesize.py b/synthesize.py index 1a760268..18048c2f 100644 --- a/synthesize.py +++ b/synthesize.py @@ -7,7 +7,8 @@ import json import string from TTS.utils.synthesis import synthesis -from TTS.utils.generic_utils import load_config, setup_model +from TTS.utils.generic_utils import setup_model +from TTS.utils.io import load_config from TTS.utils.text.symbols import make_symbols, symbols, phonemes from TTS.utils.audio import AudioProcessor From c27fd4238afb7a7c7e059f9b4cedcf37146b2aa2 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 22 May 2020 13:09:07 +0200 Subject: [PATCH 009/185] update torch version and solve compat issue with isinf --- requirements.txt | 2 +- setup.py | 2 +- utils/training.py | 12 +++++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5f31db70..862cb229 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ numpy>=1.16.0 -torch>=0.4.1 +torch>=1.5 librosa>=0.5.1 Unidecode>=0.4.20 tensorboard diff --git a/setup.py b/setup.py index 5e89723b..84a31488 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ setup( }, install_requires=[ "scipy>=0.19.0", - "torch>=0.4.1", + "torch>=1.5", "numpy>=1.16.0", "librosa==0.6.2", "unidecode==0.4.20", diff --git a/utils/training.py b/utils/training.py index ebf8fd13..5ce7948b 100644 --- a/utils/training.py +++ b/utils/training.py @@ -9,9 +9,15 @@ def check_update(model, grad_clip, ignore_stopnet=False): grad_norm = torch.nn.utils.clip_grad_norm_([param for name, param in model.named_parameters() if 'stopnet' not in name], grad_clip) else: grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), grad_clip) - if torch.isinf(grad_norm): - print(" | > Gradient is INF !!") - skip_flag = True + # compatibility with different torch versions + if isinstance(grad_norm, float): + if np.isinf(grad_norm): + print(" | > Gradient is INF !!") + skip_flag = True + else: + if torch.isinf(grad_norm): + print(" | > Gradient is INF !!") + skip_flag = True return grad_norm, skip_flag From b5f61d81c0e2e08b5be2b5e222377cc590731281 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 23 May 2020 12:39:47 +0000 Subject: [PATCH 010/185] fix error mshg grammar --- datasets/preprocess.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datasets/preprocess.py b/datasets/preprocess.py index ce876edc..e8700c6b 100644 --- a/datasets/preprocess.py +++ b/datasets/preprocess.py @@ -120,7 +120,7 @@ def mailabs(root_path, meta_files=None): text = cols[1].strip() items.append([text, wav_file, speaker_name]) else: - raise RuntimeError("> File %s is not exist!"%(wav_file)) + raise RuntimeError("> File %s does not exist!"%(wav_file)) return items @@ -185,7 +185,7 @@ def libri_tts(root_path, meta_files=None): text = cols[1] items.append([text, wav_file, speaker_name]) for item in items: - assert os.path.exists(item[1]), f" [!] wav file is not exist - {item[1]}" + assert os.path.exists(item[1]), f" [!] wav files don't exist - {item[1]}" return items @@ -203,5 +203,5 @@ def custom_turkish(root_path, meta_file): continue text = cols[1].strip() items.append([text, wav_file, speaker_name]) - print(f" [!] {len(skipped_files)} files skipped. They are not exist...") + print(f" [!] {len(skipped_files)} files skipped. They don't exist...") return items From 0333483617953bd105d68032c5d03b5819270e7f Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 23 May 2020 14:47:32 +0200 Subject: [PATCH 011/185] set the initial color right --- utils/console_logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/console_logger.py b/utils/console_logger.py index 5c6ec75f..0b361bb8 100644 --- a/utils/console_logger.py +++ b/utils/console_logger.py @@ -87,9 +87,9 @@ class ConsoleLogger(): diff = 0 if self.old_eval_loss_dict is not None: diff = value - self.old_eval_loss_dict[key] - if diff < 0: + if diff <= 0: color = tcolors.OKGREEN sign = '' log_text += "{}{}:{} {:.5f} {}({}{:.5f})\n".format(indent, key, color, value, tcolors.ENDC, sign, diff) self.old_eval_loss_dict = avg_loss_dict - print(log_text, flush=True) \ No newline at end of file + print(log_text, flush=True) From ac55f198f17ec4ef550b82ab28f22b5eea9ebbad Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 23 May 2020 14:48:34 +0200 Subject: [PATCH 012/185] commenting config.json --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 03907fb0..32debf86 100644 --- a/config.json +++ b/config.json @@ -103,7 +103,7 @@ // TENSORBOARD and LOGGING "print_step": 25, // Number of steps to log traning on console. - "print_eval": false, // If True, it prints loss values in evalulation. + "print_eval": false, // If True, it prints intermediate loss values in evalulation. "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. "checkpoint": true, // If true, it saves checkpoints per "save_step" "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. From 1d8ac4c571f543acf666cccdc0e4d4d214c8b96e Mon Sep 17 00:00:00 2001 From: George Roussos Date: Sat, 23 May 2020 23:22:04 +0200 Subject: [PATCH 013/185] Update compute_statistics.py change import of load_config (is in io) --- compute_statistics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compute_statistics.py b/compute_statistics.py index bbedf7af..9cd073cd 100755 --- a/compute_statistics.py +++ b/compute_statistics.py @@ -8,7 +8,7 @@ import numpy as np from tqdm import tqdm from TTS.datasets.preprocess import load_meta_data -from TTS.utils.generic_utils import load_config +from TTS.utils.io import load_config from TTS.utils.audio import AudioProcessor def main(): From ef7e31c498f4fdd12acc1aad5ce12fb36d80a970 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 25 May 2020 10:32:14 +0200 Subject: [PATCH 014/185] fix #412 --- speaker_encoder/train.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/speaker_encoder/train.py b/speaker_encoder/train.py index 0a137360..f74d0880 100644 --- a/speaker_encoder/train.py +++ b/speaker_encoder/train.py @@ -13,12 +13,11 @@ from TTS.speaker_encoder.model import SpeakerEncoder from TTS.speaker_encoder.visual import plot_embeddings from TTS.speaker_encoder.generic_utils import save_best_model from TTS.utils.audio import AudioProcessor -from TTS.utils.generic_utils import (NoamLR, check_update, copy_config_file, - count_parameters, - create_experiment_folder, get_git_branch, - load_config, +from TTS.utils.generic_utils import (create_experiment_folder, get_git_branch, remove_experiment_folder, set_init_dict) -from TTS.utils.logger import Logger +from TTS.utils.io import load_config, copy_config_file +from TTS.utils.training import check_update, NoamLR +from TTS.utils.tensorboard_logger import TensorboardLogger from TTS.utils.radam import RAdam torch.backends.cudnn.enabled = True @@ -237,7 +236,7 @@ if __name__ == '__main__': new_fields) LOG_DIR = OUT_PATH - tb_logger = Logger(LOG_DIR) + tb_logger = TensorboardLogger(LOG_DIR) try: main(args) From 3eacab9f6ac58be816ff7b4c5201705e3b5d73c5 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 25 May 2020 10:32:42 +0200 Subject: [PATCH 015/185] add requirements for speaker encoder --- speaker_encoder/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 speaker_encoder/requirements.txt diff --git a/speaker_encoder/requirements.txt b/speaker_encoder/requirements.txt new file mode 100644 index 00000000..a486cc45 --- /dev/null +++ b/speaker_encoder/requirements.txt @@ -0,0 +1,2 @@ +umap-learn +numpy>=1.17.0 From e71a3772021d47bbf6a9c4f1e38420ba316f7e8c Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 14:05:19 +0200 Subject: [PATCH 016/185] add a non-existing value to avg values --- utils/generic_utils.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 1c7dd5e4..5a811907 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -197,14 +197,19 @@ class KeepAverage(): self.iters[name] = init_iter def update_value(self, name, value, weighted_avg=False): - if weighted_avg: - self.avg_values[name] = 0.99 * self.avg_values[name] + 0.01 * value - self.iters[name] += 1 + if name not in self.avg_values: + # add value if not exist before + self.add_value(name, init_val=value) else: - self.avg_values[name] = self.avg_values[name] * \ - self.iters[name] + value - self.iters[name] += 1 - self.avg_values[name] /= self.iters[name] + # else update existing value + if weighted_avg: + self.avg_values[name] = 0.99 * self.avg_values[name] + 0.01 * value + self.iters[name] += 1 + else: + self.avg_values[name] = self.avg_values[name] * \ + self.iters[name] + value + self.iters[name] += 1 + self.avg_values[name] /= self.iters[name] def add_values(self, name_dict): for key, value in name_dict.items(): From 5116a20c86608a2790b1b7cecf0765a003134218 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:07:01 +0200 Subject: [PATCH 017/185] differentiate modules on TB with a prefix --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index e4963ee7..82f91cd5 100644 --- a/train.py +++ b/train.py @@ -667,7 +667,7 @@ if __name__ == '__main__': os.chmod(OUT_PATH, 0o775) LOG_DIR = OUT_PATH - tb_logger = TensorboardLogger(LOG_DIR) + tb_logger = TensorboardLogger(LOG_DIR, model_name='TTS') # write model desc to tensorboard tb_logger.tb_add_text('model-description', c['run_description'], 0) From 0372c5ce5d066667102193133aa46133037c1d09 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:08:26 +0200 Subject: [PATCH 018/185] set state dict using direct state_dict dict --- utils/generic_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 5a811907..5b135061 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -106,15 +106,15 @@ def sequence_mask(sequence_length, max_len=None): return seq_range_expand < seq_length_expand -def set_init_dict(model_dict, checkpoint, c): +def set_init_dict(model_dict, checkpoint_state, c): # Partial initialization: if there is a mismatch with new and old layer, it is skipped. - for k, v in checkpoint['model'].items(): + for k, v in checkpoint_state.items(): if k not in model_dict: print(" | > Layer missing in the model definition: {}".format(k)) # 1. filter out unnecessary keys pretrained_dict = { k: v - for k, v in checkpoint['model'].items() if k in model_dict + for k, v in checkpoint_state.items() if k in model_dict } # 2. filter out different size layers pretrained_dict = { From 4ecd47e072ab594dc0c7af952b341a8f6f8090bb Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:08:56 +0200 Subject: [PATCH 019/185] use model_name prefix in tb_logger --- utils/tensorboard_logger.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/utils/tensorboard_logger.py b/utils/tensorboard_logger.py index 15fe04e4..cbf68ad6 100644 --- a/utils/tensorboard_logger.py +++ b/utils/tensorboard_logger.py @@ -3,7 +3,8 @@ from tensorboardX import SummaryWriter class TensorboardLogger(object): - def __init__(self, log_dir): + def __init__(self, log_dir, model_name): + self.model_name = model_name self.writer = SummaryWriter(log_dir) self.train_stats = {} self.eval_stats = {} @@ -50,31 +51,31 @@ class TensorboardLogger(object): traceback.print_exc() def tb_train_iter_stats(self, step, stats): - self.dict_to_tb_scalar("TrainIterStats", stats, step) + self.dict_to_tb_scalar(f"{self.model_name}_TrainIterStats", stats, step) def tb_train_epoch_stats(self, step, stats): - self.dict_to_tb_scalar("TrainEpochStats", stats, step) + self.dict_to_tb_scalar(f"{self.model_name}_TrainEpochStats", stats, step) def tb_train_figures(self, step, figures): - self.dict_to_tb_figure("TrainFigures", figures, step) + self.dict_to_tb_figure(f"{self.model_name}_TrainFigures", figures, step) def tb_train_audios(self, step, audios, sample_rate): - self.dict_to_tb_audios("TrainAudios", audios, step, sample_rate) + self.dict_to_tb_audios(f"{self.model_name}_TrainAudios", audios, step, sample_rate) def tb_eval_stats(self, step, stats): - self.dict_to_tb_scalar("EvalStats", stats, step) + self.dict_to_tb_scalar(f"{self.model_name}_EvalStats", stats, step) def tb_eval_figures(self, step, figures): - self.dict_to_tb_figure("EvalFigures", figures, step) + self.dict_to_tb_figure(f"{self.model_name}_EvalFigures", figures, step) def tb_eval_audios(self, step, audios, sample_rate): - self.dict_to_tb_audios("EvalAudios", audios, step, sample_rate) + self.dict_to_tb_audios(f"{self.model_name}_EvalAudios", audios, step, sample_rate) def tb_test_audios(self, step, audios, sample_rate): - self.dict_to_tb_audios("TestAudios", audios, step, sample_rate) + self.dict_to_tb_audios(f"{self.model_name}_TestAudios", audios, step, sample_rate) def tb_test_figures(self, step, figures): - self.dict_to_tb_figure("TestFigures", figures, step) + self.dict_to_tb_figure(f"{self.model_name}_TestFigures", figures, step) def tb_add_text(self, title, text, step): self.writer.add_text(title, text, step) From d47c9987dbaa2dbd129b3f897c6fb45b392ae455 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:09:25 +0200 Subject: [PATCH 020/185] initial commit intro. to vocoder submodule --- vocoder/README.md | 35 + vocoder/__init__.py | 0 vocoder/compute_tts_features.py | 0 vocoder/configs/melgan_config.json | 138 ++++ vocoder/datasets/__init__.py | 0 vocoder/datasets/gan_dataset.py | 133 ++++ vocoder/datasets/preprocess.py | 16 + vocoder/layers/__init__.py | 0 vocoder/layers/losses.py | 273 +++++++ vocoder/layers/melgan.py | 48 ++ vocoder/layers/pqmf.py | 55 ++ vocoder/layers/pqmf2.py | 127 ++++ vocoder/layers/qmf.dat | 640 +++++++++++++++++ vocoder/models/__init__.py | 0 vocoder/models/melgan_discriminator.py | 80 +++ vocoder/models/melgan_generator.py | 91 +++ .../models/melgan_multiscale_discriminator.py | 41 ++ vocoder/models/multiband_melgan_generator.py | 38 + vocoder/models/random_window_discriminator.py | 225 ++++++ vocoder/notebooks/Untitled.ipynb | 678 ++++++++++++++++++ vocoder/notebooks/Untitled1.ipynb | 6 + vocoder/pqmf_output.wav | Bin 0 -> 83812 bytes vocoder/tests/__init__.py | 1 + vocoder/tests/test_config.json | 24 + vocoder/tests/test_datasets.py | 95 +++ vocoder/tests/test_losses.py | 62 ++ vocoder/tests/test_melgan_discriminator.py | 26 + vocoder/tests/test_melgan_generator.py | 15 + vocoder/tests/test_pqmf.py | 33 + vocoder/tests/test_rwd.py | 21 + vocoder/train.py | 585 +++++++++++++++ vocoder/utils/__init__.py | 0 vocoder/utils/console_logger.py | 97 +++ vocoder/utils/generic_utils.py | 102 +++ vocoder/utils/io.py | 52 ++ 35 files changed, 3737 insertions(+) create mode 100644 vocoder/README.md create mode 100644 vocoder/__init__.py create mode 100644 vocoder/compute_tts_features.py create mode 100644 vocoder/configs/melgan_config.json create mode 100644 vocoder/datasets/__init__.py create mode 100644 vocoder/datasets/gan_dataset.py create mode 100644 vocoder/datasets/preprocess.py create mode 100644 vocoder/layers/__init__.py create mode 100644 vocoder/layers/losses.py create mode 100644 vocoder/layers/melgan.py create mode 100644 vocoder/layers/pqmf.py create mode 100644 vocoder/layers/pqmf2.py create mode 100644 vocoder/layers/qmf.dat create mode 100644 vocoder/models/__init__.py create mode 100644 vocoder/models/melgan_discriminator.py create mode 100644 vocoder/models/melgan_generator.py create mode 100644 vocoder/models/melgan_multiscale_discriminator.py create mode 100644 vocoder/models/multiband_melgan_generator.py create mode 100644 vocoder/models/random_window_discriminator.py create mode 100644 vocoder/notebooks/Untitled.ipynb create mode 100644 vocoder/notebooks/Untitled1.ipynb create mode 100644 vocoder/pqmf_output.wav create mode 100644 vocoder/tests/__init__.py create mode 100644 vocoder/tests/test_config.json create mode 100644 vocoder/tests/test_datasets.py create mode 100644 vocoder/tests/test_losses.py create mode 100644 vocoder/tests/test_melgan_discriminator.py create mode 100644 vocoder/tests/test_melgan_generator.py create mode 100644 vocoder/tests/test_pqmf.py create mode 100644 vocoder/tests/test_rwd.py create mode 100644 vocoder/train.py create mode 100644 vocoder/utils/__init__.py create mode 100644 vocoder/utils/console_logger.py create mode 100644 vocoder/utils/generic_utils.py create mode 100644 vocoder/utils/io.py diff --git a/vocoder/README.md b/vocoder/README.md new file mode 100644 index 00000000..48fc24ee --- /dev/null +++ b/vocoder/README.md @@ -0,0 +1,35 @@ +# Mozilla TTS Vocoders (Experimental) + +We provide here different vocoder implementations which can be combined with our TTS models to enable "FASTER THAN REAL-TIME" end-to-end TTS stack. + +Currently, there are implementations of the following models. + +- Melgan +- MultiBand-Melgan +- GAN-TTS (Discriminator Only) + +It is also very easy to adapt different vocoder models as we provide here a flexible and modular (but not too modular) framework. + +## Training a model + +You can see here an example (Soon)[Colab Notebook]() training MelGAN with LJSpeech dataset. + +In order to train a new model, you need to collecto all your wav files under a common parent folder and give this path to `data_path` field in '''config.json''' + +You need to define other relevant parameters in your ```config.json``` and then start traning with the following command from Mozilla TTS root path. + +```CUDA_VISIBLE_DEVICES='1' python vocoder/train.py --config_path path/to/config.json``` + +Exampled config files can be found under `vocoder/configs/` folder. + +You can continue a previous training by the following command. + +```CUDA_VISIBLE_DEVICES='1' python vocoder/train.py --continue_path path/to/your/model/folder``` + +You can fine-tune a pre-trained model by the following command. + +```CUDA_VISIBLE_DEVICES='1' python vocoder/train.py --restore_path path/to/your/model.pth.tar``` + +Restoring a model starts a new training in a different output folder. It only restores model weights with the given checkpoint file. However, continuing a training starts from the same conditions the previous training run left off. + +You can also follow your training runs on Tensorboard as you do with our TTS models. \ No newline at end of file diff --git a/vocoder/__init__.py b/vocoder/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/compute_tts_features.py b/vocoder/compute_tts_features.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json new file mode 100644 index 00000000..9a3ded37 --- /dev/null +++ b/vocoder/configs/melgan_config.json @@ -0,0 +1,138 @@ +{ + "run_name": "melgan", + "run_description": "melgan initial run", + + // AUDIO PARAMETERS + "audio":{ + // stft parameters + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "win_length": 1024, // stft window length in ms. + "hop_length": 256, // stft window hop-lengh in ms. + "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. + "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. + + // Audio processing parameters + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + + // Silence trimming + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "trim_db": 60, // threshold for timming silence. Set this according to your dataset. + + // Griffin-Lim + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + + // MelSpectrogram parameters + "num_mels": 80, // size of the mel spec frame. + "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + + // Normalization parameters + "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. + "min_level_db": -100, // lower bound for normalization + "symmetric_norm": true, // move normalization to range [-1, 1] + "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "clip_norm": true, // clip normalized values into the range. + "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + }, + + // DISTRIBUTED TRAINING + // "distributed":{ + // "backend": "nccl", + // "url": "tcp:\/\/localhost:54321" + // }, + + // MODEL PARAMETERS + "use_pqmf": true, + + // LOSS PARAMETERS + "use_stft_loss": true, + "use_mse_gan_loss": true, + "use_hinge_gan_loss": false, + "use_feat_match_loss": false, // use only with melgan discriminators + + "stft_loss_alpha": 1, + "mse_gan_loss_alpha": 1, + "hinge_gan_loss_alpha": 1, + "feat_match_loss_alpha": 10.0, + + "stft_loss_params": { + "n_ffts": [1024, 2048, 512], + "hop_lengths": [120, 240, 50], + "win_lengths": [600, 1200, 240] + }, + "target_loss": "avg_G_loss", // loss value to pick the best model + + // DISCRIMINATOR + "discriminator_model": "melgan_multiscale_discriminator", + "discriminator_model_params":{ + "base_channels": 16, + "max_channels":1024, + "downsample_factors":[4, 4, 4, 4] + }, + "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 + + // "discriminator_model": "random_window_discriminator", + // "discriminator_model_params":{ + // "uncond_disc_donwsample_factors": [8, 4], + // "cond_disc_downsample_factors": [[8, 4, 2, 2, 2], [8, 4, 2, 2], [8, 4, 2], [8, 4], [4, 2, 2]], + // "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], + // "window_sizes": [512, 1024, 2048, 4096, 8192] + // }, + + + // GENERATOR + "generator_model": "multiband_melgan_generator", + "generator_model_params": { + "upsample_factors":[2 ,2, 4, 4], + "num_res_blocks": 4 + }, + + // DATASET + "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", + "seq_len": 16384, + "pad_short": 2000, + "conv_pad": 0, + "use_noise_augment": true, + "use_cache": true, + + "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. + + // TRAINING + "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. + + // VALIDATION + "run_eval": true, + "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. + "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. + + // OPTIMIZER + "noam_schedule": true, // use noam warmup and lr schedule. + "grad_clip": 1.0, // upper limit for gradients for clipping. + "epochs": 1000, // total number of epochs to train. + "wd": 0.000001, // Weight decay weight. + "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 0.0001, + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, + "gen_clip_grad": 10.0, + "disc_clip_grad": 10.0, + + // TENSORBOARD and LOGGING + "print_step": 25, // Number of steps to log traning on console. + "print_eval": false, // If True, it prints intermediate loss values in evalulation. + "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. + "checkpoint": true, // If true, it saves checkpoints per "save_step" + "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. + + // DATA LOADING + "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. + "num_val_loader_workers": 4, // number of evaluation data loader processes. + "eval_split_size": 10, + + // PATHS + "output_path": "/home/erogol/Models/LJSpeech/" +} + diff --git a/vocoder/datasets/__init__.py b/vocoder/datasets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/datasets/gan_dataset.py b/vocoder/datasets/gan_dataset.py new file mode 100644 index 00000000..10d36cab --- /dev/null +++ b/vocoder/datasets/gan_dataset.py @@ -0,0 +1,133 @@ +import os +import glob +import torch +import random +import numpy as np +from torch.utils.data import Dataset, DataLoader +from multiprocessing import Manager + + +def create_dataloader(hp, args, train): + dataset = MelFromDisk(hp, args, train) + + if train: + return DataLoader(dataset=dataset, + batch_size=hp.train.batch_size, + shuffle=True, + num_workers=hp.train.num_workers, + pin_memory=True, + drop_last=True) + else: + return DataLoader(dataset=dataset, + batch_size=1, + shuffle=False, + num_workers=hp.train.num_workers, + pin_memory=True, + drop_last=False) + + +class GANDataset(Dataset): + """ + GAN Dataset searchs for all the wav files under root path + and converts them to acoustic features on the fly and returns + random segments of (audio, feature) couples. + """ + def __init__(self, + ap, + items, + seq_len, + hop_len, + pad_short, + conv_pad=2, + is_training=True, + return_segments=True, + use_noise_augment=False, + use_cache=False, + verbose=False): + + self.ap = ap + self.item_list = items + self.seq_len = seq_len + self.hop_len = hop_len + self.pad_short = pad_short + self.conv_pad = conv_pad + self.is_training = is_training + self.return_segments = return_segments + self.use_cache = use_cache + self.use_noise_augment = use_noise_augment + + assert seq_len % hop_len == 0, " [!] seq_len has to be a multiple of hop_len." + self.feat_frame_len = seq_len // hop_len + (2 * conv_pad) + + # map G and D instances + self.G_to_D_mappings = [i for i in range(len(self.item_list))] + self.shuffle_mapping() + + # cache acoustic features + if use_cache: + self.create_feature_cache() + + + + def create_feature_cache(self): + self.manager = Manager() + self.cache = self.manager.list() + self.cache += [None for _ in range(len(self.item_list))] + + def find_wav_files(self, path): + return glob.glob(os.path.join(path, '**', '*.wav'), recursive=True) + + def __len__(self): + return len(self.item_list) + + def __getitem__(self, idx): + """ Return different items for Generator and Discriminator and + cache acoustic features """ + if self.return_segments: + idx2 = self.G_to_D_mappings[idx] + item1 = self.load_item(idx) + item2 = self.load_item(idx2) + return item1, item2 + else: + item1 = self.load_item(idx) + return item1 + + def shuffle_mapping(self): + random.shuffle(self.G_to_D_mappings) + + def load_item(self, idx): + """ load (audio, feat) couple """ + wavpath = self.item_list[idx] + # print(wavpath) + + if self.use_cache and self.cache[idx] is not None: + audio, mel = self.cache[idx] + else: + audio = self.ap.load_wav(wavpath) + mel = self.ap.melspectrogram(audio) + + if len(audio) < self.seq_len + self.pad_short: + audio = np.pad(audio, (0, self.seq_len + self.pad_short - len(audio)), \ + mode='constant', constant_values=0.0) + + # correct the audio length wrt padding applied in stft + audio = np.pad(audio, (0, self.hop_len), mode="edge") + audio = audio[:mel.shape[-1] * self.hop_len] + assert mel.shape[-1] * self.hop_len == audio.shape[-1], f' [!] {mel.shape[-1] * self.hop_len} vs {audio.shape[-1]}' + + audio = torch.from_numpy(audio).float().unsqueeze(0) + mel = torch.from_numpy(mel).float().squeeze(0) + + if self.return_segments: + max_mel_start = mel.shape[1] - self.feat_frame_len + mel_start = random.randint(0, max_mel_start) + mel_end = mel_start + self.feat_frame_len + mel = mel[:, mel_start:mel_end] + + audio_start = mel_start * self.hop_len + audio = audio[:, audio_start:audio_start + + self.seq_len] + + if self.use_noise_augment and self.is_training and self.return_segments: + audio = audio + (1 / 32768) * torch.randn_like(audio) + return (mel, audio) diff --git a/vocoder/datasets/preprocess.py b/vocoder/datasets/preprocess.py new file mode 100644 index 00000000..01e01e3e --- /dev/null +++ b/vocoder/datasets/preprocess.py @@ -0,0 +1,16 @@ +import glob +import os + +import numpy as np + + +def find_wav_files(data_path): + wav_paths = glob.glob(os.path.join(data_path, '**', '*.wav'), recursive=True) + return wav_paths + + +def load_wav_data(data_path, eval_split_size): + wav_paths = find_wav_files(data_path) + np.random.seed(0) + np.random.shuffle(wav_paths) + return wav_paths[:eval_split_size], wav_paths[eval_split_size:] diff --git a/vocoder/layers/__init__.py b/vocoder/layers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py new file mode 100644 index 00000000..11985629 --- /dev/null +++ b/vocoder/layers/losses.py @@ -0,0 +1,273 @@ +import torch + +from torch import nn +from torch.nn import functional as F + + +class TorchSTFT(): + def __init__(self, n_fft, hop_length, win_length, window='hann_window'): + self.n_fft = n_fft + self.hop_length = hop_length + self.win_length = win_length + self.window = getattr(torch, window)(win_length) + + def __call__(self, x): + # B x D x T x 2 + o = torch.stft(x, + self.n_fft, + self.hop_length, + self.win_length, + self.window, + center=True, + pad_mode="constant", # compatible with audio.py + normalized=False, + onesided=True) + M = o[:, :, :, 0] + P = o[:, :, :, 1] + return torch.sqrt(torch.clamp(M ** 2 + P ** 2, min=1e-8)) + + +################################# +# GENERATOR LOSSES +################################# + + +class STFTLoss(nn.Module): + def __init__(self, n_fft, hop_length, win_length): + super(STFTLoss, self).__init__() + self.n_fft = n_fft + self.hop_length = hop_length + self.win_length = win_length + self.stft = TorchSTFT(n_fft, hop_length, win_length) + + def forward(self, y_hat, y): + y_hat_M = self.stft(y_hat) + y_M = self.stft(y) + # magnitude loss + loss_mag = F.l1_loss(torch.log(y_M), torch.log(y_hat_M)) + # spectral convergence loss + loss_sc = torch.norm(y_M - y_hat_M, p="fro") / torch.norm(y_M, p="fro") + return loss_mag, loss_sc + + +class MultiScaleSTFTLoss(torch.nn.Module): + def __init__(self, + n_ffts=[1024, 2048, 512], + hop_lengths=[120, 240, 50], + win_lengths=[600, 1200, 240]): + super(MultiScaleSTFTLoss, self).__init__() + self.loss_funcs = torch.nn.ModuleList() + for idx in range(len(n_ffts)): + self.loss_funcs.append(STFTLoss(n_ffts[idx], hop_lengths[idx], win_lengths[idx])) + + def forward(self, y_hat, y): + N = len(self.loss_funcs) + loss_sc = 0 + loss_mag = 0 + for f in self.loss_funcs: + lm, lsc = f(y_hat, y) + loss_mag += lm + loss_sc += lsc + loss_sc /= N + loss_mag /= N + return loss_mag, loss_sc + + +class MSEGLoss(nn.Module): + """ Mean Squared Generator Loss """ + def __init__(self,): + super(MSEGLoss, self).__init__() + + def forward(self, score_fake, ): + loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + return loss_fake + + +class HingeGLoss(nn.Module): + """ Hinge Discriminator Loss """ + def __init__(self,): + super(HingeGLoss, self).__init__() + + def forward(self, score_fake, score_real): + loss_fake = torch.mean(F.relu(1. + score_fake)) + return loss_fake + + +################################## +# DISCRIMINATOR LOSSES +################################## + + +class MSEDLoss(nn.Module): + """ Mean Squared Discriminator Loss """ + def __init__(self,): + super(MSEDLoss, self).__init__() + + def forward(self, score_fake, score_real): + loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) + loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + loss_d = loss_real + loss_fake + return loss_d, loss_real, loss_fake + + +class HingeDLoss(nn.Module): + """ Hinge Discriminator Loss """ + def __init__(self,): + super(HingeDLoss, self).__init__() + + def forward(self, score_fake, score_real): + loss_real = torch.mean(F.relu(1. - score_real)) + loss_fake = torch.mean(F.relu(1. + score_fake)) + loss_d = loss_real + loss_fake + return loss_d, loss_real, loss_fake + + +class MelganFeatureLoss(nn.Module): + def __init__(self, ): + super(MelganFeatureLoss, self).__init__() + + def forward(self, fake_feats, real_feats): + loss_feats = 0 + for fake_feat, real_feat in zip(fake_feats, real_feats): + loss_feats += hp.model.feat_match * torch.mean(torch.abs(fake_feat - real_feat)) + return loss_feats + + +################################## +# LOSS WRAPPERS +################################## + + +class GeneratorLoss(nn.Module): + def __init__(self, C): + super(GeneratorLoss, self).__init__() + assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + " [!] Cannot use HingeGANLoss and MSEGANLoss together." + + self.use_stft_loss = C.use_stft_loss + self.use_mse_gan_loss = C.use_mse_gan_loss + self.use_hinge_gan_loss = C.use_hinge_gan_loss + self.use_feat_match_loss = C.use_feat_match_loss + + self.stft_loss_alpha = C.stft_loss_alpha + self.mse_gan_loss_alpha = C.mse_gan_loss_alpha + self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha + self.feat_match_loss_alpha = C.feat_match_loss_alpha + + if C.use_stft_loss: + self.stft_loss = MultiScaleSTFTLoss(**C.stft_loss_params) + if C.use_mse_gan_loss: + self.mse_loss = MSEGLoss() + if C.use_hinge_gan_loss: + self.hinge_loss = HingeGLoss() + if C.use_feat_match_loss: + self.feat_match_loss = MelganFeatureLoss() + + def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None): + loss = 0 + return_dict = {} + + # STFT Loss + if self.use_stft_loss: + stft_loss_mg, stft_loss_sc = self.stft_loss(y_hat.squeeze(1), y.squeeze(1)) + return_dict['G_stft_loss_mg'] = stft_loss_mg + return_dict['G_stft_loss_sc'] = stft_loss_sc + loss += self.stft_loss_alpha * (stft_loss_mg + stft_loss_sc) + + # Fake Losses + if self.use_mse_gan_loss and scores_fake is not None: + mse_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake in scores_fake: + fake_loss = self.mse_loss(score_fake) + mse_fake_loss += fake_loss + else: + fake_loss = self.mse_loss(scores_fake) + mse_fake_loss = fake_loss + return_dict['G_mse_fake_loss'] = mse_fake_loss + loss += self.mse_gan_loss_alpha * mse_fake_loss + + if self.use_hinge_gan_loss and not scores_fake is not None: + hinge_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake in scores_fake: + fake_loss = self.hinge_loss(score_fake) + hinge_fake_loss += fake_loss + else: + fake_loss = self.hinge_loss(scores_fake) + hinge_fake_loss = fake_loss + return_dict['G_hinge_fake_loss'] = hinge_fake_loss + loss += self.hinge_gan_loss_alpha * hinge_fake_loss + + # Feature Matching Loss + if self.use_feat_match_loss and not feats_fake: + feat_match_loss = self.feat_match_loss(feats_fake, feats_real) + return_dict['G_feat_match_loss'] = feat_match_loss + loss += self.feat_match_loss_alpha * feat_match_loss + return_dict['G_loss'] = loss + return return_dict + + +class DiscriminatorLoss(nn.Module): + def __init__(self, C): + super(DiscriminatorLoss, self).__init__() + assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + " [!] Cannot use HingeGANLoss and MSEGANLoss together." + + self.use_mse_gan_loss = C.use_mse_gan_loss + self.use_hinge_gan_loss = C.use_hinge_gan_loss + + self.mse_gan_loss_alpha = C.mse_gan_loss_alpha + self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha + + if C.use_mse_gan_loss: + self.mse_loss = MSEDLoss() + if C.use_hinge_gan_loss: + self.hinge_loss = HingeDLoss() + + def forward(self, scores_fake, scores_real): + loss = 0 + return_dict = {} + + if self.use_mse_gan_loss: + mse_gan_loss = 0 + mse_gan_real_loss = 0 + mse_gan_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake, score_real in zip(scores_fake, scores_real): + total_loss, real_loss, fake_loss = self.mse_loss(score_fake, score_real) + mse_gan_loss += total_loss + mse_gan_real_loss += real_loss + mse_gan_fake_loss += fake_loss + else: + total_loss, real_loss, fake_loss = self.mse_loss(scores_fake, scores_real) + mse_gan_loss = total_loss + mse_gan_real_loss = real_loss + mse_gan_fake_loss = fake_loss + return_dict['D_mse_gan_loss'] = mse_gan_loss + return_dict['D_mse_gan_real_loss'] = mse_gan_real_loss + return_dict['D_mse_gan_fake_loss'] = mse_gan_fake_loss + loss += self.mse_gan_loss_alpha * mse_gan_loss + + if self.use_hinge_gan_loss: + hinge_gan_loss = 0 + hinge_gan_real_loss = 0 + hinge_gan_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake, score_real in zip(scores_fake, scores_real): + total_loss, real_loss, fake_loss = self.hinge_loss(score_fake, score_real) + hinge_gan_loss += total_loss + hinge_gan_real_loss += real_loss + hinge_gan_fake_loss += fake_loss + else: + total_loss, real_loss, fake_loss = self.hinge_loss(scores_fake, scores_real) + hinge_gan_loss = total_loss + hinge_gan_real_loss = real_loss + hinge_gan_fake_loss = fake_loss + return_dict['D_hinge_gan_loss'] = hinge_gan_loss + return_dict['D_hinge_gan_real_loss'] = hinge_gan_real_loss + return_dict['D_hinge_gan_fake_loss'] = hinge_gan_fake_loss + loss += self.hinge_gan_loss_alpha * hinge_gan_loss + + return_dict['D_loss'] = loss + return return_dict \ No newline at end of file diff --git a/vocoder/layers/melgan.py b/vocoder/layers/melgan.py new file mode 100644 index 00000000..cda0413c --- /dev/null +++ b/vocoder/layers/melgan.py @@ -0,0 +1,48 @@ +import numpy as np +import torch +from torch import nn +from torch.nn import functional as F +from torch.nn.utils import weight_norm + + +class ResidualStack(nn.Module): + def __init__(self, channels, num_res_blocks, kernel_size): + super(ResidualStack, self).__init__() + + assert (kernel_size - 1) % 2 == 0, " [!] kernel_size has to be odd." + base_padding = (kernel_size - 1) // 2 + + self.blocks = nn.ModuleList() + for idx in range(num_res_blocks): + layer_kernel_size = kernel_size + layer_dilation = layer_kernel_size**idx + layer_padding = base_padding * layer_dilation + self.blocks += [nn.Sequential( + nn.LeakyReLU(0.2), + nn.ReflectionPad1d(layer_padding), + weight_norm( + nn.Conv1d(channels, + channels, + kernel_size=kernel_size, + dilation=layer_padding, + bias=True)), + nn.LeakyReLU(0.2), + weight_norm( + nn.Conv1d(channels, channels, kernel_size=1, bias=True)), + )] + + self.shortcuts = nn.ModuleList([ + weight_norm(nn.Conv1d(channels, channels, kernel_size=1, + bias=True)) for i in range(num_res_blocks) + ]) + + def forward(self, x): + for block, shortcut in zip(self.blocks, self.shortcuts): + x = shortcut(x) + block(x) + return x + + def remove_weight_norm(self): + for block, shortcut in zip(self.blocks, self.shortcuts): + nn.utils.remove_weight_norm(block[2]) + nn.utils.remove_weight_norm(block[4]) + nn.utils.remove_weight_norm(shortcut) diff --git a/vocoder/layers/pqmf.py b/vocoder/layers/pqmf.py new file mode 100644 index 00000000..f438ea00 --- /dev/null +++ b/vocoder/layers/pqmf.py @@ -0,0 +1,55 @@ +"""Pseudo QMF modules.""" + +import numpy as np +import torch +import torch.nn.functional as F + +from scipy import signal as sig + + +# adapted from +# https://github.com/kan-bayashi/ParallelWaveGAN/tree/master/parallel_wavegan +class PQMF(torch.nn.Module): + def __init__(self, N=4, taps=62, cutoff=0.15, beta=9.0): + super(PQMF, self).__init__() + + self.N = N + self.taps = taps + self.cutoff = cutoff + self.beta = beta + + QMF = sig.firwin(taps + 1, cutoff, window=('kaiser', beta)) + H = np.zeros((N, len(QMF))) + G = np.zeros((N, len(QMF))) + for k in range(N): + constant_factor = (2 * k + 1) * (np.pi / + (2 * N)) * (np.arange(taps + 1) - + ((taps - 1) / 2)) + phase = (-1)**k * np.pi / 4 + H[k] = 2 * QMF * np.cos(constant_factor + phase) + + G[k] = 2 * QMF * np.cos(constant_factor - phase) + + H = torch.from_numpy(H[:, None, :]).float() + G = torch.from_numpy(G[None, :, :]).float() + + self.register_buffer("H", H) + self.register_buffer("G", G) + + updown_filter = torch.zeros((N, N, N)).float() + for k in range(N): + updown_filter[k, k, 0] = 1.0 + self.register_buffer("updown_filter", updown_filter) + self.N = N + + self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) + + def analysis(self, x): + return F.conv1d(x, self.H, padding=self.taps // 2, stride=self.N) + + def synthesis(self, x): + x = F.conv_transpose1d(x, + self.updown_filter * self.N, + stride=self.N) + x = F.conv1d(x, self.G, padding=self.taps // 2) + return x diff --git a/vocoder/layers/pqmf2.py b/vocoder/layers/pqmf2.py new file mode 100644 index 00000000..4cffb819 --- /dev/null +++ b/vocoder/layers/pqmf2.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Tomoki Hayashi +# MIT License (https://opensource.org/licenses/MIT) + +"""Pseudo QMF modules.""" + +import numpy as np +import torch +import torch.nn.functional as F + +from scipy.signal import kaiser + + +def design_prototype_filter(taps=62, cutoff_ratio=0.15, beta=9.0): + """Design prototype filter for PQMF. + + This method is based on `A Kaiser window approach for the design of prototype + filters of cosine modulated filterbanks`_. + + Args: + taps (int): The number of filter taps. + cutoff_ratio (float): Cut-off frequency ratio. + beta (float): Beta coefficient for kaiser window. + + Returns: + ndarray: Impluse response of prototype filter (taps + 1,). + + .. _`A Kaiser window approach for the design of prototype filters of cosine modulated filterbanks`: + https://ieeexplore.ieee.org/abstract/document/681427 + + """ + # check the arguments are valid + assert taps % 2 == 0, "The number of taps mush be even number." + assert 0.0 < cutoff_ratio < 1.0, "Cutoff ratio must be > 0.0 and < 1.0." + + # make initial filter + omega_c = np.pi * cutoff_ratio + with np.errstate(invalid='ignore'): + h_i = np.sin(omega_c * (np.arange(taps + 1) - 0.5 * taps)) \ + / (np.pi * (np.arange(taps + 1) - 0.5 * taps)) + h_i[taps // 2] = np.cos(0) * cutoff_ratio # fix nan due to indeterminate form + + # apply kaiser window + w = kaiser(taps + 1, beta) + h = h_i * w + + return h + + +class PQMF(torch.nn.Module): + """PQMF module. + + This module is based on `Near-perfect-reconstruction pseudo-QMF banks`_. + + .. _`Near-perfect-reconstruction pseudo-QMF banks`: + https://ieeexplore.ieee.org/document/258122 + + """ + + def __init__(self, subbands=4, taps=62, cutoff_ratio=0.15, beta=9.0): + """Initilize PQMF module. + + Args: + subbands (int): The number of subbands. + taps (int): The number of filter taps. + cutoff_ratio (float): Cut-off frequency ratio. + beta (float): Beta coefficient for kaiser window. + + """ + super(PQMF, self).__init__() + + # define filter coefficient + h_proto = design_prototype_filter(taps, cutoff_ratio, beta) + h_analysis = np.zeros((subbands, len(h_proto))) + h_synthesis = np.zeros((subbands, len(h_proto))) + for k in range(subbands): + h_analysis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) + (-1) ** k * np.pi / 4) + h_synthesis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) - (-1) ** k * np.pi / 4) + + # convert to tensor + analysis_filter = torch.from_numpy(h_analysis).float().unsqueeze(1) + synthesis_filter = torch.from_numpy(h_synthesis).float().unsqueeze(0) + + # register coefficients as beffer + self.register_buffer("analysis_filter", analysis_filter) + self.register_buffer("synthesis_filter", synthesis_filter) + + # filter for downsampling & upsampling + updown_filter = torch.zeros((subbands, subbands, subbands)).float() + for k in range(subbands): + updown_filter[k, k, 0] = 1.0 + self.register_buffer("updown_filter", updown_filter) + self.subbands = subbands + + # keep padding info + self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) + + def analysis(self, x): + """Analysis with PQMF. + + Args: + x (Tensor): Input tensor (B, 1, T). + + Returns: + Tensor: Output tensor (B, subbands, T // subbands). + + """ + x = F.conv1d(self.pad_fn(x), self.analysis_filter) + return F.conv1d(x, self.updown_filter, stride=self.subbands) + + def synthesis(self, x): + """Synthesis with PQMF. + + Args: + x (Tensor): Input tensor (B, subbands, T // subbands). + + Returns: + Tensor: Output tensor (B, 1, T). + + """ + # NOTE(kan-bayashi): Power will be dreased so here multipy by # subbands. + # Not sure this is the correct way, it is better to check again. + # TODO(kan-bayashi): Understand the reconstruction procedure + x = F.conv_transpose1d(x, self.updown_filter * self.subbands, stride=self.subbands) + x = F.conv1d(self.pad_fn(x), self.synthesis_filter) + return x diff --git a/vocoder/layers/qmf.dat b/vocoder/layers/qmf.dat new file mode 100644 index 00000000..17eab137 --- /dev/null +++ b/vocoder/layers/qmf.dat @@ -0,0 +1,640 @@ + 0.0000000e+000 + -5.5252865e-004 + -5.6176926e-004 + -4.9475181e-004 + -4.8752280e-004 + -4.8937912e-004 + -5.0407143e-004 + -5.2265643e-004 + -5.4665656e-004 + -5.6778026e-004 + -5.8709305e-004 + -6.1327474e-004 + -6.3124935e-004 + -6.5403334e-004 + -6.7776908e-004 + -6.9416146e-004 + -7.1577365e-004 + -7.2550431e-004 + -7.4409419e-004 + -7.4905981e-004 + -7.6813719e-004 + -7.7248486e-004 + -7.8343323e-004 + -7.7798695e-004 + -7.8036647e-004 + -7.8014496e-004 + -7.7579773e-004 + -7.6307936e-004 + -7.5300014e-004 + -7.3193572e-004 + -7.2153920e-004 + -6.9179375e-004 + -6.6504151e-004 + -6.3415949e-004 + -5.9461189e-004 + -5.5645764e-004 + -5.1455722e-004 + -4.6063255e-004 + -4.0951215e-004 + -3.5011759e-004 + -2.8969812e-004 + -2.0983373e-004 + -1.4463809e-004 + -6.1733441e-005 + 1.3494974e-005 + 1.0943831e-004 + 2.0430171e-004 + 2.9495311e-004 + 4.0265402e-004 + 5.1073885e-004 + 6.2393761e-004 + 7.4580259e-004 + 8.6084433e-004 + 9.8859883e-004 + 1.1250155e-003 + 1.2577885e-003 + 1.3902495e-003 + 1.5443220e-003 + 1.6868083e-003 + 1.8348265e-003 + 1.9841141e-003 + 2.1461584e-003 + 2.3017255e-003 + 2.4625617e-003 + 2.6201759e-003 + 2.7870464e-003 + 2.9469448e-003 + 3.1125421e-003 + 3.2739613e-003 + 3.4418874e-003 + 3.6008268e-003 + 3.7603923e-003 + 3.9207432e-003 + 4.0819753e-003 + 4.2264269e-003 + 4.3730720e-003 + 4.5209853e-003 + 4.6606461e-003 + 4.7932561e-003 + 4.9137604e-003 + 5.0393023e-003 + 5.1407354e-003 + 5.2461166e-003 + 5.3471681e-003 + 5.4196776e-003 + 5.4876040e-003 + 5.5475715e-003 + 5.5938023e-003 + 5.6220643e-003 + 5.6455197e-003 + 5.6389200e-003 + 5.6266114e-003 + 5.5917129e-003 + 5.5404364e-003 + 5.4753783e-003 + 5.3838976e-003 + 5.2715759e-003 + 5.1382275e-003 + 4.9839688e-003 + 4.8109469e-003 + 4.6039530e-003 + 4.3801862e-003 + 4.1251642e-003 + 3.8456408e-003 + 3.5401247e-003 + 3.2091886e-003 + 2.8446758e-003 + 2.4508540e-003 + 2.0274176e-003 + 1.5784683e-003 + 1.0902329e-003 + 5.8322642e-004 + 2.7604519e-005 + -5.4642809e-004 + -1.1568136e-003 + -1.8039473e-003 + -2.4826724e-003 + -3.1933778e-003 + -3.9401124e-003 + -4.7222596e-003 + -5.5337211e-003 + -6.3792293e-003 + -7.2615817e-003 + -8.1798233e-003 + -9.1325330e-003 + -1.0115022e-002 + -1.1131555e-002 + -1.2185000e-002 + -1.3271822e-002 + -1.4390467e-002 + -1.5540555e-002 + -1.6732471e-002 + -1.7943338e-002 + -1.9187243e-002 + -2.0453179e-002 + -2.1746755e-002 + -2.3068017e-002 + -2.4416099e-002 + -2.5787585e-002 + -2.7185943e-002 + -2.8607217e-002 + -3.0050266e-002 + -3.1501761e-002 + -3.2975408e-002 + -3.4462095e-002 + -3.5969756e-002 + -3.7481285e-002 + -3.9005368e-002 + -4.0534917e-002 + -4.2064909e-002 + -4.3609754e-002 + -4.5148841e-002 + -4.6684303e-002 + -4.8216572e-002 + -4.9738576e-002 + -5.1255616e-002 + -5.2763075e-002 + -5.4245277e-002 + -5.5717365e-002 + -5.7161645e-002 + -5.8591568e-002 + -5.9983748e-002 + -6.1345517e-002 + -6.2685781e-002 + -6.3971590e-002 + -6.5224711e-002 + -6.6436751e-002 + -6.7607599e-002 + -6.8704383e-002 + -6.9763024e-002 + -7.0762871e-002 + -7.1700267e-002 + -7.2568258e-002 + -7.3362026e-002 + -7.4100364e-002 + -7.4745256e-002 + -7.5313734e-002 + -7.5800836e-002 + -7.6199248e-002 + -7.6499217e-002 + -7.6709349e-002 + -7.6817398e-002 + -7.6823001e-002 + -7.6720492e-002 + -7.6505072e-002 + -7.6174832e-002 + -7.5730576e-002 + -7.5157626e-002 + -7.4466439e-002 + -7.3640601e-002 + -7.2677464e-002 + -7.1582636e-002 + -7.0353307e-002 + -6.8966401e-002 + -6.7452502e-002 + -6.5769067e-002 + -6.3944481e-002 + -6.1960278e-002 + -5.9816657e-002 + -5.7515269e-002 + -5.5046003e-002 + -5.2409382e-002 + -4.9597868e-002 + -4.6630331e-002 + -4.3476878e-002 + -4.0145828e-002 + -3.6641812e-002 + -3.2958393e-002 + -2.9082401e-002 + -2.5030756e-002 + -2.0799707e-002 + -1.6370126e-002 + -1.1762383e-002 + -6.9636862e-003 + -1.9765601e-003 + 3.2086897e-003 + 8.5711749e-003 + 1.4128883e-002 + 1.9883413e-002 + 2.5822729e-002 + 3.1953127e-002 + 3.8277657e-002 + 4.4780682e-002 + 5.1480418e-002 + 5.8370533e-002 + 6.5440985e-002 + 7.2694330e-002 + 8.0137293e-002 + 8.7754754e-002 + 9.5553335e-002 + 1.0353295e-001 + 1.1168269e-001 + 1.2000780e-001 + 1.2850029e-001 + 1.3715518e-001 + 1.4597665e-001 + 1.5496071e-001 + 1.6409589e-001 + 1.7338082e-001 + 1.8281725e-001 + 1.9239667e-001 + 2.0212502e-001 + 2.1197359e-001 + 2.2196527e-001 + 2.3206909e-001 + 2.4230169e-001 + 2.5264803e-001 + 2.6310533e-001 + 2.7366340e-001 + 2.8432142e-001 + 2.9507167e-001 + 3.0590986e-001 + 3.1682789e-001 + 3.2781137e-001 + 3.3887227e-001 + 3.4999141e-001 + 3.6115899e-001 + 3.7237955e-001 + 3.8363500e-001 + 3.9492118e-001 + 4.0623177e-001 + 4.1756969e-001 + 4.2891199e-001 + 4.4025538e-001 + 4.5159965e-001 + 4.6293081e-001 + 4.7424532e-001 + 4.8552531e-001 + 4.9677083e-001 + 5.0798175e-001 + 5.1912350e-001 + 5.3022409e-001 + 5.4125534e-001 + 5.5220513e-001 + 5.6307891e-001 + 5.7385241e-001 + 5.8454032e-001 + 5.9511231e-001 + 6.0557835e-001 + 6.1591099e-001 + 6.2612427e-001 + 6.3619801e-001 + 6.4612697e-001 + 6.5590163e-001 + 6.6551399e-001 + 6.7496632e-001 + 6.8423533e-001 + 6.9332824e-001 + 7.0223887e-001 + 7.1094104e-001 + 7.1944626e-001 + 7.2774489e-001 + 7.3582118e-001 + 7.4368279e-001 + 7.5131375e-001 + 7.5870808e-001 + 7.6586749e-001 + 7.7277809e-001 + 7.7942875e-001 + 7.8583531e-001 + 7.9197358e-001 + 7.9784664e-001 + 8.0344858e-001 + 8.0876950e-001 + 8.1381913e-001 + 8.1857760e-001 + 8.2304199e-001 + 8.2722753e-001 + 8.3110385e-001 + 8.3469374e-001 + 8.3797173e-001 + 8.4095414e-001 + 8.4362383e-001 + 8.4598185e-001 + 8.4803158e-001 + 8.4978052e-001 + 8.5119715e-001 + 8.5230470e-001 + 8.5310209e-001 + 8.5357206e-001 + 8.5373856e-001 + 8.5357206e-001 + 8.5310209e-001 + 8.5230470e-001 + 8.5119715e-001 + 8.4978052e-001 + 8.4803158e-001 + 8.4598185e-001 + 8.4362383e-001 + 8.4095414e-001 + 8.3797173e-001 + 8.3469374e-001 + 8.3110385e-001 + 8.2722753e-001 + 8.2304199e-001 + 8.1857760e-001 + 8.1381913e-001 + 8.0876950e-001 + 8.0344858e-001 + 7.9784664e-001 + 7.9197358e-001 + 7.8583531e-001 + 7.7942875e-001 + 7.7277809e-001 + 7.6586749e-001 + 7.5870808e-001 + 7.5131375e-001 + 7.4368279e-001 + 7.3582118e-001 + 7.2774489e-001 + 7.1944626e-001 + 7.1094104e-001 + 7.0223887e-001 + 6.9332824e-001 + 6.8423533e-001 + 6.7496632e-001 + 6.6551399e-001 + 6.5590163e-001 + 6.4612697e-001 + 6.3619801e-001 + 6.2612427e-001 + 6.1591099e-001 + 6.0557835e-001 + 5.9511231e-001 + 5.8454032e-001 + 5.7385241e-001 + 5.6307891e-001 + 5.5220513e-001 + 5.4125534e-001 + 5.3022409e-001 + 5.1912350e-001 + 5.0798175e-001 + 4.9677083e-001 + 4.8552531e-001 + 4.7424532e-001 + 4.6293081e-001 + 4.5159965e-001 + 4.4025538e-001 + 4.2891199e-001 + 4.1756969e-001 + 4.0623177e-001 + 3.9492118e-001 + 3.8363500e-001 + 3.7237955e-001 + 3.6115899e-001 + 3.4999141e-001 + 3.3887227e-001 + 3.2781137e-001 + 3.1682789e-001 + 3.0590986e-001 + 2.9507167e-001 + 2.8432142e-001 + 2.7366340e-001 + 2.6310533e-001 + 2.5264803e-001 + 2.4230169e-001 + 2.3206909e-001 + 2.2196527e-001 + 2.1197359e-001 + 2.0212502e-001 + 1.9239667e-001 + 1.8281725e-001 + 1.7338082e-001 + 1.6409589e-001 + 1.5496071e-001 + 1.4597665e-001 + 1.3715518e-001 + 1.2850029e-001 + 1.2000780e-001 + 1.1168269e-001 + 1.0353295e-001 + 9.5553335e-002 + 8.7754754e-002 + 8.0137293e-002 + 7.2694330e-002 + 6.5440985e-002 + 5.8370533e-002 + 5.1480418e-002 + 4.4780682e-002 + 3.8277657e-002 + 3.1953127e-002 + 2.5822729e-002 + 1.9883413e-002 + 1.4128883e-002 + 8.5711749e-003 + 3.2086897e-003 + -1.9765601e-003 + -6.9636862e-003 + -1.1762383e-002 + -1.6370126e-002 + -2.0799707e-002 + -2.5030756e-002 + -2.9082401e-002 + -3.2958393e-002 + -3.6641812e-002 + -4.0145828e-002 + -4.3476878e-002 + -4.6630331e-002 + -4.9597868e-002 + -5.2409382e-002 + -5.5046003e-002 + -5.7515269e-002 + -5.9816657e-002 + -6.1960278e-002 + -6.3944481e-002 + -6.5769067e-002 + -6.7452502e-002 + -6.8966401e-002 + -7.0353307e-002 + -7.1582636e-002 + -7.2677464e-002 + -7.3640601e-002 + -7.4466439e-002 + -7.5157626e-002 + -7.5730576e-002 + -7.6174832e-002 + -7.6505072e-002 + -7.6720492e-002 + -7.6823001e-002 + -7.6817398e-002 + -7.6709349e-002 + -7.6499217e-002 + -7.6199248e-002 + -7.5800836e-002 + -7.5313734e-002 + -7.4745256e-002 + -7.4100364e-002 + -7.3362026e-002 + -7.2568258e-002 + -7.1700267e-002 + -7.0762871e-002 + -6.9763024e-002 + -6.8704383e-002 + -6.7607599e-002 + -6.6436751e-002 + -6.5224711e-002 + -6.3971590e-002 + -6.2685781e-002 + -6.1345517e-002 + -5.9983748e-002 + -5.8591568e-002 + -5.7161645e-002 + -5.5717365e-002 + -5.4245277e-002 + -5.2763075e-002 + -5.1255616e-002 + -4.9738576e-002 + -4.8216572e-002 + -4.6684303e-002 + -4.5148841e-002 + -4.3609754e-002 + -4.2064909e-002 + -4.0534917e-002 + -3.9005368e-002 + -3.7481285e-002 + -3.5969756e-002 + -3.4462095e-002 + -3.2975408e-002 + -3.1501761e-002 + -3.0050266e-002 + -2.8607217e-002 + -2.7185943e-002 + -2.5787585e-002 + -2.4416099e-002 + -2.3068017e-002 + -2.1746755e-002 + -2.0453179e-002 + -1.9187243e-002 + -1.7943338e-002 + -1.6732471e-002 + -1.5540555e-002 + -1.4390467e-002 + -1.3271822e-002 + -1.2185000e-002 + -1.1131555e-002 + -1.0115022e-002 + -9.1325330e-003 + -8.1798233e-003 + -7.2615817e-003 + -6.3792293e-003 + -5.5337211e-003 + -4.7222596e-003 + -3.9401124e-003 + -3.1933778e-003 + -2.4826724e-003 + -1.8039473e-003 + -1.1568136e-003 + -5.4642809e-004 + 2.7604519e-005 + 5.8322642e-004 + 1.0902329e-003 + 1.5784683e-003 + 2.0274176e-003 + 2.4508540e-003 + 2.8446758e-003 + 3.2091886e-003 + 3.5401247e-003 + 3.8456408e-003 + 4.1251642e-003 + 4.3801862e-003 + 4.6039530e-003 + 4.8109469e-003 + 4.9839688e-003 + 5.1382275e-003 + 5.2715759e-003 + 5.3838976e-003 + 5.4753783e-003 + 5.5404364e-003 + 5.5917129e-003 + 5.6266114e-003 + 5.6389200e-003 + 5.6455197e-003 + 5.6220643e-003 + 5.5938023e-003 + 5.5475715e-003 + 5.4876040e-003 + 5.4196776e-003 + 5.3471681e-003 + 5.2461166e-003 + 5.1407354e-003 + 5.0393023e-003 + 4.9137604e-003 + 4.7932561e-003 + 4.6606461e-003 + 4.5209853e-003 + 4.3730720e-003 + 4.2264269e-003 + 4.0819753e-003 + 3.9207432e-003 + 3.7603923e-003 + 3.6008268e-003 + 3.4418874e-003 + 3.2739613e-003 + 3.1125421e-003 + 2.9469448e-003 + 2.7870464e-003 + 2.6201759e-003 + 2.4625617e-003 + 2.3017255e-003 + 2.1461584e-003 + 1.9841141e-003 + 1.8348265e-003 + 1.6868083e-003 + 1.5443220e-003 + 1.3902495e-003 + 1.2577885e-003 + 1.1250155e-003 + 9.8859883e-004 + 8.6084433e-004 + 7.4580259e-004 + 6.2393761e-004 + 5.1073885e-004 + 4.0265402e-004 + 2.9495311e-004 + 2.0430171e-004 + 1.0943831e-004 + 1.3494974e-005 + -6.1733441e-005 + -1.4463809e-004 + -2.0983373e-004 + -2.8969812e-004 + -3.5011759e-004 + -4.0951215e-004 + -4.6063255e-004 + -5.1455722e-004 + -5.5645764e-004 + -5.9461189e-004 + -6.3415949e-004 + -6.6504151e-004 + -6.9179375e-004 + -7.2153920e-004 + -7.3193572e-004 + -7.5300014e-004 + -7.6307936e-004 + -7.7579773e-004 + -7.8014496e-004 + -7.8036647e-004 + -7.7798695e-004 + -7.8343323e-004 + -7.7248486e-004 + -7.6813719e-004 + -7.4905981e-004 + -7.4409419e-004 + -7.2550431e-004 + -7.1577365e-004 + -6.9416146e-004 + -6.7776908e-004 + -6.5403334e-004 + -6.3124935e-004 + -6.1327474e-004 + -5.8709305e-004 + -5.6778026e-004 + -5.4665656e-004 + -5.2265643e-004 + -5.0407143e-004 + -4.8937912e-004 + -4.8752280e-004 + -4.9475181e-004 + -5.6176926e-004 + -5.5252865e-004 diff --git a/vocoder/models/__init__.py b/vocoder/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/models/melgan_discriminator.py b/vocoder/models/melgan_discriminator.py new file mode 100644 index 00000000..55d3f585 --- /dev/null +++ b/vocoder/models/melgan_discriminator.py @@ -0,0 +1,80 @@ +import numpy as np +import torch +from torch import nn +from torch.nn import functional as F +from torch.nn.utils import weight_norm + + +class MelganDiscriminator(nn.Module): + def __init__(self, + in_channels=1, + out_channels=1, + kernel_sizes=(5, 3), + base_channels=16, + max_channels=1024, + downsample_factors=(4, 4, 4, 4)): + super(MelganDiscriminator, self).__init__() + self.layers = nn.ModuleList() + + layer_kernel_size = np.prod(kernel_sizes) + layer_padding = (layer_kernel_size - 1) // 2 + + # initial layer + self.layers += [ + nn.Sequential( + nn.ReflectionPad1d(layer_padding), + weight_norm( + nn.Conv1d(in_channels, + base_channels, + layer_kernel_size, + stride=1)), nn.LeakyReLU(0.2, inplace=True)) + ] + + # downsampling layers + layer_in_channels = base_channels + for idx, downsample_factor in enumerate(downsample_factors): + layer_out_channels = min(layer_in_channels * downsample_factor, + max_channels) + layer_kernel_size = downsample_factor * 10 + 1 + layer_padding = (layer_kernel_size - 1) // 2 + layer_groups = layer_in_channels // 4 + self.layers += [ + nn.Sequential( + weight_norm( + nn.Conv1d(layer_in_channels, + layer_out_channels, + kernel_size=layer_kernel_size, + stride=downsample_factor, + padding=layer_padding, + groups=layer_groups)), + nn.LeakyReLU(0.2, inplace=True)) + ] + layer_in_channels = layer_out_channels + + # last 2 layers + layer_padding1 = (kernel_sizes[0] - 1) // 2 + layer_padding2 = (kernel_sizes[1] - 1) // 2 + self.layers += [ + nn.Sequential( + weight_norm( + nn.Conv1d(layer_out_channels, + layer_out_channels, + kernel_size=kernel_sizes[0], + stride=1, + padding=layer_padding1)), + nn.LeakyReLU(0.2, inplace=True), + ), + weight_norm( + nn.Conv1d(layer_out_channels, + out_channels, + kernel_size=kernel_sizes[1], + stride=1, + padding=layer_padding2)), + ] + + def forward(self, x): + feats = [] + for layer in self.layers: + x = layer(x) + feats.append(x) + return x, feats diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py new file mode 100644 index 00000000..2d266f29 --- /dev/null +++ b/vocoder/models/melgan_generator.py @@ -0,0 +1,91 @@ +import math +import torch +from torch import nn +from torch.nn import functional as F +from torch.nn.utils import weight_norm + +from TTS.vocoder.layers.melgan import ResidualStack + + +class MelganGenerator(nn.Module): + def __init__(self, + in_channels=80, + out_channels=1, + proj_kernel=7, + base_channels=512, + upsample_factors=(8, 8, 2, 2), + res_kernel=3, + num_res_blocks=3): + super(MelganGenerator, self).__init__() + + # assert model parameters + assert (proj_kernel - + 1) % 2 == 0, " [!] proj_kernel should be an odd number." + + # setup additional model parameters + base_padding = (proj_kernel - 1) // 2 + act_slope = 0.2 + self.inference_padding = 2 + + # initial layer + layers = [] + layers += [ + nn.ReflectionPad1d(base_padding), + weight_norm( + nn.Conv1d(in_channels, + base_channels, + kernel_size=proj_kernel, + stride=1, + bias=True)) + ] + + # upsampling layers and residual stacks + for idx, upsample_factor in enumerate(upsample_factors): + layer_in_channels = base_channels // (2**idx) + layer_out_channels = base_channels // (2**(idx + 1)) + layer_filter_size = upsample_factor * 2 + layer_stride = upsample_factor + layer_output_padding = upsample_factor % 2 + layer_padding = upsample_factor // 2 + layer_output_padding + layers += [ + nn.LeakyReLU(act_slope), + weight_norm( + nn.ConvTranspose1d(layer_in_channels, + layer_out_channels, + layer_filter_size, + stride=layer_stride, + padding=layer_padding, + output_padding=layer_output_padding, + bias=True)), + ResidualStack( + channels=layer_out_channels, + num_res_blocks=num_res_blocks, + kernel_size=res_kernel + ) + ] + + layers += [nn.LeakyReLU(act_slope)] + + # final layer + layers += [ + nn.ReflectionPad1d(base_padding), + weight_norm( + nn.Conv1d(layer_out_channels, + out_channels, + proj_kernel, + stride=1, + bias=True)), + nn.Tanh() + ] + self.layers = nn.Sequential(*layers) + + def forward(self, cond_features): + return self.layers(cond_features) + + def inference(self, cond_features): + cond_features = cond_features.to(self.layers[1].weight.device) + cond_features = torch.nn.functional.pad( + cond_features, + (self.inference_padding, self.inference_padding), + 'replicate') + return self.layers(cond_features) diff --git a/vocoder/models/melgan_multiscale_discriminator.py b/vocoder/models/melgan_multiscale_discriminator.py new file mode 100644 index 00000000..d77b9ceb --- /dev/null +++ b/vocoder/models/melgan_multiscale_discriminator.py @@ -0,0 +1,41 @@ +from torch import nn + +from TTS.vocoder.models.melgan_discriminator import MelganDiscriminator + + +class MelganMultiscaleDiscriminator(nn.Module): + def __init__(self, + in_channels=1, + out_channels=1, + num_scales=3, + kernel_sizes=(5, 3), + base_channels=16, + max_channels=1024, + downsample_factors=(4, 4, 4, 4), + pooling_kernel_size=4, + pooling_stride=2, + pooling_padding=1): + super(MelganMultiscaleDiscriminator, self).__init__() + + self.discriminators = nn.ModuleList([ + MelganDiscriminator(in_channels=in_channels, + out_channels=out_channels, + kernel_sizes=kernel_sizes, + base_channels=base_channels, + max_channels=max_channels, + downsample_factors=downsample_factors) + for _ in range(num_scales) + ]) + + self.pooling = nn.AvgPool1d(kernel_size=pooling_kernel_size, stride=pooling_stride, padding=pooling_padding, count_include_pad=False) + + + def forward(self, x): + scores = list() + feats = list() + for disc in self.discriminators: + score, feat = disc(x) + scores.append(score) + feats.append(feat) + x = self.pooling(x) + return scores, feats \ No newline at end of file diff --git a/vocoder/models/multiband_melgan_generator.py b/vocoder/models/multiband_melgan_generator.py new file mode 100644 index 00000000..8feacd25 --- /dev/null +++ b/vocoder/models/multiband_melgan_generator.py @@ -0,0 +1,38 @@ +import torch + +from TTS.vocoder.models.melgan_generator import MelganGenerator +from TTS.vocoder.layers.pqmf import PQMF + + +class MultibandMelganGenerator(MelganGenerator): + def __init__(self, + in_channels=80, + out_channels=4, + proj_kernel=7, + base_channels=384, + upsample_factors=(2, 8, 2, 2), + res_kernel=3, + num_res_blocks=3): + super(MultibandMelganGenerator, + self).__init__(in_channels=in_channels, + out_channels=out_channels, + proj_kernel=proj_kernel, + base_channels=base_channels, + upsample_factors=upsample_factors, + res_kernel=res_kernel, + num_res_blocks=num_res_blocks) + self.pqmf_layer = PQMF(N=4, taps=62, cutoff=0.15, beta=9.0) + + def pqmf_analysis(self, x): + return self.pqmf_layer.analysis(x) + + def pqmf_synthesis(self, x): + return self.pqmf_layer.synthesis(x) + + def inference(self, cond_features): + cond_features = cond_features.to(self.layers[1].weight.device) + cond_features = torch.nn.functional.pad( + cond_features, + (self.inference_padding, self.inference_padding), + 'replicate') + return self.pqmf.synthesis(self.layers(cond_features)) diff --git a/vocoder/models/random_window_discriminator.py b/vocoder/models/random_window_discriminator.py new file mode 100644 index 00000000..3efd395e --- /dev/null +++ b/vocoder/models/random_window_discriminator.py @@ -0,0 +1,225 @@ +import numpy as np +from torch import nn + + +class GBlock(nn.Module): + def __init__(self, in_channels, cond_channels, downsample_factor): + super(GBlock, self).__init__() + + self.in_channels = in_channels + self.cond_channels = cond_channels + self.downsample_factor = downsample_factor + + self.start = nn.Sequential( + nn.AvgPool1d(downsample_factor, stride=downsample_factor), + nn.ReLU(), + nn.Conv1d(in_channels, in_channels * 2, kernel_size=3, padding=1)) + self.lc_conv1d = nn.Conv1d(cond_channels, + in_channels * 2, + kernel_size=1) + self.end = nn.Sequential( + nn.ReLU(), + nn.Conv1d(in_channels * 2, + in_channels * 2, + kernel_size=3, + dilation=2, + padding=2)) + self.residual = nn.Sequential( + nn.Conv1d(in_channels, in_channels * 2, kernel_size=1), + nn.AvgPool1d(downsample_factor, stride=downsample_factor)) + + def forward(self, inputs, conditions): + outputs = self.start(inputs) + self.lc_conv1d(conditions) + outputs = self.end(outputs) + residual_outputs = self.residual(inputs) + outputs = outputs + residual_outputs + + return outputs + + +class DBlock(nn.Module): + def __init__(self, in_channels, out_channels, downsample_factor): + super(DBlock, self).__init__() + + self.in_channels = in_channels + self.downsample_factor = downsample_factor + self.out_channels = out_channels + + self.donwsample_layer = nn.AvgPool1d(downsample_factor, + stride=downsample_factor) + self.layers = nn.Sequential( + nn.ReLU(), + nn.Conv1d(in_channels, out_channels, kernel_size=3, padding=1), + nn.ReLU(), + nn.Conv1d(out_channels, + out_channels, + kernel_size=3, + dilation=2, + padding=2)) + self.residual = nn.Sequential( + nn.Conv1d(in_channels, out_channels, kernel_size=1), ) + + def forward(self, inputs): + if self.downsample_factor > 1: + outputs = self.layers(self.donwsample_layer(inputs))\ + + self.donwsample_layer(self.residual(inputs)) + else: + outputs = self.layers(inputs) + self.residual(inputs) + return outputs + + +class ConditionalDiscriminator(nn.Module): + def __init__(self, + in_channels, + cond_channels, + downsample_factors=(2, 2, 2), + out_channels=(128, 256)): + super(ConditionalDiscriminator, self).__init__() + + assert len(downsample_factors) == len(out_channels) + 1 + + self.in_channels = in_channels + self.cond_channels = cond_channels + self.downsample_factors = downsample_factors + self.out_channels = out_channels + + self.pre_cond_layers = nn.ModuleList() + self.post_cond_layers = nn.ModuleList() + + # layers before condition features + self.pre_cond_layers += [DBlock(in_channels, 64, 1)] + in_channels = 64 + for (i, channel) in enumerate(out_channels): + self.pre_cond_layers.append( + DBlock(in_channels, channel, downsample_factors[i])) + in_channels = channel + + # condition block + self.cond_block = GBlock(in_channels, cond_channels, + downsample_factors[-1]) + + # layers after condition block + self.post_cond_layers += [ + DBlock(in_channels * 2, in_channels * 2, 1), + DBlock(in_channels * 2, in_channels * 2, 1), + nn.AdaptiveAvgPool1d(1), + nn.Conv1d(in_channels * 2, 1, kernel_size=1), + ] + + def forward(self, inputs, conditions): + batch_size = inputs.size()[0] + outputs = inputs.view(batch_size, self.in_channels, -1) + for layer in self.pre_cond_layers: + outputs = layer(outputs) + outputs = self.cond_block(outputs, conditions) + for layer in self.post_cond_layers: + outputs = layer(outputs) + + return outputs + + +class UnconditionalDiscriminator(nn.Module): + def __init__(self, + in_channels, + base_channels=64, + downsample_factors=(8, 4), + out_channels=(128, 256)): + super(UnconditionalDiscriminator, self).__init__() + + self.downsample_factors = downsample_factors + self.in_channels = in_channels + self.downsample_factors = downsample_factors + self.out_channels = out_channels + + self.layers = nn.ModuleList() + self.layers += [DBlock(self.in_channels, base_channels, 1)] + in_channels = base_channels + for (i, factor) in enumerate(downsample_factors): + self.layers.append(DBlock(in_channels, out_channels[i], factor)) + in_channels *= 2 + self.layers += [ + DBlock(in_channels, in_channels, 1), + DBlock(in_channels, in_channels, 1), + nn.AdaptiveAvgPool1d(1), + nn.Conv1d(in_channels, 1, kernel_size=1), + ] + + def forward(self, inputs): + batch_size = inputs.size()[0] + outputs = inputs.view(batch_size, self.in_channels, -1) + for layer in self.layers: + outputs = layer(outputs) + return outputs + + +class RandomWindowDiscriminator(nn.Module): + """Random Window Discriminator as described in + http://arxiv.org/abs/1909.11646""" + def __init__(self, + cond_channels, + hop_length, + uncond_disc_donwsample_factors=(8, 4), + cond_disc_downsample_factors=((8, 4, 2, 2, 2), (8, 4, 2, 2), + (8, 4, 2), (8, 4), (4, 2, 2)), + cond_disc_out_channels=((128, 128, 256, 256), (128, 256, 256), + (128, 256), (256, ), (128, 256)), + window_sizes=(512, 1024, 2048, 4096, 8192)): + + super(RandomWindowDiscriminator, self).__init__() + self.cond_channels = cond_channels + self.window_sizes = window_sizes + self.hop_length = hop_length + self.base_window_size = self.hop_length * 2 + self.ks = [ws // self.base_window_size for ws in window_sizes] + + # check arguments + assert len(cond_disc_downsample_factors) == len( + cond_disc_out_channels) == len(window_sizes) + for ws in window_sizes: + assert ws % hop_length == 0 + + for idx, cf in enumerate(cond_disc_downsample_factors): + assert np.prod(cf) == hop_length // self.ks[idx] + + # define layers + self.unconditional_discriminators = nn.ModuleList([]) + for k in self.ks: + layer = UnconditionalDiscriminator( + in_channels=k, + base_channels=64, + downsample_factors=uncond_disc_donwsample_factors) + self.unconditional_discriminators.append(layer) + + self.conditional_discriminators = nn.ModuleList([]) + for idx, k in enumerate(self.ks): + layer = ConditionalDiscriminator( + in_channels=k, + cond_channels=cond_channels, + downsample_factors=cond_disc_downsample_factors[idx], + out_channels=cond_disc_out_channels[idx]) + self.conditional_discriminators.append(layer) + + def forward(self, x, c): + scores = [] + feats = [] + # unconditional pass + for (window_size, layer) in zip(self.window_sizes, + self.unconditional_discriminators): + index = np.random.randint(x.shape[-1] - window_size) + + score = layer(x[:, :, index:index + window_size]) + scores.append(score) + + # conditional pass + for (window_size, layer) in zip(self.window_sizes, + self.conditional_discriminators): + frame_size = window_size // self.hop_length + lc_index = np.random.randint(c.shape[-1] - frame_size) + sample_index = lc_index * self.hop_length + x_sub = x[:, :, + sample_index:(lc_index + frame_size) * self.hop_length] + c_sub = c[:, :, lc_index:lc_index + frame_size] + + score = layer(x_sub, c_sub) + scores.append(score) + return scores, feats diff --git a/vocoder/notebooks/Untitled.ipynb b/vocoder/notebooks/Untitled.ipynb new file mode 100644 index 00000000..ce49d6fa --- /dev/null +++ b/vocoder/notebooks/Untitled.ipynb @@ -0,0 +1,678 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "#function example with several unknowns (variables) for optimization\n", + "#Gerald Schuller, Nov. 2016\n", + "import numpy as np\n", + "\n", + "def functionexamp(x):\n", + " #x: array with 2 variables\n", + " \n", + " y=np.sin(x[0])+np.cos(x[1])\n", + " return y" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " fun: -1.9999999999888387\n", + " jac: array([4.7236681e-06, 0.0000000e+00])\n", + " message: 'Optimization terminated successfully.'\n", + " nfev: 12\n", + " nit: 2\n", + " njev: 3\n", + " status: 0\n", + " success: True\n", + " x: array([-1.5707916 , -3.14159265])\n" + ] + } + ], + "source": [ + "#Optimization example, see also:\n", + "#https://docs.scipy.org/doc/scipy-0.18.1/reference/optimize.html\n", + "#Gerald Schuller, Nov. 2016\n", + "#run it with \"python optimizationExample.py\" in a termina shell\n", + "#or type \"ipython\" in a termina shell and copy lines below:\n", + "\n", + "import numpy as np\n", + "import scipy.optimize as optimize\n", + "\n", + "#Example for 2 unknowns, args: function-name, starting point, method:\n", + "xmin = optimize.minimize(functionexamp, [-1.0, -3.0], method='CG')\n", + "print(xmin)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "function [p,passedge] = opt_filter(filtorder,N)\n", + "\n", + "% opt_filter Create Lowpass Prototype Filter for the Pseudo-QMF \n", + "% Filter Bank with N Subbands\n", + "%\n", + "% Adapted from the paper by C. D. Creusere and S. K. Mitra, titled \n", + "% \"A simple method for designing high-quality prototype filters for \n", + "% M-band pseudo-QMF banks,\" IEEE Trans. Signal Processing,vol. 43, \n", + "% pp. 1005-1007, Apr. 1995 and the book by S. K. Mitra titled \"\n", + "% Digital Signal Processing: A Computer-Based Approach, McGraw-Hill, 2001\n", + "%\n", + "% Arguments:\n", + "% filtorder Filter order (i.e., filter length - 1)\n", + "% N Number of subbands\n", + "\n", + "stopedge = 1/N; % Stopband edge fixed at (1/N)pi\n", + "passedge = 1/(4*N); % Start value for passband edge\n", + "tol = 0.000001; % Tolerance\n", + "step = 0.1*passedge; % Step size for searching the passband edge\n", + "way = -1; % Search direction, increase or reduce the passband edge\n", + "tcost = 0; % Current error calculated with the cost function\n", + "pcost = 10; % Previous error calculated with the cost function\n", + "flag = 0; % Set to 1 to stop the search\n", + "\n", + "while flag == 0\n", + " \n", + "% Design the lowpass filter using Parks-McClellan algorithm\n", + " \n", + " p = remez(filtorder,[0,passedge,stopedge,1],[1,1,0,0],[5,1]);\n", + " \n", + "% Calculates the cost function according to Eq. (2.36)\n", + "\n", + " P = fft(p,4096);\n", + " OptRange = floor(2048/N); % 0 to pi/N\n", + " phi = zeros(OptRange,1); % Initialize to zeros\n", + "\n", + "% Compute the flatness in the range from 0 to pi/N\n", + "\n", + "\tfor k = 1:OptRange\n", + " phi(k) = abs(P(OptRange-k+2))^2 + abs(P(k))^2;\n", + "\tend\n", + "\ttcost = max(abs(phi - ones(max(size(phi)),1)));\n", + " \t\n", + "\tif tcost > pcost % If search in wrong direction\n", + "\t\tstep = step/2; % Reduce step size by half \n", + "\t\tway = -way; % Change the search direction \n", + "\tend\n", + "\t\n", + "\tif abs(pcost - tcost) < tol % If improvement is below tol \n", + "\t\tflag = 1; % Stop the search \n", + "\tend\n", + "\t\n", + "\tpcost = tcost;\n", + "\tpassedge = passedge + way*step; % Adjust the passband edge\n", + " \n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "sig.remez" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0125" + ] + }, + "execution_count": 101, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 / 4. / 20.0" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Band edges should be less than 1/2 the sampling frequency", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremez\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m64\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m16.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/miniconda3/lib/python3.7/site-packages/scipy/signal/fir_filter_design.py\u001b[0m in \u001b[0;36mremez\u001b[0;34m(numtaps, bands, desired, weight, Hz, type, maxiter, grid_density, fs)\u001b[0m\n\u001b[1;32m 854\u001b[0m \u001b[0mbands\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbands\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 855\u001b[0m return sigtools._remez(numtaps, bands, desired, weight, tnum, fs,\n\u001b[0;32m--> 856\u001b[0;31m maxiter, grid_density)\n\u001b[0m\u001b[1;32m 857\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 858\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Band edges should be less than 1/2 the sampling frequency" + ] + } + ], + "source": [ + "p = sig.remez(65, [0, 1/16.0, 1/4.0, 1], [1, 0], [5, 1])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "def create_pqmf_filter(filter_len=64, N=4):\n", + " stop_edge = 1 / N\n", + " pass_edge = 1 / (4 * N)\n", + " tol = 1e-8\n", + " cutoff = 0.1 * pass_edge\n", + " cost = 0\n", + " cost_prev = float('inf')\n", + " \n", + " p = sig.remez(filter_len, [0, pass_edge, stop_edge, 1], [1, 1, 0, 0], [5, 1])\n", + " \n", + " P = sig.freqz(p, workN=2048)\n", + " opt_range = 2048 // N\n", + " phi = np.zeros(opt_range)\n", + " \n", + " H = np.abs(P)\n", + " phi = H[opt_range + 2] \n", + " for i in range(opt_range):\n", + " phi[i] = abs(P(opt_range - i + 2)) ** 2 + abs(P[i]) ** 2" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy as sp\n", + "import scipy.signal as sig\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "\n", + "def optimfuncQMF(x):\n", + " \"\"\"Optimization function for a PQMF Filterbank\n", + " x: coefficients to optimize (first half of prototype h because of symmetry)\n", + " err: resulting total error\n", + " \"\"\"\n", + " K = ntaps * N \n", + " h = np.append(x, np.flipud(x))\n", + " cutoff = 0.15\n", + " \n", + "# breakpoint()\n", + " f, H_im = sig.freqz(h, worN=K)\n", + " H = np.abs(H_im) #only keeping the real part\n", + " \n", + " posfreq = np.square(H[0:K//N])\n", + " \n", + " #Negative frequencies are symmetric around 0:\n", + " negfreq = np.flipud(np.square(H[0:K//N]))\n", + " \n", + " #Sum of magnitude squared frequency responses should be closed to unity (or N)\n", + " unitycond = np.sum(np.abs(posfreq + negfreq - 2*(N*N)*np.ones(K//N)))/K\n", + " \n", + " #plt.plot(posfreq+negfreq)\n", + " \n", + " #High attenuation after the next subband:\n", + " att = np.sum(np.abs(H[int(cutoff*K//N):]))/K\n", + " \n", + " #Total (weighted) error:\n", + " err = unitycond + 100*att\n", + " return err" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(32,)" + ] + }, + "execution_count": 85, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "xmin.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8.684549400499243\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import scipy.optimize as opt\n", + "import scipy.signal as sig\n", + "\n", + "ntaps = 64\n", + "N = 4\n", + "\n", + "#optimize for 16 filter coefficients:\n", + "xmin = opt.minimize(optimfuncQMF, ntaps*np.ones(ntaps), method='SLSQP', tol=1e-8)\n", + "xmin = xmin[\"x\"]\n", + "\n", + "err = optimfuncQMF(xmin)\n", + "print(err)\n", + "\n", + "#Restore symmetric upper half of window:\n", + "h = np.concatenate((xmin, np.flipud(xmin)))\n", + "plt.plot(h)\n", + "plt.title('Resulting PQMF Window Function')\n", + "plt.xlabel('Sample')\n", + "plt.ylabel('Value')\n", + "plt.show()\n", + "\n", + "f, H = sig.freqz(h)\n", + "plt.plot(f, 20*np.log10(np.abs(H)))\n", + "plt.title('Resulting PQMF Magnitude Response')\n", + "plt.xlabel('Normalized Frequency')\n", + "plt.ylabel('dB')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "N = 4\n", + "f, H_im = sig.freqz(h)\n", + "posfreq = np.square(H[0:512//N])\n", + "negfreq = np.flipud(np.square(H[0:512//N]))\n", + "plt.plot((np.abs(posfreq) + np.abs(negfreq)))\n", + "plt.xlabel('Frequency (512 is Nyquist)')\n", + "plt.ylabel('Magnitude')\n", + "plt.title('Unity Condition, Sum of Squared Magnitude of 2 Neighboring Subbands')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "b = sig.firwin(80, 0.5, window=('kaiser', 8))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "f, H_im = sig.freqz(h)\n", + "posfreq = np.square(H[0:512//N])\n", + "negfreq = np.flipud(np.square(H[0:512//N]))\n", + "plt.plot((np.abs(posfreq) + np.abs(negfreq)))\n", + "plt.xlabel('Frequency (512 is Nyquist)')\n", + "plt.ylabel('Magnitude')\n", + "plt.title('Unity Condition, Sum of Squared Magnitude of 2 Neighboring Subbands')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(63,)" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cutoff = 0.15\n", + "beta = 9\n", + "ntaps = 63\n", + "N = 4\n", + "\n", + "b = sig.firwin(ntaps, cutoff, window=('kaiser', beta))\n", + "w, h = sig.freqz(b)\n", + "\n", + "plt.plot(b)\n", + "plt.title('Resulting PQMF Window Function')\n", + "plt.xlabel('Sample')\n", + "plt.ylabel('Value')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "fig, ax1 = plt.subplots()\n", + "ax1.set_title('Digital filter frequency response')\n", + "\n", + "ax1.plot(w / (2 * np.pi), 20 * np.log10(abs(h)), 'b')\n", + "ax1.set_ylabel('Amplitude [dB]', color='b')\n", + "ax1.set_xlabel('Frequency [rad/sample]')\n", + "\n", + "ax2 = ax1.twinx()\n", + "angles = np.unwrap(np.angle(h))\n", + "ax2.plot(w / (2 * np.pi), angles, 'g')\n", + "ax2.set_ylabel('Angle (radians)', color='g')\n", + "ax2.grid()\n", + "ax2.axis('tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(63,)" + ] + }, + "execution_count": 105, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "def optimfuncQMF(x):\n", + " \"\"\"Optimization function for a PQMF Filterbank\n", + " x: coefficients to optimize (first half of prototype h because of symmetry)\n", + " err: resulting total error\n", + " \"\"\"\n", + " N = 2 #4 subbands\n", + " cutoff = 1.5 #1.5\n", + " h = np.append(x, np.flipud(x))\n", + " f, H_im = sig.freqz(h)\n", + " H = np.abs(H_im) #only keeping the real part\n", + " \n", + " posfreq = np.square(H[0:512//N])\n", + " \n", + " #Negative frequencies are symmetric around 0:\n", + " negfreq = np.flipud(np.square(H[0:512//N]))\n", + " \n", + " #Sum of magnitude squared frequency responses should be closed to unity (or N)\n", + " unitycond = np.sum(np.abs(posfreq + negfreq - 2*(N*N)*np.ones(512//N)))//512\n", + " \n", + " #plt.plot(posfreq+negfreq)\n", + " \n", + " #High attenuation after the next subband:\n", + " att = np.sum(np.abs(H[int(cutoff*512//N):]))//512\n", + " \n", + " #Total (weighted) error:\n", + " err = unitycond + 100*att\n", + " return err" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.0\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "err = optimfuncQMF(b)\n", + "print(err)\n", + "\n", + "#Restore symmetric upper half of window:\n", + "h = np.concatenate((xmin, np.flipud(xmin)))\n", + "plt.plot(h)\n", + "plt.title('Resulting PQMF Window Function')\n", + "plt.xlabel('Sample')\n", + "plt.ylabel('Value')\n", + "plt.show()\n", + "\n", + "f, H = sig.freqz(h)\n", + "plt.plot(f, 20*np.log10(np.abs(H)))\n", + "plt.title('Resulting PQMF Magnitude Response')\n", + "plt.xlabel('Normalized Frequency')\n", + "plt.ylabel('dB')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.4 64-bit ('base': conda)", + "language": "python", + "name": "python37464bitbaseconda58faf23c4b5f4fef93406f29a1005f35" + }, + "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.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/vocoder/notebooks/Untitled1.ipynb b/vocoder/notebooks/Untitled1.ipynb new file mode 100644 index 00000000..7fec5150 --- /dev/null +++ b/vocoder/notebooks/Untitled1.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/vocoder/pqmf_output.wav b/vocoder/pqmf_output.wav new file mode 100644 index 0000000000000000000000000000000000000000..8a77747b00198a4adfd6c398998517df5b4bdb8d GIT binary patch literal 83812 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 z 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 literal 0 HcmV?d00001 diff --git a/vocoder/tests/__init__.py b/vocoder/tests/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/vocoder/tests/__init__.py @@ -0,0 +1 @@ + diff --git a/vocoder/tests/test_config.json b/vocoder/tests/test_config.json new file mode 100644 index 00000000..08acc48c --- /dev/null +++ b/vocoder/tests/test_config.json @@ -0,0 +1,24 @@ +{ + "audio":{ + "num_mels": 80, // size of the mel spec frame. + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "sample_rate": 22050, // wav sample-rate. If different than the original data, it is resampled. + "frame_length_ms": null, // stft window length in ms. + "frame_shift_ms": null, // stft window hop-lengh in ms. + "hop_length": 256, + "win_length": 1024, + "preemphasis": 0.97, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "min_level_db": -100, // normalization range + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 30,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + "signal_norm": true, // normalize the spec values in range [0, 1] + "symmetric_norm": true, // move normalization to range [-1, 1] + "clip_norm": true, // clip normalized values into the range. + "max_norm": 4, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "mel_fmin": 0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000, // maximum freq level for mel-spec. Tune for dataset!! + "do_trim_silence": false + } +} + diff --git a/vocoder/tests/test_datasets.py b/vocoder/tests/test_datasets.py new file mode 100644 index 00000000..3d6280f0 --- /dev/null +++ b/vocoder/tests/test_datasets.py @@ -0,0 +1,95 @@ +import os +import numpy as np +from torch.utils.data import DataLoader + +from TTS.vocoder.datasets.gan_dataset import GANDataset +from TTS.vocoder.datasets.preprocess import load_wav_data +from TTS.utils.audio import AudioProcessor +from TTS.utils.io import load_config + + +file_path = os.path.dirname(os.path.realpath(__file__)) +OUTPATH = os.path.join(file_path, "../../tests/outputs/loader_tests/") +os.makedirs(OUTPATH, exist_ok=True) + +C = load_config(os.path.join(file_path, 'test_config.json')) + +test_data_path = os.path.join(file_path, "../../tests/data/ljspeech/") +ok_ljspeech = os.path.exists(test_data_path) + + + +def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, use_noise_augment, use_cache, num_workers): + ''' run dataloader with given parameters and check conditions ''' + ap = AudioProcessor(**C.audio) + eval_items, train_items = load_wav_data(test_data_path, 10) + dataset = GANDataset(ap, + train_items, + seq_len=seq_len, + hop_len=hop_len, + pad_short=2000, + conv_pad=conv_pad, + return_segments=return_segments, + use_noise_augment=use_noise_augment, + use_cache=use_cache) + loader = DataLoader(dataset=dataset, + batch_size=batch_size, + shuffle=True, + num_workers=num_workers, + pin_memory=True, + drop_last=True) + + max_iter = 10 + count_iter = 0 + + # return random segments or return the whole audio + if return_segments: + for item1, item2 in loader: + feat1, wav1 = item1 + feat2, wav2 = item2 + expected_feat_shape = (batch_size, ap.num_mels, seq_len // hop_len + conv_pad * 2) + + # check shapes + assert np.all(feat1.shape == expected_feat_shape), f" [!] {feat1.shape} vs {expected_feat_shape}" + assert (feat1.shape[2] - conv_pad * 2) * hop_len == wav1.shape[2] + + # check feature vs audio match + if not use_noise_augment: + for idx in range(batch_size): + audio = wav1[idx].squeeze() + feat = feat1[idx] + mel = ap.melspectrogram(audio) + # the first 2 and the last frame is skipped due to the padding + # applied in spec. computation. + assert (feat - mel[:, :feat1.shape[-1]])[:, 2:-1].sum() == 0, f' [!] {(feat - mel[:, :feat1.shape[-1]])[:, 2:-1].sum()}' + + count_iter += 1 + # if count_iter == max_iter: + # break + else: + for item in loader: + feat, wav = item + expected_feat_shape = (batch_size, ap.num_mels, (wav.shape[-1] // hop_len) + (conv_pad * 2)) + assert np.all(feat.shape == expected_feat_shape), f" [!] {feat.shape} vs {expected_feat_shape}" + assert (feat.shape[2] - conv_pad * 2) * hop_len == wav.shape[2] + count_iter += 1 + if count_iter == max_iter: + break + + +def test_parametrized_gan_dataset(): + ''' test dataloader with different parameters ''' + params = [ + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 4], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, True, 0], + [1, C.audio['hop_length'], C.audio['hop_length'], 0, True, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 2, True, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, False, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, False, False, 0], + ] + for param in params: + print(param) + gan_dataset_case(*param) diff --git a/vocoder/tests/test_losses.py b/vocoder/tests/test_losses.py new file mode 100644 index 00000000..83314832 --- /dev/null +++ b/vocoder/tests/test_losses.py @@ -0,0 +1,62 @@ +import os +import unittest +import torch + +from TTS.vocoder.layers.losses import TorchSTFT, STFTLoss, MultiScaleSTFTLoss + +from TTS.tests import get_tests_path, get_tests_input_path, get_tests_output_path +from TTS.utils.audio import AudioProcessor +from TTS.utils.io import load_config + +TESTS_PATH = get_tests_path() + +OUT_PATH = os.path.join(get_tests_output_path(), "audio_tests") +os.makedirs(OUT_PATH, exist_ok=True) + +WAV_FILE = os.path.join(get_tests_input_path(), "example_1.wav") + +file_path = os.path.dirname(os.path.realpath(__file__)) +C = load_config(os.path.join(file_path, 'test_config.json')) +ap = AudioProcessor(**C.audio) + + +def test_torch_stft(): + torch_stft = TorchSTFT(ap.n_fft, ap.hop_length, ap.win_length) + # librosa stft + wav = ap.load_wav(WAV_FILE) + M_librosa = abs(ap._stft(wav)) + # torch stft + wav = torch.from_numpy(wav[None, :]).float() + M_torch = torch_stft(wav) + # check the difference b/w librosa and torch outputs + assert (M_librosa - M_torch[0].data.numpy()).max() < 1e-5 + + +def test_stft_loss(): + stft_loss = STFTLoss(ap.n_fft, ap.hop_length, ap.win_length) + wav = ap.load_wav(WAV_FILE) + wav = torch.from_numpy(wav[None, :]).float() + loss_m, loss_sc = stft_loss(wav, wav) + assert loss_m + loss_sc == 0 + loss_m, loss_sc = stft_loss(wav, torch.rand_like(wav)) + assert loss_sc < 1.0 + assert loss_m + loss_sc > 0 + + +def test_multiscale_stft_loss(): + stft_loss = MultiScaleSTFTLoss([ap.n_fft//2, ap.n_fft, ap.n_fft*2], + [ap.hop_length // 2, ap.hop_length, ap.hop_length * 2], + [ap.win_length // 2, ap.win_length, ap.win_length * 2]) + wav = ap.load_wav(WAV_FILE) + wav = torch.from_numpy(wav[None, :]).float() + loss_m, loss_sc = stft_loss(wav, wav) + assert loss_m + loss_sc == 0 + loss_m, loss_sc = stft_loss(wav, torch.rand_like(wav)) + assert loss_sc < 1.0 + assert loss_m + loss_sc > 0 + + + + + + diff --git a/vocoder/tests/test_melgan_discriminator.py b/vocoder/tests/test_melgan_discriminator.py new file mode 100644 index 00000000..83acec8f --- /dev/null +++ b/vocoder/tests/test_melgan_discriminator.py @@ -0,0 +1,26 @@ +import numpy as np +import torch + +from TTS.vocoder.models.melgan_discriminator import MelganDiscriminator +from TTS.vocoder.models.melgan_multiscale_discriminator import MelganMultiscaleDiscriminator + + +def test_melgan_discriminator(): + model = MelganDiscriminator() + print(model) + dummy_input = torch.rand((4, 1, 256 * 10)) + output, _ = model(dummy_input) + assert np.all(output.shape == (4, 1, 10)) + + +def test_melgan_multi_scale_discriminator(): + model = MelganMultiscaleDiscriminator() + print(model) + dummy_input = torch.rand((4, 1, 256 * 16)) + scores, feats = model(dummy_input) + assert len(scores) == 3 + assert len(scores) == len(feats) + assert np.all(scores[0].shape == (4, 1, 16)) + assert np.all(feats[0][0].shape == (4, 16, 4096)) + assert np.all(feats[0][1].shape == (4, 64, 1024)) + assert np.all(feats[0][2].shape == (4, 256, 256)) diff --git a/vocoder/tests/test_melgan_generator.py b/vocoder/tests/test_melgan_generator.py new file mode 100644 index 00000000..e9c4ad60 --- /dev/null +++ b/vocoder/tests/test_melgan_generator.py @@ -0,0 +1,15 @@ +import numpy as np +import unittest +import torch + +from TTS.vocoder.models.melgan_generator import MelganGenerator + +def test_melgan_generator(): + model = MelganGenerator() + print(model) + dummy_input = torch.rand((4, 80, 64)) + output = model(dummy_input) + assert np.all(output.shape == (4, 1, 64 * 256)) + output = model.inference(dummy_input) + assert np.all(output.shape == (4, 1, (64 + 4) * 256)) + diff --git a/vocoder/tests/test_pqmf.py b/vocoder/tests/test_pqmf.py new file mode 100644 index 00000000..8444fc5a --- /dev/null +++ b/vocoder/tests/test_pqmf.py @@ -0,0 +1,33 @@ +import os +import torch +import unittest + +import numpy as np +import soundfile as sf +from librosa.core import load + +from TTS.tests import get_tests_path, get_tests_input_path, get_tests_output_path +from TTS.utils.audio import AudioProcessor +from TTS.utils.io import load_config +from TTS.vocoder.layers.pqmf import PQMF +from TTS.vocoder.layers.pqmf2 import PQMF as PQMF2 + + +TESTS_PATH = get_tests_path() +WAV_FILE = os.path.join(get_tests_input_path(), "example_1.wav") + + +def test_pqmf(): + w, sr = load(WAV_FILE) + + layer = PQMF(N=4, taps=62, cutoff=0.15, beta=9.0) + w, sr = load(WAV_FILE) + w2 = torch.from_numpy(w[None, None, :]) + b2 = layer.analysis(w2) + w2_ = layer.synthesis(b2) + + print(w2_.max()) + print(w2_.min()) + print(w2_.mean()) + sf.write('pqmf_output.wav', w2_.flatten().detach(), sr) + diff --git a/vocoder/tests/test_rwd.py b/vocoder/tests/test_rwd.py new file mode 100644 index 00000000..424d3b49 --- /dev/null +++ b/vocoder/tests/test_rwd.py @@ -0,0 +1,21 @@ +import torch +import numpy as np + +from TTS.vocoder.models.random_window_discriminator import RandomWindowDiscriminator + + +def test_rwd(): + layer = RandomWindowDiscriminator(cond_channels=80, + window_sizes=(512, 1024, 2048, 4096, + 8192), + cond_disc_downsample_factors=[ + (8, 4, 2, 2, 2), (8, 4, 2, 2), + (8, 4, 2), (8, 4), (4, 2, 2) + ], + hop_length=256) + x = torch.rand([4, 1, 22050]) + c = torch.rand([4, 80, 22050 // 256]) + + scores, _ = layer(x, c) + assert len(scores) == 10 + assert np.all(scores[0].shape == (4, 1, 1)) diff --git a/vocoder/train.py b/vocoder/train.py new file mode 100644 index 00000000..b0b4833a --- /dev/null +++ b/vocoder/train.py @@ -0,0 +1,585 @@ +import argparse +import glob +import os +import sys +import time +import traceback + +import torch +from torch.utils.data import DataLoader + +from inspect import signature + +from TTS.utils.audio import AudioProcessor +from TTS.utils.generic_utils import (KeepAverage, count_parameters, + create_experiment_folder, get_git_branch, + remove_experiment_folder, set_init_dict) +from TTS.utils.io import copy_config_file, load_config +from TTS.utils.radam import RAdam +from TTS.utils.tensorboard_logger import TensorboardLogger +from TTS.utils.training import NoamLR +from TTS.vocoder.datasets.gan_dataset import GANDataset +from TTS.vocoder.datasets.preprocess import load_wav_data +# from distribute import (DistributedSampler, apply_gradient_allreduce, +# init_distributed, reduce_tensor) +from TTS.vocoder.layers.losses import DiscriminatorLoss, GeneratorLoss +from TTS.vocoder.utils.io import save_checkpoint, save_best_model +from TTS.vocoder.utils.console_logger import ConsoleLogger +from TTS.vocoder.utils.generic_utils import (check_config, plot_results, + setup_discriminator, + setup_generator) + +torch.backends.cudnn.enabled = True +torch.backends.cudnn.benchmark = True +torch.manual_seed(54321) +use_cuda = torch.cuda.is_available() +num_gpus = torch.cuda.device_count() +print(" > Using CUDA: ", use_cuda) +print(" > Number of GPUs: ", num_gpus) + + +def setup_loader(ap, is_val=False, verbose=False): + if is_val and not c.run_eval: + loader = None + else: + dataset = GANDataset(ap=ap, + items=eval_data if is_val else train_data, + seq_len=c.seq_len, + hop_len=ap.hop_length, + pad_short=c.pad_short, + conv_pad=c.conv_pad, + is_training=not is_val, + return_segments=False if is_val else True, + use_noise_augment=c.use_noise_augment, + use_cache=c.use_cache, + verbose=verbose) + # sampler = DistributedSampler(dataset) if num_gpus > 1 else None + loader = DataLoader(dataset, + batch_size=1 if is_val else c.batch_size, + shuffle=False, + drop_last=False, + sampler=None, + num_workers=c.num_val_loader_workers + if is_val else c.num_loader_workers, + pin_memory=False) + return loader + + +def format_data(data): + if isinstance(data[0], list): + # setup input data + c_G, x_G = data[0] + c_D, x_D = data[1] + + # dispatch data to GPU + if use_cuda: + c_G = c_G.cuda(non_blocking=True) + x_G = x_G.cuda(non_blocking=True) + c_D = c_D.cuda(non_blocking=True) + x_D = x_D.cuda(non_blocking=True) + + return c_G, x_G, c_D, x_D + + # return a whole audio segment + c, x = data + if use_cuda: + c = c.cuda(non_blocking=True) + x = x.cuda(non_blocking=True) + return c, x + + +def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, + scheduler_G, scheduler_D, ap, global_step, epoch): + data_loader = setup_loader(ap, is_val=False, verbose=(epoch == 0)) + model_G.train() + model_D.train() + epoch_time = 0 + keep_avg = KeepAverage() + if use_cuda: + batch_n_iter = int( + len(data_loader.dataset) / (c.batch_size * num_gpus)) + else: + batch_n_iter = int(len(data_loader.dataset) / c.batch_size) + end_time = time.time() + c_logger.print_train_start() + for num_iter, data in enumerate(data_loader): + start_time = time.time() + + # format data + c_G, y_G, c_D, y_D = format_data(data) + loader_time = time.time() - end_time + + global_step += 1 + + # get current learning rates + current_lr_G = list(optimizer_G.param_groups)[0]['lr'] + current_lr_D = list(optimizer_D.param_groups)[0]['lr'] + + ############################## + # GENERATOR + ############################## + + # generator pass + optimizer_G.zero_grad() + y_hat = model_G(c_G) + + in_real_D = y_hat + in_fake_D = y_G + + # PQMF formatting + if y_hat.shape[1] > 1: + in_real_D = y_G + in_fake_D = model_G.pqmf_synthesis(y_hat) + y_G = model_G.pqmf_analysis(y_G) + y_hat = y_hat.view(-1, 1, y_hat.shape[2]) + y_G = y_G.view(-1, 1, y_G.shape[2]) + + if global_step > c.steps_to_start_discriminator: + + # run D with or without cond. features + if len(signature(model_D).parameters) == 2: + D_out_fake = model_D(in_fake_D, c_G) + else: + D_out_fake = model_D(in_fake_D) + D_out_real = None + + if c.use_feat_match_loss: + with torch.no_grad(): + D_out_real = model_D(in_real_D) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + scores_real, feats_real = None, None + else: + scores_real, feats_real = D_out_real + else: + scores_fake = D_out_fake + scores_real = D_out_real + else: + scores_fake, feats_fake, feats_real = None, None, None + + # compute losses + loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, + feats_real) + loss_G = loss_G_dict['G_loss'] + + # optimizer generator + loss_G.backward() + if c.gen_clip_grad > 0: + torch.nn.utils.clip_grad_norm_(model_G.parameters(), + c.gen_clip_grad) + optimizer_G.step() + + # setup lr + if c.noam_schedule: + scheduler_G.step() + + loss_dict = dict() + for key, value in loss_G_dict.items(): + loss_dict[key] = value.item() + + ############################## + # DISCRIMINATOR + ############################## + if global_step > c.steps_to_start_discriminator: + # discriminator pass + with torch.no_grad(): + y_hat = model_G(c_D) + + # PQMF formatting + if y_hat.shape[1] > 1: + y_hat = model_G.pqmf_synthesis(y_hat) + + optimizer_D.zero_grad() + + # run D with or without cond. features + if len(signature(model_D).parameters) == 2: + D_out_fake = model_D(y_hat.detach(), c_D) + D_out_real = model_D(y_D, c_D) + else: + D_out_fake = model_D(y_hat.detach()) + D_out_real = model_D(y_D) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + scores_real, feats_real = None, None + else: + scores_real, feats_real = D_out_real + else: + scores_fake = D_out_fake + scores_real = D_out_real + + # compute losses + loss_D_dict = criterion_D(scores_fake, scores_real) + loss_D = loss_D_dict['D_loss'] + + # optimizer discriminator + loss_D.backward() + if c.disc_clip_grad > 0: + torch.nn.utils.clip_grad_norm_(model_D.parameters(), + c.disc_clip_grad) + optimizer_D.step() + + # setup lr + if c.noam_schedule: + scheduler_D.step() + + for key, value in loss_D_dict.items(): + loss_dict[key] = value.item() + + step_time = time.time() - start_time + epoch_time += step_time + + # update avg stats + update_train_values = dict() + for key, value in loss_dict.items(): + update_train_values['avg_' + key] = value + update_train_values['avg_loader_time'] = loader_time + update_train_values['avg_step_time'] = step_time + keep_avg.update_values(update_train_values) + + # print training stats + if global_step % c.print_step == 0: + c_logger.print_train_step(batch_n_iter, num_iter, global_step, + step_time, loader_time, current_lr_G, + loss_dict, keep_avg.avg_values) + + # plot step stats + if global_step % 10 == 0: + iter_stats = { + "lr_G": current_lr_G, + "lr_D": current_lr_D, + "step_time": step_time + } + iter_stats.update(loss_dict) + tb_logger.tb_train_iter_stats(global_step, iter_stats) + + # save checkpoint + if global_step % c.save_step == 0: + if c.checkpoint: + # save model + save_checkpoint(model_G, + optimizer_G, + model_D, + optimizer_D, + global_step, + epoch, + OUT_PATH, + model_losses=loss_dict) + + # compute spectrograms + figures = plot_results(in_fake_D, in_real_D, ap, global_step, + 'train') + tb_logger.tb_train_figures(global_step, figures) + + # Sample audio + sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() + tb_logger.tb_train_audios(global_step, + {'train/audio': sample_voice}, + c.audio["sample_rate"]) + end_time = time.time() + + # print epoch stats + c_logger.print_train_epoch_end(global_step, epoch, epoch_time, keep_avg) + + # Plot Training Epoch Stats + epoch_stats = {"epoch_time": epoch_time} + epoch_stats.update(keep_avg.avg_values) + tb_logger.tb_train_epoch_stats(global_step, epoch_stats) + # TODO: plot model stats + # if c.tb_model_param_stats: + # tb_logger.tb_model_weights(model, global_step) + return keep_avg.avg_values, global_step + + +@torch.no_grad() +def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): + data_loader = setup_loader(ap, is_val=True, verbose=(epoch == 0)) + model_G.eval() + model_D.eval() + epoch_time = 0 + keep_avg = KeepAverage() + end_time = time.time() + c_logger.print_eval_start() + for num_iter, data in enumerate(data_loader): + start_time = time.time() + + # format data + c_G, y_G = format_data(data) + loader_time = time.time() - end_time + + global_step += 1 + + ############################## + # GENERATOR + ############################## + + # generator pass + y_hat = model_G(c_G) + + in_real_D = y_hat + in_fake_D = y_G + + # PQMF formatting + if y_hat.shape[1] > 1: + in_real_D = y_G + in_fake_D = model_G.pqmf_synthesis(y_hat) + y_G = model_G.pqmf_analysis(y_G) + y_hat = y_hat.view(-1, 1, y_hat.shape[2]) + y_G = y_G.view(-1, 1, y_G.shape[2]) + + D_out_fake = model_D(in_fake_D) + D_out_real = None + if c.use_feat_match_loss: + with torch.no_grad(): + D_out_real = model_D(in_real_D) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + feats_real = None + else: + _, feats_real = D_out_real + else: + scores_fake = D_out_fake + + # compute losses + loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, + feats_real) + + loss_dict = dict() + for key, value in loss_G_dict.items(): + loss_dict[key] = value.item() + + step_time = time.time() - start_time + epoch_time += step_time + + # update avg stats + update_eval_values = dict() + for key, value in loss_G_dict.items(): + update_eval_values['avg_' + key] = value.item() + update_eval_values['avg_loader_time'] = loader_time + update_eval_values['avg_step_time'] = step_time + keep_avg.update_values(update_eval_values) + + # print eval stats + if c.print_eval: + c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) + + # compute spectrograms + figures = plot_results(y_hat, y_G, ap, global_step, 'eval') + tb_logger.tb_eval_figures(global_step, figures) + + # Sample audio + sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() + tb_logger.tb_eval_audios(global_step, {'eval/audio': sample_voice}, + c.audio["sample_rate"]) + + # synthesize a full voice + data_loader.return_segments = False + + return keep_avg.avg_values + + +# FIXME: move args definition/parsing inside of main? +def main(args): # pylint: disable=redefined-outer-name + # pylint: disable=global-variable-undefined + global train_data, eval_data + eval_data, train_data = load_wav_data(c.data_path, c.eval_split_size) + + # setup audio processor + ap = AudioProcessor(**c.audio) + # DISTRUBUTED + # if num_gpus > 1: + # init_distributed(args.rank, num_gpus, args.group_id, + # c.distributed["backend"], c.distributed["url"]) + + # setup models + model_gen = setup_generator(c) + model_disc = setup_discriminator(c) + + # setup optimizers + optimizer_gen = RAdam(model_gen.parameters(), lr=c.lr_gen, weight_decay=0) + optimizer_disc = RAdam(model_disc.parameters(), + lr=c.lr_disc, + weight_decay=0) + + # setup criterion + criterion_gen = GeneratorLoss(c) + criterion_disc = DiscriminatorLoss(c) + + if args.restore_path: + checkpoint = torch.load(args.restore_path, map_location='cpu') + try: + model_gen.load_state_dict(checkpoint['model']) + optimizer_gen.load_state_dict(checkpoint['optimizer']) + model_disc.load_state_dict(checkpoint['model_disc']) + optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) + except: + print(" > Partial model initialization.") + model_dict = model_gen.state_dict() + model_dict = set_init_dict(model_dict, checkpoint['model'], c) + model_gen.load_state_dict(model_dict) + + model_dict = model_disc.state_dict() + model_dict = set_init_dict(model_dict, checkpoint['model_disc'], c) + model_disc.load_state_dict(model_dict) + del model_dict + + # reset lr if not countinuining training. + for group in optimizer_gen.param_groups: + group['lr'] = c.lr_gen + + for group in optimizer_disc.param_groups: + group['lr'] = c.lr_disc + + print(" > Model restored from step %d" % checkpoint['step'], + flush=True) + args.restore_step = checkpoint['step'] + else: + args.restore_step = 0 + + if use_cuda: + model_gen.cuda() + criterion_gen.cuda() + model_disc.cuda() + criterion_disc.cuda() + + # DISTRUBUTED + # if num_gpus > 1: + # model = apply_gradient_allreduce(model) + + if c.noam_schedule: + scheduler_gen = NoamLR(optimizer_gen, + warmup_steps=c.warmup_steps_gen, + last_epoch=args.restore_step - 1) + scheduler_disc = NoamLR(optimizer_disc, + warmup_steps=c.warmup_steps_gen, + last_epoch=args.restore_step - 1) + else: + scheduler_gen, scheduler_disc = None, None + + num_params = count_parameters(model_gen) + print(" > Generator has {} parameters".format(num_params), flush=True) + num_params = count_parameters(model_disc) + print(" > Discriminator has {} parameters".format(num_params), flush=True) + + if 'best_loss' not in locals(): + best_loss = float('inf') + + global_step = args.restore_step + for epoch in range(0, c.epochs): + c_logger.print_epoch_start(epoch, c.epochs) + _, global_step = train(model_gen, criterion_gen, optimizer_gen, + model_disc, criterion_disc, optimizer_disc, + scheduler_gen, scheduler_disc, ap, global_step, + epoch) + eval_avg_loss_dict = evaluate(model_gen, criterion_gen, model_disc, ap, + global_step, epoch) + c_logger.print_epoch_end(epoch, eval_avg_loss_dict) + target_loss = eval_avg_loss_dict[c.target_loss] + best_loss = save_best_model(target_loss, + best_loss, + model_gen, + optimizer_gen, + model_disc, + optimizer_disc, + global_step, + epoch, + OUT_PATH, + model_losses=eval_avg_loss_dict) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument( + '--continue_path', + type=str, + help= + 'Training output folder to continue training. Use to continue a training. If it is used, "config_path" is ignored.', + default='', + required='--config_path' not in sys.argv) + parser.add_argument( + '--restore_path', + type=str, + help='Model file to be restored. Use to finetune a model.', + default='') + parser.add_argument('--config_path', + type=str, + help='Path to config file for training.', + required='--continue_path' not in sys.argv) + parser.add_argument('--debug', + type=bool, + default=False, + help='Do not verify commit integrity to run training.') + + # DISTRUBUTED + parser.add_argument( + '--rank', + type=int, + default=0, + help='DISTRIBUTED: process rank for distributed training.') + parser.add_argument('--group_id', + type=str, + default="", + help='DISTRIBUTED: process group id.') + args = parser.parse_args() + + if args.continue_path != '': + args.output_path = args.continue_path + args.config_path = os.path.join(args.continue_path, 'config.json') + list_of_files = glob.glob( + args.continue_path + + "/*.pth.tar") # * means all if need specific format then *.csv + latest_model_file = max(list_of_files, key=os.path.getctime) + args.restore_path = latest_model_file + print(f" > Training continues for {args.restore_path}") + + # setup output paths and read configs + c = load_config(args.config_path) + check_config(c) + _ = os.path.dirname(os.path.realpath(__file__)) + + OUT_PATH = args.continue_path + if args.continue_path == '': + OUT_PATH = create_experiment_folder(c.output_path, c.run_name, + args.debug) + + AUDIO_PATH = os.path.join(OUT_PATH, 'test_audios') + + c_logger = ConsoleLogger() + + if args.rank == 0: + os.makedirs(AUDIO_PATH, exist_ok=True) + new_fields = {} + if args.restore_path: + new_fields["restore_path"] = args.restore_path + new_fields["github_branch"] = get_git_branch() + copy_config_file(args.config_path, + os.path.join(OUT_PATH, 'config.json'), new_fields) + os.chmod(AUDIO_PATH, 0o775) + os.chmod(OUT_PATH, 0o775) + + LOG_DIR = OUT_PATH + tb_logger = TensorboardLogger(LOG_DIR, model_name='VOCODER') + + # write model desc to tensorboard + tb_logger.tb_add_text('model-description', c['run_description'], 0) + + try: + main(args) + except KeyboardInterrupt: + remove_experiment_folder(OUT_PATH) + try: + sys.exit(0) + except SystemExit: + os._exit(0) # pylint: disable=protected-access + except Exception: # pylint: disable=broad-except + remove_experiment_folder(OUT_PATH) + traceback.print_exc() + sys.exit(1) diff --git a/vocoder/utils/__init__.py b/vocoder/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py new file mode 100644 index 00000000..4fe132bb --- /dev/null +++ b/vocoder/utils/console_logger.py @@ -0,0 +1,97 @@ +import datetime +from TTS.utils.io import AttrDict + + +tcolors = AttrDict({ + 'OKBLUE': '\033[94m', + 'HEADER': '\033[95m', + 'OKGREEN': '\033[92m', + 'WARNING': '\033[93m', + 'FAIL': '\033[91m', + 'ENDC': '\033[0m', + 'BOLD': '\033[1m', + 'UNDERLINE': '\033[4m' +}) + + +class ConsoleLogger(): + def __init__(self): + # TODO: color code for value changes + # use these to compare values between iterations + self.old_train_loss_dict = None + self.old_epoch_loss_dict = None + self.old_eval_loss_dict = None + + # pylint: disable=no-self-use + def get_time(self): + now = datetime.datetime.now() + return now.strftime("%Y-%m-%d %H:%M:%S") + + def print_epoch_start(self, epoch, max_epoch): + print("\n{}{} > EPOCH: {}/{}{}".format(tcolors.UNDERLINE, tcolors.BOLD, + epoch, max_epoch, tcolors.ENDC), + flush=True) + + def print_train_start(self): + print(f"\n{tcolors.BOLD} > TRAINING ({self.get_time()}) {tcolors.ENDC}") + + def print_train_step(self, batch_steps, step, global_step, + step_time, loader_time, lr, + loss_dict, avg_loss_dict): + indent = " | > " + print() + log_text = "{} --> STEP: {}/{} -- GLOBAL_STEP: {}{}\n".format( + tcolors.BOLD, step, batch_steps, global_step, tcolors.ENDC) + for key, value in loss_dict.items(): + # print the avg value if given + if f'avg_{key}' in avg_loss_dict.keys(): + log_text += "{}{}: {:.5f} ({:.5f})\n".format(indent, key, value, avg_loss_dict[f'avg_{key}']) + else: + log_text += "{}{}: {:.5f} \n".format(indent, key, value) + log_text += f"{indent}step_time: {step_time:.2f}\n{indent}loader_time: {loader_time:.2f}\n{indent}lr: {lr:.5f}" + print(log_text, flush=True) + + # pylint: disable=unused-argument + def print_train_epoch_end(self, global_step, epoch, epoch_time, + print_dict): + indent = " | > " + log_text = f"\n{tcolors.BOLD} --> TRAIN PERFORMACE -- EPOCH TIME: {epoch} sec -- GLOBAL_STEP: {global_step}{tcolors.ENDC}\n" + for key, value in print_dict.items(): + log_text += "{}{}: {:.5f}\n".format(indent, key, value) + print(log_text, flush=True) + + def print_eval_start(self): + print(f"{tcolors.BOLD} > EVALUATION {tcolors.ENDC}\n") + + def print_eval_step(self, step, loss_dict, avg_loss_dict): + indent = " | > " + print() + log_text = f"{tcolors.BOLD} --> STEP: {step}{tcolors.ENDC}\n" + for key, value in loss_dict.items(): + # print the avg value if given + if f'avg_{key}' in avg_loss_dict.keys(): + log_text += "{}{}: {:.5f} ({:.5f})\n".format(indent, key, value, avg_loss_dict[f'avg_{key}']) + else: + log_text += "{}{}: {:.5f} \n".format(indent, key, value) + print(log_text, flush=True) + + def print_epoch_end(self, epoch, avg_loss_dict): + indent = " | > " + log_text = " {}--> EVAL PERFORMANCE{}\n".format( + tcolors.BOLD, tcolors.ENDC) + for key, value in avg_loss_dict.items(): + # print the avg value if given + color = '' + sign = '+' + diff = 0 + if self.old_eval_loss_dict is not None: + diff = value - self.old_eval_loss_dict[key] + if diff < 0: + color = tcolors.OKGREEN + sign = '' + elif diff > 0: + color = tcolors.FAIL + sing = '+' + log_text += "{}{}:{} {:.5f} {}({}{:.5f})\n".format(indent, key, color, value, tcolors.ENDC, sign, diff) + self.old_eval_loss_dict = avg_loss_dict + print(log_text, flush=True) diff --git a/vocoder/utils/generic_utils.py b/vocoder/utils/generic_utils.py new file mode 100644 index 00000000..062de160 --- /dev/null +++ b/vocoder/utils/generic_utils.py @@ -0,0 +1,102 @@ +import re +import importlib +import numpy as np +from matplotlib import pyplot as plt + +from TTS.utils.visual import plot_spectrogram + + +def plot_results(y_hat, y, ap, global_step, name_prefix): + """ Plot vocoder model results """ + + # select an instance from batch + y_hat = y_hat[0].squeeze(0).detach().cpu().numpy() + y = y[0].squeeze(0).detach().cpu().numpy() + + spec_fake = ap.spectrogram(y_hat).T + spec_real = ap.spectrogram(y).T + spec_diff = np.abs(spec_fake - spec_real) + + # plot figure and save it + fig_wave = plt.figure() + plt.subplot(2, 1, 1) + plt.plot(y) + plt.title("groundtruth speech") + plt.subplot(2, 1, 2) + plt.plot(y_hat) + plt.title(f"generated speech @ {global_step} steps") + plt.tight_layout() + plt.close() + + figures = { + name_prefix + "/spectrogram/fake": plot_spectrogram(spec_fake, ap), + name_prefix + "spectrogram/real": plot_spectrogram(spec_real, ap), + name_prefix + "spectrogram/diff": plot_spectrogram(spec_diff, ap), + name_prefix + "speech_comparison": fig_wave, + } + return figures + + +def to_camel(text): + text = text.capitalize() + return re.sub(r'(?!^)_([a-zA-Z])', lambda m: m.group(1).upper(), text) + + +def setup_generator(c): + print(" > Generator Model: {}".format(c.generator_model)) + MyModel = importlib.import_module('TTS.vocoder.models.' + + c.generator_model.lower()) + MyModel = getattr(MyModel, to_camel(c.generator_model)) + if c.generator_model in 'melgan_generator': + model = MyModel( + in_channels=c.audio['num_mels'], + out_channels=1, + proj_kernel=7, + base_channels=512, + upsample_factors=c.generator_model_params['upsample_factors'], + res_kernel=3, + num_res_blocks=c.generator_model_params['num_res_blocks']) + if c.generator_model in 'melgan_fb_generator': + pass + if c.generator_model in 'multiband_melgan_generator': + model = MyModel( + in_channels=c.audio['num_mels'], + out_channels=4, + proj_kernel=7, + base_channels=384, + upsample_factors=c.generator_model_params['upsample_factors'], + res_kernel=3, + num_res_blocks=c.generator_model_params['num_res_blocks']) + return model + + +def setup_discriminator(c): + print(" > Discriminator Model: {}".format(c.discriminator_model)) + MyModel = importlib.import_module('TTS.vocoder.models.' + + c.discriminator_model.lower()) + MyModel = getattr(MyModel, to_camel(c.discriminator_model)) + if c.discriminator_model in 'random_window_discriminator': + model = MyModel( + cond_channels=c.audio['num_mels'], + hop_length=c.audio['hop_length'], + uncond_disc_donwsample_factors=c. + discriminator_model_params['uncond_disc_donwsample_factors'], + cond_disc_downsample_factors=c. + discriminator_model_params['cond_disc_downsample_factors'], + cond_disc_out_channels=c. + discriminator_model_params['cond_disc_out_channels'], + window_sizes=c.discriminator_model_params['window_sizes']) + if c.discriminator_model in 'melgan_multiscale_discriminator': + model = MyModel( + in_channels=1, + out_channels=1, + kernel_sizes=(5, 3), + base_channels=c.discriminator_model_params['base_channels'], + max_channels=c.discriminator_model_params['max_channels'], + downsample_factors=c. + discriminator_model_params['downsample_factors']) + return model + + +# def check_config(c): +# pass \ No newline at end of file diff --git a/vocoder/utils/io.py b/vocoder/utils/io.py new file mode 100644 index 00000000..9526b9db --- /dev/null +++ b/vocoder/utils/io.py @@ -0,0 +1,52 @@ +import os +import torch +import datetime + + +def save_model(model, optimizer, model_disc, optimizer_disc, current_step, + epoch, output_path, **kwargs): + model_state = model.state_dict() + model_disc_state = model_disc.state_dict() + optimizer_state = optimizer.state_dict() if optimizer is not None else None + optimizer_disc_state = optimizer_disc.state_dict( + ) if optimizer_disc is not None else None + state = { + 'model': model_state, + 'optimizer': optimizer_state, + 'model_disc': model_disc_state, + 'optimizer_disc': optimizer_disc_state, + 'step': current_step, + 'epoch': epoch, + 'date': datetime.date.today().strftime("%B %d, %Y"), + } + state.update(kwargs) + torch.save(state, output_path) + + +def save_checkpoint(model, optimizer, model_disc, optimizer_disc, current_step, + epoch, output_folder, **kwargs): + file_name = 'checkpoint_{}.pth.tar'.format(current_step) + checkpoint_path = os.path.join(output_folder, file_name) + print(" > CHECKPOINT : {}".format(checkpoint_path)) + save_model(model, optimizer, model_disc, optimizer_disc, current_step, + epoch, checkpoint_path, **kwargs) + + +def save_best_model(target_loss, best_loss, model, optimizer, model_disc, + optimizer_disc, current_step, epoch, output_folder, + **kwargs): + if target_loss < best_loss: + file_name = 'best_model.pth.tar' + checkpoint_path = os.path.join(output_folder, file_name) + print(" > BEST MODEL : {}".format(checkpoint_path)) + save_model(model, + optimizer, + model_disc, + optimizer_disc, + current_step, + epoch, + checkpoint_path, + model_loss=target_loss, + **kwargs) + best_loss = target_loss + return best_loss \ No newline at end of file From 8e7a15f07b20d0b3134d8c33cd4e582de30db10e Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 03:31:13 +0200 Subject: [PATCH 021/185] version update --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 84a31488..e8a626c6 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ args, unknown_args = parser.parse_known_args() # Remove our arguments from argv so that setuptools doesn't see them sys.argv = [sys.argv[0]] + unknown_args -version = '0.0.2' +version = '0.1.0' # Adapted from https://github.com/pytorch/pytorch cwd = os.path.dirname(os.path.abspath(__file__)) From d5bbcd0487be1b87d5d75b78608a44e19f868b68 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 03:31:42 +0200 Subject: [PATCH 022/185] plot fix --- vocoder/configs/melgan_config.json | 7 +++---- vocoder/train.py | 4 ++-- vocoder/utils/generic_utils.py | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index 9a3ded37..7da42f75 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -109,14 +109,13 @@ "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. // OPTIMIZER - "noam_schedule": true, // use noam warmup and lr schedule. - "grad_clip": 1.0, // upper limit for gradients for clipping. + "noam_schedule": false, // use noam warmup and lr schedule. + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, "epochs": 1000, // total number of epochs to train. "wd": 0.000001, // Weight decay weight. "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. "lr_disc": 0.0001, - "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "warmup_steps_disc": 4000, "gen_clip_grad": 10.0, "disc_clip_grad": 10.0, diff --git a/vocoder/train.py b/vocoder/train.py index b0b4833a..0d039e73 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -372,11 +372,11 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) # compute spectrograms - figures = plot_results(y_hat, y_G, ap, global_step, 'eval') + figures = plot_results(in_fake_D, in_real_D, ap, global_step, 'eval') tb_logger.tb_eval_figures(global_step, figures) # Sample audio - sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() + sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_eval_audios(global_step, {'eval/audio': sample_voice}, c.audio["sample_rate"]) diff --git a/vocoder/utils/generic_utils.py b/vocoder/utils/generic_utils.py index 062de160..179c4064 100644 --- a/vocoder/utils/generic_utils.py +++ b/vocoder/utils/generic_utils.py @@ -13,8 +13,8 @@ def plot_results(y_hat, y, ap, global_step, name_prefix): y_hat = y_hat[0].squeeze(0).detach().cpu().numpy() y = y[0].squeeze(0).detach().cpu().numpy() - spec_fake = ap.spectrogram(y_hat).T - spec_real = ap.spectrogram(y).T + spec_fake = ap.melspectrogram(y_hat).T + spec_real = ap.melspectrogram(y).T spec_diff = np.abs(spec_fake - spec_real) # plot figure and save it @@ -98,5 +98,5 @@ def setup_discriminator(c): return model -# def check_config(c): -# pass \ No newline at end of file +def check_config(c): + pass \ No newline at end of file From 3f789187159e5bd385f49f26b8643e801d5838a5 Mon Sep 17 00:00:00 2001 From: ForceCore Date: Sun, 31 May 2020 19:51:16 +0900 Subject: [PATCH 023/185] Fix phoneme cache file name aliasing problem When the wav file has multiple dots in the file name, _load_or_generate_phoneme_sequence would only use only the first segment of the file name and cause overwrite of *_phoneme.npy --- datasets/TTSDataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datasets/TTSDataset.py b/datasets/TTSDataset.py index 0d884c00..7fe966d7 100644 --- a/datasets/TTSDataset.py +++ b/datasets/TTSDataset.py @@ -92,7 +92,7 @@ class MyDataset(Dataset): return phonemes def _load_or_generate_phoneme_sequence(self, wav_file, text): - file_name = os.path.basename(wav_file).split('.')[0] + file_name = os.path.splitext(os.path.basename(wav_file))[0] cache_path = os.path.join(self.phoneme_cache_path, file_name + '_phoneme.npy') try: From 29915ba85c77db944071ea1e0be2b153c2e74102 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 14:18:29 +0200 Subject: [PATCH 024/185] bug fix --- vocoder/train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 0d039e73..a30e3bff 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -137,7 +137,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if global_step > c.steps_to_start_discriminator: # run D with or without cond. features - if len(signature(model_D).parameters) == 2: + if len(signature(model_D.forward).parameters) == 2: D_out_fake = model_D(in_fake_D, c_G) else: D_out_fake = model_D(in_fake_D) @@ -195,7 +195,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, optimizer_D.zero_grad() # run D with or without cond. features - if len(signature(model_D).parameters) == 2: + if len(signature(model_D.forward).parameters) == 2: D_out_fake = model_D(y_hat.detach(), c_D) D_out_real = model_D(y_D, c_D) else: From bb6729b42ad3b46eeaf95ca5243159ef62e1f899 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 18:56:57 +0200 Subject: [PATCH 025/185] add multiband melgan config and rename loss weights for vocoder --- vocoder/configs/melgan_config.json | 8 ++++---- vocoder/layers/losses.py | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index 7da42f75..b97206fa 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -53,10 +53,10 @@ "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators - "stft_loss_alpha": 1, - "mse_gan_loss_alpha": 1, - "hinge_gan_loss_alpha": 1, - "feat_match_loss_alpha": 10.0, + "stft_loss_weight": 1, + "mse_gan_loss_weight": 2.5, + "hinge_gan_loss_weight": 2.5, + "feat_match_loss_weight": 10.0, "stft_loss_params": { "n_ffts": [1024, 2048, 512], diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 11985629..27091c0a 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -149,10 +149,10 @@ class GeneratorLoss(nn.Module): self.use_hinge_gan_loss = C.use_hinge_gan_loss self.use_feat_match_loss = C.use_feat_match_loss - self.stft_loss_alpha = C.stft_loss_alpha - self.mse_gan_loss_alpha = C.mse_gan_loss_alpha - self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha - self.feat_match_loss_alpha = C.feat_match_loss_alpha + self.stft_loss_weight = C.stft_loss_weight + self.mse_gan_loss_weight = C.mse_gan_loss_weight + self.hinge_gan_loss_weight = C.hinge_gan_loss_weight + self.feat_match_loss_weight = C.feat_match_loss_weight if C.use_stft_loss: self.stft_loss = MultiScaleSTFTLoss(**C.stft_loss_params) @@ -172,7 +172,7 @@ class GeneratorLoss(nn.Module): stft_loss_mg, stft_loss_sc = self.stft_loss(y_hat.squeeze(1), y.squeeze(1)) return_dict['G_stft_loss_mg'] = stft_loss_mg return_dict['G_stft_loss_sc'] = stft_loss_sc - loss += self.stft_loss_alpha * (stft_loss_mg + stft_loss_sc) + loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) # Fake Losses if self.use_mse_gan_loss and scores_fake is not None: @@ -185,7 +185,7 @@ class GeneratorLoss(nn.Module): fake_loss = self.mse_loss(scores_fake) mse_fake_loss = fake_loss return_dict['G_mse_fake_loss'] = mse_fake_loss - loss += self.mse_gan_loss_alpha * mse_fake_loss + loss += self.mse_gan_loss_weight * mse_fake_loss if self.use_hinge_gan_loss and not scores_fake is not None: hinge_fake_loss = 0 @@ -197,13 +197,13 @@ class GeneratorLoss(nn.Module): fake_loss = self.hinge_loss(scores_fake) hinge_fake_loss = fake_loss return_dict['G_hinge_fake_loss'] = hinge_fake_loss - loss += self.hinge_gan_loss_alpha * hinge_fake_loss + loss += self.hinge_gan_loss_weight * hinge_fake_loss # Feature Matching Loss if self.use_feat_match_loss and not feats_fake: feat_match_loss = self.feat_match_loss(feats_fake, feats_real) return_dict['G_feat_match_loss'] = feat_match_loss - loss += self.feat_match_loss_alpha * feat_match_loss + loss += self.feat_match_loss_weight * feat_match_loss return_dict['G_loss'] = loss return return_dict @@ -217,8 +217,8 @@ class DiscriminatorLoss(nn.Module): self.use_mse_gan_loss = C.use_mse_gan_loss self.use_hinge_gan_loss = C.use_hinge_gan_loss - self.mse_gan_loss_alpha = C.mse_gan_loss_alpha - self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha + self.mse_gan_loss_weight = C.mse_gan_loss_weight + self.hinge_gan_loss_weight = C.hinge_gan_loss_weight if C.use_mse_gan_loss: self.mse_loss = MSEDLoss() @@ -247,7 +247,7 @@ class DiscriminatorLoss(nn.Module): return_dict['D_mse_gan_loss'] = mse_gan_loss return_dict['D_mse_gan_real_loss'] = mse_gan_real_loss return_dict['D_mse_gan_fake_loss'] = mse_gan_fake_loss - loss += self.mse_gan_loss_alpha * mse_gan_loss + loss += self.mse_gan_loss_weight * mse_gan_loss if self.use_hinge_gan_loss: hinge_gan_loss = 0 @@ -267,7 +267,7 @@ class DiscriminatorLoss(nn.Module): return_dict['D_hinge_gan_loss'] = hinge_gan_loss return_dict['D_hinge_gan_real_loss'] = hinge_gan_real_loss return_dict['D_hinge_gan_fake_loss'] = hinge_gan_fake_loss - loss += self.hinge_gan_loss_alpha * hinge_gan_loss + loss += self.hinge_gan_loss_weight * hinge_gan_loss return_dict['D_loss'] = loss return return_dict \ No newline at end of file From 1a470ba6b94914a4170e4687639d58c4ba9efb81 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 19:03:07 +0200 Subject: [PATCH 026/185] multiband rwd D config --- .../multiband-melgan_and_rwd_config.json | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 vocoder/configs/multiband-melgan_and_rwd_config.json diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json new file mode 100644 index 00000000..9aeb7933 --- /dev/null +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -0,0 +1,136 @@ +{ + "run_name": "multiband-melgan-rwd", + "run_description": "multibadn melgan with random window discriminator", + + // AUDIO PARAMETERS + "audio":{ + // stft parameters + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "win_length": 1024, // stft window length in ms. + "hop_length": 256, // stft window hop-lengh in ms. + "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. + "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. + + // Audio processing parameters + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + + // Silence trimming + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "trim_db": 60, // threshold for timming silence. Set this according to your dataset. + + // Griffin-Lim + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + + // MelSpectrogram parameters + "num_mels": 80, // size of the mel spec frame. + "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + + // Normalization parameters + "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. + "min_level_db": -100, // lower bound for normalization + "symmetric_norm": true, // move normalization to range [-1, 1] + "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "clip_norm": true, // clip normalized values into the range. + "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + }, + + // DISTRIBUTED TRAINING + // "distributed":{ + // "backend": "nccl", + // "url": "tcp:\/\/localhost:54321" + // }, + + // MODEL PARAMETERS + "use_pqmf": true, + + // LOSS PARAMETERS + "use_stft_loss": true, + "use_mse_gan_loss": true, + "use_hinge_gan_loss": false, + "use_feat_match_loss": false, // use only with melgan discriminators + + "stft_loss_weight": 1, + "mse_gan_loss_weight": 2.5, + "hinge_gan_loss_weight": 1, + "feat_match_loss_weight": 10.0, + + "stft_loss_params": { + "n_ffts": [1024, 2048, 512], + "hop_lengths": [120, 240, 50], + "win_lengths": [600, 1200, 240] + }, + "target_loss": "avg_G_loss", // loss value to pick the best model + + // DISCRIMINATOR + // "discriminator_model": "melgan_multiscale_discriminator", + // "discriminator_model_params":{ + // "base_channels": 16, + // "max_channels":1024, + // "downsample_factors":[4, 4, 4, 4] + // }, + "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 + + "discriminator_model": "random_window_discriminator", + "discriminator_model_params":{ + "uncond_disc_donwsample_factors": [8, 4], + "cond_disc_downsample_factors": [[8, 4, 2, 2, 2], [8, 4, 2, 2], [8, 4, 2], [8, 4], [4, 2, 2]], + "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], + "window_sizes": [512, 1024, 2048, 4096, 8192] + }, + + // GENERATOR + "generator_model": "multiband_melgan_generator", + "generator_model_params": { + "upsample_factors":[2 ,2, 4, 4], + "num_res_blocks": 4 + }, + + // DATASET + "data_path": "/root/LJSpeech-1.1/wavs/", + "seq_len": 16384, + "pad_short": 2000, + "conv_pad": 0, + "use_noise_augment": true, + "use_cache": true, + + "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. + + // TRAINING + "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. + + // VALIDATION + "run_eval": true, + "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. + "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. + + // OPTIMIZER + "noam_schedule": false, // use noam warmup and lr schedule. + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, + "epochs": 1000, // total number of epochs to train. + "wd": 0.000001, // Weight decay weight. + "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 0.0001, + "gen_clip_grad": 10.0, + "disc_clip_grad": 10.0, + + // TENSORBOARD and LOGGING + "print_step": 25, // Number of steps to log traning on console. + "print_eval": false, // If True, it prints intermediate loss values in evalulation. + "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. + "checkpoint": true, // If true, it saves checkpoints per "save_step" + "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. + + // DATA LOADING + "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. + "num_val_loader_workers": 4, // number of evaluation data loader processes. + "eval_split_size": 10, + + // PATHS + "output_path": "/home/erogol/Models/LJSpeech/" +} + From 5662aa3bbe4d73120a89b4eb59a3ce8a03698abd Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 1 Jun 2020 03:02:51 +0200 Subject: [PATCH 027/185] tb eval print --- vocoder/train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vocoder/train.py b/vocoder/train.py index a30e3bff..27e14e8a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -383,6 +383,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # synthesize a full voice data_loader.return_segments = False + tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) return keep_avg.avg_values From 4619b84ddbda458b202e74f28db9a02191c0a499 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 17:07:15 +0200 Subject: [PATCH 028/185] multiscale subband stft loss and missing tb_logger for eval stats --- vocoder/configs/melgan_config.json | 8 +++++ vocoder/layers/losses.py | 21 ++++++++++-- vocoder/train.py | 53 ++++++++++++++---------------- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index b97206fa..4aeba82e 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -49,11 +49,13 @@ // LOSS PARAMETERS "use_stft_loss": true, + "use_subband_stft_loss": true, "use_mse_gan_loss": true, "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators "stft_loss_weight": 1, + "subband_stft_loss_weight": 1, "mse_gan_loss_weight": 2.5, "hinge_gan_loss_weight": 2.5, "feat_match_loss_weight": 10.0, @@ -63,6 +65,12 @@ "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240] }, + "subband_stft_loss_params":{ + "n_ffts": [384, 683, 171], + "hop_lengths": [30, 60, 10], + "win_lengths": [150, 300, 60] + }, + "target_loss": "avg_G_loss", // loss value to pick the best model // DISCRIMINATOR diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 27091c0a..e242d209 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -49,7 +49,6 @@ class STFTLoss(nn.Module): loss_sc = torch.norm(y_M - y_hat_M, p="fro") / torch.norm(y_M, p="fro") return loss_mag, loss_sc - class MultiScaleSTFTLoss(torch.nn.Module): def __init__(self, n_ffts=[1024, 2048, 512], @@ -73,6 +72,13 @@ class MultiScaleSTFTLoss(torch.nn.Module): return loss_mag, loss_sc +class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): + def forward(self, y_hat, y): + y_hat = y_hat.view(-1, 1, y_hat.shape[2]) + y = y.view(-1, 1, y.shape[2]) + return super().forward(y_hat.squeeze(1), y.squeeze(1)) + + class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ def __init__(self,): @@ -145,17 +151,21 @@ class GeneratorLoss(nn.Module): " [!] Cannot use HingeGANLoss and MSEGANLoss together." self.use_stft_loss = C.use_stft_loss + self.use_subband_stft_loss = C.use_subband_stft_loss self.use_mse_gan_loss = C.use_mse_gan_loss self.use_hinge_gan_loss = C.use_hinge_gan_loss self.use_feat_match_loss = C.use_feat_match_loss self.stft_loss_weight = C.stft_loss_weight + self.subband_stft_loss_weight = C.subband_stft_loss_weight self.mse_gan_loss_weight = C.mse_gan_loss_weight self.hinge_gan_loss_weight = C.hinge_gan_loss_weight self.feat_match_loss_weight = C.feat_match_loss_weight if C.use_stft_loss: self.stft_loss = MultiScaleSTFTLoss(**C.stft_loss_params) + if C.use_subband_stft_loss: + self.subband_stft_loss = MultiScaleSubbandSTFTLoss(**C.subband_stft_loss_params) if C.use_mse_gan_loss: self.mse_loss = MSEGLoss() if C.use_hinge_gan_loss: @@ -163,7 +173,7 @@ class GeneratorLoss(nn.Module): if C.use_feat_match_loss: self.feat_match_loss = MelganFeatureLoss() - def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None): + def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None, y_hat_sub=None, y_sub=None): loss = 0 return_dict = {} @@ -174,6 +184,13 @@ class GeneratorLoss(nn.Module): return_dict['G_stft_loss_sc'] = stft_loss_sc loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) + # subband STFT Loss + if self.use_subband_stft_loss: + subband_stft_loss_mg, subband_stft_loss_sc = self.subband_stft_loss(y_hat_sub, y_sub) + return_dict['G_subband_stft_loss_mg'] = subband_stft_loss_mg + return_dict['G_subband_stft_loss_sc'] = subband_stft_loss_sc + loss += self.subband_stft_loss_weight * (subband_stft_loss_mg + subband_stft_loss_sc) + # Fake Losses if self.use_mse_gan_loss and scores_fake is not None: mse_fake_loss = 0 diff --git a/vocoder/train.py b/vocoder/train.py index 27e14e8a..6341bb6c 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -122,30 +122,27 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # generator pass optimizer_G.zero_grad() y_hat = model_G(c_G) - - in_real_D = y_hat - in_fake_D = y_G + y_hat_sub = None + y_G_sub = None # PQMF formatting if y_hat.shape[1] > 1: - in_real_D = y_G - in_fake_D = model_G.pqmf_synthesis(y_hat) - y_G = model_G.pqmf_analysis(y_G) - y_hat = y_hat.view(-1, 1, y_hat.shape[2]) - y_G = y_G.view(-1, 1, y_G.shape[2]) + y_hat_sub = y_hat + y_hat = model_G.pqmf_synthesis(y_hat) + y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: # run D with or without cond. features if len(signature(model_D.forward).parameters) == 2: - D_out_fake = model_D(in_fake_D, c_G) + D_out_fake = model_D(y_hat, c_G) else: - D_out_fake = model_D(in_fake_D) + D_out_fake = model_D(y_hat) D_out_real = None if c.use_feat_match_loss: with torch.no_grad(): - D_out_real = model_D(in_real_D) + D_out_real = model_D(y_G) # format D outputs if isinstance(D_out_fake, tuple): @@ -162,7 +159,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # compute losses loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, - feats_real) + feats_real, y_hat_sub, y_G_sub) loss_G = loss_G_dict['G_loss'] # optimizer generator @@ -272,12 +269,12 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, model_losses=loss_dict) # compute spectrograms - figures = plot_results(in_fake_D, in_real_D, ap, global_step, + figures = plot_results(y_hat, y_G, ap, global_step, 'train') tb_logger.tb_train_figures(global_step, figures) # Sample audio - sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() + sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_train_audios(global_step, {'train/audio': sample_voice}, c.audio["sample_rate"]) @@ -320,23 +317,20 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # generator pass y_hat = model_G(c_G) - - in_real_D = y_hat - in_fake_D = y_G + y_hat_sub = None + y_G_sub = None # PQMF formatting if y_hat.shape[1] > 1: - in_real_D = y_G - in_fake_D = model_G.pqmf_synthesis(y_hat) - y_G = model_G.pqmf_analysis(y_G) - y_hat = y_hat.view(-1, 1, y_hat.shape[2]) - y_G = y_G.view(-1, 1, y_G.shape[2]) + y_hat_sub = y_hat + y_hat = model_G.pqmf_synthesis(y_hat) + y_G_sub = model_G.pqmf_analysis(y_G) - D_out_fake = model_D(in_fake_D) + D_out_fake = model_D(y_hat) D_out_real = None if c.use_feat_match_loss: with torch.no_grad(): - D_out_real = model_D(in_real_D) + D_out_real = model_D(y_G) # format D outputs if isinstance(D_out_fake, tuple): @@ -350,7 +344,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # compute losses loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, - feats_real) + feats_real, y_hat_sub, y_G_sub) loss_dict = dict() for key, value in loss_G_dict.items(): @@ -364,7 +358,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): for key, value in loss_G_dict.items(): update_eval_values['avg_' + key] = value.item() update_eval_values['avg_loader_time'] = loader_time - update_eval_values['avg_step_time'] = step_time + update_eval_values['avgP_step_time'] = step_time keep_avg.update_values(update_eval_values) # print eval stats @@ -372,18 +366,19 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) # compute spectrograms - figures = plot_results(in_fake_D, in_real_D, ap, global_step, 'eval') + figures = plot_results(y_hat, y_G, ap, global_step, 'eval') tb_logger.tb_eval_figures(global_step, figures) # Sample audio - sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() + sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_eval_audios(global_step, {'eval/audio': sample_voice}, c.audio["sample_rate"]) # synthesize a full voice data_loader.return_segments = False - tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) + tb_logger.tb_evals_stats(global_step, keep_avg.avg_values) + return keep_avg.avg_values From fd2d0dab41764890dda0aadbad782eda29005d93 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 17:09:05 +0200 Subject: [PATCH 029/185] bug fix --- vocoder/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index 6341bb6c..398051a9 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -377,7 +377,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # synthesize a full voice data_loader.return_segments = False - tb_logger.tb_evals_stats(global_step, keep_avg.avg_values) + tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) return keep_avg.avg_values From 808da15e7d50fd014687664c7664b989405a9d85 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 17:28:52 +0200 Subject: [PATCH 030/185] update travis script --- .travis/script | 4 +++- requirements_tests.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis/script b/.travis/script index ca6f4cd3..278ba4f2 100755 --- a/.travis/script +++ b/.travis/script @@ -12,7 +12,9 @@ fi if [[ "$TEST_SUITE" == "unittest" ]]; then # Run tests on all pushes pushd tts_namespace - python -m unittest + nosetests speaker_encoder.tests --nocapture + nosetests vocoder.tests --nocapture + nosetests tests --nocapture popd # Test server package ./tests/test_server_package.sh diff --git a/requirements_tests.txt b/requirements_tests.txt index 1e0615b2..243aa3a6 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -13,3 +13,4 @@ tqdm soundfile phonemizer bokeh==1.4.0 +nose From af516aff7fd6e8ee5a182af92507f6863b6b4783 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 18:54:03 +0200 Subject: [PATCH 031/185] cardboard config update --- .cardboardlint.yml | 3 +++ .pylintrc | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.cardboardlint.yml b/.cardboardlint.yml index 464ea733..4a115a37 100644 --- a/.cardboardlint.yml +++ b/.cardboardlint.yml @@ -1,2 +1,5 @@ linters: - pylint: + # pylintrc: pylintrc + filefilter: ['- test_*.py', '+ *.py', '- *.npy'] + # exclude: \ No newline at end of file diff --git a/.pylintrc b/.pylintrc index b6e04944..a78b521e 100644 --- a/.pylintrc +++ b/.pylintrc @@ -157,7 +157,8 @@ disable=missing-docstring, xreadlines-attribute, deprecated-sys-function, exception-escape, - comprehension-escape + comprehension-escape, + duplicate-code # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option From 054c1fce39bd89b8ce2194de641cb4e2c63f919b Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 18:54:29 +0200 Subject: [PATCH 032/185] travis script for nose --- .travis/script | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis/script b/.travis/script index 278ba4f2..ce886fc2 100755 --- a/.travis/script +++ b/.travis/script @@ -12,9 +12,9 @@ fi if [[ "$TEST_SUITE" == "unittest" ]]; then # Run tests on all pushes pushd tts_namespace - nosetests speaker_encoder.tests --nocapture - nosetests vocoder.tests --nocapture - nosetests tests --nocapture + nosetests TTS.speaker_encoder.tests --nocapture + nosetests TTS.vocoder.tests --nocapture + nosetests TTS.tests --nocapture popd # Test server package ./tests/test_server_package.sh From e051dd41b18fed43a71c9d6b7280548184fd3341 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 18:58:10 +0200 Subject: [PATCH 033/185] Ton of linter fixes --- train.py | 12 +-- utils/training.py | 11 +++ vocoder/datasets/gan_dataset.py | 34 ++----- vocoder/layers/losses.py | 35 ++----- vocoder/layers/melgan.py | 3 - vocoder/layers/pqmf.py | 3 + vocoder/layers/pqmf2.py | 127 ------------------------- vocoder/models/melgan_discriminator.py | 4 +- vocoder/models/melgan_generator.py | 2 - vocoder/tests/test_datasets.py | 22 ++--- vocoder/tests/test_losses.py | 3 +- vocoder/tests/test_melgan_generator.py | 1 - vocoder/tests/test_pqmf.py | 7 +- vocoder/train.py | 24 ++--- vocoder/utils/console_logger.py | 2 +- vocoder/utils/io.py | 1 - 16 files changed, 60 insertions(+), 231 deletions(-) delete mode 100644 vocoder/layers/pqmf2.py diff --git a/train.py b/train.py index 82f91cd5..5a345b59 100644 --- a/train.py +++ b/train.py @@ -20,7 +20,8 @@ from TTS.utils.generic_utils import (count_parameters, create_experiment_folder, from TTS.utils.io import (save_best_model, save_checkpoint, load_config, copy_config_file) from TTS.utils.training import (NoamLR, check_update, adam_weight_decay, - gradual_training_scheduler, set_weight_decay) + gradual_training_scheduler, set_weight_decay, + setup_torch_training_env) from TTS.utils.tensorboard_logger import TensorboardLogger from TTS.utils.console_logger import ConsoleLogger from TTS.utils.speakers import load_speaker_mapping, save_speaker_mapping, \ @@ -32,13 +33,8 @@ from TTS.datasets.preprocess import load_meta_data from TTS.utils.radam import RAdam from TTS.utils.measures import alignment_diagonal_score -torch.backends.cudnn.enabled = True -torch.backends.cudnn.benchmark = False -torch.manual_seed(54321) -use_cuda = torch.cuda.is_available() -num_gpus = torch.cuda.device_count() -print(" > Using CUDA: ", use_cuda) -print(" > Number of GPUs: ", num_gpus) + +use_cuda, num_gpus = setup_torch_training_env(True, False) def setup_loader(ap, r, is_val=False, verbose=False): diff --git a/utils/training.py b/utils/training.py index 5ce7948b..9046f9e0 100644 --- a/utils/training.py +++ b/utils/training.py @@ -2,6 +2,17 @@ import torch import numpy as np +def setup_torch_training_env(cudnn_enable, cudnn_benchmark): + torch.backends.cudnn.enabled = cudnn_enable + torch.backends.cudnn.benchmark = cudnn_benchmark + torch.manual_seed(54321) + use_cuda = torch.cuda.is_available() + num_gpus = torch.cuda.device_count() + print(" > Using CUDA: ", use_cuda) + print(" > Number of GPUs: ", num_gpus) + return use_cuda, num_gpus + + def check_update(model, grad_clip, ignore_stopnet=False): r'''Check model gradient against unexpected jumps and failures''' skip_flag = False diff --git a/vocoder/datasets/gan_dataset.py b/vocoder/datasets/gan_dataset.py index 10d36cab..5e410151 100644 --- a/vocoder/datasets/gan_dataset.py +++ b/vocoder/datasets/gan_dataset.py @@ -3,29 +3,10 @@ import glob import torch import random import numpy as np -from torch.utils.data import Dataset, DataLoader +from torch.utils.data import Dataset from multiprocessing import Manager -def create_dataloader(hp, args, train): - dataset = MelFromDisk(hp, args, train) - - if train: - return DataLoader(dataset=dataset, - batch_size=hp.train.batch_size, - shuffle=True, - num_workers=hp.train.num_workers, - pin_memory=True, - drop_last=True) - else: - return DataLoader(dataset=dataset, - batch_size=1, - shuffle=False, - num_workers=hp.train.num_workers, - pin_memory=True, - drop_last=False) - - class GANDataset(Dataset): """ GAN Dataset searchs for all the wav files under root path @@ -55,26 +36,26 @@ class GANDataset(Dataset): self.return_segments = return_segments self.use_cache = use_cache self.use_noise_augment = use_noise_augment + self.verbose = verbose assert seq_len % hop_len == 0, " [!] seq_len has to be a multiple of hop_len." self.feat_frame_len = seq_len // hop_len + (2 * conv_pad) # map G and D instances - self.G_to_D_mappings = [i for i in range(len(self.item_list))] + self.G_to_D_mappings = list(range(len(self.item_list))) self.shuffle_mapping() # cache acoustic features if use_cache: self.create_feature_cache() - - def create_feature_cache(self): self.manager = Manager() self.cache = self.manager.list() self.cache += [None for _ in range(len(self.item_list))] - def find_wav_files(self, path): + @staticmethod + def find_wav_files(path): return glob.glob(os.path.join(path, '**', '*.wav'), recursive=True) def __len__(self): @@ -88,9 +69,8 @@ class GANDataset(Dataset): item1 = self.load_item(idx) item2 = self.load_item(idx2) return item1, item2 - else: - item1 = self.load_item(idx) - return item1 + item1 = self.load_item(idx) + return item1 def shuffle_mapping(self): random.shuffle(self.G_to_D_mappings) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index e242d209..1c3d4442 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -51,13 +51,13 @@ class STFTLoss(nn.Module): class MultiScaleSTFTLoss(torch.nn.Module): def __init__(self, - n_ffts=[1024, 2048, 512], - hop_lengths=[120, 240, 50], - win_lengths=[600, 1200, 240]): + n_ffts=(1024, 2048, 512), + hop_lengths=(120, 240, 50), + win_lengths=(600, 1200, 240)): super(MultiScaleSTFTLoss, self).__init__() self.loss_funcs = torch.nn.ModuleList() - for idx in range(len(n_ffts)): - self.loss_funcs.append(STFTLoss(n_ffts[idx], hop_lengths[idx], win_lengths[idx])) + for n_fft, hop_length, win_length in zip(n_ffts, hop_lengths, win_lengths): + self.loss_funcs.append(STFTLoss(n_fft, hop_length, win_length)) def forward(self, y_hat, y): N = len(self.loss_funcs) @@ -81,20 +81,14 @@ class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ - def __init__(self,): - super(MSEGLoss, self).__init__() - - def forward(self, score_fake, ): + def forward(self, score_fake): loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) return loss_fake class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ - def __init__(self,): - super(HingeGLoss, self).__init__() - - def forward(self, score_fake, score_real): + def forward(self, score_fake): loss_fake = torch.mean(F.relu(1. + score_fake)) return loss_fake @@ -106,9 +100,6 @@ class HingeGLoss(nn.Module): class MSEDLoss(nn.Module): """ Mean Squared Discriminator Loss """ - def __init__(self,): - super(MSEDLoss, self).__init__() - def forward(self, score_fake, score_real): loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) @@ -118,9 +109,6 @@ class MSEDLoss(nn.Module): class HingeDLoss(nn.Module): """ Hinge Discriminator Loss """ - def __init__(self,): - super(HingeDLoss, self).__init__() - def forward(self, score_fake, score_real): loss_real = torch.mean(F.relu(1. - score_real)) loss_fake = torch.mean(F.relu(1. + score_fake)) @@ -129,13 +117,10 @@ class HingeDLoss(nn.Module): class MelganFeatureLoss(nn.Module): - def __init__(self, ): - super(MelganFeatureLoss, self).__init__() - def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): - loss_feats += hp.model.feat_match * torch.mean(torch.abs(fake_feat - real_feat)) + loss_feats += torch.mean(torch.abs(fake_feat - real_feat)) return loss_feats @@ -147,7 +132,7 @@ class MelganFeatureLoss(nn.Module): class GeneratorLoss(nn.Module): def __init__(self, C): super(GeneratorLoss, self).__init__() - assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ " [!] Cannot use HingeGANLoss and MSEGANLoss together." self.use_stft_loss = C.use_stft_loss @@ -228,7 +213,7 @@ class GeneratorLoss(nn.Module): class DiscriminatorLoss(nn.Module): def __init__(self, C): super(DiscriminatorLoss, self).__init__() - assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ " [!] Cannot use HingeGANLoss and MSEGANLoss together." self.use_mse_gan_loss = C.use_mse_gan_loss diff --git a/vocoder/layers/melgan.py b/vocoder/layers/melgan.py index cda0413c..61f7a96b 100644 --- a/vocoder/layers/melgan.py +++ b/vocoder/layers/melgan.py @@ -1,7 +1,4 @@ -import numpy as np -import torch from torch import nn -from torch.nn import functional as F from torch.nn.utils import weight_norm diff --git a/vocoder/layers/pqmf.py b/vocoder/layers/pqmf.py index f438ea00..3985aad4 100644 --- a/vocoder/layers/pqmf.py +++ b/vocoder/layers/pqmf.py @@ -44,6 +44,9 @@ class PQMF(torch.nn.Module): self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) + def forward(self, x): + return self.analysis(x) + def analysis(self, x): return F.conv1d(x, self.H, padding=self.taps // 2, stride=self.N) diff --git a/vocoder/layers/pqmf2.py b/vocoder/layers/pqmf2.py deleted file mode 100644 index 4cffb819..00000000 --- a/vocoder/layers/pqmf2.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2020 Tomoki Hayashi -# MIT License (https://opensource.org/licenses/MIT) - -"""Pseudo QMF modules.""" - -import numpy as np -import torch -import torch.nn.functional as F - -from scipy.signal import kaiser - - -def design_prototype_filter(taps=62, cutoff_ratio=0.15, beta=9.0): - """Design prototype filter for PQMF. - - This method is based on `A Kaiser window approach for the design of prototype - filters of cosine modulated filterbanks`_. - - Args: - taps (int): The number of filter taps. - cutoff_ratio (float): Cut-off frequency ratio. - beta (float): Beta coefficient for kaiser window. - - Returns: - ndarray: Impluse response of prototype filter (taps + 1,). - - .. _`A Kaiser window approach for the design of prototype filters of cosine modulated filterbanks`: - https://ieeexplore.ieee.org/abstract/document/681427 - - """ - # check the arguments are valid - assert taps % 2 == 0, "The number of taps mush be even number." - assert 0.0 < cutoff_ratio < 1.0, "Cutoff ratio must be > 0.0 and < 1.0." - - # make initial filter - omega_c = np.pi * cutoff_ratio - with np.errstate(invalid='ignore'): - h_i = np.sin(omega_c * (np.arange(taps + 1) - 0.5 * taps)) \ - / (np.pi * (np.arange(taps + 1) - 0.5 * taps)) - h_i[taps // 2] = np.cos(0) * cutoff_ratio # fix nan due to indeterminate form - - # apply kaiser window - w = kaiser(taps + 1, beta) - h = h_i * w - - return h - - -class PQMF(torch.nn.Module): - """PQMF module. - - This module is based on `Near-perfect-reconstruction pseudo-QMF banks`_. - - .. _`Near-perfect-reconstruction pseudo-QMF banks`: - https://ieeexplore.ieee.org/document/258122 - - """ - - def __init__(self, subbands=4, taps=62, cutoff_ratio=0.15, beta=9.0): - """Initilize PQMF module. - - Args: - subbands (int): The number of subbands. - taps (int): The number of filter taps. - cutoff_ratio (float): Cut-off frequency ratio. - beta (float): Beta coefficient for kaiser window. - - """ - super(PQMF, self).__init__() - - # define filter coefficient - h_proto = design_prototype_filter(taps, cutoff_ratio, beta) - h_analysis = np.zeros((subbands, len(h_proto))) - h_synthesis = np.zeros((subbands, len(h_proto))) - for k in range(subbands): - h_analysis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) + (-1) ** k * np.pi / 4) - h_synthesis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) - (-1) ** k * np.pi / 4) - - # convert to tensor - analysis_filter = torch.from_numpy(h_analysis).float().unsqueeze(1) - synthesis_filter = torch.from_numpy(h_synthesis).float().unsqueeze(0) - - # register coefficients as beffer - self.register_buffer("analysis_filter", analysis_filter) - self.register_buffer("synthesis_filter", synthesis_filter) - - # filter for downsampling & upsampling - updown_filter = torch.zeros((subbands, subbands, subbands)).float() - for k in range(subbands): - updown_filter[k, k, 0] = 1.0 - self.register_buffer("updown_filter", updown_filter) - self.subbands = subbands - - # keep padding info - self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) - - def analysis(self, x): - """Analysis with PQMF. - - Args: - x (Tensor): Input tensor (B, 1, T). - - Returns: - Tensor: Output tensor (B, subbands, T // subbands). - - """ - x = F.conv1d(self.pad_fn(x), self.analysis_filter) - return F.conv1d(x, self.updown_filter, stride=self.subbands) - - def synthesis(self, x): - """Synthesis with PQMF. - - Args: - x (Tensor): Input tensor (B, subbands, T // subbands). - - Returns: - Tensor: Output tensor (B, 1, T). - - """ - # NOTE(kan-bayashi): Power will be dreased so here multipy by # subbands. - # Not sure this is the correct way, it is better to check again. - # TODO(kan-bayashi): Understand the reconstruction procedure - x = F.conv_transpose1d(x, self.updown_filter * self.subbands, stride=self.subbands) - x = F.conv1d(self.pad_fn(x), self.synthesis_filter) - return x diff --git a/vocoder/models/melgan_discriminator.py b/vocoder/models/melgan_discriminator.py index 55d3f585..3847babb 100644 --- a/vocoder/models/melgan_discriminator.py +++ b/vocoder/models/melgan_discriminator.py @@ -1,7 +1,5 @@ import numpy as np -import torch from torch import nn -from torch.nn import functional as F from torch.nn.utils import weight_norm @@ -32,7 +30,7 @@ class MelganDiscriminator(nn.Module): # downsampling layers layer_in_channels = base_channels - for idx, downsample_factor in enumerate(downsample_factors): + for downsample_factor in downsample_factors: layer_out_channels = min(layer_in_channels * downsample_factor, max_channels) layer_kernel_size = downsample_factor * 10 + 1 diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py index 2d266f29..1e47816d 100644 --- a/vocoder/models/melgan_generator.py +++ b/vocoder/models/melgan_generator.py @@ -1,7 +1,5 @@ -import math import torch from torch import nn -from torch.nn import functional as F from torch.nn.utils import weight_norm from TTS.vocoder.layers.melgan import ResidualStack diff --git a/vocoder/tests/test_datasets.py b/vocoder/tests/test_datasets.py index 3d6280f0..5d409b3f 100644 --- a/vocoder/tests/test_datasets.py +++ b/vocoder/tests/test_datasets.py @@ -22,7 +22,7 @@ ok_ljspeech = os.path.exists(test_data_path) def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, use_noise_augment, use_cache, num_workers): ''' run dataloader with given parameters and check conditions ''' ap = AudioProcessor(**C.audio) - eval_items, train_items = load_wav_data(test_data_path, 10) + _, train_items = load_wav_data(test_data_path, 10) dataset = GANDataset(ap, train_items, seq_len=seq_len, @@ -44,9 +44,9 @@ def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, us # return random segments or return the whole audio if return_segments: - for item1, item2 in loader: + for item1, _ in loader: feat1, wav1 = item1 - feat2, wav2 = item2 + # feat2, wav2 = item2 expected_feat_shape = (batch_size, ap.num_mels, seq_len // hop_len + conv_pad * 2) # check shapes @@ -80,15 +80,15 @@ def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, us def test_parametrized_gan_dataset(): ''' test dataloader with different parameters ''' params = [ - [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], - [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 4], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, True, 0], + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 4], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, True, 0], [1, C.audio['hop_length'], C.audio['hop_length'], 0, True, True, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 2, True, True, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, True, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, False, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, False, False, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 2, True, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, False, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, False, False, 0], ] for param in params: print(param) diff --git a/vocoder/tests/test_losses.py b/vocoder/tests/test_losses.py index 83314832..44a1321d 100644 --- a/vocoder/tests/test_losses.py +++ b/vocoder/tests/test_losses.py @@ -1,5 +1,4 @@ import os -import unittest import torch from TTS.vocoder.layers.losses import TorchSTFT, STFTLoss, MultiScaleSTFTLoss @@ -24,7 +23,7 @@ def test_torch_stft(): torch_stft = TorchSTFT(ap.n_fft, ap.hop_length, ap.win_length) # librosa stft wav = ap.load_wav(WAV_FILE) - M_librosa = abs(ap._stft(wav)) + M_librosa = abs(ap._stft(wav)) # pylint: disable=protected-access # torch stft wav = torch.from_numpy(wav[None, :]).float() M_torch = torch_stft(wav) diff --git a/vocoder/tests/test_melgan_generator.py b/vocoder/tests/test_melgan_generator.py index e9c4ad60..e03da31b 100644 --- a/vocoder/tests/test_melgan_generator.py +++ b/vocoder/tests/test_melgan_generator.py @@ -1,5 +1,4 @@ import numpy as np -import unittest import torch from TTS.vocoder.models.melgan_generator import MelganGenerator diff --git a/vocoder/tests/test_pqmf.py b/vocoder/tests/test_pqmf.py index 8444fc5a..a26bdd59 100644 --- a/vocoder/tests/test_pqmf.py +++ b/vocoder/tests/test_pqmf.py @@ -1,16 +1,11 @@ import os import torch -import unittest -import numpy as np import soundfile as sf from librosa.core import load -from TTS.tests import get_tests_path, get_tests_input_path, get_tests_output_path -from TTS.utils.audio import AudioProcessor -from TTS.utils.io import load_config +from TTS.tests import get_tests_path, get_tests_input_path from TTS.vocoder.layers.pqmf import PQMF -from TTS.vocoder.layers.pqmf2 import PQMF as PQMF2 TESTS_PATH = get_tests_path() diff --git a/vocoder/train.py b/vocoder/train.py index 398051a9..d401e72e 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -17,7 +17,7 @@ from TTS.utils.generic_utils import (KeepAverage, count_parameters, from TTS.utils.io import copy_config_file, load_config from TTS.utils.radam import RAdam from TTS.utils.tensorboard_logger import TensorboardLogger -from TTS.utils.training import NoamLR +from TTS.utils.training import setup_torch_training_env, NoamLR from TTS.vocoder.datasets.gan_dataset import GANDataset from TTS.vocoder.datasets.preprocess import load_wav_data # from distribute import (DistributedSampler, apply_gradient_allreduce, @@ -29,13 +29,8 @@ from TTS.vocoder.utils.generic_utils import (check_config, plot_results, setup_discriminator, setup_generator) -torch.backends.cudnn.enabled = True -torch.backends.cudnn.benchmark = True -torch.manual_seed(54321) -use_cuda = torch.cuda.is_available() -num_gpus = torch.cuda.device_count() -print(" > Using CUDA: ", use_cuda) -print(" > Number of GPUs: ", num_gpus) + +use_cuda, num_gpus = setup_torch_training_env(True, True) def setup_loader(ap, is_val=False, verbose=False): @@ -49,10 +44,11 @@ def setup_loader(ap, is_val=False, verbose=False): pad_short=c.pad_short, conv_pad=c.conv_pad, is_training=not is_val, - return_segments=False if is_val else True, + return_segments=not is_val, use_noise_augment=c.use_noise_augment, use_cache=c.use_cache, verbose=verbose) + dataset.shuffle_mapping() # sampler = DistributedSampler(dataset) if num_gpus > 1 else None loader = DataLoader(dataset, batch_size=1 if is_val else c.batch_size, @@ -81,11 +77,11 @@ def format_data(data): return c_G, x_G, c_D, x_D # return a whole audio segment - c, x = data + co, x = data if use_cuda: - c = c.cuda(non_blocking=True) + co = co.cuda(non_blocking=True) x = x.cuda(non_blocking=True) - return c, x + return co, x, None, None def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, @@ -306,7 +302,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): start_time = time.time() # format data - c_G, y_G = format_data(data) + c_G, y_G, _, _ = format_data(data) loader_time = time.time() - end_time global_step += 1 @@ -416,7 +412,7 @@ def main(args): # pylint: disable=redefined-outer-name optimizer_gen.load_state_dict(checkpoint['optimizer']) model_disc.load_state_dict(checkpoint['model_disc']) optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) - except: + except KeyError: print(" > Partial model initialization.") model_dict = model_gen.state_dict() model_dict = set_init_dict(model_dict, checkpoint['model'], c) diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py index 4fe132bb..ff7edfd0 100644 --- a/vocoder/utils/console_logger.py +++ b/vocoder/utils/console_logger.py @@ -91,7 +91,7 @@ class ConsoleLogger(): sign = '' elif diff > 0: color = tcolors.FAIL - sing = '+' + sign = '+' log_text += "{}{}:{} {:.5f} {}({}{:.5f})\n".format(indent, key, color, value, tcolors.ENDC, sign, diff) self.old_eval_loss_dict = avg_loss_dict print(log_text, flush=True) diff --git a/vocoder/utils/io.py b/vocoder/utils/io.py index 9526b9db..b6ea7484 100644 --- a/vocoder/utils/io.py +++ b/vocoder/utils/io.py @@ -2,7 +2,6 @@ import os import torch import datetime - def save_model(model, optimizer, model_disc, optimizer_disc, current_step, epoch, output_path, **kwargs): model_state = model.state_dict() From b25af49c34b161cf0d2d7e6887af35a811bde33d Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 23:58:18 +0200 Subject: [PATCH 034/185] espeak install travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 645f9861..83ba25a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ language: python git: quiet: true +before_install: + - sudo apt-get update + - sudo apt-get -y install espeak + matrix: include: - name: "Lint check" From 1e017f866abf5d1249d19ec77a3a91a7b7ff227d Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 3 Jun 2020 12:15:48 +0200 Subject: [PATCH 035/185] reset loss weights --- vocoder/configs/melgan_config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index 4aeba82e..bdfdf88a 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -54,11 +54,11 @@ "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators - "stft_loss_weight": 1, - "subband_stft_loss_weight": 1, + "stft_loss_weight": 0.5, + "subband_stft_loss_weight": 0.5, "mse_gan_loss_weight": 2.5, "hinge_gan_loss_weight": 2.5, - "feat_match_loss_weight": 10.0, + "feat_match_loss_weight": 25, "stft_loss_params": { "n_ffts": [1024, 2048, 512], From 20a9d51cccbe4e995aa34d4965bde8dcd25b8f6b Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 3 Jun 2020 12:16:08 +0200 Subject: [PATCH 036/185] correct loss normalization and function refactoring --- vocoder/layers/losses.py | 141 +++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 64 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 1c3d4442..fb4e85d4 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -6,6 +6,7 @@ from torch.nn import functional as F class TorchSTFT(): def __init__(self, n_fft, hop_length, win_length, window='hann_window'): + """ Torch based STFT operation """ self.n_fft = n_fft self.hop_length = hop_length self.win_length = win_length @@ -33,6 +34,7 @@ class TorchSTFT(): class STFTLoss(nn.Module): + """ Single scale STFT Loss """ def __init__(self, n_fft, hop_length, win_length): super(STFTLoss, self).__init__() self.n_fft = n_fft @@ -50,6 +52,7 @@ class STFTLoss(nn.Module): return loss_mag, loss_sc class MultiScaleSTFTLoss(torch.nn.Module): + """ Multi scale STFT loss """ def __init__(self, n_ffts=(1024, 2048, 512), hop_lengths=(120, 240, 50), @@ -73,6 +76,7 @@ class MultiScaleSTFTLoss(torch.nn.Module): class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): + """ Multiscale STFT loss for multi band model outputs """ def forward(self, y_hat, y): y_hat = y_hat.view(-1, 1, y_hat.shape[2]) y = y.view(-1, 1, y.shape[2]) @@ -121,16 +125,62 @@ class MelganFeatureLoss(nn.Module): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): loss_feats += torch.mean(torch.abs(fake_feat - real_feat)) + loss_feats /= len(fake_feats) + len(real_feats) return loss_feats -################################## +##################################### # LOSS WRAPPERS +##################################### + + +def _apply_G_adv_loss(scores_fake, loss_func): + """ Compute G adversarial loss function + and normalize values """ + adv_loss = 0 + if isinstance(scores_fake, list): + for score_fake in scores_fake: + fake_loss = loss_func(score_fake) + adv_loss += fake_loss + adv_loss /= len(scores_fake) + else: + fake_loss = loss_func(scores_fake) + adv_loss = fake_loss + return adv_loss + + +def _apply_D_loss(scores_fake, scores_real, loss_func): + """ Compute D loss func and normalize loss values """ + loss = 0 + real_loss = 0 + fake_loss = 0 + if isinstance(scores_fake, list): + # multi-scale loss + for score_fake, score_real in zip(scores_fake, scores_real): + total_loss, real_loss, fake_loss = loss_func(score_fake, score_real) + loss += total_loss + real_loss += real_loss + fake_loss += fake_loss + # normalize loss values with number of scales + loss /= len(scores_fake) + real_loss /= len(scores_real) + fake_loss /= len(scores_fake) + else: + # single scale loss + total_loss, real_loss, fake_loss = loss_func(scores_fake, scores_real) + loss = total_loss + return loss, real_loss, fake_loss + + +################################## +# MODEL LOSSES ################################## class GeneratorLoss(nn.Module): def __init__(self, C): + """ Compute Generator Loss values depending on training + configuration """ super(GeneratorLoss, self).__init__() assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ " [!] Cannot use HingeGANLoss and MSEGANLoss together." @@ -159,7 +209,8 @@ class GeneratorLoss(nn.Module): self.feat_match_loss = MelganFeatureLoss() def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None, y_hat_sub=None, y_sub=None): - loss = 0 + gen_loss = 0 + adv_loss = 0 return_dict = {} # STFT Loss @@ -167,50 +218,41 @@ class GeneratorLoss(nn.Module): stft_loss_mg, stft_loss_sc = self.stft_loss(y_hat.squeeze(1), y.squeeze(1)) return_dict['G_stft_loss_mg'] = stft_loss_mg return_dict['G_stft_loss_sc'] = stft_loss_sc - loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) + gen_loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) # subband STFT Loss if self.use_subband_stft_loss: subband_stft_loss_mg, subband_stft_loss_sc = self.subband_stft_loss(y_hat_sub, y_sub) return_dict['G_subband_stft_loss_mg'] = subband_stft_loss_mg return_dict['G_subband_stft_loss_sc'] = subband_stft_loss_sc - loss += self.subband_stft_loss_weight * (subband_stft_loss_mg + subband_stft_loss_sc) + gen_loss += self.subband_stft_loss_weight * (subband_stft_loss_mg + subband_stft_loss_sc) - # Fake Losses + # multiscale MSE adversarial loss if self.use_mse_gan_loss and scores_fake is not None: - mse_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake in scores_fake: - fake_loss = self.mse_loss(score_fake) - mse_fake_loss += fake_loss - else: - fake_loss = self.mse_loss(scores_fake) - mse_fake_loss = fake_loss + mse_fake_loss = _apply_G_adv_loss(scores_fake, self.mse_loss) return_dict['G_mse_fake_loss'] = mse_fake_loss - loss += self.mse_gan_loss_weight * mse_fake_loss + adv_loss += self.mse_gan_loss_weight * mse_fake_loss + # multiscale Hinge adversarial loss if self.use_hinge_gan_loss and not scores_fake is not None: - hinge_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake in scores_fake: - fake_loss = self.hinge_loss(score_fake) - hinge_fake_loss += fake_loss - else: - fake_loss = self.hinge_loss(scores_fake) - hinge_fake_loss = fake_loss + hinge_fake_loss = _apply_G_adv_loss(scores_fake, self.hinge_loss) return_dict['G_hinge_fake_loss'] = hinge_fake_loss - loss += self.hinge_gan_loss_weight * hinge_fake_loss + adv_loss += self.hinge_gan_loss_weight * hinge_fake_loss # Feature Matching Loss if self.use_feat_match_loss and not feats_fake: feat_match_loss = self.feat_match_loss(feats_fake, feats_real) return_dict['G_feat_match_loss'] = feat_match_loss - loss += self.feat_match_loss_weight * feat_match_loss - return_dict['G_loss'] = loss + adv_loss += self.feat_match_loss_weight * feat_match_loss + return_dict['G_loss'] = gen_loss + adv_loss + return_dict['G_gen_loss'] = gen_loss + return_dict['G_adv_loss'] = adv_loss return return_dict class DiscriminatorLoss(nn.Module): + """ Compute Discriminator Loss values depending on training + configuration """ def __init__(self, C): super(DiscriminatorLoss, self).__init__() assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ @@ -219,9 +261,6 @@ class DiscriminatorLoss(nn.Module): self.use_mse_gan_loss = C.use_mse_gan_loss self.use_hinge_gan_loss = C.use_hinge_gan_loss - self.mse_gan_loss_weight = C.mse_gan_loss_weight - self.hinge_gan_loss_weight = C.hinge_gan_loss_weight - if C.use_mse_gan_loss: self.mse_loss = MSEDLoss() if C.use_hinge_gan_loss: @@ -232,44 +271,18 @@ class DiscriminatorLoss(nn.Module): return_dict = {} if self.use_mse_gan_loss: - mse_gan_loss = 0 - mse_gan_real_loss = 0 - mse_gan_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake, score_real in zip(scores_fake, scores_real): - total_loss, real_loss, fake_loss = self.mse_loss(score_fake, score_real) - mse_gan_loss += total_loss - mse_gan_real_loss += real_loss - mse_gan_fake_loss += fake_loss - else: - total_loss, real_loss, fake_loss = self.mse_loss(scores_fake, scores_real) - mse_gan_loss = total_loss - mse_gan_real_loss = real_loss - mse_gan_fake_loss = fake_loss - return_dict['D_mse_gan_loss'] = mse_gan_loss - return_dict['D_mse_gan_real_loss'] = mse_gan_real_loss - return_dict['D_mse_gan_fake_loss'] = mse_gan_fake_loss - loss += self.mse_gan_loss_weight * mse_gan_loss + mse_D_loss, mse_D_real_loss, mse_D_fake_loss = _apply_D_loss(scores_fake, scores_real, self.mse_loss) + return_dict['D_mse_gan_loss'] = mse_D_loss + return_dict['D_mse_gan_real_loss'] = mse_D_real_loss + return_dict['D_mse_gan_fake_loss'] = mse_D_fake_loss + loss += mse_D_loss if self.use_hinge_gan_loss: - hinge_gan_loss = 0 - hinge_gan_real_loss = 0 - hinge_gan_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake, score_real in zip(scores_fake, scores_real): - total_loss, real_loss, fake_loss = self.hinge_loss(score_fake, score_real) - hinge_gan_loss += total_loss - hinge_gan_real_loss += real_loss - hinge_gan_fake_loss += fake_loss - else: - total_loss, real_loss, fake_loss = self.hinge_loss(scores_fake, scores_real) - hinge_gan_loss = total_loss - hinge_gan_real_loss = real_loss - hinge_gan_fake_loss = fake_loss - return_dict['D_hinge_gan_loss'] = hinge_gan_loss - return_dict['D_hinge_gan_real_loss'] = hinge_gan_real_loss - return_dict['D_hinge_gan_fake_loss'] = hinge_gan_fake_loss - loss += self.hinge_gan_loss_weight * hinge_gan_loss + hinge_D_loss, hinge_D_real_loss, hinge_D_fake_loss = _apply_D_loss(scores_fake, scores_real, self.hinge_loss) + return_dict['D_hinge_gan_loss'] = hinge_D_loss + return_dict['D_hinge_gan_real_loss'] = hinge_D_real_loss + return_dict['D_hinge_gan_fake_loss'] = hinge_D_fake_loss + loss += hinge_D_loss return_dict['D_loss'] = loss return return_dict \ No newline at end of file From be861d7aa0ebfa0d926f579c4d9793314aac2808 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 3 Jun 2020 12:33:53 +0200 Subject: [PATCH 037/185] suppress pylint no-self-use for loss layers --- vocoder/layers/losses.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index fb4e85d4..22e2fb54 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -77,6 +77,7 @@ class MultiScaleSTFTLoss(torch.nn.Module): class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): """ Multiscale STFT loss for multi band model outputs """ + # pylint: disable=no-self-use def forward(self, y_hat, y): y_hat = y_hat.view(-1, 1, y_hat.shape[2]) y = y.view(-1, 1, y.shape[2]) @@ -85,6 +86,7 @@ class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake): loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) return loss_fake @@ -92,6 +94,7 @@ class MSEGLoss(nn.Module): class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake): loss_fake = torch.mean(F.relu(1. + score_fake)) return loss_fake @@ -104,6 +107,7 @@ class HingeGLoss(nn.Module): class MSEDLoss(nn.Module): """ Mean Squared Discriminator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake, score_real): loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) @@ -113,6 +117,7 @@ class MSEDLoss(nn.Module): class HingeDLoss(nn.Module): """ Hinge Discriminator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake, score_real): loss_real = torch.mean(F.relu(1. - score_real)) loss_fake = torch.mean(F.relu(1. + score_fake)) @@ -121,6 +126,7 @@ class HingeDLoss(nn.Module): class MelganFeatureLoss(nn.Module): + # pylint: disable=no-self-use def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): From ed466c8581058d5d9eeaffd237344270ba1328c7 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 02:58:25 +0200 Subject: [PATCH 038/185] update README.md --- README.md | 8 +++++--- vocoder/train.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7d9884b0..20799943 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,11 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- [Details...](https://github.com/mozilla/TTS/wiki/Mean-Opinion-Score-Results) ## Features -- High performance Text2Speech models on Torch and Tensorflow 2.0. -- High performance Speaker Encoder to compute speaker embeddings efficiently. -- Integration with various Neural Vocoders (PWGAN, MelGAN, WaveRNN) +- High performance Deep Learning models for Text2Speech related tasks. + - Text2Speech models (Tacotron, Tacotron2). + - Speaker Encoder to compute speaker embeddings efficiently. + - Vocoder models (MelGAN, Multiband-MelGAN, GAN-TTS) +- Ability to convert Torch models to Tensorflow 2.0 for inference. - Released trained models. - Efficient training codes for PyTorch. (soon for Tensorflow 2.0) - Codes to convert Torch models to Tensorflow 2.0. diff --git a/vocoder/train.py b/vocoder/train.py index d401e72e..03e14f4a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -52,7 +52,7 @@ def setup_loader(ap, is_val=False, verbose=False): # sampler = DistributedSampler(dataset) if num_gpus > 1 else None loader = DataLoader(dataset, batch_size=1 if is_val else c.batch_size, - shuffle=False, + shuffle=True, drop_last=False, sampler=None, num_workers=c.num_val_loader_workers From 2b361f0b50daed9e4555d7c09f371ba201564ed7 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 09:51:20 +0200 Subject: [PATCH 039/185] visualization fix --- vocoder/train.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 03e14f4a..a75c6a12 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -120,11 +120,13 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, y_hat = model_G(c_G) y_hat_sub = None y_G_sub = None + y_hat_vis = y_hat # for visualization # PQMF formatting if y_hat.shape[1] > 1: y_hat_sub = y_hat y_hat = model_G.pqmf_synthesis(y_hat) + y_hat_vis = y_hat y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: @@ -265,12 +267,12 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, model_losses=loss_dict) # compute spectrograms - figures = plot_results(y_hat, y_G, ap, global_step, + figures = plot_results(y_hat_vis, y_G, ap, global_step, 'train') tb_logger.tb_train_figures(global_step, figures) # Sample audio - sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() + sample_voice = y_hat_vis[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_train_audios(global_step, {'train/audio': sample_voice}, c.audio["sample_rate"]) From 1de68250407cb1b711d22fcd00018d912eb09849 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:26:30 +0200 Subject: [PATCH 040/185] tacotron abstract class --- models/tacotron_abstract.py | 160 ++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 models/tacotron_abstract.py diff --git a/models/tacotron_abstract.py b/models/tacotron_abstract.py new file mode 100644 index 00000000..db6cbdee --- /dev/null +++ b/models/tacotron_abstract.py @@ -0,0 +1,160 @@ +import copy +from abc import ABC, abstractmethod + +import torch +from torch import nn + +from TTS.layers.gst_layers import GST +from TTS.utils.generic_utils import sequence_mask + + +class TacotronAbstract(ABC, nn.Module): + def __init__(self, num_chars, + num_speakers, + r, + postnet_output_dim=80, + decoder_output_dim=80, + attn_type='original', + attn_win=False, + attn_norm="softmax", + prenet_type="original", + prenet_dropout=True, + forward_attn=False, + trans_agent=False, + forward_attn_mask=False, + location_attn=True, + attn_K=5, + separate_stopnet=True, + bidirectional_decoder=False, + double_decoder_consistency=False, + ddc_r=None, + gst=False): + """ Abstract Tacotron class """ + super().__init__() + self.r = r + self.decoder_output_dim = decoder_output_dim + self.postnet_output_dim = postnet_output_dim + self.gst = gst + self.num_speakers = num_speakers + self.bidirectional_decoder = bidirectional_decoder + self.double_decoder_consistency = double_decoder_consistency + self.ddc_r = ddc_r + + # layers + self.embedding = None + self.encoder = None + self.decoder = None + self.postnet = None + + # global style token + if self.gst: + gst_embedding_dim = None + self.gst_layer = None + + ############################# + # INIT FUNCTIONS + ############################# + + def _init_states(self): + self.speaker_embeddings = None + self.speaker_embeddings_projected = None + + def _init_backward_decoder(self): + self.decoder_backward = copy.deepcopy(self.decoder) + + def _init_coarse_decoder(self): + self.coarse_decoder = copy.deepcopy(self.decoder) + self.coarse_decoder.r_init = self.ddc_r + self.coarse_decoder.set_r(self.ddc_r) + + ############################# + # CORE FUNCTIONS + ############################# + + @abstractmethod + def forward(self): + pass + + @abstractmethod + def inference(self): + pass + + ############################# + # COMMON COMPUTE FUNCTIONS + ############################# + + def compute_masks(self, text_lengths, mel_lengths): + """Compute masks against sequence paddings.""" + # B x T_in_max (boolean) + device = text_lengths.device + input_mask = sequence_mask(text_lengths).to(device) + output_mask = None + if mel_lengths is not None: + max_len = mel_lengths.max() + r = self.decoder.r + max_len = max_len + (r - (max_len % r)) if max_len % r > 0 else max_len + output_mask = sequence_mask(mel_lengths, max_len=max_len).to(device) + return input_mask, output_mask + + def _backward_pass(self, mel_specs, encoder_outputs, mask): + """ Run backwards decoder """ + decoder_outputs_b, alignments_b, _ = self.decoder_backward( + encoder_outputs, torch.flip(mel_specs, dims=(1,)), mask, + self.speaker_embeddings_projected) + decoder_outputs_b = decoder_outputs_b.transpose(1, 2).contiguous() + return decoder_outputs_b, alignments_b + + def _coarse_decoder_pass(self, mel_specs, encoder_outputs, alignments, + input_mask): + """ Double Decoder Consistency """ + T = mel_specs.shape[1] + if T % self.coarse_decoder.r > 0: + padding_size = self.coarse_decoder.r - (T % self.coarse_decoder.r) + mel_specs = torch.nn.functional.pad(mel_specs, + (0, 0, 0, padding_size, 0, 0)) + decoder_outputs_backward, alignments_backward, _ = self.coarse_decoder( + encoder_outputs.detach(), mel_specs, input_mask) + scale_factor = self.decoder.r_init / self.decoder.r + alignments_backward = torch.nn.functional.interpolate( + alignments_backward.transpose(1, 2), + size=alignments.shape[1], + mode='nearest').transpose(1, 2) + decoder_outputs_backward = decoder_outputs_backward.transpose(1, 2) + decoder_outputs_backward = decoder_outputs_backward[:, :T, :] + return decoder_outputs_backward, alignments_backward + + ############################# + # EMBEDDING FUNCTIONS + ############################# + + def compute_speaker_embedding(self, speaker_ids): + """ Compute speaker embedding vectors """ + if hasattr(self, "speaker_embedding") and speaker_ids is None: + raise RuntimeError( + " [!] Model has speaker embedding layer but speaker_id is not provided" + ) + if hasattr(self, "speaker_embedding") and speaker_ids is not None: + self.speaker_embeddings = self.speaker_embedding(speaker_ids).unsqueeze(1) + if hasattr(self, "speaker_project_mel") and speaker_ids is not None: + self.speaker_embeddings_projected = self.speaker_project_mel( + self.speaker_embeddings).squeeze(1) + + def compute_gst(self, inputs, mel_specs): + """ Compute global style token """ + gst_outputs = self.gst_layer(mel_specs) + inputs = self._add_speaker_embedding(inputs, gst_outputs) + return inputs + + @staticmethod + def _add_speaker_embedding(outputs, speaker_embeddings): + speaker_embeddings_ = speaker_embeddings.expand( + outputs.size(0), outputs.size(1), -1) + outputs = outputs + speaker_embeddings_ + return outputs + + @staticmethod + def _concat_speaker_embedding(outputs, speaker_embeddings): + speaker_embeddings_ = speaker_embeddings.expand( + outputs.size(0), outputs.size(1), -1) + outputs = torch.cat([outputs, speaker_embeddings_], dim=-1) + return outputs From ef2369e0dac6eaa88489611c925bc929bc31571f Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:26:51 +0200 Subject: [PATCH 041/185] update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 20799943..f6ee1ade 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- [![](https://sourcerer.io/fame/erogol/erogol/TTS/images/0)](https://sourcerer.io/fame/erogol/erogol/TTS/links/0)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/1)](https://sourcerer.io/fame/erogol/erogol/TTS/links/1)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/2)](https://sourcerer.io/fame/erogol/erogol/TTS/links/2)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/3)](https://sourcerer.io/fame/erogol/erogol/TTS/links/3)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/4)](https://sourcerer.io/fame/erogol/erogol/TTS/links/4)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/5)](https://sourcerer.io/fame/erogol/erogol/TTS/links/5)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/6)](https://sourcerer.io/fame/erogol/erogol/TTS/links/6)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/7)](https://sourcerer.io/fame/erogol/erogol/TTS/links/7) -## TTS Performance +## TTS Performance

[Details...](https://github.com/mozilla/TTS/wiki/Mean-Opinion-Score-Results) @@ -19,8 +19,9 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- ## Features - High performance Deep Learning models for Text2Speech related tasks. - Text2Speech models (Tacotron, Tacotron2). - - Speaker Encoder to compute speaker embeddings efficiently. + - Speaker Encoder to compute speaker embeddings efficiently. - Vocoder models (MelGAN, Multiband-MelGAN, GAN-TTS) +- Support for multi-speaker TTS training. - Ability to convert Torch models to Tensorflow 2.0 for inference. - Released trained models. - Efficient training codes for PyTorch. (soon for Tensorflow 2.0) @@ -86,7 +87,7 @@ Audio length is approximately 6 secs. ## Datasets and Data-Loading -TTS provides a generic dataloder easy to use for new datasets. You need to write an preprocessor function to integrate your own dataset.Check ```datasets/preprocess.py``` to see some examples. After the function, you need to set ```dataset``` field in ```config.json```. Do not forget other data related fields too. +TTS provides a generic dataloder easy to use for new datasets. You need to write an preprocessor function to integrate your own dataset.Check ```datasets/preprocess.py``` to see some examples. After the function, you need to set ```dataset``` field in ```config.json```. Do not forget other data related fields too. Some of the open-sourced datasets that we successfully applied TTS, are linked below. @@ -98,9 +99,9 @@ Some of the open-sourced datasets that we successfully applied TTS, are linked b - [Spanish](https://drive.google.com/file/d/1Sm_zyBo67XHkiFhcRSQ4YaHPYM0slO_e/view?usp=sharing) - thx! @carlfm01 ## Training and Fine-tuning LJ-Speech -Here you can find a [CoLab](https://gist.github.com/erogol/97516ad65b44dbddb8cd694953187c5b) notebook for a hands-on example, training LJSpeech. Or you can manually follow the guideline below. +Here you can find a [CoLab](https://gist.github.com/erogol/97516ad65b44dbddb8cd694953187c5b) notebook for a hands-on example, training LJSpeech. Or you can manually follow the guideline below. -To start with, split ```metadata.csv``` into train and validation subsets respectively ```metadata_train.csv``` and ```metadata_val.csv```. Note that for text-to-speech, validation performance might be misleading since the loss value does not directly measure the voice quality to the human ear and it also does not measure the attention module performance. Therefore, running the model with new sentences and listening to the results is the best way to go. +To start with, split ```metadata.csv``` into train and validation subsets respectively ```metadata_train.csv``` and ```metadata_val.csv```. Note that for text-to-speech, validation performance might be misleading since the loss value does not directly measure the voice quality to the human ear and it also does not measure the attention module performance. Therefore, running the model with new sentences and listening to the results is the best way to go. ``` shuf metadata.csv > metadata_shuf.csv @@ -139,10 +140,10 @@ cardboardlinter --refspec master ``` ## Collaborative Experimentation Guide -If you like to use TTS to try a new idea and like to share your experiments with the community, we urge you to use the following guideline for a better collaboration. +If you like to use TTS to try a new idea and like to share your experiments with the community, we urge you to use the following guideline for a better collaboration. (If you have an idea for better collaboration, let us know) - Create a new branch. -- Open an issue pointing your branch. +- Open an issue pointing your branch. - Explain your experiment. - Share your results as you proceed. (Tensorboard log files, audio results, visuals etc.) - Use LJSpeech dataset (for English) if you like to compare results with the released models. (It is the most open scalable dataset for quick experimentation) From 1ca078ae7e06ab9ccb79cf6022ad56052db84964 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:27:06 +0200 Subject: [PATCH 042/185] update model config.json with double decoder consistency --- config.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.json b/config.json index 32debf86..74021970 100644 --- a/config.json +++ b/config.json @@ -96,6 +96,8 @@ "transition_agent": false, // enable/disable transition agent of forward attention. "location_attn": true, // enable_disable location sensitive attention. It is enabled for TACOTRON by default. "bidirectional_decoder": false, // use https://arxiv.org/abs/1907.09006. Use it, if attention does not work well with your dataset. + "double_decoder_consistency": true, // use DDC explained here https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency-draft/ + "ddc_r": 7, // reduction rate for coarse decoder. // STOPNET "stopnet": true, // Train stopnet predicting the end of synthesis. From b4ac68df7ba1f50c3f8f40cd61962a773367a661 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:27:40 +0200 Subject: [PATCH 043/185] add DDC loss --- layers/losses.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/layers/losses.py b/layers/losses.py index 608e247d..f7745b6e 100644 --- a/layers/losses.py +++ b/layers/losses.py @@ -184,7 +184,7 @@ class TacotronLoss(torch.nn.Module): def forward(self, postnet_output, decoder_output, mel_input, linear_input, stopnet_output, stopnet_target, output_lens, decoder_b_output, - alignments, alignment_lens, input_lens): + alignments, alignment_lens, alignments_backwards, input_lens): return_dict = {} # decoder and postnet losses @@ -226,6 +226,15 @@ class TacotronLoss(torch.nn.Module): return_dict['decoder_b_loss'] = decoder_b_loss return_dict['decoder_c_loss'] = decoder_c_loss + # double decoder consistency loss (if enabled) + if self.config.double_decoder_consistency: + decoder_b_loss = self.criterion(decoder_b_output, mel_input, output_lens) + # decoder_c_loss = torch.nn.functional.l1_loss(decoder_b_output, decoder_output) + attention_c_loss = torch.nn.functional.l1_loss(alignments, alignments_backwards) + loss += decoder_b_loss + attention_c_loss + return_dict['decoder_coarse_loss'] = decoder_b_loss + return_dict['decoder_ddc_loss'] = attention_c_loss + # guided attention loss (if enabled) if self.config.ga_alpha > 0: ga_loss = self.criterion_ga(alignments, input_lens, alignment_lens) From bd7237d916823ffd9d3832360aa057b5203947b2 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:28:16 +0200 Subject: [PATCH 044/185] inherit TacotronAbstact with both tacotron and tacotron2 --- models/tacotron.py | 135 ++++++++++++++++++------------------------- models/tacotron2.py | 136 ++++++++++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 129 deletions(-) diff --git a/models/tacotron.py b/models/tacotron.py index fba82b1b..c526374a 100644 --- a/models/tacotron.py +++ b/models/tacotron.py @@ -1,23 +1,21 @@ # coding: utf-8 import torch -import copy from torch import nn -from TTS.layers.tacotron import Encoder, Decoder, PostCBHG -from TTS.utils.generic_utils import sequence_mask + from TTS.layers.gst_layers import GST +from TTS.layers.tacotron import Decoder, Encoder, PostCBHG +from TTS.models.tacotron_abstract import TacotronAbstract -class Tacotron(nn.Module): +class Tacotron(TacotronAbstract): def __init__(self, num_chars, num_speakers, r=5, postnet_output_dim=1025, decoder_output_dim=80, - memory_size=5, attn_type='original', attn_win=False, - gst=False, attn_norm="sigmoid", prenet_type="original", prenet_dropout=True, @@ -27,38 +25,41 @@ class Tacotron(nn.Module): location_attn=True, attn_K=5, separate_stopnet=True, - bidirectional_decoder=False): - super(Tacotron, self).__init__() - self.r = r - self.decoder_output_dim = decoder_output_dim - self.postnet_output_dim = postnet_output_dim - self.gst = gst - self.num_speakers = num_speakers - self.bidirectional_decoder = bidirectional_decoder - decoder_dim = 512 if num_speakers > 1 else 256 - encoder_dim = 512 if num_speakers > 1 else 256 + bidirectional_decoder=False, + double_decoder_consistency=False, + ddc_r=None, + gst=False, + memory_size=5): + super(Tacotron, + self).__init__(num_chars, num_speakers, r, postnet_output_dim, + decoder_output_dim, attn_type, attn_win, + attn_norm, prenet_type, prenet_dropout, + forward_attn, trans_agent, forward_attn_mask, + location_attn, attn_K, separate_stopnet, + bidirectional_decoder, double_decoder_consistency, + ddc_r, gst) + decoder_in_features = 512 if num_speakers > 1 else 256 + encoder_in_features = 512 if num_speakers > 1 else 256 + speaker_embedding_dim = 256 proj_speaker_dim = 80 if num_speakers > 1 else 0 - # embedding layer + # base model layers self.embedding = nn.Embedding(num_chars, 256, padding_idx=0) self.embedding.weight.data.normal_(0, 0.3) - # boilerplate model - self.encoder = Encoder(encoder_dim) - self.decoder = Decoder(decoder_dim, decoder_output_dim, r, memory_size, attn_type, attn_win, + self.encoder = Encoder(encoder_in_features) + self.decoder = Decoder(decoder_in_features, decoder_output_dim, r, memory_size, attn_type, attn_win, attn_norm, prenet_type, prenet_dropout, forward_attn, trans_agent, forward_attn_mask, location_attn, attn_K, separate_stopnet, proj_speaker_dim) - if self.bidirectional_decoder: - self.decoder_backward = copy.deepcopy(self.decoder) self.postnet = PostCBHG(decoder_output_dim) self.last_linear = nn.Linear(self.postnet.cbhg.gru_features * 2, postnet_output_dim) # speaker embedding layers if num_speakers > 1: - self.speaker_embedding = nn.Embedding(num_speakers, 256) + self.speaker_embedding = nn.Embedding(num_speakers, speaker_embedding_dim) self.speaker_embedding.weight.data.normal_(0, 0.3) self.speaker_project_mel = nn.Sequential( - nn.Linear(256, proj_speaker_dim), nn.Tanh()) + nn.Linear(speaker_embedding_dim, proj_speaker_dim), nn.Tanh()) self.speaker_embeddings = None self.speaker_embeddings_projected = None # global style token layers @@ -68,28 +69,15 @@ class Tacotron(nn.Module): num_heads=4, num_style_tokens=10, embedding_dim=gst_embedding_dim) + # backward pass decoder + if self.bidirectional_decoder: + self._init_backward_decoder() + # setup DDC + if self.double_decoder_consistency: + self._init_coarse_decoder() - def _init_states(self): - self.speaker_embeddings = None - self.speaker_embeddings_projected = None - def compute_speaker_embedding(self, speaker_ids): - if hasattr(self, "speaker_embedding") and speaker_ids is None: - raise RuntimeError( - " [!] Model has speaker embedding layer but speaker_id is not provided" - ) - if hasattr(self, "speaker_embedding") and speaker_ids is not None: - self.speaker_embeddings = self._compute_speaker_embedding( - speaker_ids) - self.speaker_embeddings_projected = self.speaker_project_mel( - self.speaker_embeddings).squeeze(1) - - def compute_gst(self, inputs, mel_specs): - gst_outputs = self.gst_layer(mel_specs) - inputs = self._add_speaker_embedding(inputs, gst_outputs) - return inputs - - def forward(self, characters, text_lengths, mel_specs, speaker_ids=None): + def forward(self, characters, text_lengths, mel_specs, mel_lengths=None, speaker_ids=None): """ Shapes: - characters: B x T_in @@ -98,45 +86,59 @@ class Tacotron(nn.Module): - speaker_ids: B x 1 """ self._init_states() - mask = sequence_mask(text_lengths).to(characters.device) + input_mask, output_mask = self.compute_masks(text_lengths, mel_lengths) # B x T_in x embed_dim inputs = self.embedding(characters) # B x speaker_embed_dim - self.compute_speaker_embedding(speaker_ids) + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) if self.num_speakers > 1: # B x T_in x embed_dim + speaker_embed_dim inputs = self._concat_speaker_embedding(inputs, self.speaker_embeddings) - # B x T_in x encoder_dim + # B x T_in x encoder_in_features encoder_outputs = self.encoder(inputs) + # sequence masking + encoder_outputs = encoder_outputs * input_mask.unsqueeze(2).expand_as(encoder_outputs) + # global style token if self.gst: # B x gst_dim encoder_outputs = self.compute_gst(encoder_outputs, mel_specs) if self.num_speakers > 1: encoder_outputs = self._concat_speaker_embedding( encoder_outputs, self.speaker_embeddings) - # decoder_outputs: B x decoder_dim x T_out - # alignments: B x T_in x encoder_dim + # decoder_outputs: B x decoder_in_features x T_out + # alignments: B x T_in x encoder_in_features # stop_tokens: B x T_in decoder_outputs, alignments, stop_tokens = self.decoder( - encoder_outputs, mel_specs, mask, + encoder_outputs, mel_specs, input_mask, self.speaker_embeddings_projected) - # B x T_out x decoder_dim + # sequence masking + if output_mask is not None: + decoder_outputs = decoder_outputs * output_mask.unsqueeze(1).expand_as(decoder_outputs) + # B x T_out x decoder_in_features postnet_outputs = self.postnet(decoder_outputs) + # sequence masking + if output_mask is not None: + postnet_outputs = postnet_outputs * output_mask.unsqueeze(2).expand_as(postnet_outputs) # B x T_out x posnet_dim postnet_outputs = self.last_linear(postnet_outputs) - # B x T_out x decoder_dim + # B x T_out x decoder_in_features decoder_outputs = decoder_outputs.transpose(1, 2).contiguous() if self.bidirectional_decoder: - decoder_outputs_backward, alignments_backward = self._backward_inference(mel_specs, encoder_outputs, mask) + decoder_outputs_backward, alignments_backward = self._backward_pass(mel_specs, encoder_outputs, input_mask) return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward + if self.double_decoder_consistency: + decoder_outputs_backward, alignments_backward = self._coarse_decoder_pass(mel_specs, encoder_outputs, alignments, input_mask) + return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward return decoder_outputs, postnet_outputs, alignments, stop_tokens @torch.no_grad() def inference(self, characters, speaker_ids=None, style_mel=None): inputs = self.embedding(characters) self._init_states() - self.compute_speaker_embedding(speaker_ids) + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) if self.num_speakers > 1: inputs = self._concat_speaker_embedding(inputs, self.speaker_embeddings) @@ -152,28 +154,3 @@ class Tacotron(nn.Module): postnet_outputs = self.last_linear(postnet_outputs) decoder_outputs = decoder_outputs.transpose(1, 2) return decoder_outputs, postnet_outputs, alignments, stop_tokens - - def _backward_inference(self, mel_specs, encoder_outputs, mask): - decoder_outputs_b, alignments_b, _ = self.decoder_backward( - encoder_outputs, torch.flip(mel_specs, dims=(1,)), mask, - self.speaker_embeddings_projected) - decoder_outputs_b = decoder_outputs_b.transpose(1, 2).contiguous() - return decoder_outputs_b, alignments_b - - def _compute_speaker_embedding(self, speaker_ids): - speaker_embeddings = self.speaker_embedding(speaker_ids) - return speaker_embeddings.unsqueeze_(1) - - @staticmethod - def _add_speaker_embedding(outputs, speaker_embeddings): - speaker_embeddings_ = speaker_embeddings.expand( - outputs.size(0), outputs.size(1), -1) - outputs = outputs + speaker_embeddings_ - return outputs - - @staticmethod - def _concat_speaker_embedding(outputs, speaker_embeddings): - speaker_embeddings_ = speaker_embeddings.expand( - outputs.size(0), outputs.size(1), -1) - outputs = torch.cat([outputs, speaker_embeddings_], dim=-1) - return outputs diff --git a/models/tacotron2.py b/models/tacotron2.py index 3e7adfca..bbce4be9 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -1,13 +1,15 @@ -import copy -import torch from math import sqrt + +import torch from torch import nn -from TTS.layers.tacotron2 import Encoder, Decoder, Postnet -from TTS.utils.generic_utils import sequence_mask + +from TTS.layers.gst_layers import GST +from TTS.layers.tacotron2 import Decoder, Encoder, Postnet +from TTS.models.tacotron_abstract import TacotronAbstract # TODO: match function arguments with tacotron -class Tacotron2(nn.Module): +class Tacotron2(TacotronAbstract): def __init__(self, num_chars, num_speakers, @@ -25,16 +27,22 @@ class Tacotron2(nn.Module): location_attn=True, attn_K=5, separate_stopnet=True, - bidirectional_decoder=False): - super(Tacotron2, self).__init__() - self.postnet_output_dim = postnet_output_dim - self.decoder_output_dim = decoder_output_dim - self.r = r - self.bidirectional_decoder = bidirectional_decoder - decoder_dim = 512 if num_speakers > 1 else 512 - encoder_dim = 512 if num_speakers > 1 else 512 + bidirectional_decoder=False, + double_decoder_consistency=False, + ddc_r=None, + gst=False): + super(Tacotron2, + self).__init__(num_chars, num_speakers, r, postnet_output_dim, + decoder_output_dim, attn_type, attn_win, + attn_norm, prenet_type, prenet_dropout, + forward_attn, trans_agent, forward_attn_mask, + location_attn, attn_K, separate_stopnet, + bidirectional_decoder, double_decoder_consistency, + ddc_r, gst) + decoder_in_features = 512 if num_speakers > 1 else 512 + encoder_in_features = 512 if num_speakers > 1 else 512 proj_speaker_dim = 80 if num_speakers > 1 else 0 - # embedding layer + # base layers self.embedding = nn.Embedding(num_chars, 512, padding_idx=0) std = sqrt(2.0 / (num_chars + 512)) val = sqrt(3.0) * std # uniform bounds for std @@ -42,20 +50,25 @@ class Tacotron2(nn.Module): if num_speakers > 1: self.speaker_embedding = nn.Embedding(num_speakers, 512) self.speaker_embedding.weight.data.normal_(0, 0.3) - self.speaker_embeddings = None - self.speaker_embeddings_projected = None - self.encoder = Encoder(encoder_dim) - self.decoder = Decoder(decoder_dim, self.decoder_output_dim, r, attn_type, attn_win, + self.encoder = Encoder(encoder_in_features) + self.decoder = Decoder(decoder_in_features, self.decoder_output_dim, r, attn_type, attn_win, attn_norm, prenet_type, prenet_dropout, forward_attn, trans_agent, forward_attn_mask, location_attn, attn_K, separate_stopnet, proj_speaker_dim) - if self.bidirectional_decoder: - self.decoder_backward = copy.deepcopy(self.decoder) self.postnet = Postnet(self.postnet_output_dim) - - def _init_states(self): - self.speaker_embeddings = None - self.speaker_embeddings_projected = None + # global style token layers + if self.gst: + gst_embedding_dim = encoder_in_features + self.gst_layer = GST(num_mel=80, + num_heads=4, + num_style_tokens=10, + embedding_dim=gst_embedding_dim) + # backward pass decoder + if self.bidirectional_decoder: + self._init_backward_decoder() + # setup DDC + if self.double_decoder_consistency: + self._init_coarse_decoder() @staticmethod def shape_outputs(mel_outputs, mel_outputs_postnet, alignments): @@ -63,31 +76,60 @@ class Tacotron2(nn.Module): mel_outputs_postnet = mel_outputs_postnet.transpose(1, 2) return mel_outputs, mel_outputs_postnet, alignments - def forward(self, text, text_lengths, mel_specs=None, speaker_ids=None): + def forward(self, text, text_lengths, mel_specs=None, mel_lengths=None, speaker_ids=None): self._init_states() # compute mask for padding - mask = sequence_mask(text_lengths).to(text.device) + # B x T_in_max (boolean) + input_mask, output_mask = self.compute_masks(text_lengths, mel_lengths) + # B x D_embed x T_in_max embedded_inputs = self.embedding(text).transpose(1, 2) + # B x T_in_max x D_en encoder_outputs = self.encoder(embedded_inputs, text_lengths) - encoder_outputs = self._add_speaker_embedding(encoder_outputs, - speaker_ids) + # adding speaker embeddding to encoder output + # TODO: multi-speaker + # B x speaker_embed_dim + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) + if self.num_speakers > 1: + # B x T_in x embed_dim + speaker_embed_dim + encoder_outputs = self._add_speaker_embedding(encoder_outputs, + self.speaker_embeddings) + encoder_outputs = encoder_outputs * input_mask.unsqueeze(2).expand_as(encoder_outputs) + # global style token + if self.gst: + # B x gst_dim + encoder_outputs = self.compute_gst(encoder_outputs, mel_specs) + # B x mel_dim x T_out -- B x T_out//r x T_in -- B x T_out//r decoder_outputs, alignments, stop_tokens = self.decoder( - encoder_outputs, mel_specs, mask) + encoder_outputs, mel_specs, input_mask) + # sequence masking + if mel_lengths is not None: + decoder_outputs = decoder_outputs * output_mask.unsqueeze(1).expand_as(decoder_outputs) + # B x mel_dim x T_out postnet_outputs = self.postnet(decoder_outputs) - postnet_outputs = decoder_outputs + postnet_outputs + # sequence masking + if output_mask is not None: + postnet_outputs = postnet_outputs * output_mask.unsqueeze(1).expand_as(postnet_outputs) + # B x T_out x mel_dim -- B x T_out x mel_dim -- B x T_out//r x T_in decoder_outputs, postnet_outputs, alignments = self.shape_outputs( decoder_outputs, postnet_outputs, alignments) if self.bidirectional_decoder: - decoder_outputs_backward, alignments_backward = self._backward_inference(mel_specs, encoder_outputs, mask) + decoder_outputs_backward, alignments_backward = self._backward_pass(mel_specs, encoder_outputs, input_mask) return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward + if self.double_decoder_consistency: + decoder_outputs_backward, alignments_backward = self._coarse_decoder_pass(mel_specs, encoder_outputs, alignments, input_mask) + return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward return decoder_outputs, postnet_outputs, alignments, stop_tokens @torch.no_grad() def inference(self, text, speaker_ids=None): embedded_inputs = self.embedding(text).transpose(1, 2) encoder_outputs = self.encoder.inference(embedded_inputs) - encoder_outputs = self._add_speaker_embedding(encoder_outputs, - speaker_ids) + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) + if self.num_speakers > 1: + encoder_outputs = self._add_speaker_embedding(encoder_outputs, + self.speaker_embeddings) mel_outputs, alignments, stop_tokens = self.decoder.inference( encoder_outputs) mel_outputs_postnet = self.postnet(mel_outputs) @@ -112,22 +154,16 @@ class Tacotron2(nn.Module): mel_outputs, mel_outputs_postnet, alignments) return mel_outputs, mel_outputs_postnet, alignments, stop_tokens - def _backward_inference(self, mel_specs, encoder_outputs, mask): - decoder_outputs_b, alignments_b, _ = self.decoder_backward( - encoder_outputs, torch.flip(mel_specs, dims=(1,)), mask, - self.speaker_embeddings_projected) - decoder_outputs_b = decoder_outputs_b.transpose(1, 2) - return decoder_outputs_b, alignments_b - def _add_speaker_embedding(self, encoder_outputs, speaker_ids): - if hasattr(self, "speaker_embedding") and speaker_ids is None: - raise RuntimeError(" [!] Model has speaker embedding layer but speaker_id is not provided") - if hasattr(self, "speaker_embedding") and speaker_ids is not None: - speaker_embeddings = self.speaker_embedding(speaker_ids) + def _speaker_embedding_pass(self, encoder_outputs, speaker_ids): + # TODO: multi-speaker + # if hasattr(self, "speaker_embedding") and speaker_ids is None: + # raise RuntimeError(" [!] Model has speaker embedding layer but speaker_id is not provided") + # if hasattr(self, "speaker_embedding") and speaker_ids is not None: - speaker_embeddings.unsqueeze_(1) - speaker_embeddings = speaker_embeddings.expand(encoder_outputs.size(0), - encoder_outputs.size(1), - -1) - encoder_outputs = encoder_outputs + speaker_embeddings - return encoder_outputs + # speaker_embeddings = speaker_embeddings.expand(encoder_outputs.size(0), + # encoder_outputs.size(1), + # -1) + # encoder_outputs = encoder_outputs + speaker_embeddings + # return encoder_outputs + pass From e272e07ce99f6789dbf5461e3daec1e3b4bc3fc3 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:28:55 +0200 Subject: [PATCH 045/185] update dummy model config --- tests/outputs/dummy_model_config.json | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/outputs/dummy_model_config.json b/tests/outputs/dummy_model_config.json index 2f56c6ce..d301b61a 100644 --- a/tests/outputs/dummy_model_config.json +++ b/tests/outputs/dummy_model_config.json @@ -4,7 +4,7 @@ "audio":{ // Audio processing parameters - "num_mels": 80, // size of the mel spec frame. + "num_mels": 80, // size of the mel spec frame. "num_freq": 1025, // number of stft frequency levels. Size of the linear spectogram frame. "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. "frame_length_ms": 50, // stft window length in ms. @@ -31,19 +31,19 @@ "reinit_layers": [], - "model": "Tacotron2", // one of the model in models/ + "model": "Tacotron2", // one of the model in models/ "grad_clip": 1, // upper limit for gradients for clipping. "epochs": 1000, // total number of epochs to train. "lr": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. "lr_decay": false, // if true, Noam learning rate decaying is applied through training. "warmup_steps": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "windowing": false, // Enables attention windowing. Used only in eval mode. - "memory_size": 5, // ONLY TACOTRON - memory queue size used to queue network predictions to feed autoregressive connection. Useful if r < 5. + "memory_size": 5, // ONLY TACOTRON - memory queue size used to queue network predictions to feed autoregressive connection. Useful if r < 5. "attention_norm": "sigmoid", // softmax or sigmoid. Suggested to use softmax for Tacotron2 and sigmoid for Tacotron. "prenet_type": "original", // ONLY TACOTRON2 - "original" or "bn". - "prenet_dropout": true, // ONLY TACOTRON2 - enable/disable dropout at prenet. + "prenet_dropout": true, // ONLY TACOTRON2 - enable/disable dropout at prenet. "use_forward_attn": true, // ONLY TACOTRON2 - if it uses forward attention. In general, it aligns faster. - "forward_attn_mask": false, + "forward_attn_mask": false, "attention_type": "original", "attention_heads": 5, "bidirectional_decoder": false, @@ -51,13 +51,15 @@ "location_attn": false, // ONLY TACOTRON2 - enable_disable location sensitive attention. It is enabled for TACOTRON by default. "loss_masking": true, // enable / disable loss masking against the sequence padding. "enable_eos_bos_chars": false, // enable/disable beginning of sentence and end of sentence chars. - "stopnet": true, // Train stopnet predicting the end of synthesis. + "stopnet": true, // Train stopnet predicting the end of synthesis. "separate_stopnet": true, // Train stopnet seperately if 'stopnet==true'. It prevents stopnet loss to influence the rest of the model. It causes a better model, but it trains SLOWER. "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. - "use_gst": false, - + "use_gst": false, + "double_decoder_consistency": true, // use DDC explained here https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency-draft/ + "ddc_r": 7, // reduction rate for coarse decoder. + "batch_size": 32, // Batch size for training. Lower values than 32 might cause hard to learn attention. - "eval_batch_size":16, + "eval_batch_size":16, "r": 1, // Number of frames to predict for step. "wd": 0.000001, // Weight decay weight. "checkpoint": true, // If true, it saves checkpoints per "save_step" From 43d278be2f744cef27bfb25e100f74f0e6952a40 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:29:37 +0200 Subject: [PATCH 046/185] update model tests for ddc --- tests/test_tacotron2_model.py | 2 +- tests/test_tacotron_model.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_tacotron2_model.py b/tests/test_tacotron2_model.py index eb91b3cc..cf1d0778 100644 --- a/tests/test_tacotron2_model.py +++ b/tests/test_tacotron2_model.py @@ -51,7 +51,7 @@ class TacotronTrainTest(unittest.TestCase): optimizer = optim.Adam(model.parameters(), lr=c.lr) for i in range(5): mel_out, mel_postnet_out, align, stop_tokens = model.forward( - input, input_lengths, mel_spec, speaker_ids) + input, input_lengths, mel_spec, mel_lengths, speaker_ids) assert torch.sigmoid(stop_tokens).data.max() <= 1.0 assert torch.sigmoid(stop_tokens).data.min() >= 0.0 optimizer.zero_grad() diff --git a/tests/test_tacotron_model.py b/tests/test_tacotron_model.py index 7053a580..2bbb3c8d 100644 --- a/tests/test_tacotron_model.py +++ b/tests/test_tacotron_model.py @@ -66,7 +66,7 @@ class TacotronTrainTest(unittest.TestCase): optimizer = optim.Adam(model.parameters(), lr=c.lr) for _ in range(5): mel_out, linear_out, align, stop_tokens = model.forward( - input_dummy, input_lengths, mel_spec, speaker_ids) + input_dummy, input_lengths, mel_spec, mel_lengths, speaker_ids) optimizer.zero_grad() loss = criterion(mel_out, mel_spec, mel_lengths) stop_loss = criterion_st(stop_tokens, stop_targets) @@ -95,6 +95,7 @@ class TacotronGSTTrainTest(unittest.TestCase): mel_spec = torch.rand(8, 120, c.audio['num_mels']).to(device) linear_spec = torch.rand(8, 120, c.audio['num_freq']).to(device) mel_lengths = torch.randint(20, 120, (8, )).long().to(device) + mel_lengths[-1] = 120 stop_targets = torch.zeros(8, 120, 1).float().to(device) speaker_ids = torch.randint(0, 5, (8, )).long().to(device) @@ -130,7 +131,7 @@ class TacotronGSTTrainTest(unittest.TestCase): optimizer = optim.Adam(model.parameters(), lr=c.lr) for _ in range(10): mel_out, linear_out, align, stop_tokens = model.forward( - input_dummy, input_lengths, mel_spec, speaker_ids) + input_dummy, input_lengths, mel_spec, mel_lengths, speaker_ids) optimizer.zero_grad() loss = criterion(mel_out, mel_spec, mel_lengths) stop_loss = criterion_st(stop_tokens, stop_targets) From 0f88f8ec5a90ec0cf6cc355e1f45a2a77930deb6 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:30:12 +0200 Subject: [PATCH 047/185] train.py update for DDC --- train.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 5a345b59..612ee8a6 100644 --- a/train.py +++ b/train.py @@ -158,13 +158,14 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, optimizer_st.zero_grad() # forward pass model - if c.bidirectional_decoder: + if c.bidirectional_decoder or c.double_decoder_consistency: decoder_output, postnet_output, alignments, stop_tokens, decoder_backward_output, alignments_backward = model( - text_input, text_lengths, mel_input, speaker_ids=speaker_ids) + text_input, text_lengths, mel_input, mel_lengths, speaker_ids=speaker_ids) else: decoder_output, postnet_output, alignments, stop_tokens = model( - text_input, text_lengths, mel_input, speaker_ids=speaker_ids) + text_input, text_lengths, mel_input, mel_lengths, speaker_ids=speaker_ids) decoder_backward_output = None + alignments_backward = None # set the alignment lengths wrt reduction factor for guided attention if mel_lengths.max() % model.decoder.r != 0: @@ -176,7 +177,8 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, loss_dict = criterion(postnet_output, decoder_output, mel_input, linear_input, stop_tokens, stop_targets, mel_lengths, decoder_backward_output, - alignments, alignment_lengths, text_lengths) + alignments, alignment_lengths, alignments_backward, + text_lengths) if c.bidirectional_decoder: keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_backward_loss'].item(), 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) From 66ec1b2e2a89800a2b7ca93ce0dd50373c2bd99c Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:30:43 +0200 Subject: [PATCH 048/185] setup_model update following TacotronAbstract --- utils/generic_utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 5b135061..3fbe84b1 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -160,13 +160,16 @@ def setup_model(num_chars, num_speakers, c): location_attn=c.location_attn, attn_K=c.attention_heads, separate_stopnet=c.separate_stopnet, - bidirectional_decoder=c.bidirectional_decoder) + bidirectional_decoder=c.bidirectional_decoder, + double_decoder_consistency=c.double_decoder_consistency, + ddc_r=c.ddc_r) elif c.model.lower() == "tacotron2": model = MyModel(num_chars=num_chars, num_speakers=num_speakers, r=c.r, postnet_output_dim=c.audio['num_mels'], decoder_output_dim=c.audio['num_mels'], + gst=c.use_gst, attn_type=c.attention_type, attn_win=c.windowing, attn_norm=c.attention_norm, @@ -178,7 +181,9 @@ def setup_model(num_chars, num_speakers, c): location_attn=c.location_attn, attn_K=c.attention_heads, separate_stopnet=c.separate_stopnet, - bidirectional_decoder=c.bidirectional_decoder) + bidirectional_decoder=c.bidirectional_decoder, + double_decoder_consistency=c.double_decoder_consistency, + ddc_r=c.ddc_r) return model class KeepAverage(): From a82f7d129d7b5c3068d4c19dc86bf93ce09f330a Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:31:17 +0200 Subject: [PATCH 049/185] check DDC parameters in config.json --- utils/generic_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 3fbe84b1..eb6d21a9 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -318,6 +318,8 @@ def check_config(c): _check_argument('transition_agent', c, restricted=True, val_type=bool) _check_argument('location_attn', c, restricted=True, val_type=bool) _check_argument('bidirectional_decoder', c, restricted=True, val_type=bool) + _check_argument('double_decoder_consistency', c, restricted=True, val_type=bool) + _check_argument('ddc_r', c, restricted='double_decoder_consistency' in c.keys(), min_val=1, max_val=7, val_type=int) # stopnet _check_argument('stopnet', c, restricted=True, val_type=bool) From fd8f1ecb7d776918980379b59d79cc94e0970644 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:58:18 +0200 Subject: [PATCH 050/185] lint updates --- models/tacotron_abstract.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/models/tacotron_abstract.py b/models/tacotron_abstract.py index db6cbdee..75a1a5cd 100644 --- a/models/tacotron_abstract.py +++ b/models/tacotron_abstract.py @@ -4,12 +4,12 @@ from abc import ABC, abstractmethod import torch from torch import nn -from TTS.layers.gst_layers import GST from TTS.utils.generic_utils import sequence_mask class TacotronAbstract(ABC, nn.Module): - def __init__(self, num_chars, + def __init__(self, + num_chars, num_speakers, r, postnet_output_dim=80, @@ -31,6 +31,7 @@ class TacotronAbstract(ABC, nn.Module): gst=False): """ Abstract Tacotron class """ super().__init__() + self.num_chars = num_chars self.r = r self.decoder_output_dim = decoder_output_dim self.postnet_output_dim = postnet_output_dim @@ -39,6 +40,17 @@ class TacotronAbstract(ABC, nn.Module): self.bidirectional_decoder = bidirectional_decoder self.double_decoder_consistency = double_decoder_consistency self.ddc_r = ddc_r + self.attn_type = attn_type + self.attn_win = attn_win + self.attn_norm = attn_norm + self.prenet_type = prenet_type + self.prenet_dropout = prenet_dropout + self.forward_attn = forward_attn + self.trans_agent = trans_agent + self.forward_attn_mask = forward_attn_mask + self.location_attn = location_attn + self.attn_K = attn_K + self.separate_stopnet = separate_stopnet # layers self.embedding = None @@ -48,9 +60,16 @@ class TacotronAbstract(ABC, nn.Module): # global style token if self.gst: - gst_embedding_dim = None self.gst_layer = None + # model states + self.speaker_embeddings = None + self.speaker_embeddings_projected = None + + # additional layers + self.decoder_backward = None + self.coarse_decoder = None + ############################# # INIT FUNCTIONS ############################# @@ -114,7 +133,7 @@ class TacotronAbstract(ABC, nn.Module): (0, 0, 0, padding_size, 0, 0)) decoder_outputs_backward, alignments_backward, _ = self.coarse_decoder( encoder_outputs.detach(), mel_specs, input_mask) - scale_factor = self.decoder.r_init / self.decoder.r + # scale_factor = self.decoder.r_init / self.decoder.r alignments_backward = torch.nn.functional.interpolate( alignments_backward.transpose(1, 2), size=alignments.shape[1], @@ -141,6 +160,7 @@ class TacotronAbstract(ABC, nn.Module): def compute_gst(self, inputs, mel_specs): """ Compute global style token """ + # pylint: disable=not-callable gst_outputs = self.gst_layer(mel_specs) inputs = self._add_speaker_embedding(inputs, gst_outputs) return inputs From 189227c7412da63f3f4253e3296c4b95f005ff93 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:23:11 +0200 Subject: [PATCH 051/185] bug fix vocoder training --- vocoder/layers/losses.py | 4 ++-- vocoder/train.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 22e2fb54..a24b129c 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -199,8 +199,8 @@ class GeneratorLoss(nn.Module): self.stft_loss_weight = C.stft_loss_weight self.subband_stft_loss_weight = C.subband_stft_loss_weight - self.mse_gan_loss_weight = C.mse_gan_loss_weight - self.hinge_gan_loss_weight = C.hinge_gan_loss_weight + self.mse_gan_loss_weight = C.mse_G_loss_weight + self.hinge_gan_loss_weight = C.hinge_G_loss_weight self.feat_match_loss_weight = C.feat_match_loss_weight if C.use_stft_loss: diff --git a/vocoder/train.py b/vocoder/train.py index a75c6a12..d1e6befe 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -173,7 +173,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, loss_dict = dict() for key, value in loss_G_dict.items(): - loss_dict[key] = value.item() + if isinstance(value, int): + loss_dict[key] = value + else: + loss_dict[key] = value.item() ############################## # DISCRIMINATOR From c5c3f6094cfe2eadc16d2c970fbe95cb2b3bb917 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:25:53 +0200 Subject: [PATCH 052/185] bug fix for rwd discriminator --- vocoder/train.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index d1e6befe..82f3bee6 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -327,8 +327,12 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): y_hat = model_G.pqmf_synthesis(y_hat) y_G_sub = model_G.pqmf_analysis(y_G) - D_out_fake = model_D(y_hat) + if len(signature(model_D.forward).parameters) == 2: + D_out_fake = model_D(y_hat, c_G) + else: + D_out_fake = model_D(y_hat) D_out_real = None + if c.use_feat_match_loss: with torch.no_grad(): D_out_real = model_D(y_G) From 72fe5a8217f1e28439aec902f72bf8eaff7a7521 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:27:09 +0200 Subject: [PATCH 053/185] correct name --- vocoder/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index 82f3bee6..2c3a2e0a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -363,7 +363,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): for key, value in loss_G_dict.items(): update_eval_values['avg_' + key] = value.item() update_eval_values['avg_loader_time'] = loader_time - update_eval_values['avgP_step_time'] = step_time + update_eval_values['avg_step_time'] = step_time keep_avg.update_values(update_eval_values) # print eval stats From 81af469be053e6109808f2bbd73105ebd410efc8 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:28:16 +0200 Subject: [PATCH 054/185] model config update --- .../multiband-melgan_and_rwd_config.json | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index 9aeb7933..c783877d 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -49,21 +49,28 @@ // LOSS PARAMETERS "use_stft_loss": true, + "use_subband_stft_loss": true, "use_mse_gan_loss": true, "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators - "stft_loss_weight": 1, + "stft_loss_weight": 0.5, + "subband_stft_loss_weight": 0.5, "mse_gan_loss_weight": 2.5, - "hinge_gan_loss_weight": 1, - "feat_match_loss_weight": 10.0, + "hinge_gan_loss_weight": 2.5, + "feat_match_loss_weight": 25.0, "stft_loss_params": { "n_ffts": [1024, 2048, 512], "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240] }, - "target_loss": "avg_G_loss", // loss value to pick the best model + "subband_stft_loss_params":{ + "n_ffts": [384, 683, 171], + "hop_lengths": [30, 60, 10], + "win_lengths": [150, 300, 60] + }, + "target_loss": "avg_G_loss", // DISCRIMINATOR // "discriminator_model": "melgan_multiscale_discriminator", @@ -85,7 +92,7 @@ // GENERATOR "generator_model": "multiband_melgan_generator", "generator_model_params": { - "upsample_factors":[2 ,2, 4, 4], + "upsample_factors":[8, 4, 2], "num_res_blocks": 4 }, @@ -111,7 +118,7 @@ "noam_schedule": false, // use noam warmup and lr schedule. "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "warmup_steps_disc": 4000, - "epochs": 1000, // total number of epochs to train. + "epochs": 100000, // total number of epochs to train. "wd": 0.000001, // Weight decay weight. "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. "lr_disc": 0.0001, @@ -131,6 +138,6 @@ "eval_split_size": 10, // PATHS - "output_path": "/home/erogol/Models/LJSpeech/" + "output_path": "/data/rw/home/Trainings/" } From 79db7d931b213ed9a75d64fe8c5c5e1b27bcd863 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 14:47:25 +0200 Subject: [PATCH 055/185] bug fix for DDC model eval run --- train.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 612ee8a6..13bda5ef 100644 --- a/train.py +++ b/train.py @@ -331,13 +331,14 @@ def evaluate(model, criterion, ap, global_step, epoch): assert mel_input.shape[1] % model.decoder.r == 0 # forward pass model - if c.bidirectional_decoder: + if c.bidirectional_decoder or c.double_decoder_consistency: decoder_output, postnet_output, alignments, stop_tokens, decoder_backward_output, alignments_backward = model( text_input, text_lengths, mel_input, speaker_ids=speaker_ids) else: decoder_output, postnet_output, alignments, stop_tokens = model( text_input, text_lengths, mel_input, speaker_ids=speaker_ids) decoder_backward_output = None + alignments_backward = None # set the alignment lengths wrt reduction factor for guided attention if mel_lengths.max() % model.decoder.r != 0: @@ -349,7 +350,8 @@ def evaluate(model, criterion, ap, global_step, epoch): loss_dict = criterion(postnet_output, decoder_output, mel_input, linear_input, stop_tokens, stop_targets, mel_lengths, decoder_backward_output, - alignments, alignment_lengths, text_lengths) + alignments, alignment_lengths, alignments_backward, + text_lengths) if c.bidirectional_decoder: keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_b_loss'].item(), 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) From b86af6538f7044a0785cde6196c4b42748a6c04e Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 6 Jun 2020 12:59:59 +0200 Subject: [PATCH 056/185] bug fix for TTS model restore --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 13bda5ef..a47828e0 100644 --- a/train.py +++ b/train.py @@ -542,7 +542,7 @@ def main(args): # pylint: disable=redefined-outer-name except: print(" > Partial model initialization.") model_dict = model.state_dict() - model_dict = set_init_dict(model_dict, checkpoint, c) + model_dict = set_init_dict(model_dict, checkpoint['model'], c) model.load_state_dict(model_dict) del model_dict for group in optimizer.param_groups: From fedb2542be72c6f96d10c0b379968337412b24ee Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 6 Jun 2020 13:00:46 +0200 Subject: [PATCH 057/185] bug fix vocoder model restore --- vocoder/configs/multiband-melgan_and_rwd_config.json | 4 ++-- vocoder/train.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index c783877d..736f3459 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -56,8 +56,8 @@ "stft_loss_weight": 0.5, "subband_stft_loss_weight": 0.5, - "mse_gan_loss_weight": 2.5, - "hinge_gan_loss_weight": 2.5, + "mse_G_loss_weight": 2.5, + "hinge_G_loss_weight": 2.5, "feat_match_loss_weight": 25.0, "stft_loss_params": { diff --git a/vocoder/train.py b/vocoder/train.py index 2c3a2e0a..05805c68 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -421,7 +421,7 @@ def main(args): # pylint: disable=redefined-outer-name optimizer_gen.load_state_dict(checkpoint['optimizer']) model_disc.load_state_dict(checkpoint['model_disc']) optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) - except KeyError: + except RuntimeError: print(" > Partial model initialization.") model_dict = model_gen.state_dict() model_dict = set_init_dict(model_dict, checkpoint['model'], c) From 1d3c0c88467d01e114063b54279693b464ac656a Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 6 Jun 2020 13:44:03 +0200 Subject: [PATCH 058/185] raise error if training set is < 100 --- setup.py | 2 +- utils/generic_utils.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 84a31488..a7840568 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ args, unknown_args = parser.parse_known_args() # Remove our arguments from argv so that setuptools doesn't see them sys.argv = [sys.argv[0]] + unknown_args -version = '0.0.2' +version = '0.0.3' # Adapted from https://github.com/pytorch/pytorch cwd = os.path.dirname(os.path.abspath(__file__)) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 1c7dd5e4..298f5970 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -75,6 +75,7 @@ def split_dataset(items): is_multi_speaker = len(set(speakers)) > 1 eval_split_size = 500 if len(items) * 0.01 > 500 else int( len(items) * 0.01) + assert len(eval_split_size) > 0, " [!] You do not have enough samples to train. You need at least 100 samples." np.random.seed(0) np.random.shuffle(items) if is_multi_speaker: From 2404f96cba51bdb642a65296e49bda905ae70830 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 8 Jun 2020 03:22:17 +0200 Subject: [PATCH 059/185] bug fix and var renaming --- models/tacotron2.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/models/tacotron2.py b/models/tacotron2.py index bbce4be9..bce21e9e 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -107,6 +107,7 @@ class Tacotron2(TacotronAbstract): decoder_outputs = decoder_outputs * output_mask.unsqueeze(1).expand_as(decoder_outputs) # B x mel_dim x T_out postnet_outputs = self.postnet(decoder_outputs) + postnet_outputs = decoder_outputs + postnet_outputs # sequence masking if output_mask is not None: postnet_outputs = postnet_outputs * output_mask.unsqueeze(1).expand_as(postnet_outputs) @@ -130,13 +131,13 @@ class Tacotron2(TacotronAbstract): if self.num_speakers > 1: encoder_outputs = self._add_speaker_embedding(encoder_outputs, self.speaker_embeddings) - mel_outputs, alignments, stop_tokens = self.decoder.inference( + decoder_outputs, alignments, stop_tokens = self.decoder.inference( encoder_outputs) - mel_outputs_postnet = self.postnet(mel_outputs) - mel_outputs_postnet = mel_outputs + mel_outputs_postnet - mel_outputs, mel_outputs_postnet, alignments = self.shape_outputs( - mel_outputs, mel_outputs_postnet, alignments) - return mel_outputs, mel_outputs_postnet, alignments, stop_tokens + postnet_outputs = self.postnet(decoder_outputs) + postnet_outputs = decoder_outputs + postnet_outputs + decoder_outputs, postnet_outputs, alignments = self.shape_outputs( + decoder_outputs, postnet_outputs, alignments) + return decoder_outputs, postnet_outputs, alignments, stop_tokens def inference_truncated(self, text, speaker_ids=None): """ From 8d307f21336352949ff56caa29f3e582e4e7a115 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 8 Jun 2020 10:43:09 +0200 Subject: [PATCH 060/185] run D in eval --- vocoder/configs/melgan_config.json | 4 +-- vocoder/train.py | 47 +++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index bdfdf88a..0b6b16db 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -56,8 +56,8 @@ "stft_loss_weight": 0.5, "subband_stft_loss_weight": 0.5, - "mse_gan_loss_weight": 2.5, - "hinge_gan_loss_weight": 2.5, + "mse_G_loss_weight": 2.5, + "hinge_G_loss_weight": 2.5, "feat_match_loss_weight": 25, "stft_loss_params": { diff --git a/vocoder/train.py b/vocoder/train.py index 05805c68..54b36e6b 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -181,7 +181,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, ############################## # DISCRIMINATOR ############################## - if global_step > c.steps_to_start_discriminator: + if global_step >= c.steps_to_start_discriminator: # discriminator pass with torch.no_grad(): y_hat = model_G(c_D) @@ -295,7 +295,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, @torch.no_grad() -def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): +def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch): data_loader = setup_loader(ap, is_val=True, verbose=(epoch == 0)) model_G.eval() model_D.eval() @@ -355,13 +355,52 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): for key, value in loss_G_dict.items(): loss_dict[key] = value.item() + ############################## + # DISCRIMINATOR + ############################## + + if global_step >= c.steps_to_start_discriminator: + # discriminator pass + with torch.no_grad(): + y_hat = model_G(c_G) + + # PQMF formatting + if y_hat.shape[1] > 1: + y_hat = model_G.pqmf_synthesis(y_hat) + + # run D with or without cond. features + if len(signature(model_D.forward).parameters) == 2: + D_out_fake = model_D(y_hat.detach(), c_G) + D_out_real = model_D(y_G, c_G) + else: + D_out_fake = model_D(y_hat.detach()) + D_out_real = model_D(y_G) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + scores_real, feats_real = None, None + else: + scores_real, feats_real = D_out_real + else: + scores_fake = D_out_fake + scores_real = D_out_real + + # compute losses + loss_D_dict = criterion_D(scores_fake, scores_real) + + for key, value in loss_D_dict.items(): + loss_dict[key] = value.item() + + step_time = time.time() - start_time epoch_time += step_time # update avg stats update_eval_values = dict() - for key, value in loss_G_dict.items(): - update_eval_values['avg_' + key] = value.item() + for key, value in loss_dict.items(): + update_eval_values['avg_' + key] = value update_eval_values['avg_loader_time'] = loader_time update_eval_values['avg_step_time'] = step_time keep_avg.update_values(update_eval_values) From dbe381a18647d60f9ee548f11162ec57fc50e5f0 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 8 Jun 2020 10:45:38 +0200 Subject: [PATCH 061/185] linter fix --- models/tacotron2.py | 2 +- train.py | 2 +- vocoder/train.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/models/tacotron2.py b/models/tacotron2.py index bce21e9e..46b915b5 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -130,7 +130,7 @@ class Tacotron2(TacotronAbstract): self.compute_speaker_embedding(speaker_ids) if self.num_speakers > 1: encoder_outputs = self._add_speaker_embedding(encoder_outputs, - self.speaker_embeddings) + self.speaker_embeddings) decoder_outputs, alignments, stop_tokens = self.decoder.inference( encoder_outputs) postnet_outputs = self.postnet(decoder_outputs) diff --git a/train.py b/train.py index a47828e0..a5f3d2e7 100644 --- a/train.py +++ b/train.py @@ -350,7 +350,7 @@ def evaluate(model, criterion, ap, global_step, epoch): loss_dict = criterion(postnet_output, decoder_output, mel_input, linear_input, stop_tokens, stop_targets, mel_lengths, decoder_backward_output, - alignments, alignment_lengths, alignments_backward, + alignments, alignment_lengths, alignments_backward, text_lengths) if c.bidirectional_decoder: keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_b_loss'].item(), diff --git a/vocoder/train.py b/vocoder/train.py index 54b36e6b..259c5eb7 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -519,7 +519,7 @@ def main(args): # pylint: disable=redefined-outer-name model_disc, criterion_disc, optimizer_disc, scheduler_gen, scheduler_disc, ap, global_step, epoch) - eval_avg_loss_dict = evaluate(model_gen, criterion_gen, model_disc, ap, + eval_avg_loss_dict = evaluate(model_gen, criterion_gen, model_disc, criterion_disc, ap, global_step, epoch) c_logger.print_epoch_end(epoch, eval_avg_loss_dict) target_loss = eval_avg_loss_dict[c.target_loss] From 625ea70c98c67cdfa87dcbc71478a002370ac41a Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:01:13 +0200 Subject: [PATCH 062/185] TTS config update for using DDC --- config.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.json b/config.json index 74021970..5e10c535 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "model": "Tacotron2", - "run_name": "ljspeech", - "run_description": "tacotron2", + "run_name": "ljspeech-ddc-bn", + "run_description": "tacotron2 with ddc and batch-normalization", // AUDIO PARAMETERS "audio":{ @@ -83,8 +83,8 @@ // TACOTRON PRENET "memory_size": -1, // ONLY TACOTRON - size of the memory queue used fro storing last decoder predictions for auto-regression. If < 0, memory queue is disabled and decoder only uses the last prediction frame. - "prenet_type": "original", // "original" or "bn". - "prenet_dropout": true, // enable/disable dropout at prenet. + "prenet_type": "bn", // "original" or "bn". + "prenet_dropout": false, // enable/disable dropout at prenet. // ATTENTION "attention_type": "original", // 'original' or 'graves' @@ -124,7 +124,7 @@ // PHONEMES "phoneme_cache_path": "/media/erogol/data_ssd2/mozilla_us_phonemes_3", // phoneme computation is slow, therefore, it caches results in the given folder. - "use_phonemes": false, // use phonemes instead of raw characters. It is suggested for better pronounciation. + "use_phonemes": true, // use phonemes instead of raw characters. It is suggested for better pronounciation. "phoneme_language": "en-us", // depending on your target language, pick one from https://github.com/bootphon/phonemizer#languages // MULTI-SPEAKER and GST From 4ea649f59b87dd1bebbf31fa9a7015d765c21e35 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:01:34 +0200 Subject: [PATCH 063/185] change alignment_score to alignment_error --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index a5f3d2e7..869557e6 100644 --- a/train.py +++ b/train.py @@ -291,7 +291,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, "loss_postnet": keep_avg['avg_postnet_loss'], "loss_decoder": keep_avg['avg_decoder_loss'], "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_score": keep_avg['avg_align_error'], + "alignment_error": keep_avg['avg_align_error'], "epoch_time": epoch_time } if c.ga_alpha > 0: @@ -413,7 +413,7 @@ def evaluate(model, criterion, ap, global_step, epoch): "loss_postnet": keep_avg['avg_postnet_loss'], "loss_decoder": keep_avg['avg_decoder_loss'], "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_score": keep_avg['avg_align_error'], + "alignment_error": keep_avg['avg_align_error'], } if c.bidirectional_decoder: From f3aa295834007a956f115f53deed3e6b5907c9af Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:02:05 +0200 Subject: [PATCH 064/185] correction for vocoder configs --- vocoder/configs/melgan_config.json | 145 ------------------ .../multiband-melgan_and_rwd_config.json | 2 +- 2 files changed, 1 insertion(+), 146 deletions(-) delete mode 100644 vocoder/configs/melgan_config.json diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json deleted file mode 100644 index 0b6b16db..00000000 --- a/vocoder/configs/melgan_config.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "run_name": "melgan", - "run_description": "melgan initial run", - - // AUDIO PARAMETERS - "audio":{ - // stft parameters - "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. - "win_length": 1024, // stft window length in ms. - "hop_length": 256, // stft window hop-lengh in ms. - "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. - "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. - - // Audio processing parameters - "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. - "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. - "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. - - // Silence trimming - "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) - "trim_db": 60, // threshold for timming silence. Set this according to your dataset. - - // Griffin-Lim - "power": 1.5, // value to sharpen wav signals after GL algorithm. - "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. - - // MelSpectrogram parameters - "num_mels": 80, // size of the mel spec frame. - "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! - "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! - - // Normalization parameters - "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. - "min_level_db": -100, // lower bound for normalization - "symmetric_norm": true, // move normalization to range [-1, 1] - "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] - "clip_norm": true, // clip normalized values into the range. - "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored - }, - - // DISTRIBUTED TRAINING - // "distributed":{ - // "backend": "nccl", - // "url": "tcp:\/\/localhost:54321" - // }, - - // MODEL PARAMETERS - "use_pqmf": true, - - // LOSS PARAMETERS - "use_stft_loss": true, - "use_subband_stft_loss": true, - "use_mse_gan_loss": true, - "use_hinge_gan_loss": false, - "use_feat_match_loss": false, // use only with melgan discriminators - - "stft_loss_weight": 0.5, - "subband_stft_loss_weight": 0.5, - "mse_G_loss_weight": 2.5, - "hinge_G_loss_weight": 2.5, - "feat_match_loss_weight": 25, - - "stft_loss_params": { - "n_ffts": [1024, 2048, 512], - "hop_lengths": [120, 240, 50], - "win_lengths": [600, 1200, 240] - }, - "subband_stft_loss_params":{ - "n_ffts": [384, 683, 171], - "hop_lengths": [30, 60, 10], - "win_lengths": [150, 300, 60] - }, - - "target_loss": "avg_G_loss", // loss value to pick the best model - - // DISCRIMINATOR - "discriminator_model": "melgan_multiscale_discriminator", - "discriminator_model_params":{ - "base_channels": 16, - "max_channels":1024, - "downsample_factors":[4, 4, 4, 4] - }, - "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 - - // "discriminator_model": "random_window_discriminator", - // "discriminator_model_params":{ - // "uncond_disc_donwsample_factors": [8, 4], - // "cond_disc_downsample_factors": [[8, 4, 2, 2, 2], [8, 4, 2, 2], [8, 4, 2], [8, 4], [4, 2, 2]], - // "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], - // "window_sizes": [512, 1024, 2048, 4096, 8192] - // }, - - - // GENERATOR - "generator_model": "multiband_melgan_generator", - "generator_model_params": { - "upsample_factors":[2 ,2, 4, 4], - "num_res_blocks": 4 - }, - - // DATASET - "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", - "seq_len": 16384, - "pad_short": 2000, - "conv_pad": 0, - "use_noise_augment": true, - "use_cache": true, - - "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. - - // TRAINING - "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. - - // VALIDATION - "run_eval": true, - "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. - "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. - - // OPTIMIZER - "noam_schedule": false, // use noam warmup and lr schedule. - "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "warmup_steps_disc": 4000, - "epochs": 1000, // total number of epochs to train. - "wd": 0.000001, // Weight decay weight. - "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. - "lr_disc": 0.0001, - "gen_clip_grad": 10.0, - "disc_clip_grad": 10.0, - - // TENSORBOARD and LOGGING - "print_step": 25, // Number of steps to log traning on console. - "print_eval": false, // If True, it prints intermediate loss values in evalulation. - "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. - "checkpoint": true, // If true, it saves checkpoints per "save_step" - "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. - - // DATA LOADING - "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. - "num_val_loader_workers": 4, // number of evaluation data loader processes. - "eval_split_size": 10, - - // PATHS - "output_path": "/home/erogol/Models/LJSpeech/" -} - diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index 736f3459..f4b91aae 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -79,7 +79,7 @@ // "max_channels":1024, // "downsample_factors":[4, 4, 4, 4] // }, - "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 + "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 "discriminator_model": "random_window_discriminator", "discriminator_model_params":{ From aedbd318d55681d23562d4a84e843aea9b0bd396 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:02:28 +0200 Subject: [PATCH 065/185] remove weight norm for melgan generator --- vocoder/models/melgan_generator.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py index 1e47816d..e69e6ef3 100644 --- a/vocoder/models/melgan_generator.py +++ b/vocoder/models/melgan_generator.py @@ -87,3 +87,12 @@ class MelganGenerator(nn.Module): (self.inference_padding, self.inference_padding), 'replicate') return self.layers(cond_features) + + def remove_weight_norm(self): + for _, layer in enumerate(self.layers): + if len(layer.state_dict()) != 0: + try: + nn.utils.remove_weight_norm(layer) + except ValueError: + layer.remove_weight_norm() + From 8552c1d991955c8545e59b7d1af492449ee82c9a Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:02:55 +0200 Subject: [PATCH 066/185] fix multiband melgan inference --- vocoder/models/multiband_melgan_generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vocoder/models/multiband_melgan_generator.py b/vocoder/models/multiband_melgan_generator.py index 8feacd25..15e7426e 100644 --- a/vocoder/models/multiband_melgan_generator.py +++ b/vocoder/models/multiband_melgan_generator.py @@ -29,10 +29,11 @@ class MultibandMelganGenerator(MelganGenerator): def pqmf_synthesis(self, x): return self.pqmf_layer.synthesis(x) + @torch.no_grad() def inference(self, cond_features): cond_features = cond_features.to(self.layers[1].weight.device) cond_features = torch.nn.functional.pad( cond_features, (self.inference_padding, self.inference_padding), 'replicate') - return self.pqmf.synthesis(self.layers(cond_features)) + return self.pqmf_synthesis(self.layers(cond_features)) From f0144bfcba8411fd68a934158307ec49b00a0ea2 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:03:37 +0200 Subject: [PATCH 067/185] add lr schedulers for generator and discriminator --- vocoder/train.py | 56 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 259c5eb7..c563dff0 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -107,10 +107,6 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, global_step += 1 - # get current learning rates - current_lr_G = list(optimizer_G.param_groups)[0]['lr'] - current_lr_D = list(optimizer_D.param_groups)[0]['lr'] - ############################## # GENERATOR ############################## @@ -166,9 +162,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, torch.nn.utils.clip_grad_norm_(model_G.parameters(), c.gen_clip_grad) optimizer_G.step() - - # setup lr - if c.noam_schedule: + if scheduler_G is not None: scheduler_G.step() loss_dict = dict() @@ -221,9 +215,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, torch.nn.utils.clip_grad_norm_(model_D.parameters(), c.disc_clip_grad) optimizer_D.step() - - # setup lr - if c.noam_schedule: + if c.scheduler_D is not None: scheduler_D.step() for key, value in loss_D_dict.items(): @@ -232,6 +224,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, step_time = time.time() - start_time epoch_time += step_time + # get current learning rates + current_lr_G = list(optimizer_G.param_groups)[0]['lr'] + current_lr_D = list(optimizer_D.param_groups)[0]['lr'] + # update avg stats update_train_values = dict() for key, value in loss_dict.items(): @@ -244,7 +240,8 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if global_step % c.print_step == 0: c_logger.print_train_step(batch_n_iter, num_iter, global_step, step_time, loader_time, current_lr_G, - loss_dict, keep_avg.avg_values) + current_lr_D, loss_dict, + keep_avg.avg_values) # plot step stats if global_step % 10 == 0: @@ -262,8 +259,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # save model save_checkpoint(model_G, optimizer_G, + scheduler_G, model_D, optimizer_D, + scheduler_D, global_step, epoch, OUT_PATH, @@ -434,6 +433,7 @@ def main(args): # pylint: disable=redefined-outer-name # setup audio processor ap = AudioProcessor(**c.audio) + # DISTRUBUTED # if num_gpus > 1: # init_distributed(args.rank, num_gpus, args.group_id, @@ -449,6 +449,12 @@ def main(args): # pylint: disable=redefined-outer-name lr=c.lr_disc, weight_decay=0) + # schedulers + scheduler_gen = getattr(torch.optim.lr_scheduler, c.lr_scheduler_gen) + scheduler_disc = getattr(torch.optim.lr_scheduler, c.lr_scheduler_disc) + scheduler_gen = scheduler_gen(optimizer_gen, **c.lr_scheduler_gen_params) + scheduler_disc = scheduler_disc(optimizer_disc, **c.lr_scheduler_disc_params) + # setup criterion criterion_gen = GeneratorLoss(c) criterion_disc = DiscriminatorLoss(c) @@ -456,12 +462,26 @@ def main(args): # pylint: disable=redefined-outer-name if args.restore_path: checkpoint = torch.load(args.restore_path, map_location='cpu') try: + print(" > Restoring Generator Model...") model_gen.load_state_dict(checkpoint['model']) + print(" > Restoring Generator Optimizer...") optimizer_gen.load_state_dict(checkpoint['optimizer']) + print(" > Restoring Discriminator Model...") model_disc.load_state_dict(checkpoint['model_disc']) + print(" > Restoring Discriminator Optimizer...") optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) + if 'scheduler' in checkpoint: + print(" > Restoring Generator LR Scheduler...") + scheduler_gen.load_state_dict(checkpoint['scheduler']) + # NOTE: Not sure if necessary + scheduler_gen.optimizer = optimizer_gen + if 'scheduler_disc' in checkpoint: + print(" > Restoring Discriminator LR Scheduler...") + scheduler_disc.load_state_dict(checkpoint['scheduler_disc']) + scheduler_disc.optimizer = optimizer_disc except RuntimeError: - print(" > Partial model initialization.") + # retore only matching layers. + print(" > Partial model initialization...") model_dict = model_gen.state_dict() model_dict = set_init_dict(model_dict, checkpoint['model'], c) model_gen.load_state_dict(model_dict) @@ -494,16 +514,6 @@ def main(args): # pylint: disable=redefined-outer-name # if num_gpus > 1: # model = apply_gradient_allreduce(model) - if c.noam_schedule: - scheduler_gen = NoamLR(optimizer_gen, - warmup_steps=c.warmup_steps_gen, - last_epoch=args.restore_step - 1) - scheduler_disc = NoamLR(optimizer_disc, - warmup_steps=c.warmup_steps_gen, - last_epoch=args.restore_step - 1) - else: - scheduler_gen, scheduler_disc = None, None - num_params = count_parameters(model_gen) print(" > Generator has {} parameters".format(num_params), flush=True) num_params = count_parameters(model_disc) @@ -526,9 +536,11 @@ def main(args): # pylint: disable=redefined-outer-name best_loss = save_best_model(target_loss, best_loss, model_gen, + scheduler_gen, optimizer_gen, model_disc, optimizer_disc, + scheduler_disc, global_step, epoch, OUT_PATH, From dcfd62678480a1b3d02e9b91dbb22fa6d2c0ea8c Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:04:02 +0200 Subject: [PATCH 068/185] print lrg and lrD --- vocoder/utils/console_logger.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py index ff7edfd0..50882160 100644 --- a/vocoder/utils/console_logger.py +++ b/vocoder/utils/console_logger.py @@ -15,8 +15,8 @@ tcolors = AttrDict({ class ConsoleLogger(): + # TODO: merge this with TTS ConsoleLogger def __init__(self): - # TODO: color code for value changes # use these to compare values between iterations self.old_train_loss_dict = None self.old_epoch_loss_dict = None @@ -36,7 +36,7 @@ class ConsoleLogger(): print(f"\n{tcolors.BOLD} > TRAINING ({self.get_time()}) {tcolors.ENDC}") def print_train_step(self, batch_steps, step, global_step, - step_time, loader_time, lr, + step_time, loader_time, lrG, lrD, loss_dict, avg_loss_dict): indent = " | > " print() @@ -48,7 +48,7 @@ class ConsoleLogger(): log_text += "{}{}: {:.5f} ({:.5f})\n".format(indent, key, value, avg_loss_dict[f'avg_{key}']) else: log_text += "{}{}: {:.5f} \n".format(indent, key, value) - log_text += f"{indent}step_time: {step_time:.2f}\n{indent}loader_time: {loader_time:.2f}\n{indent}lr: {lr:.5f}" + log_text += f"{indent}step_time: {step_time:.2f}\n{indent}loader_time: {loader_time:.2f}\n{indent}lrG: {lrG}\n{indent}lrD: {lrD}" print(log_text, flush=True) # pylint: disable=unused-argument From b445bcb9624905b58cbcac1196f708bb55e5a154 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:04:16 +0200 Subject: [PATCH 069/185] save schedulers with checkpoints --- vocoder/utils/io.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/vocoder/utils/io.py b/vocoder/utils/io.py index b6ea7484..9d350238 100644 --- a/vocoder/utils/io.py +++ b/vocoder/utils/io.py @@ -2,18 +2,27 @@ import os import torch import datetime -def save_model(model, optimizer, model_disc, optimizer_disc, current_step, - epoch, output_path, **kwargs): + +def save_model(model, optimizer, scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, output_path, **kwargs): model_state = model.state_dict() - model_disc_state = model_disc.state_dict() - optimizer_state = optimizer.state_dict() if optimizer is not None else None - optimizer_disc_state = optimizer_disc.state_dict( - ) if optimizer_disc is not None else None + model_disc_state = model_disc.state_dict()\ + if model_disc is not None else None + optimizer_state = optimizer.state_dict()\ + if optimizer is not None else None + optimizer_disc_state = optimizer_disc.state_dict()\ + if optimizer_disc is not None else None + scheduler_state = scheduler.state_dict()\ + if scheduler is not None else None + scheduler_disc_state = scheduler_disc.state_dict()\ + if scheduler_disc is not None else None state = { 'model': model_state, 'optimizer': optimizer_state, + 'scheduler': scheduler_state, 'model_disc': model_disc_state, 'optimizer_disc': optimizer_disc_state, + 'scheduler_disc': scheduler_disc_state, 'step': current_step, 'epoch': epoch, 'date': datetime.date.today().strftime("%B %d, %Y"), @@ -22,26 +31,29 @@ def save_model(model, optimizer, model_disc, optimizer_disc, current_step, torch.save(state, output_path) -def save_checkpoint(model, optimizer, model_disc, optimizer_disc, current_step, - epoch, output_folder, **kwargs): +def save_checkpoint(model, optimizer, scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, output_folder, + **kwargs): file_name = 'checkpoint_{}.pth.tar'.format(current_step) checkpoint_path = os.path.join(output_folder, file_name) print(" > CHECKPOINT : {}".format(checkpoint_path)) - save_model(model, optimizer, model_disc, optimizer_disc, current_step, - epoch, checkpoint_path, **kwargs) + save_model(model, optimizer, scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, checkpoint_path, **kwargs) -def save_best_model(target_loss, best_loss, model, optimizer, model_disc, - optimizer_disc, current_step, epoch, output_folder, - **kwargs): +def save_best_model(target_loss, best_loss, model, optimizer, scheduler, + model_disc, optimizer_disc, scheduler_disc, current_step, + epoch, output_folder, **kwargs): if target_loss < best_loss: file_name = 'best_model.pth.tar' checkpoint_path = os.path.join(output_folder, file_name) print(" > BEST MODEL : {}".format(checkpoint_path)) save_model(model, optimizer, + scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, checkpoint_path, From a1368e3eb741f9e4c9448fbab0b8bd936786ac02 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:05:02 +0200 Subject: [PATCH 070/185] multiband melga nconfig --- vocoder/configs/multiband_melgan_config.json | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 vocoder/configs/multiband_melgan_config.json diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json new file mode 100644 index 00000000..3a5f0673 --- /dev/null +++ b/vocoder/configs/multiband_melgan_config.json @@ -0,0 +1,150 @@ +{ + "run_name": "multiband-melgan", + "run_description": "multiband melgan", + + // AUDIO PARAMETERS + "audio":{ + // stft parameters + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "win_length": 1024, // stft window length in ms. + "hop_length": 256, // stft window hop-lengh in ms. + "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. + "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. + + // Audio processing parameters + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + + // Silence trimming + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "trim_db": 60, // threshold for timming silence. Set this according to your dataset. + + // Griffin-Lim + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + + // MelSpectrogram parameters + "num_mels": 80, // size of the mel spec frame. + "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + + // Normalization parameters + "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. + "min_level_db": -100, // lower bound for normalization + "symmetric_norm": true, // move normalization to range [-1, 1] + "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "clip_norm": true, // clip normalized values into the range. + "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + }, + + // DISTRIBUTED TRAINING + // "distributed":{ + // "backend": "nccl", + // "url": "tcp:\/\/localhost:54321" + // }, + + // MODEL PARAMETERS + "use_pqmf": true, + + // LOSS PARAMETERS + "use_stft_loss": true, + "use_subband_stft_loss": true, + "use_mse_gan_loss": true, + "use_hinge_gan_loss": false, + "use_feat_match_loss": false, // use only with melgan discriminators + + // loss weights + "stft_loss_weight": 0.5, + "subband_stft_loss_weight": 0.5, + "mse_G_loss_weight": 2.5, + "hinge_G_loss_weight": 2.5, + "feat_match_loss_weight": 25, + + // multiscale stft loss parameters + "stft_loss_params": { + "n_ffts": [1024, 2048, 512], + "hop_lengths": [120, 240, 50], + "win_lengths": [600, 1200, 240] + }, + + // subband multiscale stft loss parameters + "subband_stft_loss_params":{ + "n_ffts": [384, 683, 171], + "hop_lengths": [30, 60, 10], + "win_lengths": [150, 300, 60] + }, + + "target_loss": "avg_G_loss", // loss value to pick the best model to save after each epoch + + // DISCRIMINATOR + "discriminator_model": "melgan_multiscale_discriminator", + "discriminator_model_params":{ + "base_channels": 16, + "max_channels":1024, + "downsample_factors":[4, 4, 4, 4] + }, + "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 + + // GENERATOR + "generator_model": "multiband_melgan_generator", + "generator_model_params": { + "upsample_factors":[8, 4, 2], + "num_res_blocks": 4 + }, + + // DATASET + "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", + "seq_len": 16384, + "pad_short": 2000, + "conv_pad": 0, + "use_noise_augment": false, + "use_cache": true, + + "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. + + // TRAINING + "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. + + // VALIDATION + "run_eval": true, + "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. + "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. + + // OPTIMIZER + "noam_schedule": false, // use noam warmup and lr schedule. + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, + "epochs": 10000, // total number of epochs to train. + "wd": 0.0, // Weight decay weight. + "gen_clip_grad": -1, // Generator gradient clipping threshold. Apply gradient clipping if > 0 + "disc_clip_grad": -1, // Discriminator gradient clipping threshold. + "lr_scheduler_gen": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_gen_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_scheduler_disc": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_disc_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_gen": 1e-4, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 1e-4, + + // TENSORBOARD and LOGGING + "print_step": 25, // Number of steps to log traning on console. + "print_eval": false, // If True, it prints loss values for each step in eval run. + "save_step": 25000, // Number of training steps expected to plot training stats on TB and save model checkpoints. + "checkpoint": true, // If true, it saves checkpoints per "save_step" + "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. + + // DATA LOADING + "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. + "num_val_loader_workers": 4, // number of evaluation data loader processes. + "eval_split_size": 10, + + // PATHS + "output_path": "/home/erogol/Models/LJSpeech/" +} + From 6d2cda97c8709f4697b03fb040f0b8afcb91c6ad Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:14:10 +0200 Subject: [PATCH 071/185] q --- .../multiband-melgan_and_rwd_config.json | 52 +++++++++++-------- vocoder/train.py | 2 +- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index f4b91aae..0b751854 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -1,6 +1,6 @@ { "run_name": "multiband-melgan-rwd", - "run_description": "multibadn melgan with random window discriminator", + "run_description": "multiband melgan with random window discriminator from https://arxiv.org/pdf/1909.11646.pdf", // AUDIO PARAMETERS "audio":{ @@ -54,33 +54,30 @@ "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators + // loss weights "stft_loss_weight": 0.5, "subband_stft_loss_weight": 0.5, "mse_G_loss_weight": 2.5, "hinge_G_loss_weight": 2.5, - "feat_match_loss_weight": 25.0, + "feat_match_loss_weight": 25, + // multiscale stft loss parameters "stft_loss_params": { "n_ffts": [1024, 2048, 512], "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240] }, + + // subband multiscale stft loss parameters "subband_stft_loss_params":{ "n_ffts": [384, 683, 171], "hop_lengths": [30, 60, 10], "win_lengths": [150, 300, 60] }, - "target_loss": "avg_G_loss", + + "target_loss": "avg_G_loss", // loss value to pick the best model to save after each epoch // DISCRIMINATOR - // "discriminator_model": "melgan_multiscale_discriminator", - // "discriminator_model_params":{ - // "base_channels": 16, - // "max_channels":1024, - // "downsample_factors":[4, 4, 4, 4] - // }, - "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 - "discriminator_model": "random_window_discriminator", "discriminator_model_params":{ "uncond_disc_donwsample_factors": [8, 4], @@ -88,6 +85,7 @@ "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], "window_sizes": [512, 1024, 2048, 4096, 8192] }, + "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 // GENERATOR "generator_model": "multiband_melgan_generator", @@ -97,11 +95,11 @@ }, // DATASET - "data_path": "/root/LJSpeech-1.1/wavs/", + "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", "seq_len": 16384, "pad_short": 2000, "conv_pad": 0, - "use_noise_augment": true, + "use_noise_augment": false, "use_cache": true, "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. @@ -118,17 +116,27 @@ "noam_schedule": false, // use noam warmup and lr schedule. "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "warmup_steps_disc": 4000, - "epochs": 100000, // total number of epochs to train. - "wd": 0.000001, // Weight decay weight. - "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. - "lr_disc": 0.0001, - "gen_clip_grad": 10.0, - "disc_clip_grad": 10.0, + "epochs": 10000, // total number of epochs to train. + "wd": 0.0, // Weight decay weight. + "gen_clip_grad": -1, // Generator gradient clipping threshold. Apply gradient clipping if > 0 + "disc_clip_grad": -1, // Discriminator gradient clipping threshold. + "lr_scheduler_gen": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_gen_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_scheduler_disc": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_disc_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_gen": 1e-4, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 1e-4, // TENSORBOARD and LOGGING "print_step": 25, // Number of steps to log traning on console. - "print_eval": false, // If True, it prints intermediate loss values in evalulation. - "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. + "print_eval": false, // If True, it prints loss values for each step in eval run. + "save_step": 25000, // Number of training steps expected to plot training stats on TB and save model checkpoints. "checkpoint": true, // If true, it saves checkpoints per "save_step" "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. @@ -138,6 +146,6 @@ "eval_split_size": 10, // PATHS - "output_path": "/data/rw/home/Trainings/" + "output_path": "/home/erogol/Models/LJSpeech/" } diff --git a/vocoder/train.py b/vocoder/train.py index c563dff0..a8a8f011 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -215,7 +215,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, torch.nn.utils.clip_grad_norm_(model_D.parameters(), c.disc_clip_grad) optimizer_D.step() - if c.scheduler_D is not None: + if scheduler_D is not None: scheduler_D.step() for key, value in loss_D_dict.items(): From 53f13461b921f861d5b07f2de28892e4704b96e1 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:45:43 +0200 Subject: [PATCH 072/185] better stats logging for TTS training --- train.py | 132 +++++++++++++++++++------------------------------------ 1 file changed, 45 insertions(+), 87 deletions(-) diff --git a/train.py b/train.py index 869557e6..51c73a9f 100644 --- a/train.py +++ b/train.py @@ -119,21 +119,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, verbose=(epoch == 0)) model.train() epoch_time = 0 - train_values = { - 'avg_postnet_loss': 0, - 'avg_decoder_loss': 0, - 'avg_stopnet_loss': 0, - 'avg_align_error': 0, - 'avg_step_time': 0, - 'avg_loader_time': 0 - } - if c.bidirectional_decoder: - train_values['avg_decoder_b_loss'] = 0 # decoder backward loss - train_values['avg_decoder_c_loss'] = 0 # decoder consistency loss - if c.ga_alpha > 0: - train_values['avg_ga_loss'] = 0 # guidede attention loss keep_avg = KeepAverage() - keep_avg.add_values(train_values) if use_cuda: batch_n_iter = int( len(data_loader.dataset) / (c.batch_size * num_gpus)) @@ -179,11 +165,6 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, mel_lengths, decoder_backward_output, alignments, alignment_lengths, alignments_backward, text_lengths) - if c.bidirectional_decoder: - keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_backward_loss'].item(), - 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) - if c.ga_alpha > 0: - keep_avg.update_values({'avg_ga_loss': loss_dict['ga_loss'].item()}) # backward pass loss_dict['loss'].backward() @@ -193,7 +174,6 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # compute alignment error (the lower the better ) align_error = 1 - alignment_diagonal_score(alignments) - keep_avg.update_value('avg_align_error', align_error) loss_dict['align_error'] = align_error # backpass and check the grad norm for stop loss @@ -208,23 +188,6 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, step_time = time.time() - start_time epoch_time += step_time - # update avg stats - update_train_values = { - 'avg_postnet_loss': float(loss_dict['postnet_loss'].item()), - 'avg_decoder_loss': float(loss_dict['decoder_loss'].item()), - 'avg_stopnet_loss': loss_dict['stopnet_loss'].item() \ - if isinstance(loss_dict['stopnet_loss'], float) else float(loss_dict['stopnet_loss'].item()), - 'avg_step_time': step_time, - 'avg_loader_time': loader_time - } - keep_avg.update_values(update_train_values) - - if global_step % c.print_step == 0: - c_logger.print_train_step(batch_n_iter, num_iter, global_step, - avg_spec_length, avg_text_length, - step_time, loader_time, current_lr, - loss_dict, keep_avg.avg_values) - # aggregate losses from processes if num_gpus > 1: loss_dict['postnet_loss'] = reduce_tensor(loss_dict['postnet_loss'].data, num_gpus) @@ -232,6 +195,30 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, loss_dict['loss'] = reduce_tensor(loss_dict['loss'] .data, num_gpus) loss_dict['stopnet_loss'] = reduce_tensor(loss_dict['stopnet_loss'].data, num_gpus) if c.stopnet else loss_dict['stopnet_loss'] + # detach loss values + loss_dict_new = dict() + for key, value in loss_dict.items(): + if isinstance(value, int) or isinstance(value, float): + loss_dict_new[key] = value + else: + loss_dict_new[key] = value.item() + loss_dict = loss_dict_new + + # update avg stats + update_train_values = dict() + for key, value in loss_dict.items(): + update_train_values['avg_' + key] = value + update_train_values['avg_loader_time'] = loader_time + update_train_values['avg_step_time'] = step_time + keep_avg.update_values(update_train_values) + + # print training progress + if global_step % c.print_step == 0: + c_logger.print_train_step(batch_n_iter, num_iter, global_step, + avg_spec_length, avg_text_length, + step_time, loader_time, current_lr, + loss_dict, keep_avg.avg_values) + if args.rank == 0: # Plot Training Iter Stats # reduce TB load @@ -266,7 +253,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, "alignment": plot_alignment(align_img), } - if c.bidirectional_decoder: + if c.bidirectional_decoder or c.double_decoder_consistency: figures["alignment_backward"] = plot_alignment(alignments_backward[0].data.cpu().numpy()) tb_logger.tb_train_figures(global_step, figures) @@ -286,16 +273,8 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # Plot Epoch Stats if args.rank == 0: - # Plot Training Epoch Stats - epoch_stats = { - "loss_postnet": keep_avg['avg_postnet_loss'], - "loss_decoder": keep_avg['avg_decoder_loss'], - "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_error": keep_avg['avg_align_error'], - "epoch_time": epoch_time - } - if c.ga_alpha > 0: - epoch_stats['guided_attention_loss'] = keep_avg['avg_ga_loss'] + epoch_stats = {"epoch_time": epoch_time} + epoch_stats.update(keep_avg.avg_values) tb_logger.tb_train_epoch_stats(global_step, epoch_stats) if c.tb_model_param_stats: tb_logger.tb_model_weights(model, global_step) @@ -307,20 +286,7 @@ def evaluate(model, criterion, ap, global_step, epoch): data_loader = setup_loader(ap, model.decoder.r, is_val=True) model.eval() epoch_time = 0 - eval_values_dict = { - 'avg_postnet_loss': 0, - 'avg_decoder_loss': 0, - 'avg_stopnet_loss': 0, - 'avg_align_error': 0 - } - if c.bidirectional_decoder: - eval_values_dict['avg_decoder_b_loss'] = 0 # decoder backward loss - eval_values_dict['avg_decoder_c_loss'] = 0 # decoder consistency loss - if c.ga_alpha > 0: - eval_values_dict['avg_ga_loss'] = 0 # guidede attention loss keep_avg = KeepAverage() - keep_avg.add_values(eval_values_dict) - c_logger.print_eval_start() if data_loader is not None: for num_iter, data in enumerate(data_loader): @@ -352,11 +318,6 @@ def evaluate(model, criterion, ap, global_step, epoch): mel_lengths, decoder_backward_output, alignments, alignment_lengths, alignments_backward, text_lengths) - if c.bidirectional_decoder: - keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_b_loss'].item(), - 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) - if c.ga_alpha > 0: - keep_avg.update_values({'avg_ga_loss': loss_dict['ga_loss'].item()}) # step time step_time = time.time() - start_time @@ -364,7 +325,7 @@ def evaluate(model, criterion, ap, global_step, epoch): # compute alignment score align_error = 1 - alignment_diagonal_score(alignments) - keep_avg.update_value('avg_align_error', align_error) + loss_dict['align_error'] = align_error # aggregate losses from processes if num_gpus > 1: @@ -373,14 +334,20 @@ def evaluate(model, criterion, ap, global_step, epoch): if c.stopnet: loss_dict['stopnet_loss'] = reduce_tensor(loss_dict['stopnet_loss'].data, num_gpus) - keep_avg.update_values({ - 'avg_postnet_loss': - float(loss_dict['postnet_loss'].item()), - 'avg_decoder_loss': - float(loss_dict['decoder_loss'].item()), - 'avg_stopnet_loss': - float(loss_dict['stopnet_loss'].item()), - }) + # detach loss values + loss_dict_new = dict() + for key, value in loss_dict.items(): + if isinstance(value, int) or isinstance(value, float): + loss_dict_new[key] = value + else: + loss_dict_new[key] = value.item() + loss_dict = loss_dict_new + + # update avg stats + update_train_values = dict() + for key, value in loss_dict.items(): + update_train_values['avg_' + key] = value + keep_avg.update_values(update_train_values) if c.print_eval: c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) @@ -409,20 +376,11 @@ def evaluate(model, criterion, ap, global_step, epoch): c.audio["sample_rate"]) # Plot Validation Stats - epoch_stats = { - "loss_postnet": keep_avg['avg_postnet_loss'], - "loss_decoder": keep_avg['avg_decoder_loss'], - "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_error": keep_avg['avg_align_error'], - } - if c.bidirectional_decoder: - epoch_stats['loss_decoder_backward'] = keep_avg['avg_decoder_b_loss'] + if c.bidirectional_decoder or c.double_decoder_consistency: align_b_img = alignments_backward[idx].data.cpu().numpy() - eval_figures['alignment_backward'] = plot_alignment(align_b_img) - if c.ga_alpha > 0: - epoch_stats['guided_attention_loss'] = keep_avg['avg_ga_loss'] - tb_logger.tb_eval_stats(global_step, epoch_stats) + eval_figures['alignment2'] = plot_alignment(align_b_img) + tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) tb_logger.tb_eval_figures(global_step, eval_figures) if args.rank == 0 and epoch > c.test_delay_epochs: From 1a061c4af5a407590d922cb809906670c7510a2c Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:51:59 +0200 Subject: [PATCH 073/185] new config argument to plot tb figures at training --- config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 5e10c535..53b12fe1 100644 --- a/config.json +++ b/config.json @@ -104,7 +104,8 @@ "separate_stopnet": true, // Train stopnet seperately if 'stopnet==true'. It prevents stopnet loss to influence the rest of the model. It causes a better model, but it trains SLOWER. // TENSORBOARD and LOGGING - "print_step": 25, // Number of steps to log traning on console. + "print_step": 25, // Number of steps to log training on console. + "tb_plot_step:": 100, // Number of steps to plot TB training figures. "print_eval": false, // If True, it prints intermediate loss values in evalulation. "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. "checkpoint": true, // If true, it saves checkpoints per "save_step" From c24b57452da92f4e6bb819b38d218ed5861c5267 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:52:31 +0200 Subject: [PATCH 074/185] bug fix --- train.py | 5 ++--- utils/generic_utils.py | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 51c73a9f..02f28c1d 100644 --- a/train.py +++ b/train.py @@ -222,15 +222,14 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, if args.rank == 0: # Plot Training Iter Stats # reduce TB load - if global_step % 10 == 0: + if global_step % c.tb_plot_step == 0: iter_stats = { - "loss_posnet": loss_dict['postnet_loss'].item(), - "loss_decoder": loss_dict['decoder_loss'].item(), "lr": current_lr, "grad_norm": grad_norm, "grad_norm_st": grad_norm_st, "step_time": step_time } + iter_stats.update(loss_dict) tb_logger.tb_train_iter_stats(global_step, iter_stats) if global_step % c.save_step == 0: diff --git a/utils/generic_utils.py b/utils/generic_utils.py index eb6d21a9..a6398771 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -327,6 +327,7 @@ def check_config(c): # tensorboard _check_argument('print_step', c, restricted=True, val_type=int, min_val=1) + _check_argument('tb_plot_step', c, restricted=True, val_type=int, min_val=1) _check_argument('save_step', c, restricted=True, val_type=int, min_val=1) _check_argument('checkpoint', c, restricted=True, val_type=bool) _check_argument('tb_model_param_stats', c, restricted=True, val_type=bool) From 99420a2d9bbd91ac3ef1fe07a0b9b6af4fd40aea Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:55:37 +0200 Subject: [PATCH 075/185] restore vocoder scheduler if it is in checkpoint --- vocoder/train.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index a8a8f011..091a6932 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -450,10 +450,14 @@ def main(args): # pylint: disable=redefined-outer-name weight_decay=0) # schedulers - scheduler_gen = getattr(torch.optim.lr_scheduler, c.lr_scheduler_gen) - scheduler_disc = getattr(torch.optim.lr_scheduler, c.lr_scheduler_disc) - scheduler_gen = scheduler_gen(optimizer_gen, **c.lr_scheduler_gen_params) - scheduler_disc = scheduler_disc(optimizer_disc, **c.lr_scheduler_disc_params) + scheduler_gen = None + scheduler_disc = None + if 'lr_scheduler_gen' in c: + scheduler_gen = getattr(torch.optim.lr_scheduler, c.lr_scheduler_gen) + scheduler_gen = scheduler_gen(optimizer_gen, **c.lr_scheduler_gen_params) + if 'lr_scheduler_disc' in c: + scheduler_disc = getattr(torch.optim.lr_scheduler, c.lr_scheduler_disc) + scheduler_disc = scheduler_disc(optimizer_disc, **c.lr_scheduler_disc_params) # setup criterion criterion_gen = GeneratorLoss(c) From 6a661f98e2778befc58d1c3da229ea629abb4e15 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:57:49 +0200 Subject: [PATCH 076/185] linter fix --- train.py | 4 ++-- vocoder/train.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 02f28c1d..f6d73a4a 100644 --- a/train.py +++ b/train.py @@ -198,7 +198,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # detach loss values loss_dict_new = dict() for key, value in loss_dict.items(): - if isinstance(value, int) or isinstance(value, float): + if isinstance(value, (int, float)): loss_dict_new[key] = value else: loss_dict_new[key] = value.item() @@ -336,7 +336,7 @@ def evaluate(model, criterion, ap, global_step, epoch): # detach loss values loss_dict_new = dict() for key, value in loss_dict.items(): - if isinstance(value, int) or isinstance(value, float): + if isinstance(value, (int, float)): loss_dict_new[key] = value else: loss_dict_new[key] = value.item() diff --git a/vocoder/train.py b/vocoder/train.py index 091a6932..ce8f111a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -17,7 +17,7 @@ from TTS.utils.generic_utils import (KeepAverage, count_parameters, from TTS.utils.io import copy_config_file, load_config from TTS.utils.radam import RAdam from TTS.utils.tensorboard_logger import TensorboardLogger -from TTS.utils.training import setup_torch_training_env, NoamLR +from TTS.utils.training import setup_torch_training_env from TTS.vocoder.datasets.gan_dataset import GANDataset from TTS.vocoder.datasets.preprocess import load_wav_data # from distribute import (DistributedSampler, apply_gradient_allreduce, From 4d1d04a6a03a270e867c12ece86418988867bee9 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 11 Jun 2020 10:48:20 +0200 Subject: [PATCH 077/185] bug fix --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index f6d73a4a..8581132a 100644 --- a/train.py +++ b/train.py @@ -237,7 +237,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # save model save_checkpoint(model, optimizer, global_step, epoch, model.decoder.r, OUT_PATH, optimizer_st=optimizer_st, - model_loss=loss_dict['postnet_loss'].item()) + model_loss=loss_dict['postnet_loss']) # Diagnostic visualizations const_spec = postnet_output[0].data.cpu().numpy() From 92ed9b90c3de90523be1898145b99722acc80fea Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 11 Jun 2020 12:42:13 +0200 Subject: [PATCH 078/185] reformatting vocoder training and disable G_adv eval if step < d_training --- vocoder/train.py | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index ce8f111a..74b3e759 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -112,7 +112,6 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, ############################## # generator pass - optimizer_G.zero_grad() y_hat = model_G(c_G) y_hat_sub = None y_G_sub = None @@ -121,8 +120,8 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # PQMF formatting if y_hat.shape[1] > 1: y_hat_sub = y_hat - y_hat = model_G.pqmf_synthesis(y_hat) y_hat_vis = y_hat + y_hat = model_G.pqmf_synthesis(y_hat) y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: @@ -142,12 +141,11 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if isinstance(D_out_fake, tuple): scores_fake, feats_fake = D_out_fake if D_out_real is None: - scores_real, feats_real = None, None + feats_real = None else: - scores_real, feats_real = D_out_real + _, feats_real = D_out_real else: scores_fake = D_out_fake - scores_real = D_out_real else: scores_fake, feats_fake, feats_real = None, None, None @@ -157,6 +155,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, loss_G = loss_G_dict['G_loss'] # optimizer generator + optimizer_G.zero_grad() loss_G.backward() if c.gen_clip_grad > 0: torch.nn.utils.clip_grad_norm_(model_G.parameters(), @@ -184,8 +183,6 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if y_hat.shape[1] > 1: y_hat = model_G.pqmf_synthesis(y_hat) - optimizer_D.zero_grad() - # run D with or without cond. features if len(signature(model_D.forward).parameters) == 2: D_out_fake = model_D(y_hat.detach(), c_D) @@ -210,6 +207,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, loss_D = loss_D_dict['D_loss'] # optimizer discriminator + optimizer_D.zero_grad() loss_D.backward() if c.disc_clip_grad > 0: torch.nn.utils.clip_grad_norm_(model_D.parameters(), @@ -326,25 +324,30 @@ def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch) y_hat = model_G.pqmf_synthesis(y_hat) y_G_sub = model_G.pqmf_analysis(y_G) - if len(signature(model_D.forward).parameters) == 2: - D_out_fake = model_D(y_hat, c_G) - else: - D_out_fake = model_D(y_hat) - D_out_real = None - if c.use_feat_match_loss: - with torch.no_grad(): - D_out_real = model_D(y_G) + if global_step > c.steps_to_start_discriminator: - # format D outputs - if isinstance(D_out_fake, tuple): - scores_fake, feats_fake = D_out_fake - if D_out_real is None: - feats_real = None + if len(signature(model_D.forward).parameters) == 2: + D_out_fake = model_D(y_hat, c_G) else: - _, feats_real = D_out_real + D_out_fake = model_D(y_hat) + D_out_real = None + + if c.use_feat_match_loss: + with torch.no_grad(): + D_out_real = model_D(y_G) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + feats_real = None + else: + _, feats_real = D_out_real + else: + scores_fake = D_out_fake else: - scores_fake = D_out_fake + scores_fake, feats_fake, feats_real = None, None, None # compute losses loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, From 7e799d58d6b8e7c56967c54f6f45c7b3d599a660 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 11 Jun 2020 15:34:38 +0200 Subject: [PATCH 079/185] bug fix --- utils/generic_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 298f5970..e6466e0c 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -75,7 +75,7 @@ def split_dataset(items): is_multi_speaker = len(set(speakers)) > 1 eval_split_size = 500 if len(items) * 0.01 > 500 else int( len(items) * 0.01) - assert len(eval_split_size) > 0, " [!] You do not have enough samples to train. You need at least 100 samples." + assert eval_split_size > 0, " [!] You do not have enough samples to train. You need at least 100 samples." np.random.seed(0) np.random.shuffle(items) if is_multi_speaker: From 1c2dc9f73909590aed91734cc1ea0a83ee1fb97c Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 11:12:57 +0200 Subject: [PATCH 080/185] enable loading precomputed vocoder dataset --- vocoder/datasets/gan_dataset.py | 25 +++++++++++++++++++------ vocoder/datasets/preprocess.py | 21 +++++++++++++++++++++ vocoder/train.py | 4 ++-- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/vocoder/datasets/gan_dataset.py b/vocoder/datasets/gan_dataset.py index 5e410151..55513e7d 100644 --- a/vocoder/datasets/gan_dataset.py +++ b/vocoder/datasets/gan_dataset.py @@ -28,6 +28,7 @@ class GANDataset(Dataset): self.ap = ap self.item_list = items + self.compute_feat = not isinstance(items[0], (tuple, list)) self.seq_len = seq_len self.hop_len = hop_len self.pad_short = pad_short @@ -77,14 +78,26 @@ class GANDataset(Dataset): def load_item(self, idx): """ load (audio, feat) couple """ - wavpath = self.item_list[idx] - # print(wavpath) + if self.compute_feat: + # compute features from wav + wavpath = self.item_list[idx] + # print(wavpath) - if self.use_cache and self.cache[idx] is not None: - audio, mel = self.cache[idx] + if self.use_cache and self.cache[idx] is not None: + audio, mel = self.cache[idx] + else: + audio = self.ap.load_wav(wavpath) + mel = self.ap.melspectrogram(audio) else: - audio = self.ap.load_wav(wavpath) - mel = self.ap.melspectrogram(audio) + + # load precomputed features + wavpath, feat_path = self.item_list[idx] + + if self.use_cache and self.cache[idx] is not None: + audio, mel = self.cache[idx] + else: + audio = self.ap.load_wav(wavpath) + mel = np.load(feat_path) if len(audio) < self.seq_len + self.pad_short: audio = np.pad(audio, (0, self.seq_len + self.pad_short - len(audio)), \ diff --git a/vocoder/datasets/preprocess.py b/vocoder/datasets/preprocess.py index 01e01e3e..be60c13a 100644 --- a/vocoder/datasets/preprocess.py +++ b/vocoder/datasets/preprocess.py @@ -1,5 +1,6 @@ import glob import os +from pathlib import Path import numpy as np @@ -9,8 +10,28 @@ def find_wav_files(data_path): return wav_paths +def find_feat_files(data_path): + feat_paths = glob.glob(os.path.join(data_path, '**', '*.npy'), recursive=True) + return feat_paths + + def load_wav_data(data_path, eval_split_size): wav_paths = find_wav_files(data_path) np.random.seed(0) np.random.shuffle(wav_paths) return wav_paths[:eval_split_size], wav_paths[eval_split_size:] + + +def load_wav_feat_data(data_path, feat_path, eval_split_size): + wav_paths = sorted(find_wav_files(data_path)) + feat_paths = sorted(find_feat_files(feat_path)) + assert len(wav_paths) == len(feat_paths) + for wav, feat in zip(wav_paths, feat_paths): + wav_name = Path(wav).stem + feat_name = Path(feat).stem + assert wav_name == feat_name + + items = list(zip(wav_paths, feat_paths)) + np.random.seed(0) + np.random.shuffle(items) + return items[:eval_split_size], items[eval_split_size:] diff --git a/vocoder/train.py b/vocoder/train.py index 74b3e759..4d1b1029 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -19,7 +19,7 @@ from TTS.utils.radam import RAdam from TTS.utils.tensorboard_logger import TensorboardLogger from TTS.utils.training import setup_torch_training_env from TTS.vocoder.datasets.gan_dataset import GANDataset -from TTS.vocoder.datasets.preprocess import load_wav_data +from TTS.vocoder.datasets.preprocess import load_wav_data, load_wav_feat_data # from distribute import (DistributedSampler, apply_gradient_allreduce, # init_distributed, reduce_tensor) from TTS.vocoder.layers.losses import DiscriminatorLoss, GeneratorLoss @@ -543,8 +543,8 @@ def main(args): # pylint: disable=redefined-outer-name best_loss = save_best_model(target_loss, best_loss, model_gen, - scheduler_gen, optimizer_gen, + scheduler_gen, model_disc, optimizer_disc, scheduler_disc, From 9af6bb0c297511c31973c898a8cd4da263a70849 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 11:37:32 +0200 Subject: [PATCH 081/185] bug fix --- vocoder/utils/console_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py index 50882160..4f44986c 100644 --- a/vocoder/utils/console_logger.py +++ b/vocoder/utils/console_logger.py @@ -84,7 +84,7 @@ class ConsoleLogger(): color = '' sign = '+' diff = 0 - if self.old_eval_loss_dict is not None: + if self.old_eval_loss_dict is not None and key in self.old_eval_loss_dict: diff = value - self.old_eval_loss_dict[key] if diff < 0: color = tcolors.OKGREEN From 546186bbf1f62c2d36c982eb01d85bbdd8f09ec9 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 11:54:54 +0200 Subject: [PATCH 082/185] visualization bug fix --- vocoder/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index 4d1b1029..326bd90e 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -120,8 +120,8 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # PQMF formatting if y_hat.shape[1] > 1: y_hat_sub = y_hat - y_hat_vis = y_hat y_hat = model_G.pqmf_synthesis(y_hat) + y_hat_vis = y_hat y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: From 0b78977662bfa9d59da4c2f9ce8d4647e093c3db Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 12:11:23 +0200 Subject: [PATCH 083/185] more comments to audio.py --- utils/audio.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/audio.py b/utils/audio.py index 13eab3d6..f941f609 100644 --- a/utils/audio.py +++ b/utils/audio.py @@ -57,8 +57,10 @@ class AudioProcessor(object): self.stats_path = stats_path # setup stft parameters if hop_length is None: + # compute stft parameters from given time values self.n_fft, self.hop_length, self.win_length = self._stft_parameters() else: + # use stft parameters from config file self.hop_length = hop_length self.win_length = win_length self.n_fft = (self.num_freq - 1) * 2 From 3eb730acf0a660d96f3af78cde0f5379b72fb3c6 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 19:32:49 +0200 Subject: [PATCH 084/185] update vocoder loss implemenatations and fix MSEDLoss --- vocoder/layers/losses.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index a24b129c..4774ab4e 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -88,7 +88,7 @@ class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ # pylint: disable=no-self-use def forward(self, score_fake): - loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + loss_fake = F.mse_loss(score_fake, score_fake.new_ones(score_fake.shape)) return loss_fake @@ -96,7 +96,8 @@ class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ # pylint: disable=no-self-use def forward(self, score_fake): - loss_fake = torch.mean(F.relu(1. + score_fake)) + # TODO: this might be wrong + loss_fake = torch.mean(F.relu(1. - score_fake)) return loss_fake @@ -107,10 +108,14 @@ class HingeGLoss(nn.Module): class MSEDLoss(nn.Module): """ Mean Squared Discriminator Loss """ + def __init__(self,): + super(MSEDLoss, self).__init__() + self.loss_func = nn.MSELoss() + # pylint: disable=no-self-use def forward(self, score_fake, score_real): - loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) - loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + loss_real = self.loss_func(score_real, score_real.new_ones(score_real.shape)) + loss_fake = self.loss_func(score_fake, score_fake.new_zeros(score_fake.shape)) loss_d = loss_real + loss_fake return loss_d, loss_real, loss_fake @@ -126,11 +131,15 @@ class HingeDLoss(nn.Module): class MelganFeatureLoss(nn.Module): + def __init__(self,): + super(MelganFeatureLoss, self).__init__() + self.loss_func = nn.L1Loss() + # pylint: disable=no-self-use def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): - loss_feats += torch.mean(torch.abs(fake_feat - real_feat)) + loss_feats += self.loss_func(fake_feats, real_feats) loss_feats /= len(fake_feats) + len(real_feats) return loss_feats From 773e9c7a72ab7fc930ad0e26cafbb660fcdb82b2 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 19:50:07 +0200 Subject: [PATCH 085/185] remove redundant params in vocoder config file --- vocoder/configs/multiband_melgan_config.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json index 3a5f0673..164fe037 100644 --- a/vocoder/configs/multiband_melgan_config.json +++ b/vocoder/configs/multiband_melgan_config.json @@ -20,9 +20,6 @@ "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) "trim_db": 60, // threshold for timming silence. Set this according to your dataset. - // Griffin-Lim - "power": 1.5, // value to sharpen wav signals after GL algorithm. - "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. // MelSpectrogram parameters "num_mels": 80, // size of the mel spec frame. From 3e5ce85bf7b4d84575632908c962151b355a6a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sat, 13 Jun 2020 19:34:26 +0100 Subject: [PATCH 086/185] load ParallelWaveGAN from PYTHONPATH if pwgan_lib_path is unset --- server/synthesizer.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/server/synthesizer.py b/server/synthesizer.py index 392dcc4a..c6fde902 100644 --- a/server/synthesizer.py +++ b/server/synthesizer.py @@ -37,7 +37,7 @@ class Synthesizer(object): if self.config.wavernn_lib_path: self.load_wavernn(self.config.wavernn_lib_path, self.config.wavernn_file, self.config.wavernn_config, self.config.use_cuda) - if self.config.pwgan_lib_path: + if self.config.pwgan_file: self.load_pwgan(self.config.pwgan_lib_path, self.config.pwgan_file, self.config.pwgan_config, self.config.use_cuda) @@ -113,9 +113,14 @@ class Synthesizer(object): self.wavernn.eval() def load_pwgan(self, lib_path, model_file, model_config, use_cuda): - sys.path.append(lib_path) # set this if ParallelWaveGAN is not installed globally - #pylint: disable=import-outside-toplevel - from parallel_wavegan.models import ParallelWaveGANGenerator + if lib_path: + # set this if ParallelWaveGAN is not installed globally + sys.path.append(lib_path) + try: + #pylint: disable=import-outside-toplevel + from parallel_wavegan.models import ParallelWaveGANGenerator + except ImportError as e: + raise RuntimeError(f"cannot import parallel-wavegan, either install it or set its directory using the --pwgan_lib_path command line argument: {e}") print(" > Loading PWGAN model ...") print(" | > model config: ", model_config) print(" | > model file: ", model_file) From 9f83b6797f26be631d7717bcb8be53e59846f596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eren=20G=C3=B6lge?= Date: Mon, 15 Jun 2020 11:41:42 +0200 Subject: [PATCH 087/185] handling librosa conflict with numba https://github.com/librosa/librosa/issues/1160 --- requirements_tests.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements_tests.txt b/requirements_tests.txt index 1e0615b2..5aacdb56 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -1,4 +1,5 @@ numpy>=1.16.0 +numba==0.48 torch>=0.4.1 tensorflow>=2.2 librosa>=0.5.1 From a2e74c58f9c54b36586497e37150f58b7b8d9d8f Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 14:05:19 +0200 Subject: [PATCH 088/185] add a non-existing value to avg values --- utils/generic_utils.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index e6466e0c..4a7aaef9 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -198,14 +198,19 @@ class KeepAverage(): self.iters[name] = init_iter def update_value(self, name, value, weighted_avg=False): - if weighted_avg: - self.avg_values[name] = 0.99 * self.avg_values[name] + 0.01 * value - self.iters[name] += 1 + if name not in self.avg_values: + # add value if not exist before + self.add_value(name, init_val=value) else: - self.avg_values[name] = self.avg_values[name] * \ - self.iters[name] + value - self.iters[name] += 1 - self.avg_values[name] /= self.iters[name] + # else update existing value + if weighted_avg: + self.avg_values[name] = 0.99 * self.avg_values[name] + 0.01 * value + self.iters[name] += 1 + else: + self.avg_values[name] = self.avg_values[name] * \ + self.iters[name] + value + self.iters[name] += 1 + self.avg_values[name] /= self.iters[name] def add_values(self, name_dict): for key, value in name_dict.items(): From 30347972111ff4b0c9c189e15ec037a6ae9d0fb2 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:07:01 +0200 Subject: [PATCH 089/185] differentiate modules on TB with a prefix --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index e4963ee7..82f91cd5 100644 --- a/train.py +++ b/train.py @@ -667,7 +667,7 @@ if __name__ == '__main__': os.chmod(OUT_PATH, 0o775) LOG_DIR = OUT_PATH - tb_logger = TensorboardLogger(LOG_DIR) + tb_logger = TensorboardLogger(LOG_DIR, model_name='TTS') # write model desc to tensorboard tb_logger.tb_add_text('model-description', c['run_description'], 0) From a5fc2f578f0d570d79a67fe8a0251a2160736a67 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:08:26 +0200 Subject: [PATCH 090/185] set state dict using direct state_dict dict --- utils/generic_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 4a7aaef9..f7c04859 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -107,15 +107,15 @@ def sequence_mask(sequence_length, max_len=None): return seq_range_expand < seq_length_expand -def set_init_dict(model_dict, checkpoint, c): +def set_init_dict(model_dict, checkpoint_state, c): # Partial initialization: if there is a mismatch with new and old layer, it is skipped. - for k, v in checkpoint['model'].items(): + for k, v in checkpoint_state.items(): if k not in model_dict: print(" | > Layer missing in the model definition: {}".format(k)) # 1. filter out unnecessary keys pretrained_dict = { k: v - for k, v in checkpoint['model'].items() if k in model_dict + for k, v in checkpoint_state.items() if k in model_dict } # 2. filter out different size layers pretrained_dict = { From e9f3a476cfaf66b5fe9e3336d48a3f0c93d15343 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:08:56 +0200 Subject: [PATCH 091/185] use model_name prefix in tb_logger --- utils/tensorboard_logger.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/utils/tensorboard_logger.py b/utils/tensorboard_logger.py index 15fe04e4..cbf68ad6 100644 --- a/utils/tensorboard_logger.py +++ b/utils/tensorboard_logger.py @@ -3,7 +3,8 @@ from tensorboardX import SummaryWriter class TensorboardLogger(object): - def __init__(self, log_dir): + def __init__(self, log_dir, model_name): + self.model_name = model_name self.writer = SummaryWriter(log_dir) self.train_stats = {} self.eval_stats = {} @@ -50,31 +51,31 @@ class TensorboardLogger(object): traceback.print_exc() def tb_train_iter_stats(self, step, stats): - self.dict_to_tb_scalar("TrainIterStats", stats, step) + self.dict_to_tb_scalar(f"{self.model_name}_TrainIterStats", stats, step) def tb_train_epoch_stats(self, step, stats): - self.dict_to_tb_scalar("TrainEpochStats", stats, step) + self.dict_to_tb_scalar(f"{self.model_name}_TrainEpochStats", stats, step) def tb_train_figures(self, step, figures): - self.dict_to_tb_figure("TrainFigures", figures, step) + self.dict_to_tb_figure(f"{self.model_name}_TrainFigures", figures, step) def tb_train_audios(self, step, audios, sample_rate): - self.dict_to_tb_audios("TrainAudios", audios, step, sample_rate) + self.dict_to_tb_audios(f"{self.model_name}_TrainAudios", audios, step, sample_rate) def tb_eval_stats(self, step, stats): - self.dict_to_tb_scalar("EvalStats", stats, step) + self.dict_to_tb_scalar(f"{self.model_name}_EvalStats", stats, step) def tb_eval_figures(self, step, figures): - self.dict_to_tb_figure("EvalFigures", figures, step) + self.dict_to_tb_figure(f"{self.model_name}_EvalFigures", figures, step) def tb_eval_audios(self, step, audios, sample_rate): - self.dict_to_tb_audios("EvalAudios", audios, step, sample_rate) + self.dict_to_tb_audios(f"{self.model_name}_EvalAudios", audios, step, sample_rate) def tb_test_audios(self, step, audios, sample_rate): - self.dict_to_tb_audios("TestAudios", audios, step, sample_rate) + self.dict_to_tb_audios(f"{self.model_name}_TestAudios", audios, step, sample_rate) def tb_test_figures(self, step, figures): - self.dict_to_tb_figure("TestFigures", figures, step) + self.dict_to_tb_figure(f"{self.model_name}_TestFigures", figures, step) def tb_add_text(self, title, text, step): self.writer.add_text(title, text, step) From 0bb0ba182e24ed84880f95f5f2dc8586409c6ff9 Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 30 May 2020 18:09:25 +0200 Subject: [PATCH 092/185] initial commit intro. to vocoder submodule --- vocoder/README.md | 35 + vocoder/__init__.py | 0 vocoder/compute_tts_features.py | 0 vocoder/configs/melgan_config.json | 138 ++++ vocoder/datasets/__init__.py | 0 vocoder/datasets/gan_dataset.py | 133 ++++ vocoder/datasets/preprocess.py | 16 + vocoder/layers/__init__.py | 0 vocoder/layers/losses.py | 273 +++++++ vocoder/layers/melgan.py | 48 ++ vocoder/layers/pqmf.py | 55 ++ vocoder/layers/pqmf2.py | 127 ++++ vocoder/layers/qmf.dat | 640 +++++++++++++++++ vocoder/models/__init__.py | 0 vocoder/models/melgan_discriminator.py | 80 +++ vocoder/models/melgan_generator.py | 91 +++ .../models/melgan_multiscale_discriminator.py | 41 ++ vocoder/models/multiband_melgan_generator.py | 38 + vocoder/models/random_window_discriminator.py | 225 ++++++ vocoder/notebooks/Untitled.ipynb | 678 ++++++++++++++++++ vocoder/notebooks/Untitled1.ipynb | 6 + vocoder/pqmf_output.wav | Bin 0 -> 83812 bytes vocoder/tests/__init__.py | 1 + vocoder/tests/test_config.json | 24 + vocoder/tests/test_datasets.py | 95 +++ vocoder/tests/test_losses.py | 62 ++ vocoder/tests/test_melgan_discriminator.py | 26 + vocoder/tests/test_melgan_generator.py | 15 + vocoder/tests/test_pqmf.py | 33 + vocoder/tests/test_rwd.py | 21 + vocoder/train.py | 585 +++++++++++++++ vocoder/utils/__init__.py | 0 vocoder/utils/console_logger.py | 97 +++ vocoder/utils/generic_utils.py | 102 +++ vocoder/utils/io.py | 52 ++ 35 files changed, 3737 insertions(+) create mode 100644 vocoder/README.md create mode 100644 vocoder/__init__.py create mode 100644 vocoder/compute_tts_features.py create mode 100644 vocoder/configs/melgan_config.json create mode 100644 vocoder/datasets/__init__.py create mode 100644 vocoder/datasets/gan_dataset.py create mode 100644 vocoder/datasets/preprocess.py create mode 100644 vocoder/layers/__init__.py create mode 100644 vocoder/layers/losses.py create mode 100644 vocoder/layers/melgan.py create mode 100644 vocoder/layers/pqmf.py create mode 100644 vocoder/layers/pqmf2.py create mode 100644 vocoder/layers/qmf.dat create mode 100644 vocoder/models/__init__.py create mode 100644 vocoder/models/melgan_discriminator.py create mode 100644 vocoder/models/melgan_generator.py create mode 100644 vocoder/models/melgan_multiscale_discriminator.py create mode 100644 vocoder/models/multiband_melgan_generator.py create mode 100644 vocoder/models/random_window_discriminator.py create mode 100644 vocoder/notebooks/Untitled.ipynb create mode 100644 vocoder/notebooks/Untitled1.ipynb create mode 100644 vocoder/pqmf_output.wav create mode 100644 vocoder/tests/__init__.py create mode 100644 vocoder/tests/test_config.json create mode 100644 vocoder/tests/test_datasets.py create mode 100644 vocoder/tests/test_losses.py create mode 100644 vocoder/tests/test_melgan_discriminator.py create mode 100644 vocoder/tests/test_melgan_generator.py create mode 100644 vocoder/tests/test_pqmf.py create mode 100644 vocoder/tests/test_rwd.py create mode 100644 vocoder/train.py create mode 100644 vocoder/utils/__init__.py create mode 100644 vocoder/utils/console_logger.py create mode 100644 vocoder/utils/generic_utils.py create mode 100644 vocoder/utils/io.py diff --git a/vocoder/README.md b/vocoder/README.md new file mode 100644 index 00000000..48fc24ee --- /dev/null +++ b/vocoder/README.md @@ -0,0 +1,35 @@ +# Mozilla TTS Vocoders (Experimental) + +We provide here different vocoder implementations which can be combined with our TTS models to enable "FASTER THAN REAL-TIME" end-to-end TTS stack. + +Currently, there are implementations of the following models. + +- Melgan +- MultiBand-Melgan +- GAN-TTS (Discriminator Only) + +It is also very easy to adapt different vocoder models as we provide here a flexible and modular (but not too modular) framework. + +## Training a model + +You can see here an example (Soon)[Colab Notebook]() training MelGAN with LJSpeech dataset. + +In order to train a new model, you need to collecto all your wav files under a common parent folder and give this path to `data_path` field in '''config.json''' + +You need to define other relevant parameters in your ```config.json``` and then start traning with the following command from Mozilla TTS root path. + +```CUDA_VISIBLE_DEVICES='1' python vocoder/train.py --config_path path/to/config.json``` + +Exampled config files can be found under `vocoder/configs/` folder. + +You can continue a previous training by the following command. + +```CUDA_VISIBLE_DEVICES='1' python vocoder/train.py --continue_path path/to/your/model/folder``` + +You can fine-tune a pre-trained model by the following command. + +```CUDA_VISIBLE_DEVICES='1' python vocoder/train.py --restore_path path/to/your/model.pth.tar``` + +Restoring a model starts a new training in a different output folder. It only restores model weights with the given checkpoint file. However, continuing a training starts from the same conditions the previous training run left off. + +You can also follow your training runs on Tensorboard as you do with our TTS models. \ No newline at end of file diff --git a/vocoder/__init__.py b/vocoder/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/compute_tts_features.py b/vocoder/compute_tts_features.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json new file mode 100644 index 00000000..9a3ded37 --- /dev/null +++ b/vocoder/configs/melgan_config.json @@ -0,0 +1,138 @@ +{ + "run_name": "melgan", + "run_description": "melgan initial run", + + // AUDIO PARAMETERS + "audio":{ + // stft parameters + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "win_length": 1024, // stft window length in ms. + "hop_length": 256, // stft window hop-lengh in ms. + "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. + "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. + + // Audio processing parameters + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + + // Silence trimming + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "trim_db": 60, // threshold for timming silence. Set this according to your dataset. + + // Griffin-Lim + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + + // MelSpectrogram parameters + "num_mels": 80, // size of the mel spec frame. + "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + + // Normalization parameters + "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. + "min_level_db": -100, // lower bound for normalization + "symmetric_norm": true, // move normalization to range [-1, 1] + "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "clip_norm": true, // clip normalized values into the range. + "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + }, + + // DISTRIBUTED TRAINING + // "distributed":{ + // "backend": "nccl", + // "url": "tcp:\/\/localhost:54321" + // }, + + // MODEL PARAMETERS + "use_pqmf": true, + + // LOSS PARAMETERS + "use_stft_loss": true, + "use_mse_gan_loss": true, + "use_hinge_gan_loss": false, + "use_feat_match_loss": false, // use only with melgan discriminators + + "stft_loss_alpha": 1, + "mse_gan_loss_alpha": 1, + "hinge_gan_loss_alpha": 1, + "feat_match_loss_alpha": 10.0, + + "stft_loss_params": { + "n_ffts": [1024, 2048, 512], + "hop_lengths": [120, 240, 50], + "win_lengths": [600, 1200, 240] + }, + "target_loss": "avg_G_loss", // loss value to pick the best model + + // DISCRIMINATOR + "discriminator_model": "melgan_multiscale_discriminator", + "discriminator_model_params":{ + "base_channels": 16, + "max_channels":1024, + "downsample_factors":[4, 4, 4, 4] + }, + "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 + + // "discriminator_model": "random_window_discriminator", + // "discriminator_model_params":{ + // "uncond_disc_donwsample_factors": [8, 4], + // "cond_disc_downsample_factors": [[8, 4, 2, 2, 2], [8, 4, 2, 2], [8, 4, 2], [8, 4], [4, 2, 2]], + // "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], + // "window_sizes": [512, 1024, 2048, 4096, 8192] + // }, + + + // GENERATOR + "generator_model": "multiband_melgan_generator", + "generator_model_params": { + "upsample_factors":[2 ,2, 4, 4], + "num_res_blocks": 4 + }, + + // DATASET + "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", + "seq_len": 16384, + "pad_short": 2000, + "conv_pad": 0, + "use_noise_augment": true, + "use_cache": true, + + "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. + + // TRAINING + "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. + + // VALIDATION + "run_eval": true, + "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. + "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. + + // OPTIMIZER + "noam_schedule": true, // use noam warmup and lr schedule. + "grad_clip": 1.0, // upper limit for gradients for clipping. + "epochs": 1000, // total number of epochs to train. + "wd": 0.000001, // Weight decay weight. + "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 0.0001, + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, + "gen_clip_grad": 10.0, + "disc_clip_grad": 10.0, + + // TENSORBOARD and LOGGING + "print_step": 25, // Number of steps to log traning on console. + "print_eval": false, // If True, it prints intermediate loss values in evalulation. + "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. + "checkpoint": true, // If true, it saves checkpoints per "save_step" + "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. + + // DATA LOADING + "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. + "num_val_loader_workers": 4, // number of evaluation data loader processes. + "eval_split_size": 10, + + // PATHS + "output_path": "/home/erogol/Models/LJSpeech/" +} + diff --git a/vocoder/datasets/__init__.py b/vocoder/datasets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/datasets/gan_dataset.py b/vocoder/datasets/gan_dataset.py new file mode 100644 index 00000000..10d36cab --- /dev/null +++ b/vocoder/datasets/gan_dataset.py @@ -0,0 +1,133 @@ +import os +import glob +import torch +import random +import numpy as np +from torch.utils.data import Dataset, DataLoader +from multiprocessing import Manager + + +def create_dataloader(hp, args, train): + dataset = MelFromDisk(hp, args, train) + + if train: + return DataLoader(dataset=dataset, + batch_size=hp.train.batch_size, + shuffle=True, + num_workers=hp.train.num_workers, + pin_memory=True, + drop_last=True) + else: + return DataLoader(dataset=dataset, + batch_size=1, + shuffle=False, + num_workers=hp.train.num_workers, + pin_memory=True, + drop_last=False) + + +class GANDataset(Dataset): + """ + GAN Dataset searchs for all the wav files under root path + and converts them to acoustic features on the fly and returns + random segments of (audio, feature) couples. + """ + def __init__(self, + ap, + items, + seq_len, + hop_len, + pad_short, + conv_pad=2, + is_training=True, + return_segments=True, + use_noise_augment=False, + use_cache=False, + verbose=False): + + self.ap = ap + self.item_list = items + self.seq_len = seq_len + self.hop_len = hop_len + self.pad_short = pad_short + self.conv_pad = conv_pad + self.is_training = is_training + self.return_segments = return_segments + self.use_cache = use_cache + self.use_noise_augment = use_noise_augment + + assert seq_len % hop_len == 0, " [!] seq_len has to be a multiple of hop_len." + self.feat_frame_len = seq_len // hop_len + (2 * conv_pad) + + # map G and D instances + self.G_to_D_mappings = [i for i in range(len(self.item_list))] + self.shuffle_mapping() + + # cache acoustic features + if use_cache: + self.create_feature_cache() + + + + def create_feature_cache(self): + self.manager = Manager() + self.cache = self.manager.list() + self.cache += [None for _ in range(len(self.item_list))] + + def find_wav_files(self, path): + return glob.glob(os.path.join(path, '**', '*.wav'), recursive=True) + + def __len__(self): + return len(self.item_list) + + def __getitem__(self, idx): + """ Return different items for Generator and Discriminator and + cache acoustic features """ + if self.return_segments: + idx2 = self.G_to_D_mappings[idx] + item1 = self.load_item(idx) + item2 = self.load_item(idx2) + return item1, item2 + else: + item1 = self.load_item(idx) + return item1 + + def shuffle_mapping(self): + random.shuffle(self.G_to_D_mappings) + + def load_item(self, idx): + """ load (audio, feat) couple """ + wavpath = self.item_list[idx] + # print(wavpath) + + if self.use_cache and self.cache[idx] is not None: + audio, mel = self.cache[idx] + else: + audio = self.ap.load_wav(wavpath) + mel = self.ap.melspectrogram(audio) + + if len(audio) < self.seq_len + self.pad_short: + audio = np.pad(audio, (0, self.seq_len + self.pad_short - len(audio)), \ + mode='constant', constant_values=0.0) + + # correct the audio length wrt padding applied in stft + audio = np.pad(audio, (0, self.hop_len), mode="edge") + audio = audio[:mel.shape[-1] * self.hop_len] + assert mel.shape[-1] * self.hop_len == audio.shape[-1], f' [!] {mel.shape[-1] * self.hop_len} vs {audio.shape[-1]}' + + audio = torch.from_numpy(audio).float().unsqueeze(0) + mel = torch.from_numpy(mel).float().squeeze(0) + + if self.return_segments: + max_mel_start = mel.shape[1] - self.feat_frame_len + mel_start = random.randint(0, max_mel_start) + mel_end = mel_start + self.feat_frame_len + mel = mel[:, mel_start:mel_end] + + audio_start = mel_start * self.hop_len + audio = audio[:, audio_start:audio_start + + self.seq_len] + + if self.use_noise_augment and self.is_training and self.return_segments: + audio = audio + (1 / 32768) * torch.randn_like(audio) + return (mel, audio) diff --git a/vocoder/datasets/preprocess.py b/vocoder/datasets/preprocess.py new file mode 100644 index 00000000..01e01e3e --- /dev/null +++ b/vocoder/datasets/preprocess.py @@ -0,0 +1,16 @@ +import glob +import os + +import numpy as np + + +def find_wav_files(data_path): + wav_paths = glob.glob(os.path.join(data_path, '**', '*.wav'), recursive=True) + return wav_paths + + +def load_wav_data(data_path, eval_split_size): + wav_paths = find_wav_files(data_path) + np.random.seed(0) + np.random.shuffle(wav_paths) + return wav_paths[:eval_split_size], wav_paths[eval_split_size:] diff --git a/vocoder/layers/__init__.py b/vocoder/layers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py new file mode 100644 index 00000000..11985629 --- /dev/null +++ b/vocoder/layers/losses.py @@ -0,0 +1,273 @@ +import torch + +from torch import nn +from torch.nn import functional as F + + +class TorchSTFT(): + def __init__(self, n_fft, hop_length, win_length, window='hann_window'): + self.n_fft = n_fft + self.hop_length = hop_length + self.win_length = win_length + self.window = getattr(torch, window)(win_length) + + def __call__(self, x): + # B x D x T x 2 + o = torch.stft(x, + self.n_fft, + self.hop_length, + self.win_length, + self.window, + center=True, + pad_mode="constant", # compatible with audio.py + normalized=False, + onesided=True) + M = o[:, :, :, 0] + P = o[:, :, :, 1] + return torch.sqrt(torch.clamp(M ** 2 + P ** 2, min=1e-8)) + + +################################# +# GENERATOR LOSSES +################################# + + +class STFTLoss(nn.Module): + def __init__(self, n_fft, hop_length, win_length): + super(STFTLoss, self).__init__() + self.n_fft = n_fft + self.hop_length = hop_length + self.win_length = win_length + self.stft = TorchSTFT(n_fft, hop_length, win_length) + + def forward(self, y_hat, y): + y_hat_M = self.stft(y_hat) + y_M = self.stft(y) + # magnitude loss + loss_mag = F.l1_loss(torch.log(y_M), torch.log(y_hat_M)) + # spectral convergence loss + loss_sc = torch.norm(y_M - y_hat_M, p="fro") / torch.norm(y_M, p="fro") + return loss_mag, loss_sc + + +class MultiScaleSTFTLoss(torch.nn.Module): + def __init__(self, + n_ffts=[1024, 2048, 512], + hop_lengths=[120, 240, 50], + win_lengths=[600, 1200, 240]): + super(MultiScaleSTFTLoss, self).__init__() + self.loss_funcs = torch.nn.ModuleList() + for idx in range(len(n_ffts)): + self.loss_funcs.append(STFTLoss(n_ffts[idx], hop_lengths[idx], win_lengths[idx])) + + def forward(self, y_hat, y): + N = len(self.loss_funcs) + loss_sc = 0 + loss_mag = 0 + for f in self.loss_funcs: + lm, lsc = f(y_hat, y) + loss_mag += lm + loss_sc += lsc + loss_sc /= N + loss_mag /= N + return loss_mag, loss_sc + + +class MSEGLoss(nn.Module): + """ Mean Squared Generator Loss """ + def __init__(self,): + super(MSEGLoss, self).__init__() + + def forward(self, score_fake, ): + loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + return loss_fake + + +class HingeGLoss(nn.Module): + """ Hinge Discriminator Loss """ + def __init__(self,): + super(HingeGLoss, self).__init__() + + def forward(self, score_fake, score_real): + loss_fake = torch.mean(F.relu(1. + score_fake)) + return loss_fake + + +################################## +# DISCRIMINATOR LOSSES +################################## + + +class MSEDLoss(nn.Module): + """ Mean Squared Discriminator Loss """ + def __init__(self,): + super(MSEDLoss, self).__init__() + + def forward(self, score_fake, score_real): + loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) + loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + loss_d = loss_real + loss_fake + return loss_d, loss_real, loss_fake + + +class HingeDLoss(nn.Module): + """ Hinge Discriminator Loss """ + def __init__(self,): + super(HingeDLoss, self).__init__() + + def forward(self, score_fake, score_real): + loss_real = torch.mean(F.relu(1. - score_real)) + loss_fake = torch.mean(F.relu(1. + score_fake)) + loss_d = loss_real + loss_fake + return loss_d, loss_real, loss_fake + + +class MelganFeatureLoss(nn.Module): + def __init__(self, ): + super(MelganFeatureLoss, self).__init__() + + def forward(self, fake_feats, real_feats): + loss_feats = 0 + for fake_feat, real_feat in zip(fake_feats, real_feats): + loss_feats += hp.model.feat_match * torch.mean(torch.abs(fake_feat - real_feat)) + return loss_feats + + +################################## +# LOSS WRAPPERS +################################## + + +class GeneratorLoss(nn.Module): + def __init__(self, C): + super(GeneratorLoss, self).__init__() + assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + " [!] Cannot use HingeGANLoss and MSEGANLoss together." + + self.use_stft_loss = C.use_stft_loss + self.use_mse_gan_loss = C.use_mse_gan_loss + self.use_hinge_gan_loss = C.use_hinge_gan_loss + self.use_feat_match_loss = C.use_feat_match_loss + + self.stft_loss_alpha = C.stft_loss_alpha + self.mse_gan_loss_alpha = C.mse_gan_loss_alpha + self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha + self.feat_match_loss_alpha = C.feat_match_loss_alpha + + if C.use_stft_loss: + self.stft_loss = MultiScaleSTFTLoss(**C.stft_loss_params) + if C.use_mse_gan_loss: + self.mse_loss = MSEGLoss() + if C.use_hinge_gan_loss: + self.hinge_loss = HingeGLoss() + if C.use_feat_match_loss: + self.feat_match_loss = MelganFeatureLoss() + + def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None): + loss = 0 + return_dict = {} + + # STFT Loss + if self.use_stft_loss: + stft_loss_mg, stft_loss_sc = self.stft_loss(y_hat.squeeze(1), y.squeeze(1)) + return_dict['G_stft_loss_mg'] = stft_loss_mg + return_dict['G_stft_loss_sc'] = stft_loss_sc + loss += self.stft_loss_alpha * (stft_loss_mg + stft_loss_sc) + + # Fake Losses + if self.use_mse_gan_loss and scores_fake is not None: + mse_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake in scores_fake: + fake_loss = self.mse_loss(score_fake) + mse_fake_loss += fake_loss + else: + fake_loss = self.mse_loss(scores_fake) + mse_fake_loss = fake_loss + return_dict['G_mse_fake_loss'] = mse_fake_loss + loss += self.mse_gan_loss_alpha * mse_fake_loss + + if self.use_hinge_gan_loss and not scores_fake is not None: + hinge_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake in scores_fake: + fake_loss = self.hinge_loss(score_fake) + hinge_fake_loss += fake_loss + else: + fake_loss = self.hinge_loss(scores_fake) + hinge_fake_loss = fake_loss + return_dict['G_hinge_fake_loss'] = hinge_fake_loss + loss += self.hinge_gan_loss_alpha * hinge_fake_loss + + # Feature Matching Loss + if self.use_feat_match_loss and not feats_fake: + feat_match_loss = self.feat_match_loss(feats_fake, feats_real) + return_dict['G_feat_match_loss'] = feat_match_loss + loss += self.feat_match_loss_alpha * feat_match_loss + return_dict['G_loss'] = loss + return return_dict + + +class DiscriminatorLoss(nn.Module): + def __init__(self, C): + super(DiscriminatorLoss, self).__init__() + assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + " [!] Cannot use HingeGANLoss and MSEGANLoss together." + + self.use_mse_gan_loss = C.use_mse_gan_loss + self.use_hinge_gan_loss = C.use_hinge_gan_loss + + self.mse_gan_loss_alpha = C.mse_gan_loss_alpha + self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha + + if C.use_mse_gan_loss: + self.mse_loss = MSEDLoss() + if C.use_hinge_gan_loss: + self.hinge_loss = HingeDLoss() + + def forward(self, scores_fake, scores_real): + loss = 0 + return_dict = {} + + if self.use_mse_gan_loss: + mse_gan_loss = 0 + mse_gan_real_loss = 0 + mse_gan_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake, score_real in zip(scores_fake, scores_real): + total_loss, real_loss, fake_loss = self.mse_loss(score_fake, score_real) + mse_gan_loss += total_loss + mse_gan_real_loss += real_loss + mse_gan_fake_loss += fake_loss + else: + total_loss, real_loss, fake_loss = self.mse_loss(scores_fake, scores_real) + mse_gan_loss = total_loss + mse_gan_real_loss = real_loss + mse_gan_fake_loss = fake_loss + return_dict['D_mse_gan_loss'] = mse_gan_loss + return_dict['D_mse_gan_real_loss'] = mse_gan_real_loss + return_dict['D_mse_gan_fake_loss'] = mse_gan_fake_loss + loss += self.mse_gan_loss_alpha * mse_gan_loss + + if self.use_hinge_gan_loss: + hinge_gan_loss = 0 + hinge_gan_real_loss = 0 + hinge_gan_fake_loss = 0 + if isinstance(scores_fake, list): + for score_fake, score_real in zip(scores_fake, scores_real): + total_loss, real_loss, fake_loss = self.hinge_loss(score_fake, score_real) + hinge_gan_loss += total_loss + hinge_gan_real_loss += real_loss + hinge_gan_fake_loss += fake_loss + else: + total_loss, real_loss, fake_loss = self.hinge_loss(scores_fake, scores_real) + hinge_gan_loss = total_loss + hinge_gan_real_loss = real_loss + hinge_gan_fake_loss = fake_loss + return_dict['D_hinge_gan_loss'] = hinge_gan_loss + return_dict['D_hinge_gan_real_loss'] = hinge_gan_real_loss + return_dict['D_hinge_gan_fake_loss'] = hinge_gan_fake_loss + loss += self.hinge_gan_loss_alpha * hinge_gan_loss + + return_dict['D_loss'] = loss + return return_dict \ No newline at end of file diff --git a/vocoder/layers/melgan.py b/vocoder/layers/melgan.py new file mode 100644 index 00000000..cda0413c --- /dev/null +++ b/vocoder/layers/melgan.py @@ -0,0 +1,48 @@ +import numpy as np +import torch +from torch import nn +from torch.nn import functional as F +from torch.nn.utils import weight_norm + + +class ResidualStack(nn.Module): + def __init__(self, channels, num_res_blocks, kernel_size): + super(ResidualStack, self).__init__() + + assert (kernel_size - 1) % 2 == 0, " [!] kernel_size has to be odd." + base_padding = (kernel_size - 1) // 2 + + self.blocks = nn.ModuleList() + for idx in range(num_res_blocks): + layer_kernel_size = kernel_size + layer_dilation = layer_kernel_size**idx + layer_padding = base_padding * layer_dilation + self.blocks += [nn.Sequential( + nn.LeakyReLU(0.2), + nn.ReflectionPad1d(layer_padding), + weight_norm( + nn.Conv1d(channels, + channels, + kernel_size=kernel_size, + dilation=layer_padding, + bias=True)), + nn.LeakyReLU(0.2), + weight_norm( + nn.Conv1d(channels, channels, kernel_size=1, bias=True)), + )] + + self.shortcuts = nn.ModuleList([ + weight_norm(nn.Conv1d(channels, channels, kernel_size=1, + bias=True)) for i in range(num_res_blocks) + ]) + + def forward(self, x): + for block, shortcut in zip(self.blocks, self.shortcuts): + x = shortcut(x) + block(x) + return x + + def remove_weight_norm(self): + for block, shortcut in zip(self.blocks, self.shortcuts): + nn.utils.remove_weight_norm(block[2]) + nn.utils.remove_weight_norm(block[4]) + nn.utils.remove_weight_norm(shortcut) diff --git a/vocoder/layers/pqmf.py b/vocoder/layers/pqmf.py new file mode 100644 index 00000000..f438ea00 --- /dev/null +++ b/vocoder/layers/pqmf.py @@ -0,0 +1,55 @@ +"""Pseudo QMF modules.""" + +import numpy as np +import torch +import torch.nn.functional as F + +from scipy import signal as sig + + +# adapted from +# https://github.com/kan-bayashi/ParallelWaveGAN/tree/master/parallel_wavegan +class PQMF(torch.nn.Module): + def __init__(self, N=4, taps=62, cutoff=0.15, beta=9.0): + super(PQMF, self).__init__() + + self.N = N + self.taps = taps + self.cutoff = cutoff + self.beta = beta + + QMF = sig.firwin(taps + 1, cutoff, window=('kaiser', beta)) + H = np.zeros((N, len(QMF))) + G = np.zeros((N, len(QMF))) + for k in range(N): + constant_factor = (2 * k + 1) * (np.pi / + (2 * N)) * (np.arange(taps + 1) - + ((taps - 1) / 2)) + phase = (-1)**k * np.pi / 4 + H[k] = 2 * QMF * np.cos(constant_factor + phase) + + G[k] = 2 * QMF * np.cos(constant_factor - phase) + + H = torch.from_numpy(H[:, None, :]).float() + G = torch.from_numpy(G[None, :, :]).float() + + self.register_buffer("H", H) + self.register_buffer("G", G) + + updown_filter = torch.zeros((N, N, N)).float() + for k in range(N): + updown_filter[k, k, 0] = 1.0 + self.register_buffer("updown_filter", updown_filter) + self.N = N + + self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) + + def analysis(self, x): + return F.conv1d(x, self.H, padding=self.taps // 2, stride=self.N) + + def synthesis(self, x): + x = F.conv_transpose1d(x, + self.updown_filter * self.N, + stride=self.N) + x = F.conv1d(x, self.G, padding=self.taps // 2) + return x diff --git a/vocoder/layers/pqmf2.py b/vocoder/layers/pqmf2.py new file mode 100644 index 00000000..4cffb819 --- /dev/null +++ b/vocoder/layers/pqmf2.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Tomoki Hayashi +# MIT License (https://opensource.org/licenses/MIT) + +"""Pseudo QMF modules.""" + +import numpy as np +import torch +import torch.nn.functional as F + +from scipy.signal import kaiser + + +def design_prototype_filter(taps=62, cutoff_ratio=0.15, beta=9.0): + """Design prototype filter for PQMF. + + This method is based on `A Kaiser window approach for the design of prototype + filters of cosine modulated filterbanks`_. + + Args: + taps (int): The number of filter taps. + cutoff_ratio (float): Cut-off frequency ratio. + beta (float): Beta coefficient for kaiser window. + + Returns: + ndarray: Impluse response of prototype filter (taps + 1,). + + .. _`A Kaiser window approach for the design of prototype filters of cosine modulated filterbanks`: + https://ieeexplore.ieee.org/abstract/document/681427 + + """ + # check the arguments are valid + assert taps % 2 == 0, "The number of taps mush be even number." + assert 0.0 < cutoff_ratio < 1.0, "Cutoff ratio must be > 0.0 and < 1.0." + + # make initial filter + omega_c = np.pi * cutoff_ratio + with np.errstate(invalid='ignore'): + h_i = np.sin(omega_c * (np.arange(taps + 1) - 0.5 * taps)) \ + / (np.pi * (np.arange(taps + 1) - 0.5 * taps)) + h_i[taps // 2] = np.cos(0) * cutoff_ratio # fix nan due to indeterminate form + + # apply kaiser window + w = kaiser(taps + 1, beta) + h = h_i * w + + return h + + +class PQMF(torch.nn.Module): + """PQMF module. + + This module is based on `Near-perfect-reconstruction pseudo-QMF banks`_. + + .. _`Near-perfect-reconstruction pseudo-QMF banks`: + https://ieeexplore.ieee.org/document/258122 + + """ + + def __init__(self, subbands=4, taps=62, cutoff_ratio=0.15, beta=9.0): + """Initilize PQMF module. + + Args: + subbands (int): The number of subbands. + taps (int): The number of filter taps. + cutoff_ratio (float): Cut-off frequency ratio. + beta (float): Beta coefficient for kaiser window. + + """ + super(PQMF, self).__init__() + + # define filter coefficient + h_proto = design_prototype_filter(taps, cutoff_ratio, beta) + h_analysis = np.zeros((subbands, len(h_proto))) + h_synthesis = np.zeros((subbands, len(h_proto))) + for k in range(subbands): + h_analysis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) + (-1) ** k * np.pi / 4) + h_synthesis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) - (-1) ** k * np.pi / 4) + + # convert to tensor + analysis_filter = torch.from_numpy(h_analysis).float().unsqueeze(1) + synthesis_filter = torch.from_numpy(h_synthesis).float().unsqueeze(0) + + # register coefficients as beffer + self.register_buffer("analysis_filter", analysis_filter) + self.register_buffer("synthesis_filter", synthesis_filter) + + # filter for downsampling & upsampling + updown_filter = torch.zeros((subbands, subbands, subbands)).float() + for k in range(subbands): + updown_filter[k, k, 0] = 1.0 + self.register_buffer("updown_filter", updown_filter) + self.subbands = subbands + + # keep padding info + self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) + + def analysis(self, x): + """Analysis with PQMF. + + Args: + x (Tensor): Input tensor (B, 1, T). + + Returns: + Tensor: Output tensor (B, subbands, T // subbands). + + """ + x = F.conv1d(self.pad_fn(x), self.analysis_filter) + return F.conv1d(x, self.updown_filter, stride=self.subbands) + + def synthesis(self, x): + """Synthesis with PQMF. + + Args: + x (Tensor): Input tensor (B, subbands, T // subbands). + + Returns: + Tensor: Output tensor (B, 1, T). + + """ + # NOTE(kan-bayashi): Power will be dreased so here multipy by # subbands. + # Not sure this is the correct way, it is better to check again. + # TODO(kan-bayashi): Understand the reconstruction procedure + x = F.conv_transpose1d(x, self.updown_filter * self.subbands, stride=self.subbands) + x = F.conv1d(self.pad_fn(x), self.synthesis_filter) + return x diff --git a/vocoder/layers/qmf.dat b/vocoder/layers/qmf.dat new file mode 100644 index 00000000..17eab137 --- /dev/null +++ b/vocoder/layers/qmf.dat @@ -0,0 +1,640 @@ + 0.0000000e+000 + -5.5252865e-004 + -5.6176926e-004 + -4.9475181e-004 + -4.8752280e-004 + -4.8937912e-004 + -5.0407143e-004 + -5.2265643e-004 + -5.4665656e-004 + -5.6778026e-004 + -5.8709305e-004 + -6.1327474e-004 + -6.3124935e-004 + -6.5403334e-004 + -6.7776908e-004 + -6.9416146e-004 + -7.1577365e-004 + -7.2550431e-004 + -7.4409419e-004 + -7.4905981e-004 + -7.6813719e-004 + -7.7248486e-004 + -7.8343323e-004 + -7.7798695e-004 + -7.8036647e-004 + -7.8014496e-004 + -7.7579773e-004 + -7.6307936e-004 + -7.5300014e-004 + -7.3193572e-004 + -7.2153920e-004 + -6.9179375e-004 + -6.6504151e-004 + -6.3415949e-004 + -5.9461189e-004 + -5.5645764e-004 + -5.1455722e-004 + -4.6063255e-004 + -4.0951215e-004 + -3.5011759e-004 + -2.8969812e-004 + -2.0983373e-004 + -1.4463809e-004 + -6.1733441e-005 + 1.3494974e-005 + 1.0943831e-004 + 2.0430171e-004 + 2.9495311e-004 + 4.0265402e-004 + 5.1073885e-004 + 6.2393761e-004 + 7.4580259e-004 + 8.6084433e-004 + 9.8859883e-004 + 1.1250155e-003 + 1.2577885e-003 + 1.3902495e-003 + 1.5443220e-003 + 1.6868083e-003 + 1.8348265e-003 + 1.9841141e-003 + 2.1461584e-003 + 2.3017255e-003 + 2.4625617e-003 + 2.6201759e-003 + 2.7870464e-003 + 2.9469448e-003 + 3.1125421e-003 + 3.2739613e-003 + 3.4418874e-003 + 3.6008268e-003 + 3.7603923e-003 + 3.9207432e-003 + 4.0819753e-003 + 4.2264269e-003 + 4.3730720e-003 + 4.5209853e-003 + 4.6606461e-003 + 4.7932561e-003 + 4.9137604e-003 + 5.0393023e-003 + 5.1407354e-003 + 5.2461166e-003 + 5.3471681e-003 + 5.4196776e-003 + 5.4876040e-003 + 5.5475715e-003 + 5.5938023e-003 + 5.6220643e-003 + 5.6455197e-003 + 5.6389200e-003 + 5.6266114e-003 + 5.5917129e-003 + 5.5404364e-003 + 5.4753783e-003 + 5.3838976e-003 + 5.2715759e-003 + 5.1382275e-003 + 4.9839688e-003 + 4.8109469e-003 + 4.6039530e-003 + 4.3801862e-003 + 4.1251642e-003 + 3.8456408e-003 + 3.5401247e-003 + 3.2091886e-003 + 2.8446758e-003 + 2.4508540e-003 + 2.0274176e-003 + 1.5784683e-003 + 1.0902329e-003 + 5.8322642e-004 + 2.7604519e-005 + -5.4642809e-004 + -1.1568136e-003 + -1.8039473e-003 + -2.4826724e-003 + -3.1933778e-003 + -3.9401124e-003 + -4.7222596e-003 + -5.5337211e-003 + -6.3792293e-003 + -7.2615817e-003 + -8.1798233e-003 + -9.1325330e-003 + -1.0115022e-002 + -1.1131555e-002 + -1.2185000e-002 + -1.3271822e-002 + -1.4390467e-002 + -1.5540555e-002 + -1.6732471e-002 + -1.7943338e-002 + -1.9187243e-002 + -2.0453179e-002 + -2.1746755e-002 + -2.3068017e-002 + -2.4416099e-002 + -2.5787585e-002 + -2.7185943e-002 + -2.8607217e-002 + -3.0050266e-002 + -3.1501761e-002 + -3.2975408e-002 + -3.4462095e-002 + -3.5969756e-002 + -3.7481285e-002 + -3.9005368e-002 + -4.0534917e-002 + -4.2064909e-002 + -4.3609754e-002 + -4.5148841e-002 + -4.6684303e-002 + -4.8216572e-002 + -4.9738576e-002 + -5.1255616e-002 + -5.2763075e-002 + -5.4245277e-002 + -5.5717365e-002 + -5.7161645e-002 + -5.8591568e-002 + -5.9983748e-002 + -6.1345517e-002 + -6.2685781e-002 + -6.3971590e-002 + -6.5224711e-002 + -6.6436751e-002 + -6.7607599e-002 + -6.8704383e-002 + -6.9763024e-002 + -7.0762871e-002 + -7.1700267e-002 + -7.2568258e-002 + -7.3362026e-002 + -7.4100364e-002 + -7.4745256e-002 + -7.5313734e-002 + -7.5800836e-002 + -7.6199248e-002 + -7.6499217e-002 + -7.6709349e-002 + -7.6817398e-002 + -7.6823001e-002 + -7.6720492e-002 + -7.6505072e-002 + -7.6174832e-002 + -7.5730576e-002 + -7.5157626e-002 + -7.4466439e-002 + -7.3640601e-002 + -7.2677464e-002 + -7.1582636e-002 + -7.0353307e-002 + -6.8966401e-002 + -6.7452502e-002 + -6.5769067e-002 + -6.3944481e-002 + -6.1960278e-002 + -5.9816657e-002 + -5.7515269e-002 + -5.5046003e-002 + -5.2409382e-002 + -4.9597868e-002 + -4.6630331e-002 + -4.3476878e-002 + -4.0145828e-002 + -3.6641812e-002 + -3.2958393e-002 + -2.9082401e-002 + -2.5030756e-002 + -2.0799707e-002 + -1.6370126e-002 + -1.1762383e-002 + -6.9636862e-003 + -1.9765601e-003 + 3.2086897e-003 + 8.5711749e-003 + 1.4128883e-002 + 1.9883413e-002 + 2.5822729e-002 + 3.1953127e-002 + 3.8277657e-002 + 4.4780682e-002 + 5.1480418e-002 + 5.8370533e-002 + 6.5440985e-002 + 7.2694330e-002 + 8.0137293e-002 + 8.7754754e-002 + 9.5553335e-002 + 1.0353295e-001 + 1.1168269e-001 + 1.2000780e-001 + 1.2850029e-001 + 1.3715518e-001 + 1.4597665e-001 + 1.5496071e-001 + 1.6409589e-001 + 1.7338082e-001 + 1.8281725e-001 + 1.9239667e-001 + 2.0212502e-001 + 2.1197359e-001 + 2.2196527e-001 + 2.3206909e-001 + 2.4230169e-001 + 2.5264803e-001 + 2.6310533e-001 + 2.7366340e-001 + 2.8432142e-001 + 2.9507167e-001 + 3.0590986e-001 + 3.1682789e-001 + 3.2781137e-001 + 3.3887227e-001 + 3.4999141e-001 + 3.6115899e-001 + 3.7237955e-001 + 3.8363500e-001 + 3.9492118e-001 + 4.0623177e-001 + 4.1756969e-001 + 4.2891199e-001 + 4.4025538e-001 + 4.5159965e-001 + 4.6293081e-001 + 4.7424532e-001 + 4.8552531e-001 + 4.9677083e-001 + 5.0798175e-001 + 5.1912350e-001 + 5.3022409e-001 + 5.4125534e-001 + 5.5220513e-001 + 5.6307891e-001 + 5.7385241e-001 + 5.8454032e-001 + 5.9511231e-001 + 6.0557835e-001 + 6.1591099e-001 + 6.2612427e-001 + 6.3619801e-001 + 6.4612697e-001 + 6.5590163e-001 + 6.6551399e-001 + 6.7496632e-001 + 6.8423533e-001 + 6.9332824e-001 + 7.0223887e-001 + 7.1094104e-001 + 7.1944626e-001 + 7.2774489e-001 + 7.3582118e-001 + 7.4368279e-001 + 7.5131375e-001 + 7.5870808e-001 + 7.6586749e-001 + 7.7277809e-001 + 7.7942875e-001 + 7.8583531e-001 + 7.9197358e-001 + 7.9784664e-001 + 8.0344858e-001 + 8.0876950e-001 + 8.1381913e-001 + 8.1857760e-001 + 8.2304199e-001 + 8.2722753e-001 + 8.3110385e-001 + 8.3469374e-001 + 8.3797173e-001 + 8.4095414e-001 + 8.4362383e-001 + 8.4598185e-001 + 8.4803158e-001 + 8.4978052e-001 + 8.5119715e-001 + 8.5230470e-001 + 8.5310209e-001 + 8.5357206e-001 + 8.5373856e-001 + 8.5357206e-001 + 8.5310209e-001 + 8.5230470e-001 + 8.5119715e-001 + 8.4978052e-001 + 8.4803158e-001 + 8.4598185e-001 + 8.4362383e-001 + 8.4095414e-001 + 8.3797173e-001 + 8.3469374e-001 + 8.3110385e-001 + 8.2722753e-001 + 8.2304199e-001 + 8.1857760e-001 + 8.1381913e-001 + 8.0876950e-001 + 8.0344858e-001 + 7.9784664e-001 + 7.9197358e-001 + 7.8583531e-001 + 7.7942875e-001 + 7.7277809e-001 + 7.6586749e-001 + 7.5870808e-001 + 7.5131375e-001 + 7.4368279e-001 + 7.3582118e-001 + 7.2774489e-001 + 7.1944626e-001 + 7.1094104e-001 + 7.0223887e-001 + 6.9332824e-001 + 6.8423533e-001 + 6.7496632e-001 + 6.6551399e-001 + 6.5590163e-001 + 6.4612697e-001 + 6.3619801e-001 + 6.2612427e-001 + 6.1591099e-001 + 6.0557835e-001 + 5.9511231e-001 + 5.8454032e-001 + 5.7385241e-001 + 5.6307891e-001 + 5.5220513e-001 + 5.4125534e-001 + 5.3022409e-001 + 5.1912350e-001 + 5.0798175e-001 + 4.9677083e-001 + 4.8552531e-001 + 4.7424532e-001 + 4.6293081e-001 + 4.5159965e-001 + 4.4025538e-001 + 4.2891199e-001 + 4.1756969e-001 + 4.0623177e-001 + 3.9492118e-001 + 3.8363500e-001 + 3.7237955e-001 + 3.6115899e-001 + 3.4999141e-001 + 3.3887227e-001 + 3.2781137e-001 + 3.1682789e-001 + 3.0590986e-001 + 2.9507167e-001 + 2.8432142e-001 + 2.7366340e-001 + 2.6310533e-001 + 2.5264803e-001 + 2.4230169e-001 + 2.3206909e-001 + 2.2196527e-001 + 2.1197359e-001 + 2.0212502e-001 + 1.9239667e-001 + 1.8281725e-001 + 1.7338082e-001 + 1.6409589e-001 + 1.5496071e-001 + 1.4597665e-001 + 1.3715518e-001 + 1.2850029e-001 + 1.2000780e-001 + 1.1168269e-001 + 1.0353295e-001 + 9.5553335e-002 + 8.7754754e-002 + 8.0137293e-002 + 7.2694330e-002 + 6.5440985e-002 + 5.8370533e-002 + 5.1480418e-002 + 4.4780682e-002 + 3.8277657e-002 + 3.1953127e-002 + 2.5822729e-002 + 1.9883413e-002 + 1.4128883e-002 + 8.5711749e-003 + 3.2086897e-003 + -1.9765601e-003 + -6.9636862e-003 + -1.1762383e-002 + -1.6370126e-002 + -2.0799707e-002 + -2.5030756e-002 + -2.9082401e-002 + -3.2958393e-002 + -3.6641812e-002 + -4.0145828e-002 + -4.3476878e-002 + -4.6630331e-002 + -4.9597868e-002 + -5.2409382e-002 + -5.5046003e-002 + -5.7515269e-002 + -5.9816657e-002 + -6.1960278e-002 + -6.3944481e-002 + -6.5769067e-002 + -6.7452502e-002 + -6.8966401e-002 + -7.0353307e-002 + -7.1582636e-002 + -7.2677464e-002 + -7.3640601e-002 + -7.4466439e-002 + -7.5157626e-002 + -7.5730576e-002 + -7.6174832e-002 + -7.6505072e-002 + -7.6720492e-002 + -7.6823001e-002 + -7.6817398e-002 + -7.6709349e-002 + -7.6499217e-002 + -7.6199248e-002 + -7.5800836e-002 + -7.5313734e-002 + -7.4745256e-002 + -7.4100364e-002 + -7.3362026e-002 + -7.2568258e-002 + -7.1700267e-002 + -7.0762871e-002 + -6.9763024e-002 + -6.8704383e-002 + -6.7607599e-002 + -6.6436751e-002 + -6.5224711e-002 + -6.3971590e-002 + -6.2685781e-002 + -6.1345517e-002 + -5.9983748e-002 + -5.8591568e-002 + -5.7161645e-002 + -5.5717365e-002 + -5.4245277e-002 + -5.2763075e-002 + -5.1255616e-002 + -4.9738576e-002 + -4.8216572e-002 + -4.6684303e-002 + -4.5148841e-002 + -4.3609754e-002 + -4.2064909e-002 + -4.0534917e-002 + -3.9005368e-002 + -3.7481285e-002 + -3.5969756e-002 + -3.4462095e-002 + -3.2975408e-002 + -3.1501761e-002 + -3.0050266e-002 + -2.8607217e-002 + -2.7185943e-002 + -2.5787585e-002 + -2.4416099e-002 + -2.3068017e-002 + -2.1746755e-002 + -2.0453179e-002 + -1.9187243e-002 + -1.7943338e-002 + -1.6732471e-002 + -1.5540555e-002 + -1.4390467e-002 + -1.3271822e-002 + -1.2185000e-002 + -1.1131555e-002 + -1.0115022e-002 + -9.1325330e-003 + -8.1798233e-003 + -7.2615817e-003 + -6.3792293e-003 + -5.5337211e-003 + -4.7222596e-003 + -3.9401124e-003 + -3.1933778e-003 + -2.4826724e-003 + -1.8039473e-003 + -1.1568136e-003 + -5.4642809e-004 + 2.7604519e-005 + 5.8322642e-004 + 1.0902329e-003 + 1.5784683e-003 + 2.0274176e-003 + 2.4508540e-003 + 2.8446758e-003 + 3.2091886e-003 + 3.5401247e-003 + 3.8456408e-003 + 4.1251642e-003 + 4.3801862e-003 + 4.6039530e-003 + 4.8109469e-003 + 4.9839688e-003 + 5.1382275e-003 + 5.2715759e-003 + 5.3838976e-003 + 5.4753783e-003 + 5.5404364e-003 + 5.5917129e-003 + 5.6266114e-003 + 5.6389200e-003 + 5.6455197e-003 + 5.6220643e-003 + 5.5938023e-003 + 5.5475715e-003 + 5.4876040e-003 + 5.4196776e-003 + 5.3471681e-003 + 5.2461166e-003 + 5.1407354e-003 + 5.0393023e-003 + 4.9137604e-003 + 4.7932561e-003 + 4.6606461e-003 + 4.5209853e-003 + 4.3730720e-003 + 4.2264269e-003 + 4.0819753e-003 + 3.9207432e-003 + 3.7603923e-003 + 3.6008268e-003 + 3.4418874e-003 + 3.2739613e-003 + 3.1125421e-003 + 2.9469448e-003 + 2.7870464e-003 + 2.6201759e-003 + 2.4625617e-003 + 2.3017255e-003 + 2.1461584e-003 + 1.9841141e-003 + 1.8348265e-003 + 1.6868083e-003 + 1.5443220e-003 + 1.3902495e-003 + 1.2577885e-003 + 1.1250155e-003 + 9.8859883e-004 + 8.6084433e-004 + 7.4580259e-004 + 6.2393761e-004 + 5.1073885e-004 + 4.0265402e-004 + 2.9495311e-004 + 2.0430171e-004 + 1.0943831e-004 + 1.3494974e-005 + -6.1733441e-005 + -1.4463809e-004 + -2.0983373e-004 + -2.8969812e-004 + -3.5011759e-004 + -4.0951215e-004 + -4.6063255e-004 + -5.1455722e-004 + -5.5645764e-004 + -5.9461189e-004 + -6.3415949e-004 + -6.6504151e-004 + -6.9179375e-004 + -7.2153920e-004 + -7.3193572e-004 + -7.5300014e-004 + -7.6307936e-004 + -7.7579773e-004 + -7.8014496e-004 + -7.8036647e-004 + -7.7798695e-004 + -7.8343323e-004 + -7.7248486e-004 + -7.6813719e-004 + -7.4905981e-004 + -7.4409419e-004 + -7.2550431e-004 + -7.1577365e-004 + -6.9416146e-004 + -6.7776908e-004 + -6.5403334e-004 + -6.3124935e-004 + -6.1327474e-004 + -5.8709305e-004 + -5.6778026e-004 + -5.4665656e-004 + -5.2265643e-004 + -5.0407143e-004 + -4.8937912e-004 + -4.8752280e-004 + -4.9475181e-004 + -5.6176926e-004 + -5.5252865e-004 diff --git a/vocoder/models/__init__.py b/vocoder/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/models/melgan_discriminator.py b/vocoder/models/melgan_discriminator.py new file mode 100644 index 00000000..55d3f585 --- /dev/null +++ b/vocoder/models/melgan_discriminator.py @@ -0,0 +1,80 @@ +import numpy as np +import torch +from torch import nn +from torch.nn import functional as F +from torch.nn.utils import weight_norm + + +class MelganDiscriminator(nn.Module): + def __init__(self, + in_channels=1, + out_channels=1, + kernel_sizes=(5, 3), + base_channels=16, + max_channels=1024, + downsample_factors=(4, 4, 4, 4)): + super(MelganDiscriminator, self).__init__() + self.layers = nn.ModuleList() + + layer_kernel_size = np.prod(kernel_sizes) + layer_padding = (layer_kernel_size - 1) // 2 + + # initial layer + self.layers += [ + nn.Sequential( + nn.ReflectionPad1d(layer_padding), + weight_norm( + nn.Conv1d(in_channels, + base_channels, + layer_kernel_size, + stride=1)), nn.LeakyReLU(0.2, inplace=True)) + ] + + # downsampling layers + layer_in_channels = base_channels + for idx, downsample_factor in enumerate(downsample_factors): + layer_out_channels = min(layer_in_channels * downsample_factor, + max_channels) + layer_kernel_size = downsample_factor * 10 + 1 + layer_padding = (layer_kernel_size - 1) // 2 + layer_groups = layer_in_channels // 4 + self.layers += [ + nn.Sequential( + weight_norm( + nn.Conv1d(layer_in_channels, + layer_out_channels, + kernel_size=layer_kernel_size, + stride=downsample_factor, + padding=layer_padding, + groups=layer_groups)), + nn.LeakyReLU(0.2, inplace=True)) + ] + layer_in_channels = layer_out_channels + + # last 2 layers + layer_padding1 = (kernel_sizes[0] - 1) // 2 + layer_padding2 = (kernel_sizes[1] - 1) // 2 + self.layers += [ + nn.Sequential( + weight_norm( + nn.Conv1d(layer_out_channels, + layer_out_channels, + kernel_size=kernel_sizes[0], + stride=1, + padding=layer_padding1)), + nn.LeakyReLU(0.2, inplace=True), + ), + weight_norm( + nn.Conv1d(layer_out_channels, + out_channels, + kernel_size=kernel_sizes[1], + stride=1, + padding=layer_padding2)), + ] + + def forward(self, x): + feats = [] + for layer in self.layers: + x = layer(x) + feats.append(x) + return x, feats diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py new file mode 100644 index 00000000..2d266f29 --- /dev/null +++ b/vocoder/models/melgan_generator.py @@ -0,0 +1,91 @@ +import math +import torch +from torch import nn +from torch.nn import functional as F +from torch.nn.utils import weight_norm + +from TTS.vocoder.layers.melgan import ResidualStack + + +class MelganGenerator(nn.Module): + def __init__(self, + in_channels=80, + out_channels=1, + proj_kernel=7, + base_channels=512, + upsample_factors=(8, 8, 2, 2), + res_kernel=3, + num_res_blocks=3): + super(MelganGenerator, self).__init__() + + # assert model parameters + assert (proj_kernel - + 1) % 2 == 0, " [!] proj_kernel should be an odd number." + + # setup additional model parameters + base_padding = (proj_kernel - 1) // 2 + act_slope = 0.2 + self.inference_padding = 2 + + # initial layer + layers = [] + layers += [ + nn.ReflectionPad1d(base_padding), + weight_norm( + nn.Conv1d(in_channels, + base_channels, + kernel_size=proj_kernel, + stride=1, + bias=True)) + ] + + # upsampling layers and residual stacks + for idx, upsample_factor in enumerate(upsample_factors): + layer_in_channels = base_channels // (2**idx) + layer_out_channels = base_channels // (2**(idx + 1)) + layer_filter_size = upsample_factor * 2 + layer_stride = upsample_factor + layer_output_padding = upsample_factor % 2 + layer_padding = upsample_factor // 2 + layer_output_padding + layers += [ + nn.LeakyReLU(act_slope), + weight_norm( + nn.ConvTranspose1d(layer_in_channels, + layer_out_channels, + layer_filter_size, + stride=layer_stride, + padding=layer_padding, + output_padding=layer_output_padding, + bias=True)), + ResidualStack( + channels=layer_out_channels, + num_res_blocks=num_res_blocks, + kernel_size=res_kernel + ) + ] + + layers += [nn.LeakyReLU(act_slope)] + + # final layer + layers += [ + nn.ReflectionPad1d(base_padding), + weight_norm( + nn.Conv1d(layer_out_channels, + out_channels, + proj_kernel, + stride=1, + bias=True)), + nn.Tanh() + ] + self.layers = nn.Sequential(*layers) + + def forward(self, cond_features): + return self.layers(cond_features) + + def inference(self, cond_features): + cond_features = cond_features.to(self.layers[1].weight.device) + cond_features = torch.nn.functional.pad( + cond_features, + (self.inference_padding, self.inference_padding), + 'replicate') + return self.layers(cond_features) diff --git a/vocoder/models/melgan_multiscale_discriminator.py b/vocoder/models/melgan_multiscale_discriminator.py new file mode 100644 index 00000000..d77b9ceb --- /dev/null +++ b/vocoder/models/melgan_multiscale_discriminator.py @@ -0,0 +1,41 @@ +from torch import nn + +from TTS.vocoder.models.melgan_discriminator import MelganDiscriminator + + +class MelganMultiscaleDiscriminator(nn.Module): + def __init__(self, + in_channels=1, + out_channels=1, + num_scales=3, + kernel_sizes=(5, 3), + base_channels=16, + max_channels=1024, + downsample_factors=(4, 4, 4, 4), + pooling_kernel_size=4, + pooling_stride=2, + pooling_padding=1): + super(MelganMultiscaleDiscriminator, self).__init__() + + self.discriminators = nn.ModuleList([ + MelganDiscriminator(in_channels=in_channels, + out_channels=out_channels, + kernel_sizes=kernel_sizes, + base_channels=base_channels, + max_channels=max_channels, + downsample_factors=downsample_factors) + for _ in range(num_scales) + ]) + + self.pooling = nn.AvgPool1d(kernel_size=pooling_kernel_size, stride=pooling_stride, padding=pooling_padding, count_include_pad=False) + + + def forward(self, x): + scores = list() + feats = list() + for disc in self.discriminators: + score, feat = disc(x) + scores.append(score) + feats.append(feat) + x = self.pooling(x) + return scores, feats \ No newline at end of file diff --git a/vocoder/models/multiband_melgan_generator.py b/vocoder/models/multiband_melgan_generator.py new file mode 100644 index 00000000..8feacd25 --- /dev/null +++ b/vocoder/models/multiband_melgan_generator.py @@ -0,0 +1,38 @@ +import torch + +from TTS.vocoder.models.melgan_generator import MelganGenerator +from TTS.vocoder.layers.pqmf import PQMF + + +class MultibandMelganGenerator(MelganGenerator): + def __init__(self, + in_channels=80, + out_channels=4, + proj_kernel=7, + base_channels=384, + upsample_factors=(2, 8, 2, 2), + res_kernel=3, + num_res_blocks=3): + super(MultibandMelganGenerator, + self).__init__(in_channels=in_channels, + out_channels=out_channels, + proj_kernel=proj_kernel, + base_channels=base_channels, + upsample_factors=upsample_factors, + res_kernel=res_kernel, + num_res_blocks=num_res_blocks) + self.pqmf_layer = PQMF(N=4, taps=62, cutoff=0.15, beta=9.0) + + def pqmf_analysis(self, x): + return self.pqmf_layer.analysis(x) + + def pqmf_synthesis(self, x): + return self.pqmf_layer.synthesis(x) + + def inference(self, cond_features): + cond_features = cond_features.to(self.layers[1].weight.device) + cond_features = torch.nn.functional.pad( + cond_features, + (self.inference_padding, self.inference_padding), + 'replicate') + return self.pqmf.synthesis(self.layers(cond_features)) diff --git a/vocoder/models/random_window_discriminator.py b/vocoder/models/random_window_discriminator.py new file mode 100644 index 00000000..3efd395e --- /dev/null +++ b/vocoder/models/random_window_discriminator.py @@ -0,0 +1,225 @@ +import numpy as np +from torch import nn + + +class GBlock(nn.Module): + def __init__(self, in_channels, cond_channels, downsample_factor): + super(GBlock, self).__init__() + + self.in_channels = in_channels + self.cond_channels = cond_channels + self.downsample_factor = downsample_factor + + self.start = nn.Sequential( + nn.AvgPool1d(downsample_factor, stride=downsample_factor), + nn.ReLU(), + nn.Conv1d(in_channels, in_channels * 2, kernel_size=3, padding=1)) + self.lc_conv1d = nn.Conv1d(cond_channels, + in_channels * 2, + kernel_size=1) + self.end = nn.Sequential( + nn.ReLU(), + nn.Conv1d(in_channels * 2, + in_channels * 2, + kernel_size=3, + dilation=2, + padding=2)) + self.residual = nn.Sequential( + nn.Conv1d(in_channels, in_channels * 2, kernel_size=1), + nn.AvgPool1d(downsample_factor, stride=downsample_factor)) + + def forward(self, inputs, conditions): + outputs = self.start(inputs) + self.lc_conv1d(conditions) + outputs = self.end(outputs) + residual_outputs = self.residual(inputs) + outputs = outputs + residual_outputs + + return outputs + + +class DBlock(nn.Module): + def __init__(self, in_channels, out_channels, downsample_factor): + super(DBlock, self).__init__() + + self.in_channels = in_channels + self.downsample_factor = downsample_factor + self.out_channels = out_channels + + self.donwsample_layer = nn.AvgPool1d(downsample_factor, + stride=downsample_factor) + self.layers = nn.Sequential( + nn.ReLU(), + nn.Conv1d(in_channels, out_channels, kernel_size=3, padding=1), + nn.ReLU(), + nn.Conv1d(out_channels, + out_channels, + kernel_size=3, + dilation=2, + padding=2)) + self.residual = nn.Sequential( + nn.Conv1d(in_channels, out_channels, kernel_size=1), ) + + def forward(self, inputs): + if self.downsample_factor > 1: + outputs = self.layers(self.donwsample_layer(inputs))\ + + self.donwsample_layer(self.residual(inputs)) + else: + outputs = self.layers(inputs) + self.residual(inputs) + return outputs + + +class ConditionalDiscriminator(nn.Module): + def __init__(self, + in_channels, + cond_channels, + downsample_factors=(2, 2, 2), + out_channels=(128, 256)): + super(ConditionalDiscriminator, self).__init__() + + assert len(downsample_factors) == len(out_channels) + 1 + + self.in_channels = in_channels + self.cond_channels = cond_channels + self.downsample_factors = downsample_factors + self.out_channels = out_channels + + self.pre_cond_layers = nn.ModuleList() + self.post_cond_layers = nn.ModuleList() + + # layers before condition features + self.pre_cond_layers += [DBlock(in_channels, 64, 1)] + in_channels = 64 + for (i, channel) in enumerate(out_channels): + self.pre_cond_layers.append( + DBlock(in_channels, channel, downsample_factors[i])) + in_channels = channel + + # condition block + self.cond_block = GBlock(in_channels, cond_channels, + downsample_factors[-1]) + + # layers after condition block + self.post_cond_layers += [ + DBlock(in_channels * 2, in_channels * 2, 1), + DBlock(in_channels * 2, in_channels * 2, 1), + nn.AdaptiveAvgPool1d(1), + nn.Conv1d(in_channels * 2, 1, kernel_size=1), + ] + + def forward(self, inputs, conditions): + batch_size = inputs.size()[0] + outputs = inputs.view(batch_size, self.in_channels, -1) + for layer in self.pre_cond_layers: + outputs = layer(outputs) + outputs = self.cond_block(outputs, conditions) + for layer in self.post_cond_layers: + outputs = layer(outputs) + + return outputs + + +class UnconditionalDiscriminator(nn.Module): + def __init__(self, + in_channels, + base_channels=64, + downsample_factors=(8, 4), + out_channels=(128, 256)): + super(UnconditionalDiscriminator, self).__init__() + + self.downsample_factors = downsample_factors + self.in_channels = in_channels + self.downsample_factors = downsample_factors + self.out_channels = out_channels + + self.layers = nn.ModuleList() + self.layers += [DBlock(self.in_channels, base_channels, 1)] + in_channels = base_channels + for (i, factor) in enumerate(downsample_factors): + self.layers.append(DBlock(in_channels, out_channels[i], factor)) + in_channels *= 2 + self.layers += [ + DBlock(in_channels, in_channels, 1), + DBlock(in_channels, in_channels, 1), + nn.AdaptiveAvgPool1d(1), + nn.Conv1d(in_channels, 1, kernel_size=1), + ] + + def forward(self, inputs): + batch_size = inputs.size()[0] + outputs = inputs.view(batch_size, self.in_channels, -1) + for layer in self.layers: + outputs = layer(outputs) + return outputs + + +class RandomWindowDiscriminator(nn.Module): + """Random Window Discriminator as described in + http://arxiv.org/abs/1909.11646""" + def __init__(self, + cond_channels, + hop_length, + uncond_disc_donwsample_factors=(8, 4), + cond_disc_downsample_factors=((8, 4, 2, 2, 2), (8, 4, 2, 2), + (8, 4, 2), (8, 4), (4, 2, 2)), + cond_disc_out_channels=((128, 128, 256, 256), (128, 256, 256), + (128, 256), (256, ), (128, 256)), + window_sizes=(512, 1024, 2048, 4096, 8192)): + + super(RandomWindowDiscriminator, self).__init__() + self.cond_channels = cond_channels + self.window_sizes = window_sizes + self.hop_length = hop_length + self.base_window_size = self.hop_length * 2 + self.ks = [ws // self.base_window_size for ws in window_sizes] + + # check arguments + assert len(cond_disc_downsample_factors) == len( + cond_disc_out_channels) == len(window_sizes) + for ws in window_sizes: + assert ws % hop_length == 0 + + for idx, cf in enumerate(cond_disc_downsample_factors): + assert np.prod(cf) == hop_length // self.ks[idx] + + # define layers + self.unconditional_discriminators = nn.ModuleList([]) + for k in self.ks: + layer = UnconditionalDiscriminator( + in_channels=k, + base_channels=64, + downsample_factors=uncond_disc_donwsample_factors) + self.unconditional_discriminators.append(layer) + + self.conditional_discriminators = nn.ModuleList([]) + for idx, k in enumerate(self.ks): + layer = ConditionalDiscriminator( + in_channels=k, + cond_channels=cond_channels, + downsample_factors=cond_disc_downsample_factors[idx], + out_channels=cond_disc_out_channels[idx]) + self.conditional_discriminators.append(layer) + + def forward(self, x, c): + scores = [] + feats = [] + # unconditional pass + for (window_size, layer) in zip(self.window_sizes, + self.unconditional_discriminators): + index = np.random.randint(x.shape[-1] - window_size) + + score = layer(x[:, :, index:index + window_size]) + scores.append(score) + + # conditional pass + for (window_size, layer) in zip(self.window_sizes, + self.conditional_discriminators): + frame_size = window_size // self.hop_length + lc_index = np.random.randint(c.shape[-1] - frame_size) + sample_index = lc_index * self.hop_length + x_sub = x[:, :, + sample_index:(lc_index + frame_size) * self.hop_length] + c_sub = c[:, :, lc_index:lc_index + frame_size] + + score = layer(x_sub, c_sub) + scores.append(score) + return scores, feats diff --git a/vocoder/notebooks/Untitled.ipynb b/vocoder/notebooks/Untitled.ipynb new file mode 100644 index 00000000..ce49d6fa --- /dev/null +++ b/vocoder/notebooks/Untitled.ipynb @@ -0,0 +1,678 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "#function example with several unknowns (variables) for optimization\n", + "#Gerald Schuller, Nov. 2016\n", + "import numpy as np\n", + "\n", + "def functionexamp(x):\n", + " #x: array with 2 variables\n", + " \n", + " y=np.sin(x[0])+np.cos(x[1])\n", + " return y" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " fun: -1.9999999999888387\n", + " jac: array([4.7236681e-06, 0.0000000e+00])\n", + " message: 'Optimization terminated successfully.'\n", + " nfev: 12\n", + " nit: 2\n", + " njev: 3\n", + " status: 0\n", + " success: True\n", + " x: array([-1.5707916 , -3.14159265])\n" + ] + } + ], + "source": [ + "#Optimization example, see also:\n", + "#https://docs.scipy.org/doc/scipy-0.18.1/reference/optimize.html\n", + "#Gerald Schuller, Nov. 2016\n", + "#run it with \"python optimizationExample.py\" in a termina shell\n", + "#or type \"ipython\" in a termina shell and copy lines below:\n", + "\n", + "import numpy as np\n", + "import scipy.optimize as optimize\n", + "\n", + "#Example for 2 unknowns, args: function-name, starting point, method:\n", + "xmin = optimize.minimize(functionexamp, [-1.0, -3.0], method='CG')\n", + "print(xmin)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "function [p,passedge] = opt_filter(filtorder,N)\n", + "\n", + "% opt_filter Create Lowpass Prototype Filter for the Pseudo-QMF \n", + "% Filter Bank with N Subbands\n", + "%\n", + "% Adapted from the paper by C. D. Creusere and S. K. Mitra, titled \n", + "% \"A simple method for designing high-quality prototype filters for \n", + "% M-band pseudo-QMF banks,\" IEEE Trans. Signal Processing,vol. 43, \n", + "% pp. 1005-1007, Apr. 1995 and the book by S. K. Mitra titled \"\n", + "% Digital Signal Processing: A Computer-Based Approach, McGraw-Hill, 2001\n", + "%\n", + "% Arguments:\n", + "% filtorder Filter order (i.e., filter length - 1)\n", + "% N Number of subbands\n", + "\n", + "stopedge = 1/N; % Stopband edge fixed at (1/N)pi\n", + "passedge = 1/(4*N); % Start value for passband edge\n", + "tol = 0.000001; % Tolerance\n", + "step = 0.1*passedge; % Step size for searching the passband edge\n", + "way = -1; % Search direction, increase or reduce the passband edge\n", + "tcost = 0; % Current error calculated with the cost function\n", + "pcost = 10; % Previous error calculated with the cost function\n", + "flag = 0; % Set to 1 to stop the search\n", + "\n", + "while flag == 0\n", + " \n", + "% Design the lowpass filter using Parks-McClellan algorithm\n", + " \n", + " p = remez(filtorder,[0,passedge,stopedge,1],[1,1,0,0],[5,1]);\n", + " \n", + "% Calculates the cost function according to Eq. (2.36)\n", + "\n", + " P = fft(p,4096);\n", + " OptRange = floor(2048/N); % 0 to pi/N\n", + " phi = zeros(OptRange,1); % Initialize to zeros\n", + "\n", + "% Compute the flatness in the range from 0 to pi/N\n", + "\n", + "\tfor k = 1:OptRange\n", + " phi(k) = abs(P(OptRange-k+2))^2 + abs(P(k))^2;\n", + "\tend\n", + "\ttcost = max(abs(phi - ones(max(size(phi)),1)));\n", + " \t\n", + "\tif tcost > pcost % If search in wrong direction\n", + "\t\tstep = step/2; % Reduce step size by half \n", + "\t\tway = -way; % Change the search direction \n", + "\tend\n", + "\t\n", + "\tif abs(pcost - tcost) < tol % If improvement is below tol \n", + "\t\tflag = 1; % Stop the search \n", + "\tend\n", + "\t\n", + "\tpcost = tcost;\n", + "\tpassedge = passedge + way*step; % Adjust the passband edge\n", + " \n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "sig.remez" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0125" + ] + }, + "execution_count": 101, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 / 4. / 20.0" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Band edges should be less than 1/2 the sampling frequency", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremez\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m64\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m16.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/miniconda3/lib/python3.7/site-packages/scipy/signal/fir_filter_design.py\u001b[0m in \u001b[0;36mremez\u001b[0;34m(numtaps, bands, desired, weight, Hz, type, maxiter, grid_density, fs)\u001b[0m\n\u001b[1;32m 854\u001b[0m \u001b[0mbands\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbands\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 855\u001b[0m return sigtools._remez(numtaps, bands, desired, weight, tnum, fs,\n\u001b[0;32m--> 856\u001b[0;31m maxiter, grid_density)\n\u001b[0m\u001b[1;32m 857\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 858\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Band edges should be less than 1/2 the sampling frequency" + ] + } + ], + "source": [ + "p = sig.remez(65, [0, 1/16.0, 1/4.0, 1], [1, 0], [5, 1])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "def create_pqmf_filter(filter_len=64, N=4):\n", + " stop_edge = 1 / N\n", + " pass_edge = 1 / (4 * N)\n", + " tol = 1e-8\n", + " cutoff = 0.1 * pass_edge\n", + " cost = 0\n", + " cost_prev = float('inf')\n", + " \n", + " p = sig.remez(filter_len, [0, pass_edge, stop_edge, 1], [1, 1, 0, 0], [5, 1])\n", + " \n", + " P = sig.freqz(p, workN=2048)\n", + " opt_range = 2048 // N\n", + " phi = np.zeros(opt_range)\n", + " \n", + " H = np.abs(P)\n", + " phi = H[opt_range + 2] \n", + " for i in range(opt_range):\n", + " phi[i] = abs(P(opt_range - i + 2)) ** 2 + abs(P[i]) ** 2" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy as sp\n", + "import scipy.signal as sig\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "\n", + "def optimfuncQMF(x):\n", + " \"\"\"Optimization function for a PQMF Filterbank\n", + " x: coefficients to optimize (first half of prototype h because of symmetry)\n", + " err: resulting total error\n", + " \"\"\"\n", + " K = ntaps * N \n", + " h = np.append(x, np.flipud(x))\n", + " cutoff = 0.15\n", + " \n", + "# breakpoint()\n", + " f, H_im = sig.freqz(h, worN=K)\n", + " H = np.abs(H_im) #only keeping the real part\n", + " \n", + " posfreq = np.square(H[0:K//N])\n", + " \n", + " #Negative frequencies are symmetric around 0:\n", + " negfreq = np.flipud(np.square(H[0:K//N]))\n", + " \n", + " #Sum of magnitude squared frequency responses should be closed to unity (or N)\n", + " unitycond = np.sum(np.abs(posfreq + negfreq - 2*(N*N)*np.ones(K//N)))/K\n", + " \n", + " #plt.plot(posfreq+negfreq)\n", + " \n", + " #High attenuation after the next subband:\n", + " att = np.sum(np.abs(H[int(cutoff*K//N):]))/K\n", + " \n", + " #Total (weighted) error:\n", + " err = unitycond + 100*att\n", + " return err" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(32,)" + ] + }, + "execution_count": 85, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "xmin.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8.684549400499243\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import scipy.optimize as opt\n", + "import scipy.signal as sig\n", + "\n", + "ntaps = 64\n", + "N = 4\n", + "\n", + "#optimize for 16 filter coefficients:\n", + "xmin = opt.minimize(optimfuncQMF, ntaps*np.ones(ntaps), method='SLSQP', tol=1e-8)\n", + "xmin = xmin[\"x\"]\n", + "\n", + "err = optimfuncQMF(xmin)\n", + "print(err)\n", + "\n", + "#Restore symmetric upper half of window:\n", + "h = np.concatenate((xmin, np.flipud(xmin)))\n", + "plt.plot(h)\n", + "plt.title('Resulting PQMF Window Function')\n", + "plt.xlabel('Sample')\n", + "plt.ylabel('Value')\n", + "plt.show()\n", + "\n", + "f, H = sig.freqz(h)\n", + "plt.plot(f, 20*np.log10(np.abs(H)))\n", + "plt.title('Resulting PQMF Magnitude Response')\n", + "plt.xlabel('Normalized Frequency')\n", + "plt.ylabel('dB')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "N = 4\n", + "f, H_im = sig.freqz(h)\n", + "posfreq = np.square(H[0:512//N])\n", + "negfreq = np.flipud(np.square(H[0:512//N]))\n", + "plt.plot((np.abs(posfreq) + np.abs(negfreq)))\n", + "plt.xlabel('Frequency (512 is Nyquist)')\n", + "plt.ylabel('Magnitude')\n", + "plt.title('Unity Condition, Sum of Squared Magnitude of 2 Neighboring Subbands')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "b = sig.firwin(80, 0.5, window=('kaiser', 8))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "f, H_im = sig.freqz(h)\n", + "posfreq = np.square(H[0:512//N])\n", + "negfreq = np.flipud(np.square(H[0:512//N]))\n", + "plt.plot((np.abs(posfreq) + np.abs(negfreq)))\n", + "plt.xlabel('Frequency (512 is Nyquist)')\n", + "plt.ylabel('Magnitude')\n", + "plt.title('Unity Condition, Sum of Squared Magnitude of 2 Neighboring Subbands')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(63,)" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZcAAAEWCAYAAACqitpwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADt0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjByYzMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy9h23ruAAAgAElEQVR4nO3deXycZbn4/8+VTPakSZomXdOk0JRSCrSQtqAIiKBFloIilIMCfjlf9Kscj4eDCi6oHDgH1N9BPeKCiIKsPSxSZKkgsimUpjultE3bpEmXrE2bpVkmc/3+eJ4p0yF7ZuaZSa/36zWvzNzPdt/JZK65l+e+RVUxxhhjIinJ6wwYY4wZeyy4GGOMiTgLLsYYYyLOgosxxpiIs+BijDEm4iy4GGOMiTgLLiZuiMirIvLPA2z/tYh8L5Z5ShQiMl1E2kQkeYTHV4nIuZHOVzwRkU0icrbX+ThaWHAxfXI/bA65H1j7ROQPIpIdw+tfKyJvhqap6pdV9T+icK1SEVG3rG1u2W8O2S4i8g0R2eb+TnaJyH+KSGrIPn9wz7Ek7Nx3u+nXhpSrN+RabSLyiz7ydKWIbA5Le6mftJtVdZeqZqtqb4R+LRElIj8QkZ6wcn8zitf7g4jcHpqmqieo6qvRuqY5kgUXM5CLVDUbmAfMB27xOD/RlueW90rgVhFZ7Kb/HLgeuBrIAc4HzgUeCzt+q7sPACLiAy4Htoft95YbCIKPG/rIy+vAbBEpDDnXyUBGWNrp7r6J4PGwcv/I6wyZ6LHgYgalqvuAFThBBgAROU1E/iEiLSKyPrS5wf12vkNEWkVkp4hc5ab/QEQeCtkvWGPwhV5PRI4Hfg2c7n7DbXHTD38bFZGzRaRWRP5dROpFZK+IfDHkHAUi8qyIHBSRVSJye3hNaIDyvgVsAuaKSBnwFeAqVX1LVf2qugn4LHCBiJwVcuizwBkiku++XgxsAPYN5bphedgN7ADOdJNOcfP0WlhaErAq/HfpNjH+h4j83f07/EVEJoT8fr4gItUi0iQi3wm9toikichPRWSP+/ipiKS5214Tkc+6zz/qXvMC9/UnRGTdcMo52HtiCOU4I+R9WOO+964HrgK+6b5/nnX3Pdz0N0gZB3xvmaGx4GIGJSLTcL6tV7qvpwLPAbcD44GbgCdFpFBEsnC+6Z+vqjnAR4BhfeCo6mbgy3zwDT+vn10nAbnAVOA64J6QD/Z7gHZ3n2vcx1DKKiLyUeAEYC3wCaBWVd8Jy2MN8DbwyZDkTuAZYKn7+mrgwaFctx+v80EgORN4A3gzLO1tVe3p5/h/Ar4IFAGpOH8nRGQO8CvgC8AUoACYFnLcd4DTcL5MnAwsBL7rbnsNONt9fhZHBsCz3O2R1l85SoAXgP8BCt38rlPVe4GHgR+575+L+jjnQGWEgd9bZggsuJiB/ElEWoEaoB74vpv+eeB5VX1eVQOq+hJQAXza3R7A+dafoap73W/60dAD3KaqPar6PNAGHCdOp/Znge+raoeqvgc8MITzNQLNwH3Azar6V2ACsLef/ffifKiFehC4WkTycD5s/9THcae537SDj9P6OX9oLeVjOMHljbC0gT7Mf6+qW1X1ELCMD2qelwF/VtXXVbUL+B7O3yzoKpzfa72qNgA/xAlEwTwFa2tnAv8V8nqw4HJ5WLmnDLDvUMrxT8DLqvqo+x5oUtWhfpEZqIzQz3triOc2WHAxA7vErX2cDczG+aAFKAE+F/pBAZwBTFbVduAKnJrHXhF5TkRmRyl/TarqD3ndAWTjfOD7cIJiUOjz/kxQ1XxVPV5Vf+6mNQKT+9l/srv9MFV9073+d3A+wA/1cdzbqpoX8ni7n/O/DpzkfmM+Dacm9z4w2U07g4H7W0Kb44K/G3BqK4d/H+7frClk3ylAdcjrajcN4C1glohMxPmQfxAodpuqFg6Sn2Vh5d4zwL5DKUcxH+7PGqqBygj9v7fMEFlwMYNS1deAPwA/cZNqgD+GfVBkqeqd7v4rVPU8nA/f94Hfuse1A5khp5400GVHkeUGwM+RTT3FIzzXKzgfngtDE0WkGOcD/9U+jnkI+HdG1ySGqu4A9uAMJtilqm3uprfctGycprnh2kvI70NEMnGaxoL24HyBCJrupqGqHcBq4F+Bd1W1G/gHcCOwXVWPCLZDMJz3RLga4Nh+tg32/um3jCYyLLiYofopcJ6InIzz4XmRiHxKRJJFJN3tBJ0mIhNFZInb99KF05wQbHJZB5wpzj0ZuQw8+qwOmCYhw32Hyh2O+xTwAxHJdGtOVw9yWH/n2oozuOBhcQYxJIvICcCTOB+qL/dx2M+B84jMKK43cD643whJe9NNq+inZjSYJ4AL3c7wVOA2jvwseBT4rtuHNgG4FedvHvQacAMfNIG9GvZ6OIbzngj3MHCuiFwuIj5xBnEEm8zqgGMGOHawMppRsuBihsRtl34QuNXtzF4CfBunllADfAPn/ZSE88G3B6f/4izg/7nneAl4HGcE1WrgzwNc8hWc0VH7RGS434bB+bDLxWlS+SPOh0nXCM4TPNd9OB8+HcC7OM0ol6hqIHxnVW1W1b9qZBZLeg2nIzt0pNsbbtqIgpfbB/ZV4BGcWsx+oDZkl9tx+tA2ABuBNW5aaJ5yQq4f/no4eRnOeyL82F04/Xz/jvNeW4fTOQ/wO2CO22zbV7/XYGU0oyS2WJg5GojIXcAkVR3SqLFBzvVD4FLgTFVtGXXmjBmDrOZixiQRmS0iJ7lDixfiDCd9OhLnVtXvA/fi9LkYY/pgNRczJonIApymsCk47e/3AndGqKnKGDMICy7GGGMizprFjDHGRJxv8F3GvgkTJmhpaanX2TDGmISyevXqRlUNn6UCsOACQGlpKRUVFV5nwxhjEoqIVPe3zZrFjDHGRJwFF2OMMRFnwcUYY0zEWXAxxhgTcRZcjDHGRJynwUVEFovIFhGpFJGb+9h+poisERG/iFwWtq1XRNa5j+Uh6TNEZKV7zsdHMquuMcaY0fEsuLirBd6Ds3zuHOBKd/nVULuAa3Fmbw13SFXnuY+LQ9LvAu5W1Zk4s71eF/HMG2OMGZCXNZeFQKWq7nAXHHoMZxr3w1S1SlU3cOQSrP0SEQHOwVmvApylbS+JXJaNiZ2Obj/LKmro7On1OivGDJuXwWUqRy49W+umDVW6iFSIyNsiEgwgBUBLyPKk/Z5TRK53j69oaGgYbt6Nibpbn9nEN5/YwJ0vvO91VowZtkTu0C9R1XLgn4Cfikh/y532SVXvVdVyVS0vLOxz9gJjPPPiu3t5YnUt08dn8od/VPHGNvsCZBKLl8FlN0euaz7NTRsSVd3t/tyBs8zqfKAJyBOR4LQ2wzqnMfGgvrWTW57ayIlTc3nua2cwsyibm/53PS0d3V5nzZgh8zK4rALK3NFdqcBSYPkgxwAgIvkikuY+nwB8FHjPXavjb0BwZNk1wDMRz7kxUaKqfPOJDXR093L3FSeTk57CT6+YR1NbN9/907vYEhkmUXgWXNx+kRuAFcBmYJmqbhKR20TkYnAWfBKRWuBzwG9EZJN7+PFAhYisxwkmd6rqe+62bwE3ikglTh/M72JXKmNG5+GVu3h1SwPf/vTxzCzKAWDu1Fz+7bxZ/HnDXpav3+NxDo0ZGlssDCgvL1ebFdl4bUdDGxf8/E3KS/N54IsLSUqSw9v8vQGuuPdttta18uLXz2RqXoaHOTXGISKr3b7vD0nkDn1jxgx/b4B/W7aeVF8SP77s5CMCC4AvOYn/vvxkAgHlpmXrCQTsS6GJbxZcjIkDK3c2s76mhe9dOIdJuel97lNSkMU3F8/mrR1NbNx9IMY5NGZ4LLgYEwdW7mgiSeBTJ0wccL/z505y9t/ZFItsGTNiFlyMiQNv72zmhCm55KSnDLhf0bh0ZkzIYuWO5hjlzJiRseBijMc6e3pZV9PCohnjh7T/ohnjeaeqmV7rdzFxzIKLMR5bV9NCtz/AomMKhrT/omPG09rpZ/Peg1HOmTEjZ8HFGI+t3NGMCCwsHWrNxQlCK3da05iJXxZcjPHYyp1NzJ40jtzMgftbgqbkZVA8PoOVO6xT38QvCy7GeKjbH2DNrv1D7m8JWjSjgHeqmu1+FxO3LLgY46ENtS109gQ47ZjhBpfxtHT0sLW+NUo5M2Z0LLgY46Fgv8nCGUPrzA86ze38f8f6XUycsuBijIdW7mxm1sRsxmelDuu4afkZTMlNt/tdTNyy4GKMR/y9AVZXNR8e/TUcIsKiYwpYubPJpuE3ccmCizEeeXfPQdq7e1k0zP6WoEUzxtPY1s32hvYI58yY0bPgYoxHgkOJFw5zpFhQ8KZLm2fMxCMLLsZ4ZOXOZo4pzKIop+9ZkAdTWpBJUU6a9buYuGTBxRgP9AaUVTubh31/SygRYeGM8dbvYuKSBRdjPLB570Fau/wj6swPteiYAuoOdlHd1BGhnBkTGRZcjPFA8P6WkXbmB53m1nzsfhcTbyy4GOOBlTuamD4+k8m5GaM6z8yibAqyUnnbOvVNnPE0uIjIYhHZIiKVInJzH9vPFJE1IuIXkctC0ueJyFsisklENojIFSHb/iAiO0VknfuYF6vyGDMUgYDyTtXo+luCDve7WKe+iTOeBRcRSQbuAc4H5gBXisicsN12AdcCj4SldwBXq+oJwGLgpyKSF7L9G6o6z32si0oBjBmh6uYOWjp6KC/Nj8j5ykvHs7vlEA2tXRE5nzGR4GXNZSFQqao7VLUbeAxYErqDqlap6gYgEJa+VVW3uc/3APVAYWyybczobKtzJps8btK4iJzvuIk5znltEksTR7wMLlOBmpDXtW7asIjIQiAV2B6SfIfbXHa3iKT1c9z1IlIhIhUNDQ3DvawxI7atvg1w+ksiYdZE5zzb6toicj5jIiGhO/RFZDLwR+CLqhqs3dwCzAYWAOOBb/V1rKreq6rlqlpeWGiVHhM72+pamZqXQXaaLyLnK8xJY1y6z2ouJq54GVx2A8Uhr6e5aUMiIuOA54DvqOrbwXRV3auOLuD3OM1vxsSNbfVtEau1gNOpXzYxx2ouJq54GVxWAWUiMkNEUoGlwPKhHOju/zTwoKo+EbZtsvtTgEuAdyOaa2NGoTegVNa3HW7KipRZE7MPN7cZEw88Cy6q6gduAFYAm4FlqrpJRG4TkYsBRGSBiNQCnwN+IyKb3MMvB84Eru1jyPHDIrIR2AhMAG6PYbGMGVDt/g66/AHKinIiet6ZRTk0t3fT1GYjxkx8iEyj7wip6vPA82Fpt4Y8X4XTXBZ+3EPAQ/2c85wIZ9OYiAk2Xc2McM2lzG1m21rXxunZfY5hMSamErpD35hEE1zzviyCfS4As9zhyJXWqW/ihAUXY2Kosq6Nybnp5KSnRPS8E8elkZPms34XEzcsuBgTQ5EeKRYkIsycmM3WOqu5mPhgwcWYGAkcHikW2c78oFlFOVRazcXECQsuxsTI7pZDHOrpjXh/S1DZxGwa27ppbu+OyvmNGQ4LLsbESPAO+rIIjxQLCja3bbOmMRMHLLgYEyNbg8OQI3yPS9CswxNYWtOY8Z4FF2NiZFtdGxPHpZGbEdmRYkGTc9PJTvNZzcXEBQsuxsTItvrWqHXmgztirMimgTHxwYKLMTEQHCkWjWHIocosuJg4YcHFmBjYc+AQHd29EZ9TLFzZxGwaWrto6bARY8ZbFlyMiYHgnGKRng05XJl16ps4YcHFmBgIDkOORbMYYHfqG89ZcDEmBrbVtVGYk0ZeZmpUrzMlN4PM1GRbOMx4zoKLMTGwNQoLhPUlKUkoK8q2aWCM5yy4GBNlqkplXWvUO/ODZhblWLOY8ZwFF2OibO+BTtq7e6Pe3xJUNjGb+tYuDnT0xOR6xvTFgosxURasRUTzBspQwea3bbZwmPGQBRdjoizY/xGt2ZDDBZvfbDiy8ZIFF2OibFtdGxOyU8nPiu5IsaCpeRlkpNiIMeMtT4OLiCwWkS0iUikiN/ex/UwRWSMifhG5LGzbNSKyzX1cE5J+qohsdM/5cxGRWJTFmP5srY9dZz44I8acOcasWcx4x7PgIiLJwD3A+cAc4EoRmRO22y7gWuCRsGPHA98HFgELge+LSL67+VfA/wXK3MfiKBXBmEE5I8XaoraGS3/KimzJY+MtL2suC4FKVd2hqt3AY8CS0B1UtUpVNwCBsGM/Bbykqs2quh94CVgsIpOBcar6tqoq8CBwSdRLYkw/Gtu6ae3yc8yErJhe99iibOoOdtHR7Y/pdY0J8jK4TAVqQl7XummjOXaq+3zQc4rI9SJSISIVDQ0NQ860McNR3dQOQGmMg0tJQaZ7/Y6YXteYoKO2Q19V71XVclUtLyws9Do7Zoza2egGl4LYBpfg9arc6xsTa14Gl91AccjraW7aaI7d7T4fyTmNibjqpg6Sk4Sp+Rkxve50t+ZSZTUX4xEvg8sqoExEZohIKrAUWD7EY1cAnxSRfLcj/5PAClXdCxwUkdPcUWJXA89EI/PGDEVVUzvT8jNISY7tv9q49BQKslIPN8sZE2ueBRdV9QM34ASKzcAyVd0kIreJyMUAIrJARGqBzwG/EZFN7rHNwH/gBKhVwG1uGsBXgPuASmA78EIMi2XMEaqbOmLeJBZUOiGLKgsuxiM+Ly+uqs8Dz4el3RryfBVHNnOF7nc/cH8f6RXA3Mjm1JjhU1Wqmto5ZXqeJ9cvKcjkre1NnlzbmKO2Q9+YaNvf0UNrp58Sr2ouBVnsPdBJZ0+vJ9c3RzcLLsZEyeGRYhMyPbm+DUc2XrLgYkyUBDvTvay5ANbvYjxhwcWYKKlq6iBJoDjfm5pLMLjYiDHjBQsuxkRJdVM7U/MzSPV582+Wm5lCfmaK3etiPGHBxZgoqfJwGHJQSUGW1VyMJyy4GBMl1U3thzvVvVJakElVo9VcTOxZcDEmClo6umnp6ImLmsueA4dsOLKJOQsuxkRBsJ/Dq5FiQaUTMlGF2v1WezGxZcHFmCg4PNW+x81iJYdnR7bgYmLLgosxUVDV2IEIFI/3NrjMsHtdjEcsuBgTBdVN7UzJzSA9JdnTfORlpjAu3Wd36ZuYs+BiTBTsjIORYgAiYrMjG09YcDEmCqqbOjzvzA8qKbDgYmLPgosxEXbgUA/N7d2ed+YHlRZksnv/Ibr9Aa+zYo4iFlyMibBdcTIMOaikIIuADUc2MWbBxZgICzZBzZgQH8FlxgSbet/EngUXYyIseI/LdI+HIQeV2HBk4wELLsZE2M7GDiaNSycj1dthyEEFWalkp/moarTgYmLH0+AiIotFZIuIVIrIzX1sTxORx93tK0Wk1E2/SkTWhTwCIjLP3faqe87gtqLYlsoc7eJhwspQIkJJQaZNvW9iyrPgIiLJwD3A+cAc4EoRmRO223XAflWdCdwN3AWgqg+r6jxVnQd8AdipqutCjrsquF1V66NeGGNCxMNU++FKbep9E2Ne1lwWApWqukNVu4HHgCVh+ywBHnCfPwF8QkQkbJ8r3WON8Vxbl5/Gti5KJsRPzQWgpCCT2v2H6Om14cgmNrwMLlOBmpDXtW5an/uoqh84ABSE7XMF8GhY2u/dJrHv9RGMjImaYO1gRrzVXCZk4Q8oe1oOeZ0Vc5RI6A59EVkEdKjquyHJV6nqicDH3McX+jn2ehGpEJGKhoaGGOTWHA2q4+wel6DSwyPGrN/FxMaQg4uIRLqevxsoDnk9zU3rcx8R8QG5QFPI9qWE1VpUdbf7sxV4BKf57UNU9V5VLVfV8sLCwlEUw5gP7HRHZMVThz58MPW/jRgzsTJocBGRj4jIe8D77uuTReSXEbj2KqBMRGaISCpOoFgets9y4Br3+WXAK6qqbj6SgMsJ6W8REZ+ITHCfpwAXAu9iTIxUN7VTmJNGVprP66wcoTAnjYyUZLvXxcTMUP4D7gY+hfvBr6rrReTM0V5YVf0icgOwAkgG7lfVTSJyG1ChqsuB3wF/FJFKoBknAAWdCdSo6o6QtDRghRtYkoGXgd+ONq/GDJUzUiy+ai3wwXBku0vfxMqQvl6pak1Yv3hEFuRW1eeB58PSbg153gl8rp9jXwVOC0trB06NRN6MGYnqpnY+VhafzaylBVlsrWv1OhvmKDGUPpcaEfkIoCKSIiI3AZujnC9jEk5Ht5+6g11xM6dYuNIJWdTs76A3oF5nxRwFhhJcvgx8FWdY8G5gnvvaGBPig5Fi8dcsBk6nfk+vDUc2sTFos5iqNgJXxSAvxiS04D0u8XZ3flDoBJbFcTKpphm7Bg0uIvJ74EP1aFX9P1HJkTEJKngPyfR4rbm4swZUNXXwsTKPM2PGvKF06P855Hk6cCmwJzrZMSZxVTe1U5CVyrj0FK+z0qeJOemk+ZKotntdTAwMpVnsydDXIvIo8GbUcmRMgqpq7Ijb/haApCSbHdnEzkimfykDbBp7Y8JUN7VTGqcjxYJsdmQTK0Ppc2nF6XMR9+c+4FtRzpcxCaWzp5c9BzrjtjM/qHRCFq9ubSAQUJKSbE5XEz1DaRbLiUVGjElku5rjexhyUElBJt3+AHsPdjI1L8Pr7JgxrN/gIiKnDHSgqq6JfHaMSUzBCSHjvubi5q+6sd2Ci4mqgWou/98A2xQ4J8J5MSZhBW+gjPfgEqxZVTV18JGZHmfGjGn9BhdV/XgsM2JMIqtqaicvM4XczPgchhw0OTeD1OQk69Q3UTekiStFZC7OOvfpwTRVfTBamTIm0VQ3dcR9rQUgOUmYXpBpU++bqBvKaLHvA2fjBJfngfNx7nOx4GKMa2djOwtK873OxpCU2tT7JgaGcp/LZcAngH2q+kXgZJwVIY0xQJe/lz0HDsXd0sb9KSnIoqqpHXfdPWOiYijBpVNVA4BfRMYB9Ry5PLExR7Wa5kOofjB3V7wrLciksydA3cEur7NixrB+g4uI3CMiZwDviEgezoqOq4E1wFsxyp8xcS/YOZ5INRfA+l1MVA3U57IV+DEwBWgHHgXOA8ap6oYY5M2YhFCVIMOQgw7f69LUzmnHFHicGzNW9VtzUdWfqerpOGvVNwH3Ay8Cl4qITdhtjKuqsZ1x6T7y43wYctCUvHRSksUmsDRRNWifi6pWq+pdqjofuBK4BHg/6jkzJkFUuRNWiiTGXF2+5CSK8zPtXhcTVYMGFxHxichFIvIw8AKwBfhMJC4uIotFZIuIVIrIzX1sTxORx93tK0Wk1E0vFZFDIrLOffw65JhTRWSje8zPJVH+403Cqm7qSJj+lqCSgkyqGq3mYqJnoA7980TkfqAW+L/Ac8CxqrpUVZ8Z7YVFJBm4B+e+mTnAlSIyJ2y364D9qjoTuBu4K2TbdlWd5z6+HJL+Kze/Ze5j8Wjzakx/uv0Bavd3UBrnE1aGK3Gn3rfhyCZaBqq53AL8AzheVS9W1UdUNZL16IVAparuUNVu4DFgSdg+S4AH3OdPAJ8YqCYiIpNxBhy8rc5/zYM4zXjGRMXulkMENHFGigWVFmTS3t1LQ5sNRzbRMVCH/jmqep+q7o/StacCNSGva920PvdRVT9wAAgOb5khImtF5DUR+VjI/rWDnBMAEbleRCpEpKKhoWF0JTFHreBw3oSruUwIjhizpjETHSNZiTIe7AWmu4MMbgQecW/wHDJVvVdVy1W1vLCwMCqZNGPf4an243wFynAzgve6NFqnvokOL4PLbo6803+am9bnPiLiw5l2pklVu1S1CUBVVwPbgVnu/tMGOacxEVPd1EF2mo+CrFSvszIsU/MzSE4Sq7mYqPEyuKwCykRkhoikAkuB5WH7LAeucZ9fBryiqioihe6AAETkGJyO+x2quhc4KCKnuX0zVwOjHnxgTH+qmtopKchMmGHIQSnJSUzLz7C79E3UDGnK/WhQVb+I3ACsAJKB+1V1k4jcBlSo6nLgd8AfRaQSaMYJQODc2HmbiPQAAeDLqtrsbvsK8AcgA2fo9AuxKpM5+lQ3dTBn8rBaZOOGM2LMai4mOjwLLgCq+jzONP6habeGPO8EPtfHcU8CT/ZzzgpgbmRzasyH+XsD1DR3cP7cSV5nZURKCzJZu2s/qppwNS8T/xK1Q98Yz+1p6cQf0ISZUyxcSUEWrZ1+mtu7vc6KGYMsuBgzQjsPz4acWMOQg4LDp22OMRMNFlyMGaHg3FwzEmwYclDphA9mRzYm0iy4GDNCVY0dZKQkU5iT5nVWRmRafgZJYjUXEx0WXIwZoeoEHYYclOZLZkpehtVcTFRYcDFmhHY2tidsZ37QjAlZ7LS79E0UWHAxZgS6/L1UN3cwsyjb66yMyrGF2VTWt9nsyCbiLLgYMwJVjR30BpSyiYkdXGYWZdPR3cueA51eZ8WMMRZcjBmByvo2wPnmn8iCNa9geYyJFAsuxozAtvpWRBI/uJS5wWVbXavHOTFjjQUXY0agsr6NafkZZKQme52VUSnITiM/M4XtDVZzMZFlwcWYEaisb6OsKMfrbEREWVEO2+osuJjIsuBizDD5ewPsaGxP+JFiQccWZbPNRoyZCLPgYsww1ew/RLc/MGaCS1lRNgcO9dDYZhNYmsix4GLMMAVHVpWNleAy0UaMmciz4GLMMG2rd0ZWHTtGgssHw5FtxJiJHAsuxgxTZX0bk8alMy49xeusRMSkcelkp/ms5mIiyoKLMcNUWd82ZvpbAETkcKe+MZFiwcWYYVDVMRdcwOk/spqLiSQLLsYMw54DnXR094654DKzKJv61i4OHOrxOitmjPA0uIjIYhHZIiKVInJzH9vTRORxd/tKESl1088TkdUistH9eU7IMa+651znPopiVyIz1o21kWJBZTbHmIkwz4KLiCQD9wDnA3OAK0VkTthu1wH7VXUmcDdwl5veCFykqicC1wB/DDvuKlWd5z7qo1YIc9QJzsE1FmsuYCPGTOR4WXNZCFSq6g5V7QYeA5aE7bMEeMB9/gTwCRERVV2rqnvc9E1Ahogk5lqzJqFsb2hjfFYqBdlj6+02LT+TNF+STQNjIsbL4DIVqAl5Xeum9bmPqvqBA0BB2D6fBdaoaldI2u/dJrHvST9r0IrI9SJSISIVDQ0NoymHOYpsq2tjZoLPhNyX5CThmMJsKm0CSxMhCd2hLyIn4DSVfSkk+Sq3uexj7nXtQTkAABl0SURBVOMLfR2rqveqarmqlhcWFkY/sybhqSqVDW3MTPAFwvpTVpRtNRcTMV4Gl91AccjraW5an/uIiA/IBZrc19OAp4GrVXV78ABV3e3+bAUewWl+M2bUmtq7aenoGZM1F3D6XXa3HKKj2+91VswY4GVwWQWUicgMEUkFlgLLw/ZZjtNhD3AZ8IqqqojkAc8BN6vq34M7i4hPRCa4z1OAC4F3o1wOc5QIfqtP9KWN+xMcMba9vt3jnJixwLPg4vah3ACsADYDy1R1k4jcJiIXu7v9DigQkUrgRiA4XPkGYCZwa9iQ4zRghYhsANbh1Hx+G7tSmbEs2B8x1kaKBR0eMdZgI8bM6Pm8vLiqPg88H5Z2a8jzTuBzfRx3O3B7P6c9NZJ5NCaosq6V7DQfk8ale52VqCgpyMKXJNbvYiIioTv0jYmlyoY2ji3Kpp8BiAkv1ZdESUGm3UhpIsKCizFDtK2ubczdmR+urCjHgouJCAsuxgzBgUM91Ld2jdn+lqCZRdlUN3fQ5e/1OismwVlwMWYIxuqcYuHKJmbTG1CqGju8zopJcBZcjBmC7fVje6RY0LGFNoGliQwLLsYMwbb6VtJ8SUzLz/Q6K1F1bGE2Ih8s5WzMSFlwMWYItta1cUxhNslJY3OkWFBGajLF+Zk2HNmMmgUXYwahqmyobeHEqeO8zkpMzJ06jvW1LV5nwyQ4Cy7GDKK6qYP9HT3Mn57vdVZiYn5xPrX7D9HQ2jX4zsb0w4KLMYNYV+N8i59XnOdxTmJj3nSnnMFyGzMSFlyMGcTaXfvJTE1m1sQcr7MSE3On5OJLEtbu2u91VkwCs+BizCDW1bRw0rTcMd+ZH5SRmszsyTlWczGjYsHFmAF09vTy3t6DR01/S9D84nzW17TQG1Cvs2ISlAUXYwawac9BenqV+UdJf0vQ/Ol5tHf32s2UZsQsuBgzgGC/Q7CT+2gRHLxg/S5mpDxdz8WMbYGAs+b86ur9dPX0UpiTTtG4NAqz0ygal0Zmavy//dbVtDA1L4OinLG5hkt/ZkzIIjcjhXU1LSxdON3r7AyqvctPfWsXDa1d1Ld2Un+wi+w0H6eU5HNsYdaYXSYhnsX/f7dJKO/uPsBrWxuoqGpmza4WDhzq6Xff048p4DsXHM/cqbkxzOHwrN3VctTVWgBEhHnFeazdFd+d+mt27eeO5zazurr/GlZ+ZgqnluRTXjqejx9XxHGTjo5Rf16z4GJG7UBHD8+s381j79Tw3t6DgDPB4/lzJx3+px6X7qOhrYv6g863y+rmDh56u5qLfvEmnz1lGjd98jgm5cZX7aC+tZPdLYf44kdLvc6KJ+ZPz+Nnf91GW5ef7LT4+qio3d/Bj17cwvL1eyjMSePG82YxLT+Dwpw0inLSKcxJY39HNxVVzVRU7Wd19X5e3lzPnS+8z8nFeSxdUMyFJ00mJz3F66KMWfH1jjEJQ1V5e0czj6/axQvv7qPLH+CEKeO4bckJXHDiZAqy0z50TEF2GrMnffD6ujNm8Mu/VfL7v1fx3Ia9fOmsY/jyWceSnpIcw5L0b537rX3+UVhzAaffRRU21LTwkZkTvM4O4DR/3fO3Su57cydJAl87ZyZfOutYsvoIfuOzUjm2MJsrFjjNevWtnTy7fi/LVtVwy1Mbue3Z97jgpMksXVDMqSX51nQWYRZczLA0tnXxxOpaHl9Vw87GdnLSfVxeXswVC4qH3byVm5HCLZ8+nqsWlXDXi+/z05e38c7OZu6/dkFcBJi1NS2kJAsnTInfZrtoOtypHyfBpb3Lz+d/t5K1u1r4zPyp3PSp45iSlzHk44ty0rnujBn8n4+Wsq6mhWUVNSxft4cnVtdSVpTN0oXT+cz8qeRnpUaxFEcPUfVuHLuILAZ+BiQD96nqnWHb04AHgVOBJuAKVa1yt90CXAf0Al9T1RVDOWdfysvLtaKiIlLFGnM6uv28sa2RZ9bt5i+b6vAHlAWl+SxdMJ1PnziZjNTIBIKn1tRy47L1fHLORH551Sn4kr0dzHjlvW/T3u1n+Q1neJoPL53zk1c5pjCb+64p9zQfXf5e/vmBCv5e2cgvrzqFxXMnR+S87V1+ntuwl0fe2cW6mhZSk5NYPHcSS+ZN4aMzJ8TFl5x4JiKrVbXPN4dnNRcRSQbuAc4DaoFVIrJcVd8L2e06YL+qzhSRpcBdwBUiMgdYCpwATAFeFpFZ7jGDnTNiVBVVUCBw+Ln7M+R5QBXFSXMODPk9JEGyCEkiiIAvSTz/UAWoO9jJy5vr+Ovmet6sbKTbHyA/M4VrP1LK0oXFzCyKfKfoZ06ZRmunn+8v38S3ntzIjy87iSSP7orvDTgzIV926jRPrh8v5k3P4/WtDaiqZ81GvQHl64+t441tjfz4spMiFlgAstJ8XL6gmMsXFLN570Eee2cXT6/dzfL1e0hPSeJjZYWcd/xEPj67iMKcDzf1xpKq0htQ/AEloEog+NkSCNnJ/ROJOE+DnyuC+9N9niTOoA0J7huFv62XzWILgUpV3QEgIo8BS4DQQLAE+IH7/AngF+L8FpYAj6lqF7BTRCrd8zGEc0bMb17fwZ0vvB/x8yYJpPqSSE1OItWXTEZqElmpPrLTfGSl+chKS2Zcegq5mSnkZvT/yElP6XfKElWlyx+gtdNPU3sXW/a1smVfK1vrWnl/Xyu1+w8BUDw+g88vKuHcOUUsKB1PSpQD3zUfKeXAoR7++6WtjMvwceuFczz5UNtW30p7d+9ROVIs1PziPJ5as5va/YcoHh/7hdJUlW8/tZEX3t3H9y6cw+fKi6N2reMnj+OHS+by7QuOZ+WOZl7eXMfL79Xx0nt1AEwfn8lxk3KYPSmHWROdx/isVHLSfaT5kvp9n/YGlIOHejjgPg52Oj9bOtzXIeltXb20d/mdR7efQ929dPkDdPsDdPcGiEZD0+2XzOXzp5VE/LxeBpepQE3I61pgUX/7qKpfRA4ABW7622HHTnWfD3ZOAETkeuB6gOnTRzaOv7wkn6+fW+Z8O+DIbwDBbwxJId8a3Os6P8GtzXzwLaQ34HwzCb6Ruv0BuvwBDnX7ae923nQtHd3U7vdzsNPPgUM9dPsDfeYtKCVZ3CDlPHxJSXR0+2nt9OMPm9rDlyQcU5jF/On5fP60Es6ZXURZUXbMP9z/5ZyZtHT0cP/fd5KXkcq/nlsW0+sDh4fgzi8+uqZ9CRec9mZtTUvMg4uq8p/Pb+bxihq+9okyrjtjRkyum+ZL5sxZhZw5q5AfXnwC7+09yKtbGnhvz0G21LXyyvv1H5oWJyVZyE7zkZnqwx9wg4H7f9zTO3BESPMlkZuRwriMFLLSfGSnJTM+K5PsNB/pKcmkuf+7wf/j5CRxHsFaifv5c7hhxI1AwdaTgNuSEjicHmxRcbafNC06fYpHbYe+qt4L3AtOn8tIzlFeOp7y0vERzddwdfb0Hv4GFPotKPhN6PC3HvfhDyhZaclkp/nITveRk+YjNzOVsqJsji3MJtXnfZOciPDdC47nYGcPd7+8lWn5GXw2xs1T63a1kJ+ZQknB2F7WeDDHTcohzZfEul0tXHzylJhe+6G3q/ntGzu59iOl/JsHXzDAeS+eMCX3iEEdnT29bG9oo7K+jYOHejjY6aety09bp1PbSEn64Mtcmi+JNF8y4zJ8TgDpo8VhrPbreBlcdgOhddxpblpf+9SKiA/IxenYH+jYwc45pqSnJDMpNznu7hEZraQk4c7PnMiu5g5+sHwTpx9bMKyRQaO1tmY/84rzjvrhqSnJSZw0LZe1NbGdBmZHQxt3PL+Zs48r9KxptD/pKckfCjjmw7z8mroKKBORGSKSitNBvzxsn+XANe7zy4BX1KnzLQeWikiaiMwAyoB3hnhOkyB8yUn85LKT6VXlW09uIFYjG1s7e9hW38a8o7xJLGhecR6b9hyky98bk+v1BpSb/nc9ab5k7vqsd4M6zOh4FlxU1Q/cAKwANgPLVHWTiNwmIhe7u/0OKHA77G8EbnaP3QQsw+mofxH4qqr29nfOWJbLRNb0gky+/enjeWNbIw+v3BWTa26oPYDq0XvzZLj50/Pp9gfYvLc1Jtf77Rs7WLOrhduWnMDEcWOrRn408bTPRVWfB54PS7s15Hkn8Ll+jr0DuGMo5zSJ7apF01mxaR//+fxmziwrZHqU+0GCi2SdfJRNs9+f4M2U63btj/pSz1vrWvnvv2xl8QmTYt7HYyLL+95bYwYhItz12ZNIFuGmJ9YTiPICVq9vbWDWxGxyM2zeKYDJuelMzcvg9W2NUb1OT2+AG5etIyfdx+2Xzo2rfhYzfBZcTEKYkpfBrRfN4Z2dzfz+H1VRu87ulkOs3NnMRSfZt+YgEeHCkybz+tYGmtq6onadX/5tO+/uPsgdl85lQh9z05nEYsHFJIzLTp3GJ2YX8aMX32d7Q3RWSHxmnTO48JL5UwfZ8+hyyfyp+APKcxv3RuX8m/Yc4H9e2caSeVMiege+8Y4FF5MwRIT/+syJpPmS+M7TGyM+ekxVeXrNbhaU5ntyN3o8O37yOGZPyuGpNZEf2d8bUG55aiN5man88OITIn5+4w0LLiahFI1L5+bzj+ftHc08sbo2oufetOcg2+rbrNbSj0vnT2VdTQs7G9sjet4H36piQ+0Bbr1oDnmZNiPxWGHBxSScpQuKKS/J547nN0e0D+DptbtJTU7ighOtWaYvF8+bggj8aW3kai97Wg7xkxVbOGtWIRedZL/3scSCi0k4SUlO81h7l587ntsckXP6ewMsX7+Hj88utG/P/Zicm8FHji3gT+t2R6xJ8gfLN9Gryu2X2OiwscaCi0lIZRNz+NKZx/LU2t28GYEhsv/Y3kRDaxeXWpPYgC6ZN5Xqpg7WuBN7jsaKTfv4y3t1fP3cWdbHNQZZcDEJ64ZzZlJakMl3/7SRzp7RTU3y9NrdjEv38fHZRRHK3di0eO4k0nxJo24aa+vy8/1nNjF7Uk7MZjs2sWXBxSSs9JRk7rj0RKqaOvjFK5UjPk97l58X393HBSdNIc03NmeojZSc9BQ+ecIknt2wZ9DlHgbykxVbqGvt5L8+c2LU1wgy3rC/qkloH505gc/Mn8qvX9vOxtoDIzrHX97bx6GeXmsSG6JL50+hpaOH17Y2jOj4VVXNPPBWFV84reTwejFm7LHgYhLedy+cQ1FOGl9+aDXN7d3DPv7ptXuYmpdBeYl90A3Fx8oKKchKHVHTWN3BTr7y8BpKxmfyjU8dF4XcmXhhwcUkvPFZqfzq86fS0NbFvzy6Bn/v0Jtr6ls7eXNbA5fOn2pTuw9RSnISF508hZc213Gws2fIx3X7A/y/h1bT3uXn3qvLyUm3udvGMgsuZkw4uTiP25fM5e+VTfx4xZYhH/fQW9UEFC6Zb3OJDccl86fS7Q/w6DCWQfjhs5tYs6uFH192MrMm5kQxdyYeWHAxY8blC4r5/GnT+c3rO/jzhj2D7v/Ht6r4+SuVXHDSZGYW2YfdcJw8LZezjyvkzhff58khzJTw+KpdPLxyF18+61gusJsljwoWXMyYcuuFJ3BqST7ffGIDW/b1v7jVIyt38b1nNnHu8UXcffm8GOZwbBARfv35Uzn9mAJuemL9gP0v62pa+N6fNvGxsgnWz3IUseBixpRUXxK/vOoUstJ8/PODq1i+fs+H7oF5fNUuvv30Rs6ZXcQ9V51Cqs/+DUYiPSWZ312zgEUzxnPjsnUsX39kbfFQdy9Pranly39cTdG4NH6+dD7J1q911JBYrUsez8rLy7WiosLrbJgIWrNrP//yyFp2txxiXLqPS+ZP5fLyYjbvPcg3n9zAmWWF/OYLp5KeYve1jFZHt59r71/F6l37+dnSeUzNy2BZRS3Prt9DW5ef0oJMfnnVqcyZMs7rrJoIE5HVqlre5zYLLhZcxqpAQPnH9iaWVdTw4qZ9h2/6+1jZBH57dbkFlghq7/Jzzf3vUFG9H4D0lCQ+feJkLi8vZtGM8TZv2BgVd8FFRMYDjwOlQBVwuaru72O/a4Dvui9vV9UHRCQT+F/gWKAXeFZVb3b3vxb4MRBsAP6Fqt43WH4suIx9Bzp6WL5+N1VNHXzjU8dZYImCti4/P1mxheMm5XDhSZNtqPFRIB6Dy4+AZlW9U0RuBvJV9Vth+4wHKoByQIHVwKlAF7BIVf8mIqnAX4H/VNUX3OBSrqo3DCc/FlyMMWb4BgouXvVkLgEecJ8/AFzSxz6fAl5S1Wa3VvMSsFhVO1T1bwCq2g2sAabFIM/GGGOGyKvgMlFVg4tx7wMm9rHPVKAm5HWtm3aYiOQBF+HUXoI+KyIbROQJESmOYJ6NMcYMkS9aJxaRl4FJfWz6TugLVVURGXbbnIj4gEeBn6vqDjf5WeBRVe0SkS/h1IrO6ef464HrAaZPnz7cyxtjjBlA1IKLqp7b3zYRqRORyaq6V0QmA/V97LYbODvk9TTg1ZDX9wLbVPWnIddsCtl+H/CjAfJ3r3sOysvLbcicMcZEkFfNYsuBa9zn1wDP9LHPCuCTIpIvIvnAJ900ROR2IBf4eugBbqAKuhiIzBq4xhhjhsWr4HIncJ6IbAPOdV8jIuUich+AqjYD/wGsch+3qWqziEzDaVqbA6wRkXUi8s/ueb8mIptEZD3wNeDaWBbKGGOMw26ixIYiG2PMSMTjUGRjjDFjmNVcABFpAKpHePgEoDGC2fGClSF+jIVyWBniQyzKUKKqhX1tsOAySiJS0V+1MFFYGeLHWCiHlSE+eF0GaxYzxhgTcRZcjDHGRJwFl9G71+sMRICVIX6MhXJYGeKDp2WwPhdjjDERZzUXY4wxEWfBxRhjTMRZcBkFEVksIltEpNJd9Czuicj9IlIvIu+GpI0XkZdEZJv7M9/LPA5GRIpF5G8i8p473c+/uukJUw4RSReRd0RkvVuGH7rpM0RkpfueetxdEC+uiUiyiKwVkT+7rxOqDCJSJSIb3amkKty0hHkvgbP8iLvMyPsisllETve6DBZcRkhEkoF7gPNx5jm7UkTmeJurIfkDsDgs7Wbgr6pahrM2TrwHSj/w76o6BzgN+Kr7u0+kcnQB56jqycA8YLGInAbcBdytqjOB/cB1HuZxqP6VIyeJTcQyfFxV54XcF5JI7yWAnwEvqups4GScv4e3ZVBVe4zgAZwOrAh5fQtwi9f5GmLeS4F3Q15vASa7zycDW7zO4zDL8wxwXqKWA8jEWVF1Ec4d1T43/Yj3WDw+cJbC+CvOukl/BiQBy1AFTAhLS5j3Es4M8TtxB2jFSxms5jJyg66UmUCGsjJoXBKRUmA+sJIEK4fbnLQOZz2jl4DtQIuq+t1dEuE99VPgm0DAfV1A4pVBgb+IyGp3EUFIrPfSDKAB+L3bPHmfiGThcRksuJgjqPM1JyHGp4tINvAk8HVVPRi6LRHKoaq9qjoP59v/QmC2x1kaFhG5EKhX1dVe52WUzlDVU3CauL8qImeGbkyA95IPOAX4larOB9oJawLzogwWXEZuN1Ac8nqam5aI6oILrQ2wMmhcEZEUnMDysKo+5SYnXDkAVLUF+BtOE1Keu4Q3xP976qPAxSJSBTyG0zT2MxKrDKjqbvdnPfA0TqBPpPdSLVCrqivd10/gBBtPy2DBZeRWAWXuyJhUYCnOCpuJaCgrg8YNERHgd8BmVf3vkE0JUw4RKRSRPPd5Bk6f0WacIHOZu1tcl0FVb1HVaapaivP+f0VVryKByiAiWSKSE3yOs+LtuyTQe0lV9wE1InKcm/QJ4D08LoPdoT8KIvJpnDbnZOB+Vb3D4ywNSkQeBc7GmY67Dvg+8CdgGTAdZ+mBy9VZCTQuicgZwBvARj5o6/82Tr9LQpRDRE4CHsB57yQBy1T1NhE5BqcWMB5YC3xeVbu8y+nQiMjZwE2qemEilcHN69PuSx/wiKreISIFJMh7CUBE5gH3AanADuCLuO8rPCqDBRdjjDERZ81ixhhjIs6CizHGmIiz4GKMMSbiLLgYY4yJOAsuxhhjIs6CizFRIiLfcWc83uDOuLsoitd6VUTKB9/TmNjwDb6LMWa4ROR04ELgFFXtEpEJOPcgGHNUsJqLMdExGWgM3jyoqo2qukdEbhWRVSLyrojc6842EKx53C0iFe56HAtE5Cl3LY7b3X1K3fU6Hnb3eUJEMsMvLCKfFJG3RGSNiPyvOwebMTFlwcWY6PgLUCwiW0XklyJylpv+C1VdoKpzgQyc2k1QtzrrifwaZ6qOrwJzgWvdO8YBjgN+qarHAweBr4Re1K0hfRc4152MsQK4MTpFNKZ/FlyMiQJVbQNOBa7HmQ79cRG5Fvi4u0rjRpyJHk8IOSw4N91GYJOq7nVrPjv4YJLUGlX9u/v8IeCMsEufhrN43d/d6fyvAUoiWjhjhsD6XIyJElXtBV4FXnWDyZeAk4ByVa0RkR8A6SGHBOffCoQ8D74O/q+Gz9cU/lqAl1T1ylEXwJhRsJqLMVEgIseJSFlI0jyclQEBGt1+kMs+fOSgpruDBQD+CXgzbPvbwEdFZKabjywRmTWC6xgzKlZzMSY6soH/cafV9wOVOE1kLThTuu/DWbZhuLbgLGh1P8606r8K3aiqDW7z26MikuYmfxfYOpJCGDNSNiuyMQnCXdL5z+5gAGPimjWLGWOMiTiruRhjjIk4q7kYY4yJOAsuxhhjIs6CizHGmIiz4GKMMSbiLLgYY4yJuP8f4qhAidPtIUcAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cutoff = 0.15\n", + "beta = 9\n", + "ntaps = 63\n", + "N = 4\n", + "\n", + "b = sig.firwin(ntaps, cutoff, window=('kaiser', beta))\n", + "w, h = sig.freqz(b)\n", + "\n", + "plt.plot(b)\n", + "plt.title('Resulting PQMF Window Function')\n", + "plt.xlabel('Sample')\n", + "plt.ylabel('Value')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "fig, ax1 = plt.subplots()\n", + "ax1.set_title('Digital filter frequency response')\n", + "\n", + "ax1.plot(w / (2 * np.pi), 20 * np.log10(abs(h)), 'b')\n", + "ax1.set_ylabel('Amplitude [dB]', color='b')\n", + "ax1.set_xlabel('Frequency [rad/sample]')\n", + "\n", + "ax2 = ax1.twinx()\n", + "angles = np.unwrap(np.angle(h))\n", + "ax2.plot(w / (2 * np.pi), angles, 'g')\n", + "ax2.set_ylabel('Angle (radians)', color='g')\n", + "ax2.grid()\n", + "ax2.axis('tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(63,)" + ] + }, + "execution_count": 105, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "def optimfuncQMF(x):\n", + " \"\"\"Optimization function for a PQMF Filterbank\n", + " x: coefficients to optimize (first half of prototype h because of symmetry)\n", + " err: resulting total error\n", + " \"\"\"\n", + " N = 2 #4 subbands\n", + " cutoff = 1.5 #1.5\n", + " h = np.append(x, np.flipud(x))\n", + " f, H_im = sig.freqz(h)\n", + " H = np.abs(H_im) #only keeping the real part\n", + " \n", + " posfreq = np.square(H[0:512//N])\n", + " \n", + " #Negative frequencies are symmetric around 0:\n", + " negfreq = np.flipud(np.square(H[0:512//N]))\n", + " \n", + " #Sum of magnitude squared frequency responses should be closed to unity (or N)\n", + " unitycond = np.sum(np.abs(posfreq + negfreq - 2*(N*N)*np.ones(512//N)))//512\n", + " \n", + " #plt.plot(posfreq+negfreq)\n", + " \n", + " #High attenuation after the next subband:\n", + " att = np.sum(np.abs(H[int(cutoff*512//N):]))//512\n", + " \n", + " #Total (weighted) error:\n", + " err = unitycond + 100*att\n", + " return err" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "metadata": { + "Collapsed": "false" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.0\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "err = optimfuncQMF(b)\n", + "print(err)\n", + "\n", + "#Restore symmetric upper half of window:\n", + "h = np.concatenate((xmin, np.flipud(xmin)))\n", + "plt.plot(h)\n", + "plt.title('Resulting PQMF Window Function')\n", + "plt.xlabel('Sample')\n", + "plt.ylabel('Value')\n", + "plt.show()\n", + "\n", + "f, H = sig.freqz(h)\n", + "plt.plot(f, 20*np.log10(np.abs(H)))\n", + "plt.title('Resulting PQMF Magnitude Response')\n", + "plt.xlabel('Normalized Frequency')\n", + "plt.ylabel('dB')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.4 64-bit ('base': conda)", + "language": "python", + "name": "python37464bitbaseconda58faf23c4b5f4fef93406f29a1005f35" + }, + "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.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/vocoder/notebooks/Untitled1.ipynb b/vocoder/notebooks/Untitled1.ipynb new file mode 100644 index 00000000..7fec5150 --- /dev/null +++ b/vocoder/notebooks/Untitled1.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/vocoder/pqmf_output.wav b/vocoder/pqmf_output.wav new file mode 100644 index 0000000000000000000000000000000000000000..8a77747b00198a4adfd6c398998517df5b4bdb8d GIT binary patch literal 83812 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 z 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 literal 0 HcmV?d00001 diff --git a/vocoder/tests/__init__.py b/vocoder/tests/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/vocoder/tests/__init__.py @@ -0,0 +1 @@ + diff --git a/vocoder/tests/test_config.json b/vocoder/tests/test_config.json new file mode 100644 index 00000000..08acc48c --- /dev/null +++ b/vocoder/tests/test_config.json @@ -0,0 +1,24 @@ +{ + "audio":{ + "num_mels": 80, // size of the mel spec frame. + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "sample_rate": 22050, // wav sample-rate. If different than the original data, it is resampled. + "frame_length_ms": null, // stft window length in ms. + "frame_shift_ms": null, // stft window hop-lengh in ms. + "hop_length": 256, + "win_length": 1024, + "preemphasis": 0.97, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "min_level_db": -100, // normalization range + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 30,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + "signal_norm": true, // normalize the spec values in range [0, 1] + "symmetric_norm": true, // move normalization to range [-1, 1] + "clip_norm": true, // clip normalized values into the range. + "max_norm": 4, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "mel_fmin": 0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000, // maximum freq level for mel-spec. Tune for dataset!! + "do_trim_silence": false + } +} + diff --git a/vocoder/tests/test_datasets.py b/vocoder/tests/test_datasets.py new file mode 100644 index 00000000..3d6280f0 --- /dev/null +++ b/vocoder/tests/test_datasets.py @@ -0,0 +1,95 @@ +import os +import numpy as np +from torch.utils.data import DataLoader + +from TTS.vocoder.datasets.gan_dataset import GANDataset +from TTS.vocoder.datasets.preprocess import load_wav_data +from TTS.utils.audio import AudioProcessor +from TTS.utils.io import load_config + + +file_path = os.path.dirname(os.path.realpath(__file__)) +OUTPATH = os.path.join(file_path, "../../tests/outputs/loader_tests/") +os.makedirs(OUTPATH, exist_ok=True) + +C = load_config(os.path.join(file_path, 'test_config.json')) + +test_data_path = os.path.join(file_path, "../../tests/data/ljspeech/") +ok_ljspeech = os.path.exists(test_data_path) + + + +def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, use_noise_augment, use_cache, num_workers): + ''' run dataloader with given parameters and check conditions ''' + ap = AudioProcessor(**C.audio) + eval_items, train_items = load_wav_data(test_data_path, 10) + dataset = GANDataset(ap, + train_items, + seq_len=seq_len, + hop_len=hop_len, + pad_short=2000, + conv_pad=conv_pad, + return_segments=return_segments, + use_noise_augment=use_noise_augment, + use_cache=use_cache) + loader = DataLoader(dataset=dataset, + batch_size=batch_size, + shuffle=True, + num_workers=num_workers, + pin_memory=True, + drop_last=True) + + max_iter = 10 + count_iter = 0 + + # return random segments or return the whole audio + if return_segments: + for item1, item2 in loader: + feat1, wav1 = item1 + feat2, wav2 = item2 + expected_feat_shape = (batch_size, ap.num_mels, seq_len // hop_len + conv_pad * 2) + + # check shapes + assert np.all(feat1.shape == expected_feat_shape), f" [!] {feat1.shape} vs {expected_feat_shape}" + assert (feat1.shape[2] - conv_pad * 2) * hop_len == wav1.shape[2] + + # check feature vs audio match + if not use_noise_augment: + for idx in range(batch_size): + audio = wav1[idx].squeeze() + feat = feat1[idx] + mel = ap.melspectrogram(audio) + # the first 2 and the last frame is skipped due to the padding + # applied in spec. computation. + assert (feat - mel[:, :feat1.shape[-1]])[:, 2:-1].sum() == 0, f' [!] {(feat - mel[:, :feat1.shape[-1]])[:, 2:-1].sum()}' + + count_iter += 1 + # if count_iter == max_iter: + # break + else: + for item in loader: + feat, wav = item + expected_feat_shape = (batch_size, ap.num_mels, (wav.shape[-1] // hop_len) + (conv_pad * 2)) + assert np.all(feat.shape == expected_feat_shape), f" [!] {feat.shape} vs {expected_feat_shape}" + assert (feat.shape[2] - conv_pad * 2) * hop_len == wav.shape[2] + count_iter += 1 + if count_iter == max_iter: + break + + +def test_parametrized_gan_dataset(): + ''' test dataloader with different parameters ''' + params = [ + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 4], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, True, 0], + [1, C.audio['hop_length'], C.audio['hop_length'], 0, True, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 2, True, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, False, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, False, False, 0], + ] + for param in params: + print(param) + gan_dataset_case(*param) diff --git a/vocoder/tests/test_losses.py b/vocoder/tests/test_losses.py new file mode 100644 index 00000000..83314832 --- /dev/null +++ b/vocoder/tests/test_losses.py @@ -0,0 +1,62 @@ +import os +import unittest +import torch + +from TTS.vocoder.layers.losses import TorchSTFT, STFTLoss, MultiScaleSTFTLoss + +from TTS.tests import get_tests_path, get_tests_input_path, get_tests_output_path +from TTS.utils.audio import AudioProcessor +from TTS.utils.io import load_config + +TESTS_PATH = get_tests_path() + +OUT_PATH = os.path.join(get_tests_output_path(), "audio_tests") +os.makedirs(OUT_PATH, exist_ok=True) + +WAV_FILE = os.path.join(get_tests_input_path(), "example_1.wav") + +file_path = os.path.dirname(os.path.realpath(__file__)) +C = load_config(os.path.join(file_path, 'test_config.json')) +ap = AudioProcessor(**C.audio) + + +def test_torch_stft(): + torch_stft = TorchSTFT(ap.n_fft, ap.hop_length, ap.win_length) + # librosa stft + wav = ap.load_wav(WAV_FILE) + M_librosa = abs(ap._stft(wav)) + # torch stft + wav = torch.from_numpy(wav[None, :]).float() + M_torch = torch_stft(wav) + # check the difference b/w librosa and torch outputs + assert (M_librosa - M_torch[0].data.numpy()).max() < 1e-5 + + +def test_stft_loss(): + stft_loss = STFTLoss(ap.n_fft, ap.hop_length, ap.win_length) + wav = ap.load_wav(WAV_FILE) + wav = torch.from_numpy(wav[None, :]).float() + loss_m, loss_sc = stft_loss(wav, wav) + assert loss_m + loss_sc == 0 + loss_m, loss_sc = stft_loss(wav, torch.rand_like(wav)) + assert loss_sc < 1.0 + assert loss_m + loss_sc > 0 + + +def test_multiscale_stft_loss(): + stft_loss = MultiScaleSTFTLoss([ap.n_fft//2, ap.n_fft, ap.n_fft*2], + [ap.hop_length // 2, ap.hop_length, ap.hop_length * 2], + [ap.win_length // 2, ap.win_length, ap.win_length * 2]) + wav = ap.load_wav(WAV_FILE) + wav = torch.from_numpy(wav[None, :]).float() + loss_m, loss_sc = stft_loss(wav, wav) + assert loss_m + loss_sc == 0 + loss_m, loss_sc = stft_loss(wav, torch.rand_like(wav)) + assert loss_sc < 1.0 + assert loss_m + loss_sc > 0 + + + + + + diff --git a/vocoder/tests/test_melgan_discriminator.py b/vocoder/tests/test_melgan_discriminator.py new file mode 100644 index 00000000..83acec8f --- /dev/null +++ b/vocoder/tests/test_melgan_discriminator.py @@ -0,0 +1,26 @@ +import numpy as np +import torch + +from TTS.vocoder.models.melgan_discriminator import MelganDiscriminator +from TTS.vocoder.models.melgan_multiscale_discriminator import MelganMultiscaleDiscriminator + + +def test_melgan_discriminator(): + model = MelganDiscriminator() + print(model) + dummy_input = torch.rand((4, 1, 256 * 10)) + output, _ = model(dummy_input) + assert np.all(output.shape == (4, 1, 10)) + + +def test_melgan_multi_scale_discriminator(): + model = MelganMultiscaleDiscriminator() + print(model) + dummy_input = torch.rand((4, 1, 256 * 16)) + scores, feats = model(dummy_input) + assert len(scores) == 3 + assert len(scores) == len(feats) + assert np.all(scores[0].shape == (4, 1, 16)) + assert np.all(feats[0][0].shape == (4, 16, 4096)) + assert np.all(feats[0][1].shape == (4, 64, 1024)) + assert np.all(feats[0][2].shape == (4, 256, 256)) diff --git a/vocoder/tests/test_melgan_generator.py b/vocoder/tests/test_melgan_generator.py new file mode 100644 index 00000000..e9c4ad60 --- /dev/null +++ b/vocoder/tests/test_melgan_generator.py @@ -0,0 +1,15 @@ +import numpy as np +import unittest +import torch + +from TTS.vocoder.models.melgan_generator import MelganGenerator + +def test_melgan_generator(): + model = MelganGenerator() + print(model) + dummy_input = torch.rand((4, 80, 64)) + output = model(dummy_input) + assert np.all(output.shape == (4, 1, 64 * 256)) + output = model.inference(dummy_input) + assert np.all(output.shape == (4, 1, (64 + 4) * 256)) + diff --git a/vocoder/tests/test_pqmf.py b/vocoder/tests/test_pqmf.py new file mode 100644 index 00000000..8444fc5a --- /dev/null +++ b/vocoder/tests/test_pqmf.py @@ -0,0 +1,33 @@ +import os +import torch +import unittest + +import numpy as np +import soundfile as sf +from librosa.core import load + +from TTS.tests import get_tests_path, get_tests_input_path, get_tests_output_path +from TTS.utils.audio import AudioProcessor +from TTS.utils.io import load_config +from TTS.vocoder.layers.pqmf import PQMF +from TTS.vocoder.layers.pqmf2 import PQMF as PQMF2 + + +TESTS_PATH = get_tests_path() +WAV_FILE = os.path.join(get_tests_input_path(), "example_1.wav") + + +def test_pqmf(): + w, sr = load(WAV_FILE) + + layer = PQMF(N=4, taps=62, cutoff=0.15, beta=9.0) + w, sr = load(WAV_FILE) + w2 = torch.from_numpy(w[None, None, :]) + b2 = layer.analysis(w2) + w2_ = layer.synthesis(b2) + + print(w2_.max()) + print(w2_.min()) + print(w2_.mean()) + sf.write('pqmf_output.wav', w2_.flatten().detach(), sr) + diff --git a/vocoder/tests/test_rwd.py b/vocoder/tests/test_rwd.py new file mode 100644 index 00000000..424d3b49 --- /dev/null +++ b/vocoder/tests/test_rwd.py @@ -0,0 +1,21 @@ +import torch +import numpy as np + +from TTS.vocoder.models.random_window_discriminator import RandomWindowDiscriminator + + +def test_rwd(): + layer = RandomWindowDiscriminator(cond_channels=80, + window_sizes=(512, 1024, 2048, 4096, + 8192), + cond_disc_downsample_factors=[ + (8, 4, 2, 2, 2), (8, 4, 2, 2), + (8, 4, 2), (8, 4), (4, 2, 2) + ], + hop_length=256) + x = torch.rand([4, 1, 22050]) + c = torch.rand([4, 80, 22050 // 256]) + + scores, _ = layer(x, c) + assert len(scores) == 10 + assert np.all(scores[0].shape == (4, 1, 1)) diff --git a/vocoder/train.py b/vocoder/train.py new file mode 100644 index 00000000..b0b4833a --- /dev/null +++ b/vocoder/train.py @@ -0,0 +1,585 @@ +import argparse +import glob +import os +import sys +import time +import traceback + +import torch +from torch.utils.data import DataLoader + +from inspect import signature + +from TTS.utils.audio import AudioProcessor +from TTS.utils.generic_utils import (KeepAverage, count_parameters, + create_experiment_folder, get_git_branch, + remove_experiment_folder, set_init_dict) +from TTS.utils.io import copy_config_file, load_config +from TTS.utils.radam import RAdam +from TTS.utils.tensorboard_logger import TensorboardLogger +from TTS.utils.training import NoamLR +from TTS.vocoder.datasets.gan_dataset import GANDataset +from TTS.vocoder.datasets.preprocess import load_wav_data +# from distribute import (DistributedSampler, apply_gradient_allreduce, +# init_distributed, reduce_tensor) +from TTS.vocoder.layers.losses import DiscriminatorLoss, GeneratorLoss +from TTS.vocoder.utils.io import save_checkpoint, save_best_model +from TTS.vocoder.utils.console_logger import ConsoleLogger +from TTS.vocoder.utils.generic_utils import (check_config, plot_results, + setup_discriminator, + setup_generator) + +torch.backends.cudnn.enabled = True +torch.backends.cudnn.benchmark = True +torch.manual_seed(54321) +use_cuda = torch.cuda.is_available() +num_gpus = torch.cuda.device_count() +print(" > Using CUDA: ", use_cuda) +print(" > Number of GPUs: ", num_gpus) + + +def setup_loader(ap, is_val=False, verbose=False): + if is_val and not c.run_eval: + loader = None + else: + dataset = GANDataset(ap=ap, + items=eval_data if is_val else train_data, + seq_len=c.seq_len, + hop_len=ap.hop_length, + pad_short=c.pad_short, + conv_pad=c.conv_pad, + is_training=not is_val, + return_segments=False if is_val else True, + use_noise_augment=c.use_noise_augment, + use_cache=c.use_cache, + verbose=verbose) + # sampler = DistributedSampler(dataset) if num_gpus > 1 else None + loader = DataLoader(dataset, + batch_size=1 if is_val else c.batch_size, + shuffle=False, + drop_last=False, + sampler=None, + num_workers=c.num_val_loader_workers + if is_val else c.num_loader_workers, + pin_memory=False) + return loader + + +def format_data(data): + if isinstance(data[0], list): + # setup input data + c_G, x_G = data[0] + c_D, x_D = data[1] + + # dispatch data to GPU + if use_cuda: + c_G = c_G.cuda(non_blocking=True) + x_G = x_G.cuda(non_blocking=True) + c_D = c_D.cuda(non_blocking=True) + x_D = x_D.cuda(non_blocking=True) + + return c_G, x_G, c_D, x_D + + # return a whole audio segment + c, x = data + if use_cuda: + c = c.cuda(non_blocking=True) + x = x.cuda(non_blocking=True) + return c, x + + +def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, + scheduler_G, scheduler_D, ap, global_step, epoch): + data_loader = setup_loader(ap, is_val=False, verbose=(epoch == 0)) + model_G.train() + model_D.train() + epoch_time = 0 + keep_avg = KeepAverage() + if use_cuda: + batch_n_iter = int( + len(data_loader.dataset) / (c.batch_size * num_gpus)) + else: + batch_n_iter = int(len(data_loader.dataset) / c.batch_size) + end_time = time.time() + c_logger.print_train_start() + for num_iter, data in enumerate(data_loader): + start_time = time.time() + + # format data + c_G, y_G, c_D, y_D = format_data(data) + loader_time = time.time() - end_time + + global_step += 1 + + # get current learning rates + current_lr_G = list(optimizer_G.param_groups)[0]['lr'] + current_lr_D = list(optimizer_D.param_groups)[0]['lr'] + + ############################## + # GENERATOR + ############################## + + # generator pass + optimizer_G.zero_grad() + y_hat = model_G(c_G) + + in_real_D = y_hat + in_fake_D = y_G + + # PQMF formatting + if y_hat.shape[1] > 1: + in_real_D = y_G + in_fake_D = model_G.pqmf_synthesis(y_hat) + y_G = model_G.pqmf_analysis(y_G) + y_hat = y_hat.view(-1, 1, y_hat.shape[2]) + y_G = y_G.view(-1, 1, y_G.shape[2]) + + if global_step > c.steps_to_start_discriminator: + + # run D with or without cond. features + if len(signature(model_D).parameters) == 2: + D_out_fake = model_D(in_fake_D, c_G) + else: + D_out_fake = model_D(in_fake_D) + D_out_real = None + + if c.use_feat_match_loss: + with torch.no_grad(): + D_out_real = model_D(in_real_D) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + scores_real, feats_real = None, None + else: + scores_real, feats_real = D_out_real + else: + scores_fake = D_out_fake + scores_real = D_out_real + else: + scores_fake, feats_fake, feats_real = None, None, None + + # compute losses + loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, + feats_real) + loss_G = loss_G_dict['G_loss'] + + # optimizer generator + loss_G.backward() + if c.gen_clip_grad > 0: + torch.nn.utils.clip_grad_norm_(model_G.parameters(), + c.gen_clip_grad) + optimizer_G.step() + + # setup lr + if c.noam_schedule: + scheduler_G.step() + + loss_dict = dict() + for key, value in loss_G_dict.items(): + loss_dict[key] = value.item() + + ############################## + # DISCRIMINATOR + ############################## + if global_step > c.steps_to_start_discriminator: + # discriminator pass + with torch.no_grad(): + y_hat = model_G(c_D) + + # PQMF formatting + if y_hat.shape[1] > 1: + y_hat = model_G.pqmf_synthesis(y_hat) + + optimizer_D.zero_grad() + + # run D with or without cond. features + if len(signature(model_D).parameters) == 2: + D_out_fake = model_D(y_hat.detach(), c_D) + D_out_real = model_D(y_D, c_D) + else: + D_out_fake = model_D(y_hat.detach()) + D_out_real = model_D(y_D) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + scores_real, feats_real = None, None + else: + scores_real, feats_real = D_out_real + else: + scores_fake = D_out_fake + scores_real = D_out_real + + # compute losses + loss_D_dict = criterion_D(scores_fake, scores_real) + loss_D = loss_D_dict['D_loss'] + + # optimizer discriminator + loss_D.backward() + if c.disc_clip_grad > 0: + torch.nn.utils.clip_grad_norm_(model_D.parameters(), + c.disc_clip_grad) + optimizer_D.step() + + # setup lr + if c.noam_schedule: + scheduler_D.step() + + for key, value in loss_D_dict.items(): + loss_dict[key] = value.item() + + step_time = time.time() - start_time + epoch_time += step_time + + # update avg stats + update_train_values = dict() + for key, value in loss_dict.items(): + update_train_values['avg_' + key] = value + update_train_values['avg_loader_time'] = loader_time + update_train_values['avg_step_time'] = step_time + keep_avg.update_values(update_train_values) + + # print training stats + if global_step % c.print_step == 0: + c_logger.print_train_step(batch_n_iter, num_iter, global_step, + step_time, loader_time, current_lr_G, + loss_dict, keep_avg.avg_values) + + # plot step stats + if global_step % 10 == 0: + iter_stats = { + "lr_G": current_lr_G, + "lr_D": current_lr_D, + "step_time": step_time + } + iter_stats.update(loss_dict) + tb_logger.tb_train_iter_stats(global_step, iter_stats) + + # save checkpoint + if global_step % c.save_step == 0: + if c.checkpoint: + # save model + save_checkpoint(model_G, + optimizer_G, + model_D, + optimizer_D, + global_step, + epoch, + OUT_PATH, + model_losses=loss_dict) + + # compute spectrograms + figures = plot_results(in_fake_D, in_real_D, ap, global_step, + 'train') + tb_logger.tb_train_figures(global_step, figures) + + # Sample audio + sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() + tb_logger.tb_train_audios(global_step, + {'train/audio': sample_voice}, + c.audio["sample_rate"]) + end_time = time.time() + + # print epoch stats + c_logger.print_train_epoch_end(global_step, epoch, epoch_time, keep_avg) + + # Plot Training Epoch Stats + epoch_stats = {"epoch_time": epoch_time} + epoch_stats.update(keep_avg.avg_values) + tb_logger.tb_train_epoch_stats(global_step, epoch_stats) + # TODO: plot model stats + # if c.tb_model_param_stats: + # tb_logger.tb_model_weights(model, global_step) + return keep_avg.avg_values, global_step + + +@torch.no_grad() +def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): + data_loader = setup_loader(ap, is_val=True, verbose=(epoch == 0)) + model_G.eval() + model_D.eval() + epoch_time = 0 + keep_avg = KeepAverage() + end_time = time.time() + c_logger.print_eval_start() + for num_iter, data in enumerate(data_loader): + start_time = time.time() + + # format data + c_G, y_G = format_data(data) + loader_time = time.time() - end_time + + global_step += 1 + + ############################## + # GENERATOR + ############################## + + # generator pass + y_hat = model_G(c_G) + + in_real_D = y_hat + in_fake_D = y_G + + # PQMF formatting + if y_hat.shape[1] > 1: + in_real_D = y_G + in_fake_D = model_G.pqmf_synthesis(y_hat) + y_G = model_G.pqmf_analysis(y_G) + y_hat = y_hat.view(-1, 1, y_hat.shape[2]) + y_G = y_G.view(-1, 1, y_G.shape[2]) + + D_out_fake = model_D(in_fake_D) + D_out_real = None + if c.use_feat_match_loss: + with torch.no_grad(): + D_out_real = model_D(in_real_D) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + feats_real = None + else: + _, feats_real = D_out_real + else: + scores_fake = D_out_fake + + # compute losses + loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, + feats_real) + + loss_dict = dict() + for key, value in loss_G_dict.items(): + loss_dict[key] = value.item() + + step_time = time.time() - start_time + epoch_time += step_time + + # update avg stats + update_eval_values = dict() + for key, value in loss_G_dict.items(): + update_eval_values['avg_' + key] = value.item() + update_eval_values['avg_loader_time'] = loader_time + update_eval_values['avg_step_time'] = step_time + keep_avg.update_values(update_eval_values) + + # print eval stats + if c.print_eval: + c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) + + # compute spectrograms + figures = plot_results(y_hat, y_G, ap, global_step, 'eval') + tb_logger.tb_eval_figures(global_step, figures) + + # Sample audio + sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() + tb_logger.tb_eval_audios(global_step, {'eval/audio': sample_voice}, + c.audio["sample_rate"]) + + # synthesize a full voice + data_loader.return_segments = False + + return keep_avg.avg_values + + +# FIXME: move args definition/parsing inside of main? +def main(args): # pylint: disable=redefined-outer-name + # pylint: disable=global-variable-undefined + global train_data, eval_data + eval_data, train_data = load_wav_data(c.data_path, c.eval_split_size) + + # setup audio processor + ap = AudioProcessor(**c.audio) + # DISTRUBUTED + # if num_gpus > 1: + # init_distributed(args.rank, num_gpus, args.group_id, + # c.distributed["backend"], c.distributed["url"]) + + # setup models + model_gen = setup_generator(c) + model_disc = setup_discriminator(c) + + # setup optimizers + optimizer_gen = RAdam(model_gen.parameters(), lr=c.lr_gen, weight_decay=0) + optimizer_disc = RAdam(model_disc.parameters(), + lr=c.lr_disc, + weight_decay=0) + + # setup criterion + criterion_gen = GeneratorLoss(c) + criterion_disc = DiscriminatorLoss(c) + + if args.restore_path: + checkpoint = torch.load(args.restore_path, map_location='cpu') + try: + model_gen.load_state_dict(checkpoint['model']) + optimizer_gen.load_state_dict(checkpoint['optimizer']) + model_disc.load_state_dict(checkpoint['model_disc']) + optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) + except: + print(" > Partial model initialization.") + model_dict = model_gen.state_dict() + model_dict = set_init_dict(model_dict, checkpoint['model'], c) + model_gen.load_state_dict(model_dict) + + model_dict = model_disc.state_dict() + model_dict = set_init_dict(model_dict, checkpoint['model_disc'], c) + model_disc.load_state_dict(model_dict) + del model_dict + + # reset lr if not countinuining training. + for group in optimizer_gen.param_groups: + group['lr'] = c.lr_gen + + for group in optimizer_disc.param_groups: + group['lr'] = c.lr_disc + + print(" > Model restored from step %d" % checkpoint['step'], + flush=True) + args.restore_step = checkpoint['step'] + else: + args.restore_step = 0 + + if use_cuda: + model_gen.cuda() + criterion_gen.cuda() + model_disc.cuda() + criterion_disc.cuda() + + # DISTRUBUTED + # if num_gpus > 1: + # model = apply_gradient_allreduce(model) + + if c.noam_schedule: + scheduler_gen = NoamLR(optimizer_gen, + warmup_steps=c.warmup_steps_gen, + last_epoch=args.restore_step - 1) + scheduler_disc = NoamLR(optimizer_disc, + warmup_steps=c.warmup_steps_gen, + last_epoch=args.restore_step - 1) + else: + scheduler_gen, scheduler_disc = None, None + + num_params = count_parameters(model_gen) + print(" > Generator has {} parameters".format(num_params), flush=True) + num_params = count_parameters(model_disc) + print(" > Discriminator has {} parameters".format(num_params), flush=True) + + if 'best_loss' not in locals(): + best_loss = float('inf') + + global_step = args.restore_step + for epoch in range(0, c.epochs): + c_logger.print_epoch_start(epoch, c.epochs) + _, global_step = train(model_gen, criterion_gen, optimizer_gen, + model_disc, criterion_disc, optimizer_disc, + scheduler_gen, scheduler_disc, ap, global_step, + epoch) + eval_avg_loss_dict = evaluate(model_gen, criterion_gen, model_disc, ap, + global_step, epoch) + c_logger.print_epoch_end(epoch, eval_avg_loss_dict) + target_loss = eval_avg_loss_dict[c.target_loss] + best_loss = save_best_model(target_loss, + best_loss, + model_gen, + optimizer_gen, + model_disc, + optimizer_disc, + global_step, + epoch, + OUT_PATH, + model_losses=eval_avg_loss_dict) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument( + '--continue_path', + type=str, + help= + 'Training output folder to continue training. Use to continue a training. If it is used, "config_path" is ignored.', + default='', + required='--config_path' not in sys.argv) + parser.add_argument( + '--restore_path', + type=str, + help='Model file to be restored. Use to finetune a model.', + default='') + parser.add_argument('--config_path', + type=str, + help='Path to config file for training.', + required='--continue_path' not in sys.argv) + parser.add_argument('--debug', + type=bool, + default=False, + help='Do not verify commit integrity to run training.') + + # DISTRUBUTED + parser.add_argument( + '--rank', + type=int, + default=0, + help='DISTRIBUTED: process rank for distributed training.') + parser.add_argument('--group_id', + type=str, + default="", + help='DISTRIBUTED: process group id.') + args = parser.parse_args() + + if args.continue_path != '': + args.output_path = args.continue_path + args.config_path = os.path.join(args.continue_path, 'config.json') + list_of_files = glob.glob( + args.continue_path + + "/*.pth.tar") # * means all if need specific format then *.csv + latest_model_file = max(list_of_files, key=os.path.getctime) + args.restore_path = latest_model_file + print(f" > Training continues for {args.restore_path}") + + # setup output paths and read configs + c = load_config(args.config_path) + check_config(c) + _ = os.path.dirname(os.path.realpath(__file__)) + + OUT_PATH = args.continue_path + if args.continue_path == '': + OUT_PATH = create_experiment_folder(c.output_path, c.run_name, + args.debug) + + AUDIO_PATH = os.path.join(OUT_PATH, 'test_audios') + + c_logger = ConsoleLogger() + + if args.rank == 0: + os.makedirs(AUDIO_PATH, exist_ok=True) + new_fields = {} + if args.restore_path: + new_fields["restore_path"] = args.restore_path + new_fields["github_branch"] = get_git_branch() + copy_config_file(args.config_path, + os.path.join(OUT_PATH, 'config.json'), new_fields) + os.chmod(AUDIO_PATH, 0o775) + os.chmod(OUT_PATH, 0o775) + + LOG_DIR = OUT_PATH + tb_logger = TensorboardLogger(LOG_DIR, model_name='VOCODER') + + # write model desc to tensorboard + tb_logger.tb_add_text('model-description', c['run_description'], 0) + + try: + main(args) + except KeyboardInterrupt: + remove_experiment_folder(OUT_PATH) + try: + sys.exit(0) + except SystemExit: + os._exit(0) # pylint: disable=protected-access + except Exception: # pylint: disable=broad-except + remove_experiment_folder(OUT_PATH) + traceback.print_exc() + sys.exit(1) diff --git a/vocoder/utils/__init__.py b/vocoder/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py new file mode 100644 index 00000000..4fe132bb --- /dev/null +++ b/vocoder/utils/console_logger.py @@ -0,0 +1,97 @@ +import datetime +from TTS.utils.io import AttrDict + + +tcolors = AttrDict({ + 'OKBLUE': '\033[94m', + 'HEADER': '\033[95m', + 'OKGREEN': '\033[92m', + 'WARNING': '\033[93m', + 'FAIL': '\033[91m', + 'ENDC': '\033[0m', + 'BOLD': '\033[1m', + 'UNDERLINE': '\033[4m' +}) + + +class ConsoleLogger(): + def __init__(self): + # TODO: color code for value changes + # use these to compare values between iterations + self.old_train_loss_dict = None + self.old_epoch_loss_dict = None + self.old_eval_loss_dict = None + + # pylint: disable=no-self-use + def get_time(self): + now = datetime.datetime.now() + return now.strftime("%Y-%m-%d %H:%M:%S") + + def print_epoch_start(self, epoch, max_epoch): + print("\n{}{} > EPOCH: {}/{}{}".format(tcolors.UNDERLINE, tcolors.BOLD, + epoch, max_epoch, tcolors.ENDC), + flush=True) + + def print_train_start(self): + print(f"\n{tcolors.BOLD} > TRAINING ({self.get_time()}) {tcolors.ENDC}") + + def print_train_step(self, batch_steps, step, global_step, + step_time, loader_time, lr, + loss_dict, avg_loss_dict): + indent = " | > " + print() + log_text = "{} --> STEP: {}/{} -- GLOBAL_STEP: {}{}\n".format( + tcolors.BOLD, step, batch_steps, global_step, tcolors.ENDC) + for key, value in loss_dict.items(): + # print the avg value if given + if f'avg_{key}' in avg_loss_dict.keys(): + log_text += "{}{}: {:.5f} ({:.5f})\n".format(indent, key, value, avg_loss_dict[f'avg_{key}']) + else: + log_text += "{}{}: {:.5f} \n".format(indent, key, value) + log_text += f"{indent}step_time: {step_time:.2f}\n{indent}loader_time: {loader_time:.2f}\n{indent}lr: {lr:.5f}" + print(log_text, flush=True) + + # pylint: disable=unused-argument + def print_train_epoch_end(self, global_step, epoch, epoch_time, + print_dict): + indent = " | > " + log_text = f"\n{tcolors.BOLD} --> TRAIN PERFORMACE -- EPOCH TIME: {epoch} sec -- GLOBAL_STEP: {global_step}{tcolors.ENDC}\n" + for key, value in print_dict.items(): + log_text += "{}{}: {:.5f}\n".format(indent, key, value) + print(log_text, flush=True) + + def print_eval_start(self): + print(f"{tcolors.BOLD} > EVALUATION {tcolors.ENDC}\n") + + def print_eval_step(self, step, loss_dict, avg_loss_dict): + indent = " | > " + print() + log_text = f"{tcolors.BOLD} --> STEP: {step}{tcolors.ENDC}\n" + for key, value in loss_dict.items(): + # print the avg value if given + if f'avg_{key}' in avg_loss_dict.keys(): + log_text += "{}{}: {:.5f} ({:.5f})\n".format(indent, key, value, avg_loss_dict[f'avg_{key}']) + else: + log_text += "{}{}: {:.5f} \n".format(indent, key, value) + print(log_text, flush=True) + + def print_epoch_end(self, epoch, avg_loss_dict): + indent = " | > " + log_text = " {}--> EVAL PERFORMANCE{}\n".format( + tcolors.BOLD, tcolors.ENDC) + for key, value in avg_loss_dict.items(): + # print the avg value if given + color = '' + sign = '+' + diff = 0 + if self.old_eval_loss_dict is not None: + diff = value - self.old_eval_loss_dict[key] + if diff < 0: + color = tcolors.OKGREEN + sign = '' + elif diff > 0: + color = tcolors.FAIL + sing = '+' + log_text += "{}{}:{} {:.5f} {}({}{:.5f})\n".format(indent, key, color, value, tcolors.ENDC, sign, diff) + self.old_eval_loss_dict = avg_loss_dict + print(log_text, flush=True) diff --git a/vocoder/utils/generic_utils.py b/vocoder/utils/generic_utils.py new file mode 100644 index 00000000..062de160 --- /dev/null +++ b/vocoder/utils/generic_utils.py @@ -0,0 +1,102 @@ +import re +import importlib +import numpy as np +from matplotlib import pyplot as plt + +from TTS.utils.visual import plot_spectrogram + + +def plot_results(y_hat, y, ap, global_step, name_prefix): + """ Plot vocoder model results """ + + # select an instance from batch + y_hat = y_hat[0].squeeze(0).detach().cpu().numpy() + y = y[0].squeeze(0).detach().cpu().numpy() + + spec_fake = ap.spectrogram(y_hat).T + spec_real = ap.spectrogram(y).T + spec_diff = np.abs(spec_fake - spec_real) + + # plot figure and save it + fig_wave = plt.figure() + plt.subplot(2, 1, 1) + plt.plot(y) + plt.title("groundtruth speech") + plt.subplot(2, 1, 2) + plt.plot(y_hat) + plt.title(f"generated speech @ {global_step} steps") + plt.tight_layout() + plt.close() + + figures = { + name_prefix + "/spectrogram/fake": plot_spectrogram(spec_fake, ap), + name_prefix + "spectrogram/real": plot_spectrogram(spec_real, ap), + name_prefix + "spectrogram/diff": plot_spectrogram(spec_diff, ap), + name_prefix + "speech_comparison": fig_wave, + } + return figures + + +def to_camel(text): + text = text.capitalize() + return re.sub(r'(?!^)_([a-zA-Z])', lambda m: m.group(1).upper(), text) + + +def setup_generator(c): + print(" > Generator Model: {}".format(c.generator_model)) + MyModel = importlib.import_module('TTS.vocoder.models.' + + c.generator_model.lower()) + MyModel = getattr(MyModel, to_camel(c.generator_model)) + if c.generator_model in 'melgan_generator': + model = MyModel( + in_channels=c.audio['num_mels'], + out_channels=1, + proj_kernel=7, + base_channels=512, + upsample_factors=c.generator_model_params['upsample_factors'], + res_kernel=3, + num_res_blocks=c.generator_model_params['num_res_blocks']) + if c.generator_model in 'melgan_fb_generator': + pass + if c.generator_model in 'multiband_melgan_generator': + model = MyModel( + in_channels=c.audio['num_mels'], + out_channels=4, + proj_kernel=7, + base_channels=384, + upsample_factors=c.generator_model_params['upsample_factors'], + res_kernel=3, + num_res_blocks=c.generator_model_params['num_res_blocks']) + return model + + +def setup_discriminator(c): + print(" > Discriminator Model: {}".format(c.discriminator_model)) + MyModel = importlib.import_module('TTS.vocoder.models.' + + c.discriminator_model.lower()) + MyModel = getattr(MyModel, to_camel(c.discriminator_model)) + if c.discriminator_model in 'random_window_discriminator': + model = MyModel( + cond_channels=c.audio['num_mels'], + hop_length=c.audio['hop_length'], + uncond_disc_donwsample_factors=c. + discriminator_model_params['uncond_disc_donwsample_factors'], + cond_disc_downsample_factors=c. + discriminator_model_params['cond_disc_downsample_factors'], + cond_disc_out_channels=c. + discriminator_model_params['cond_disc_out_channels'], + window_sizes=c.discriminator_model_params['window_sizes']) + if c.discriminator_model in 'melgan_multiscale_discriminator': + model = MyModel( + in_channels=1, + out_channels=1, + kernel_sizes=(5, 3), + base_channels=c.discriminator_model_params['base_channels'], + max_channels=c.discriminator_model_params['max_channels'], + downsample_factors=c. + discriminator_model_params['downsample_factors']) + return model + + +# def check_config(c): +# pass \ No newline at end of file diff --git a/vocoder/utils/io.py b/vocoder/utils/io.py new file mode 100644 index 00000000..9526b9db --- /dev/null +++ b/vocoder/utils/io.py @@ -0,0 +1,52 @@ +import os +import torch +import datetime + + +def save_model(model, optimizer, model_disc, optimizer_disc, current_step, + epoch, output_path, **kwargs): + model_state = model.state_dict() + model_disc_state = model_disc.state_dict() + optimizer_state = optimizer.state_dict() if optimizer is not None else None + optimizer_disc_state = optimizer_disc.state_dict( + ) if optimizer_disc is not None else None + state = { + 'model': model_state, + 'optimizer': optimizer_state, + 'model_disc': model_disc_state, + 'optimizer_disc': optimizer_disc_state, + 'step': current_step, + 'epoch': epoch, + 'date': datetime.date.today().strftime("%B %d, %Y"), + } + state.update(kwargs) + torch.save(state, output_path) + + +def save_checkpoint(model, optimizer, model_disc, optimizer_disc, current_step, + epoch, output_folder, **kwargs): + file_name = 'checkpoint_{}.pth.tar'.format(current_step) + checkpoint_path = os.path.join(output_folder, file_name) + print(" > CHECKPOINT : {}".format(checkpoint_path)) + save_model(model, optimizer, model_disc, optimizer_disc, current_step, + epoch, checkpoint_path, **kwargs) + + +def save_best_model(target_loss, best_loss, model, optimizer, model_disc, + optimizer_disc, current_step, epoch, output_folder, + **kwargs): + if target_loss < best_loss: + file_name = 'best_model.pth.tar' + checkpoint_path = os.path.join(output_folder, file_name) + print(" > BEST MODEL : {}".format(checkpoint_path)) + save_model(model, + optimizer, + model_disc, + optimizer_disc, + current_step, + epoch, + checkpoint_path, + model_loss=target_loss, + **kwargs) + best_loss = target_loss + return best_loss \ No newline at end of file From a361df3186827d3e84bc30b8e6b41a31c11c50e8 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 03:31:42 +0200 Subject: [PATCH 093/185] plot fix --- vocoder/configs/melgan_config.json | 7 +++---- vocoder/train.py | 4 ++-- vocoder/utils/generic_utils.py | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index 9a3ded37..7da42f75 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -109,14 +109,13 @@ "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. // OPTIMIZER - "noam_schedule": true, // use noam warmup and lr schedule. - "grad_clip": 1.0, // upper limit for gradients for clipping. + "noam_schedule": false, // use noam warmup and lr schedule. + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, "epochs": 1000, // total number of epochs to train. "wd": 0.000001, // Weight decay weight. "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. "lr_disc": 0.0001, - "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "warmup_steps_disc": 4000, "gen_clip_grad": 10.0, "disc_clip_grad": 10.0, diff --git a/vocoder/train.py b/vocoder/train.py index b0b4833a..0d039e73 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -372,11 +372,11 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) # compute spectrograms - figures = plot_results(y_hat, y_G, ap, global_step, 'eval') + figures = plot_results(in_fake_D, in_real_D, ap, global_step, 'eval') tb_logger.tb_eval_figures(global_step, figures) # Sample audio - sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() + sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_eval_audios(global_step, {'eval/audio': sample_voice}, c.audio["sample_rate"]) diff --git a/vocoder/utils/generic_utils.py b/vocoder/utils/generic_utils.py index 062de160..179c4064 100644 --- a/vocoder/utils/generic_utils.py +++ b/vocoder/utils/generic_utils.py @@ -13,8 +13,8 @@ def plot_results(y_hat, y, ap, global_step, name_prefix): y_hat = y_hat[0].squeeze(0).detach().cpu().numpy() y = y[0].squeeze(0).detach().cpu().numpy() - spec_fake = ap.spectrogram(y_hat).T - spec_real = ap.spectrogram(y).T + spec_fake = ap.melspectrogram(y_hat).T + spec_real = ap.melspectrogram(y).T spec_diff = np.abs(spec_fake - spec_real) # plot figure and save it @@ -98,5 +98,5 @@ def setup_discriminator(c): return model -# def check_config(c): -# pass \ No newline at end of file +def check_config(c): + pass \ No newline at end of file From f675fca345a48d20ea2a6fc80488652488fc847e Mon Sep 17 00:00:00 2001 From: ForceCore Date: Sun, 31 May 2020 19:51:16 +0900 Subject: [PATCH 094/185] Fix phoneme cache file name aliasing problem When the wav file has multiple dots in the file name, _load_or_generate_phoneme_sequence would only use only the first segment of the file name and cause overwrite of *_phoneme.npy --- datasets/TTSDataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datasets/TTSDataset.py b/datasets/TTSDataset.py index 0d884c00..7fe966d7 100644 --- a/datasets/TTSDataset.py +++ b/datasets/TTSDataset.py @@ -92,7 +92,7 @@ class MyDataset(Dataset): return phonemes def _load_or_generate_phoneme_sequence(self, wav_file, text): - file_name = os.path.basename(wav_file).split('.')[0] + file_name = os.path.splitext(os.path.basename(wav_file))[0] cache_path = os.path.join(self.phoneme_cache_path, file_name + '_phoneme.npy') try: From 1a49ce895652ef9815e45b584f2c4c1ead5d1b09 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 14:18:29 +0200 Subject: [PATCH 095/185] bug fix --- vocoder/train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 0d039e73..a30e3bff 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -137,7 +137,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if global_step > c.steps_to_start_discriminator: # run D with or without cond. features - if len(signature(model_D).parameters) == 2: + if len(signature(model_D.forward).parameters) == 2: D_out_fake = model_D(in_fake_D, c_G) else: D_out_fake = model_D(in_fake_D) @@ -195,7 +195,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, optimizer_D.zero_grad() # run D with or without cond. features - if len(signature(model_D).parameters) == 2: + if len(signature(model_D.forward).parameters) == 2: D_out_fake = model_D(y_hat.detach(), c_D) D_out_real = model_D(y_D, c_D) else: From 604453bcb770149a54a0deabcc00baa888a5dd02 Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 18:56:57 +0200 Subject: [PATCH 096/185] add multiband melgan config and rename loss weights for vocoder --- vocoder/configs/melgan_config.json | 8 ++++---- vocoder/layers/losses.py | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index 7da42f75..b97206fa 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -53,10 +53,10 @@ "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators - "stft_loss_alpha": 1, - "mse_gan_loss_alpha": 1, - "hinge_gan_loss_alpha": 1, - "feat_match_loss_alpha": 10.0, + "stft_loss_weight": 1, + "mse_gan_loss_weight": 2.5, + "hinge_gan_loss_weight": 2.5, + "feat_match_loss_weight": 10.0, "stft_loss_params": { "n_ffts": [1024, 2048, 512], diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 11985629..27091c0a 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -149,10 +149,10 @@ class GeneratorLoss(nn.Module): self.use_hinge_gan_loss = C.use_hinge_gan_loss self.use_feat_match_loss = C.use_feat_match_loss - self.stft_loss_alpha = C.stft_loss_alpha - self.mse_gan_loss_alpha = C.mse_gan_loss_alpha - self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha - self.feat_match_loss_alpha = C.feat_match_loss_alpha + self.stft_loss_weight = C.stft_loss_weight + self.mse_gan_loss_weight = C.mse_gan_loss_weight + self.hinge_gan_loss_weight = C.hinge_gan_loss_weight + self.feat_match_loss_weight = C.feat_match_loss_weight if C.use_stft_loss: self.stft_loss = MultiScaleSTFTLoss(**C.stft_loss_params) @@ -172,7 +172,7 @@ class GeneratorLoss(nn.Module): stft_loss_mg, stft_loss_sc = self.stft_loss(y_hat.squeeze(1), y.squeeze(1)) return_dict['G_stft_loss_mg'] = stft_loss_mg return_dict['G_stft_loss_sc'] = stft_loss_sc - loss += self.stft_loss_alpha * (stft_loss_mg + stft_loss_sc) + loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) # Fake Losses if self.use_mse_gan_loss and scores_fake is not None: @@ -185,7 +185,7 @@ class GeneratorLoss(nn.Module): fake_loss = self.mse_loss(scores_fake) mse_fake_loss = fake_loss return_dict['G_mse_fake_loss'] = mse_fake_loss - loss += self.mse_gan_loss_alpha * mse_fake_loss + loss += self.mse_gan_loss_weight * mse_fake_loss if self.use_hinge_gan_loss and not scores_fake is not None: hinge_fake_loss = 0 @@ -197,13 +197,13 @@ class GeneratorLoss(nn.Module): fake_loss = self.hinge_loss(scores_fake) hinge_fake_loss = fake_loss return_dict['G_hinge_fake_loss'] = hinge_fake_loss - loss += self.hinge_gan_loss_alpha * hinge_fake_loss + loss += self.hinge_gan_loss_weight * hinge_fake_loss # Feature Matching Loss if self.use_feat_match_loss and not feats_fake: feat_match_loss = self.feat_match_loss(feats_fake, feats_real) return_dict['G_feat_match_loss'] = feat_match_loss - loss += self.feat_match_loss_alpha * feat_match_loss + loss += self.feat_match_loss_weight * feat_match_loss return_dict['G_loss'] = loss return return_dict @@ -217,8 +217,8 @@ class DiscriminatorLoss(nn.Module): self.use_mse_gan_loss = C.use_mse_gan_loss self.use_hinge_gan_loss = C.use_hinge_gan_loss - self.mse_gan_loss_alpha = C.mse_gan_loss_alpha - self.hinge_gan_loss_alpha = C.hinge_gan_loss_alpha + self.mse_gan_loss_weight = C.mse_gan_loss_weight + self.hinge_gan_loss_weight = C.hinge_gan_loss_weight if C.use_mse_gan_loss: self.mse_loss = MSEDLoss() @@ -247,7 +247,7 @@ class DiscriminatorLoss(nn.Module): return_dict['D_mse_gan_loss'] = mse_gan_loss return_dict['D_mse_gan_real_loss'] = mse_gan_real_loss return_dict['D_mse_gan_fake_loss'] = mse_gan_fake_loss - loss += self.mse_gan_loss_alpha * mse_gan_loss + loss += self.mse_gan_loss_weight * mse_gan_loss if self.use_hinge_gan_loss: hinge_gan_loss = 0 @@ -267,7 +267,7 @@ class DiscriminatorLoss(nn.Module): return_dict['D_hinge_gan_loss'] = hinge_gan_loss return_dict['D_hinge_gan_real_loss'] = hinge_gan_real_loss return_dict['D_hinge_gan_fake_loss'] = hinge_gan_fake_loss - loss += self.hinge_gan_loss_alpha * hinge_gan_loss + loss += self.hinge_gan_loss_weight * hinge_gan_loss return_dict['D_loss'] = loss return return_dict \ No newline at end of file From 78cb7478d15108a004384f849ac17d494673a0bf Mon Sep 17 00:00:00 2001 From: erogol Date: Sun, 31 May 2020 19:03:07 +0200 Subject: [PATCH 097/185] multiband rwd D config --- .../multiband-melgan_and_rwd_config.json | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 vocoder/configs/multiband-melgan_and_rwd_config.json diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json new file mode 100644 index 00000000..9aeb7933 --- /dev/null +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -0,0 +1,136 @@ +{ + "run_name": "multiband-melgan-rwd", + "run_description": "multibadn melgan with random window discriminator", + + // AUDIO PARAMETERS + "audio":{ + // stft parameters + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "win_length": 1024, // stft window length in ms. + "hop_length": 256, // stft window hop-lengh in ms. + "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. + "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. + + // Audio processing parameters + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + + // Silence trimming + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "trim_db": 60, // threshold for timming silence. Set this according to your dataset. + + // Griffin-Lim + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + + // MelSpectrogram parameters + "num_mels": 80, // size of the mel spec frame. + "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + + // Normalization parameters + "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. + "min_level_db": -100, // lower bound for normalization + "symmetric_norm": true, // move normalization to range [-1, 1] + "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "clip_norm": true, // clip normalized values into the range. + "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + }, + + // DISTRIBUTED TRAINING + // "distributed":{ + // "backend": "nccl", + // "url": "tcp:\/\/localhost:54321" + // }, + + // MODEL PARAMETERS + "use_pqmf": true, + + // LOSS PARAMETERS + "use_stft_loss": true, + "use_mse_gan_loss": true, + "use_hinge_gan_loss": false, + "use_feat_match_loss": false, // use only with melgan discriminators + + "stft_loss_weight": 1, + "mse_gan_loss_weight": 2.5, + "hinge_gan_loss_weight": 1, + "feat_match_loss_weight": 10.0, + + "stft_loss_params": { + "n_ffts": [1024, 2048, 512], + "hop_lengths": [120, 240, 50], + "win_lengths": [600, 1200, 240] + }, + "target_loss": "avg_G_loss", // loss value to pick the best model + + // DISCRIMINATOR + // "discriminator_model": "melgan_multiscale_discriminator", + // "discriminator_model_params":{ + // "base_channels": 16, + // "max_channels":1024, + // "downsample_factors":[4, 4, 4, 4] + // }, + "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 + + "discriminator_model": "random_window_discriminator", + "discriminator_model_params":{ + "uncond_disc_donwsample_factors": [8, 4], + "cond_disc_downsample_factors": [[8, 4, 2, 2, 2], [8, 4, 2, 2], [8, 4, 2], [8, 4], [4, 2, 2]], + "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], + "window_sizes": [512, 1024, 2048, 4096, 8192] + }, + + // GENERATOR + "generator_model": "multiband_melgan_generator", + "generator_model_params": { + "upsample_factors":[2 ,2, 4, 4], + "num_res_blocks": 4 + }, + + // DATASET + "data_path": "/root/LJSpeech-1.1/wavs/", + "seq_len": 16384, + "pad_short": 2000, + "conv_pad": 0, + "use_noise_augment": true, + "use_cache": true, + + "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. + + // TRAINING + "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. + + // VALIDATION + "run_eval": true, + "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. + "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. + + // OPTIMIZER + "noam_schedule": false, // use noam warmup and lr schedule. + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, + "epochs": 1000, // total number of epochs to train. + "wd": 0.000001, // Weight decay weight. + "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 0.0001, + "gen_clip_grad": 10.0, + "disc_clip_grad": 10.0, + + // TENSORBOARD and LOGGING + "print_step": 25, // Number of steps to log traning on console. + "print_eval": false, // If True, it prints intermediate loss values in evalulation. + "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. + "checkpoint": true, // If true, it saves checkpoints per "save_step" + "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. + + // DATA LOADING + "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. + "num_val_loader_workers": 4, // number of evaluation data loader processes. + "eval_split_size": 10, + + // PATHS + "output_path": "/home/erogol/Models/LJSpeech/" +} + From d425daad5b383007b3e9d40bf591ebe2f75ea008 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 1 Jun 2020 03:02:51 +0200 Subject: [PATCH 098/185] tb eval print --- vocoder/train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vocoder/train.py b/vocoder/train.py index a30e3bff..27e14e8a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -383,6 +383,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # synthesize a full voice data_loader.return_segments = False + tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) return keep_avg.avg_values From 3dff81e7e228e1d20e6ed8669c4eb5bbcea26709 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 17:07:15 +0200 Subject: [PATCH 099/185] multiscale subband stft loss and missing tb_logger for eval stats --- vocoder/configs/melgan_config.json | 8 +++++ vocoder/layers/losses.py | 21 ++++++++++-- vocoder/train.py | 53 ++++++++++++++---------------- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index b97206fa..4aeba82e 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -49,11 +49,13 @@ // LOSS PARAMETERS "use_stft_loss": true, + "use_subband_stft_loss": true, "use_mse_gan_loss": true, "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators "stft_loss_weight": 1, + "subband_stft_loss_weight": 1, "mse_gan_loss_weight": 2.5, "hinge_gan_loss_weight": 2.5, "feat_match_loss_weight": 10.0, @@ -63,6 +65,12 @@ "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240] }, + "subband_stft_loss_params":{ + "n_ffts": [384, 683, 171], + "hop_lengths": [30, 60, 10], + "win_lengths": [150, 300, 60] + }, + "target_loss": "avg_G_loss", // loss value to pick the best model // DISCRIMINATOR diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 27091c0a..e242d209 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -49,7 +49,6 @@ class STFTLoss(nn.Module): loss_sc = torch.norm(y_M - y_hat_M, p="fro") / torch.norm(y_M, p="fro") return loss_mag, loss_sc - class MultiScaleSTFTLoss(torch.nn.Module): def __init__(self, n_ffts=[1024, 2048, 512], @@ -73,6 +72,13 @@ class MultiScaleSTFTLoss(torch.nn.Module): return loss_mag, loss_sc +class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): + def forward(self, y_hat, y): + y_hat = y_hat.view(-1, 1, y_hat.shape[2]) + y = y.view(-1, 1, y.shape[2]) + return super().forward(y_hat.squeeze(1), y.squeeze(1)) + + class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ def __init__(self,): @@ -145,17 +151,21 @@ class GeneratorLoss(nn.Module): " [!] Cannot use HingeGANLoss and MSEGANLoss together." self.use_stft_loss = C.use_stft_loss + self.use_subband_stft_loss = C.use_subband_stft_loss self.use_mse_gan_loss = C.use_mse_gan_loss self.use_hinge_gan_loss = C.use_hinge_gan_loss self.use_feat_match_loss = C.use_feat_match_loss self.stft_loss_weight = C.stft_loss_weight + self.subband_stft_loss_weight = C.subband_stft_loss_weight self.mse_gan_loss_weight = C.mse_gan_loss_weight self.hinge_gan_loss_weight = C.hinge_gan_loss_weight self.feat_match_loss_weight = C.feat_match_loss_weight if C.use_stft_loss: self.stft_loss = MultiScaleSTFTLoss(**C.stft_loss_params) + if C.use_subband_stft_loss: + self.subband_stft_loss = MultiScaleSubbandSTFTLoss(**C.subband_stft_loss_params) if C.use_mse_gan_loss: self.mse_loss = MSEGLoss() if C.use_hinge_gan_loss: @@ -163,7 +173,7 @@ class GeneratorLoss(nn.Module): if C.use_feat_match_loss: self.feat_match_loss = MelganFeatureLoss() - def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None): + def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None, y_hat_sub=None, y_sub=None): loss = 0 return_dict = {} @@ -174,6 +184,13 @@ class GeneratorLoss(nn.Module): return_dict['G_stft_loss_sc'] = stft_loss_sc loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) + # subband STFT Loss + if self.use_subband_stft_loss: + subband_stft_loss_mg, subband_stft_loss_sc = self.subband_stft_loss(y_hat_sub, y_sub) + return_dict['G_subband_stft_loss_mg'] = subband_stft_loss_mg + return_dict['G_subband_stft_loss_sc'] = subband_stft_loss_sc + loss += self.subband_stft_loss_weight * (subband_stft_loss_mg + subband_stft_loss_sc) + # Fake Losses if self.use_mse_gan_loss and scores_fake is not None: mse_fake_loss = 0 diff --git a/vocoder/train.py b/vocoder/train.py index 27e14e8a..6341bb6c 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -122,30 +122,27 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # generator pass optimizer_G.zero_grad() y_hat = model_G(c_G) - - in_real_D = y_hat - in_fake_D = y_G + y_hat_sub = None + y_G_sub = None # PQMF formatting if y_hat.shape[1] > 1: - in_real_D = y_G - in_fake_D = model_G.pqmf_synthesis(y_hat) - y_G = model_G.pqmf_analysis(y_G) - y_hat = y_hat.view(-1, 1, y_hat.shape[2]) - y_G = y_G.view(-1, 1, y_G.shape[2]) + y_hat_sub = y_hat + y_hat = model_G.pqmf_synthesis(y_hat) + y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: # run D with or without cond. features if len(signature(model_D.forward).parameters) == 2: - D_out_fake = model_D(in_fake_D, c_G) + D_out_fake = model_D(y_hat, c_G) else: - D_out_fake = model_D(in_fake_D) + D_out_fake = model_D(y_hat) D_out_real = None if c.use_feat_match_loss: with torch.no_grad(): - D_out_real = model_D(in_real_D) + D_out_real = model_D(y_G) # format D outputs if isinstance(D_out_fake, tuple): @@ -162,7 +159,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # compute losses loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, - feats_real) + feats_real, y_hat_sub, y_G_sub) loss_G = loss_G_dict['G_loss'] # optimizer generator @@ -272,12 +269,12 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, model_losses=loss_dict) # compute spectrograms - figures = plot_results(in_fake_D, in_real_D, ap, global_step, + figures = plot_results(y_hat, y_G, ap, global_step, 'train') tb_logger.tb_train_figures(global_step, figures) # Sample audio - sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() + sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_train_audios(global_step, {'train/audio': sample_voice}, c.audio["sample_rate"]) @@ -320,23 +317,20 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # generator pass y_hat = model_G(c_G) - - in_real_D = y_hat - in_fake_D = y_G + y_hat_sub = None + y_G_sub = None # PQMF formatting if y_hat.shape[1] > 1: - in_real_D = y_G - in_fake_D = model_G.pqmf_synthesis(y_hat) - y_G = model_G.pqmf_analysis(y_G) - y_hat = y_hat.view(-1, 1, y_hat.shape[2]) - y_G = y_G.view(-1, 1, y_G.shape[2]) + y_hat_sub = y_hat + y_hat = model_G.pqmf_synthesis(y_hat) + y_G_sub = model_G.pqmf_analysis(y_G) - D_out_fake = model_D(in_fake_D) + D_out_fake = model_D(y_hat) D_out_real = None if c.use_feat_match_loss: with torch.no_grad(): - D_out_real = model_D(in_real_D) + D_out_real = model_D(y_G) # format D outputs if isinstance(D_out_fake, tuple): @@ -350,7 +344,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # compute losses loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, - feats_real) + feats_real, y_hat_sub, y_G_sub) loss_dict = dict() for key, value in loss_G_dict.items(): @@ -364,7 +358,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): for key, value in loss_G_dict.items(): update_eval_values['avg_' + key] = value.item() update_eval_values['avg_loader_time'] = loader_time - update_eval_values['avg_step_time'] = step_time + update_eval_values['avgP_step_time'] = step_time keep_avg.update_values(update_eval_values) # print eval stats @@ -372,18 +366,19 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) # compute spectrograms - figures = plot_results(in_fake_D, in_real_D, ap, global_step, 'eval') + figures = plot_results(y_hat, y_G, ap, global_step, 'eval') tb_logger.tb_eval_figures(global_step, figures) # Sample audio - sample_voice = in_fake_D[0].squeeze(0).detach().cpu().numpy() + sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_eval_audios(global_step, {'eval/audio': sample_voice}, c.audio["sample_rate"]) # synthesize a full voice data_loader.return_segments = False - tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) + tb_logger.tb_evals_stats(global_step, keep_avg.avg_values) + return keep_avg.avg_values From 3a2e501b7a4d8f04d7d13474a8c153f16a8165dc Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 17:09:05 +0200 Subject: [PATCH 100/185] bug fix --- vocoder/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index 6341bb6c..398051a9 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -377,7 +377,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): # synthesize a full voice data_loader.return_segments = False - tb_logger.tb_evals_stats(global_step, keep_avg.avg_values) + tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) return keep_avg.avg_values From b7b0c58e3f0c6c6ad1c815044f6d32aee4908956 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 17:28:52 +0200 Subject: [PATCH 101/185] update travis script --- .travis/script | 4 +++- requirements_tests.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis/script b/.travis/script index ca6f4cd3..278ba4f2 100755 --- a/.travis/script +++ b/.travis/script @@ -12,7 +12,9 @@ fi if [[ "$TEST_SUITE" == "unittest" ]]; then # Run tests on all pushes pushd tts_namespace - python -m unittest + nosetests speaker_encoder.tests --nocapture + nosetests vocoder.tests --nocapture + nosetests tests --nocapture popd # Test server package ./tests/test_server_package.sh diff --git a/requirements_tests.txt b/requirements_tests.txt index 5aacdb56..36243398 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -14,3 +14,4 @@ tqdm soundfile phonemizer bokeh==1.4.0 +nose From 502ba2d5c4ea5b80e91c6dffc16a5a57d9070528 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 18:54:03 +0200 Subject: [PATCH 102/185] cardboard config update --- .cardboardlint.yml | 3 +++ .pylintrc | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.cardboardlint.yml b/.cardboardlint.yml index 464ea733..4a115a37 100644 --- a/.cardboardlint.yml +++ b/.cardboardlint.yml @@ -1,2 +1,5 @@ linters: - pylint: + # pylintrc: pylintrc + filefilter: ['- test_*.py', '+ *.py', '- *.npy'] + # exclude: \ No newline at end of file diff --git a/.pylintrc b/.pylintrc index b6e04944..a78b521e 100644 --- a/.pylintrc +++ b/.pylintrc @@ -157,7 +157,8 @@ disable=missing-docstring, xreadlines-attribute, deprecated-sys-function, exception-escape, - comprehension-escape + comprehension-escape, + duplicate-code # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option From 58117c0c6e3d38c9ccf4c2e193a8afd299aa799d Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 18:54:29 +0200 Subject: [PATCH 103/185] travis script for nose --- .travis/script | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis/script b/.travis/script index 278ba4f2..ce886fc2 100755 --- a/.travis/script +++ b/.travis/script @@ -12,9 +12,9 @@ fi if [[ "$TEST_SUITE" == "unittest" ]]; then # Run tests on all pushes pushd tts_namespace - nosetests speaker_encoder.tests --nocapture - nosetests vocoder.tests --nocapture - nosetests tests --nocapture + nosetests TTS.speaker_encoder.tests --nocapture + nosetests TTS.vocoder.tests --nocapture + nosetests TTS.tests --nocapture popd # Test server package ./tests/test_server_package.sh From d6b9a5738af8c6dbe642b2464b4fec31c306aaa7 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 18:58:10 +0200 Subject: [PATCH 104/185] Ton of linter fixes --- train.py | 12 +-- utils/training.py | 11 +++ vocoder/datasets/gan_dataset.py | 34 ++----- vocoder/layers/losses.py | 35 ++----- vocoder/layers/melgan.py | 3 - vocoder/layers/pqmf.py | 3 + vocoder/layers/pqmf2.py | 127 ------------------------- vocoder/models/melgan_discriminator.py | 4 +- vocoder/models/melgan_generator.py | 2 - vocoder/tests/test_datasets.py | 22 ++--- vocoder/tests/test_losses.py | 3 +- vocoder/tests/test_melgan_generator.py | 1 - vocoder/tests/test_pqmf.py | 7 +- vocoder/train.py | 24 ++--- vocoder/utils/console_logger.py | 2 +- vocoder/utils/io.py | 1 - 16 files changed, 60 insertions(+), 231 deletions(-) delete mode 100644 vocoder/layers/pqmf2.py diff --git a/train.py b/train.py index 82f91cd5..5a345b59 100644 --- a/train.py +++ b/train.py @@ -20,7 +20,8 @@ from TTS.utils.generic_utils import (count_parameters, create_experiment_folder, from TTS.utils.io import (save_best_model, save_checkpoint, load_config, copy_config_file) from TTS.utils.training import (NoamLR, check_update, adam_weight_decay, - gradual_training_scheduler, set_weight_decay) + gradual_training_scheduler, set_weight_decay, + setup_torch_training_env) from TTS.utils.tensorboard_logger import TensorboardLogger from TTS.utils.console_logger import ConsoleLogger from TTS.utils.speakers import load_speaker_mapping, save_speaker_mapping, \ @@ -32,13 +33,8 @@ from TTS.datasets.preprocess import load_meta_data from TTS.utils.radam import RAdam from TTS.utils.measures import alignment_diagonal_score -torch.backends.cudnn.enabled = True -torch.backends.cudnn.benchmark = False -torch.manual_seed(54321) -use_cuda = torch.cuda.is_available() -num_gpus = torch.cuda.device_count() -print(" > Using CUDA: ", use_cuda) -print(" > Number of GPUs: ", num_gpus) + +use_cuda, num_gpus = setup_torch_training_env(True, False) def setup_loader(ap, r, is_val=False, verbose=False): diff --git a/utils/training.py b/utils/training.py index 5ce7948b..9046f9e0 100644 --- a/utils/training.py +++ b/utils/training.py @@ -2,6 +2,17 @@ import torch import numpy as np +def setup_torch_training_env(cudnn_enable, cudnn_benchmark): + torch.backends.cudnn.enabled = cudnn_enable + torch.backends.cudnn.benchmark = cudnn_benchmark + torch.manual_seed(54321) + use_cuda = torch.cuda.is_available() + num_gpus = torch.cuda.device_count() + print(" > Using CUDA: ", use_cuda) + print(" > Number of GPUs: ", num_gpus) + return use_cuda, num_gpus + + def check_update(model, grad_clip, ignore_stopnet=False): r'''Check model gradient against unexpected jumps and failures''' skip_flag = False diff --git a/vocoder/datasets/gan_dataset.py b/vocoder/datasets/gan_dataset.py index 10d36cab..5e410151 100644 --- a/vocoder/datasets/gan_dataset.py +++ b/vocoder/datasets/gan_dataset.py @@ -3,29 +3,10 @@ import glob import torch import random import numpy as np -from torch.utils.data import Dataset, DataLoader +from torch.utils.data import Dataset from multiprocessing import Manager -def create_dataloader(hp, args, train): - dataset = MelFromDisk(hp, args, train) - - if train: - return DataLoader(dataset=dataset, - batch_size=hp.train.batch_size, - shuffle=True, - num_workers=hp.train.num_workers, - pin_memory=True, - drop_last=True) - else: - return DataLoader(dataset=dataset, - batch_size=1, - shuffle=False, - num_workers=hp.train.num_workers, - pin_memory=True, - drop_last=False) - - class GANDataset(Dataset): """ GAN Dataset searchs for all the wav files under root path @@ -55,26 +36,26 @@ class GANDataset(Dataset): self.return_segments = return_segments self.use_cache = use_cache self.use_noise_augment = use_noise_augment + self.verbose = verbose assert seq_len % hop_len == 0, " [!] seq_len has to be a multiple of hop_len." self.feat_frame_len = seq_len // hop_len + (2 * conv_pad) # map G and D instances - self.G_to_D_mappings = [i for i in range(len(self.item_list))] + self.G_to_D_mappings = list(range(len(self.item_list))) self.shuffle_mapping() # cache acoustic features if use_cache: self.create_feature_cache() - - def create_feature_cache(self): self.manager = Manager() self.cache = self.manager.list() self.cache += [None for _ in range(len(self.item_list))] - def find_wav_files(self, path): + @staticmethod + def find_wav_files(path): return glob.glob(os.path.join(path, '**', '*.wav'), recursive=True) def __len__(self): @@ -88,9 +69,8 @@ class GANDataset(Dataset): item1 = self.load_item(idx) item2 = self.load_item(idx2) return item1, item2 - else: - item1 = self.load_item(idx) - return item1 + item1 = self.load_item(idx) + return item1 def shuffle_mapping(self): random.shuffle(self.G_to_D_mappings) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index e242d209..1c3d4442 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -51,13 +51,13 @@ class STFTLoss(nn.Module): class MultiScaleSTFTLoss(torch.nn.Module): def __init__(self, - n_ffts=[1024, 2048, 512], - hop_lengths=[120, 240, 50], - win_lengths=[600, 1200, 240]): + n_ffts=(1024, 2048, 512), + hop_lengths=(120, 240, 50), + win_lengths=(600, 1200, 240)): super(MultiScaleSTFTLoss, self).__init__() self.loss_funcs = torch.nn.ModuleList() - for idx in range(len(n_ffts)): - self.loss_funcs.append(STFTLoss(n_ffts[idx], hop_lengths[idx], win_lengths[idx])) + for n_fft, hop_length, win_length in zip(n_ffts, hop_lengths, win_lengths): + self.loss_funcs.append(STFTLoss(n_fft, hop_length, win_length)) def forward(self, y_hat, y): N = len(self.loss_funcs) @@ -81,20 +81,14 @@ class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ - def __init__(self,): - super(MSEGLoss, self).__init__() - - def forward(self, score_fake, ): + def forward(self, score_fake): loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) return loss_fake class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ - def __init__(self,): - super(HingeGLoss, self).__init__() - - def forward(self, score_fake, score_real): + def forward(self, score_fake): loss_fake = torch.mean(F.relu(1. + score_fake)) return loss_fake @@ -106,9 +100,6 @@ class HingeGLoss(nn.Module): class MSEDLoss(nn.Module): """ Mean Squared Discriminator Loss """ - def __init__(self,): - super(MSEDLoss, self).__init__() - def forward(self, score_fake, score_real): loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) @@ -118,9 +109,6 @@ class MSEDLoss(nn.Module): class HingeDLoss(nn.Module): """ Hinge Discriminator Loss """ - def __init__(self,): - super(HingeDLoss, self).__init__() - def forward(self, score_fake, score_real): loss_real = torch.mean(F.relu(1. - score_real)) loss_fake = torch.mean(F.relu(1. + score_fake)) @@ -129,13 +117,10 @@ class HingeDLoss(nn.Module): class MelganFeatureLoss(nn.Module): - def __init__(self, ): - super(MelganFeatureLoss, self).__init__() - def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): - loss_feats += hp.model.feat_match * torch.mean(torch.abs(fake_feat - real_feat)) + loss_feats += torch.mean(torch.abs(fake_feat - real_feat)) return loss_feats @@ -147,7 +132,7 @@ class MelganFeatureLoss(nn.Module): class GeneratorLoss(nn.Module): def __init__(self, C): super(GeneratorLoss, self).__init__() - assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ " [!] Cannot use HingeGANLoss and MSEGANLoss together." self.use_stft_loss = C.use_stft_loss @@ -228,7 +213,7 @@ class GeneratorLoss(nn.Module): class DiscriminatorLoss(nn.Module): def __init__(self, C): super(DiscriminatorLoss, self).__init__() - assert C.use_mse_gan_loss and C.use_hinge_gan_loss == False,\ + assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ " [!] Cannot use HingeGANLoss and MSEGANLoss together." self.use_mse_gan_loss = C.use_mse_gan_loss diff --git a/vocoder/layers/melgan.py b/vocoder/layers/melgan.py index cda0413c..61f7a96b 100644 --- a/vocoder/layers/melgan.py +++ b/vocoder/layers/melgan.py @@ -1,7 +1,4 @@ -import numpy as np -import torch from torch import nn -from torch.nn import functional as F from torch.nn.utils import weight_norm diff --git a/vocoder/layers/pqmf.py b/vocoder/layers/pqmf.py index f438ea00..3985aad4 100644 --- a/vocoder/layers/pqmf.py +++ b/vocoder/layers/pqmf.py @@ -44,6 +44,9 @@ class PQMF(torch.nn.Module): self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) + def forward(self, x): + return self.analysis(x) + def analysis(self, x): return F.conv1d(x, self.H, padding=self.taps // 2, stride=self.N) diff --git a/vocoder/layers/pqmf2.py b/vocoder/layers/pqmf2.py deleted file mode 100644 index 4cffb819..00000000 --- a/vocoder/layers/pqmf2.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2020 Tomoki Hayashi -# MIT License (https://opensource.org/licenses/MIT) - -"""Pseudo QMF modules.""" - -import numpy as np -import torch -import torch.nn.functional as F - -from scipy.signal import kaiser - - -def design_prototype_filter(taps=62, cutoff_ratio=0.15, beta=9.0): - """Design prototype filter for PQMF. - - This method is based on `A Kaiser window approach for the design of prototype - filters of cosine modulated filterbanks`_. - - Args: - taps (int): The number of filter taps. - cutoff_ratio (float): Cut-off frequency ratio. - beta (float): Beta coefficient for kaiser window. - - Returns: - ndarray: Impluse response of prototype filter (taps + 1,). - - .. _`A Kaiser window approach for the design of prototype filters of cosine modulated filterbanks`: - https://ieeexplore.ieee.org/abstract/document/681427 - - """ - # check the arguments are valid - assert taps % 2 == 0, "The number of taps mush be even number." - assert 0.0 < cutoff_ratio < 1.0, "Cutoff ratio must be > 0.0 and < 1.0." - - # make initial filter - omega_c = np.pi * cutoff_ratio - with np.errstate(invalid='ignore'): - h_i = np.sin(omega_c * (np.arange(taps + 1) - 0.5 * taps)) \ - / (np.pi * (np.arange(taps + 1) - 0.5 * taps)) - h_i[taps // 2] = np.cos(0) * cutoff_ratio # fix nan due to indeterminate form - - # apply kaiser window - w = kaiser(taps + 1, beta) - h = h_i * w - - return h - - -class PQMF(torch.nn.Module): - """PQMF module. - - This module is based on `Near-perfect-reconstruction pseudo-QMF banks`_. - - .. _`Near-perfect-reconstruction pseudo-QMF banks`: - https://ieeexplore.ieee.org/document/258122 - - """ - - def __init__(self, subbands=4, taps=62, cutoff_ratio=0.15, beta=9.0): - """Initilize PQMF module. - - Args: - subbands (int): The number of subbands. - taps (int): The number of filter taps. - cutoff_ratio (float): Cut-off frequency ratio. - beta (float): Beta coefficient for kaiser window. - - """ - super(PQMF, self).__init__() - - # define filter coefficient - h_proto = design_prototype_filter(taps, cutoff_ratio, beta) - h_analysis = np.zeros((subbands, len(h_proto))) - h_synthesis = np.zeros((subbands, len(h_proto))) - for k in range(subbands): - h_analysis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) + (-1) ** k * np.pi / 4) - h_synthesis[k] = 2 * h_proto * np.cos((2 * k + 1) * (np.pi / (2 * subbands)) * (np.arange(taps + 1) - ((taps - 1) / 2)) - (-1) ** k * np.pi / 4) - - # convert to tensor - analysis_filter = torch.from_numpy(h_analysis).float().unsqueeze(1) - synthesis_filter = torch.from_numpy(h_synthesis).float().unsqueeze(0) - - # register coefficients as beffer - self.register_buffer("analysis_filter", analysis_filter) - self.register_buffer("synthesis_filter", synthesis_filter) - - # filter for downsampling & upsampling - updown_filter = torch.zeros((subbands, subbands, subbands)).float() - for k in range(subbands): - updown_filter[k, k, 0] = 1.0 - self.register_buffer("updown_filter", updown_filter) - self.subbands = subbands - - # keep padding info - self.pad_fn = torch.nn.ConstantPad1d(taps // 2, 0.0) - - def analysis(self, x): - """Analysis with PQMF. - - Args: - x (Tensor): Input tensor (B, 1, T). - - Returns: - Tensor: Output tensor (B, subbands, T // subbands). - - """ - x = F.conv1d(self.pad_fn(x), self.analysis_filter) - return F.conv1d(x, self.updown_filter, stride=self.subbands) - - def synthesis(self, x): - """Synthesis with PQMF. - - Args: - x (Tensor): Input tensor (B, subbands, T // subbands). - - Returns: - Tensor: Output tensor (B, 1, T). - - """ - # NOTE(kan-bayashi): Power will be dreased so here multipy by # subbands. - # Not sure this is the correct way, it is better to check again. - # TODO(kan-bayashi): Understand the reconstruction procedure - x = F.conv_transpose1d(x, self.updown_filter * self.subbands, stride=self.subbands) - x = F.conv1d(self.pad_fn(x), self.synthesis_filter) - return x diff --git a/vocoder/models/melgan_discriminator.py b/vocoder/models/melgan_discriminator.py index 55d3f585..3847babb 100644 --- a/vocoder/models/melgan_discriminator.py +++ b/vocoder/models/melgan_discriminator.py @@ -1,7 +1,5 @@ import numpy as np -import torch from torch import nn -from torch.nn import functional as F from torch.nn.utils import weight_norm @@ -32,7 +30,7 @@ class MelganDiscriminator(nn.Module): # downsampling layers layer_in_channels = base_channels - for idx, downsample_factor in enumerate(downsample_factors): + for downsample_factor in downsample_factors: layer_out_channels = min(layer_in_channels * downsample_factor, max_channels) layer_kernel_size = downsample_factor * 10 + 1 diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py index 2d266f29..1e47816d 100644 --- a/vocoder/models/melgan_generator.py +++ b/vocoder/models/melgan_generator.py @@ -1,7 +1,5 @@ -import math import torch from torch import nn -from torch.nn import functional as F from torch.nn.utils import weight_norm from TTS.vocoder.layers.melgan import ResidualStack diff --git a/vocoder/tests/test_datasets.py b/vocoder/tests/test_datasets.py index 3d6280f0..5d409b3f 100644 --- a/vocoder/tests/test_datasets.py +++ b/vocoder/tests/test_datasets.py @@ -22,7 +22,7 @@ ok_ljspeech = os.path.exists(test_data_path) def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, use_noise_augment, use_cache, num_workers): ''' run dataloader with given parameters and check conditions ''' ap = AudioProcessor(**C.audio) - eval_items, train_items = load_wav_data(test_data_path, 10) + _, train_items = load_wav_data(test_data_path, 10) dataset = GANDataset(ap, train_items, seq_len=seq_len, @@ -44,9 +44,9 @@ def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, us # return random segments or return the whole audio if return_segments: - for item1, item2 in loader: + for item1, _ in loader: feat1, wav1 = item1 - feat2, wav2 = item2 + # feat2, wav2 = item2 expected_feat_shape = (batch_size, ap.num_mels, seq_len // hop_len + conv_pad * 2) # check shapes @@ -80,15 +80,15 @@ def gan_dataset_case(batch_size, seq_len, hop_len, conv_pad, return_segments, us def test_parametrized_gan_dataset(): ''' test dataloader with different parameters ''' params = [ - [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], - [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 4], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, True, 0], + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [32, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 4], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, True, 0], [1, C.audio['hop_length'], C.audio['hop_length'], 0, True, True, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 2, True, True, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, True, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, False, 0], - [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, False, False, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 2, True, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, True, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, False, True, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, True, True, False, 0], + [1, C.audio['hop_length'] * 10, C.audio['hop_length'], 0, False, False, False, 0], ] for param in params: print(param) diff --git a/vocoder/tests/test_losses.py b/vocoder/tests/test_losses.py index 83314832..44a1321d 100644 --- a/vocoder/tests/test_losses.py +++ b/vocoder/tests/test_losses.py @@ -1,5 +1,4 @@ import os -import unittest import torch from TTS.vocoder.layers.losses import TorchSTFT, STFTLoss, MultiScaleSTFTLoss @@ -24,7 +23,7 @@ def test_torch_stft(): torch_stft = TorchSTFT(ap.n_fft, ap.hop_length, ap.win_length) # librosa stft wav = ap.load_wav(WAV_FILE) - M_librosa = abs(ap._stft(wav)) + M_librosa = abs(ap._stft(wav)) # pylint: disable=protected-access # torch stft wav = torch.from_numpy(wav[None, :]).float() M_torch = torch_stft(wav) diff --git a/vocoder/tests/test_melgan_generator.py b/vocoder/tests/test_melgan_generator.py index e9c4ad60..e03da31b 100644 --- a/vocoder/tests/test_melgan_generator.py +++ b/vocoder/tests/test_melgan_generator.py @@ -1,5 +1,4 @@ import numpy as np -import unittest import torch from TTS.vocoder.models.melgan_generator import MelganGenerator diff --git a/vocoder/tests/test_pqmf.py b/vocoder/tests/test_pqmf.py index 8444fc5a..a26bdd59 100644 --- a/vocoder/tests/test_pqmf.py +++ b/vocoder/tests/test_pqmf.py @@ -1,16 +1,11 @@ import os import torch -import unittest -import numpy as np import soundfile as sf from librosa.core import load -from TTS.tests import get_tests_path, get_tests_input_path, get_tests_output_path -from TTS.utils.audio import AudioProcessor -from TTS.utils.io import load_config +from TTS.tests import get_tests_path, get_tests_input_path from TTS.vocoder.layers.pqmf import PQMF -from TTS.vocoder.layers.pqmf2 import PQMF as PQMF2 TESTS_PATH = get_tests_path() diff --git a/vocoder/train.py b/vocoder/train.py index 398051a9..d401e72e 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -17,7 +17,7 @@ from TTS.utils.generic_utils import (KeepAverage, count_parameters, from TTS.utils.io import copy_config_file, load_config from TTS.utils.radam import RAdam from TTS.utils.tensorboard_logger import TensorboardLogger -from TTS.utils.training import NoamLR +from TTS.utils.training import setup_torch_training_env, NoamLR from TTS.vocoder.datasets.gan_dataset import GANDataset from TTS.vocoder.datasets.preprocess import load_wav_data # from distribute import (DistributedSampler, apply_gradient_allreduce, @@ -29,13 +29,8 @@ from TTS.vocoder.utils.generic_utils import (check_config, plot_results, setup_discriminator, setup_generator) -torch.backends.cudnn.enabled = True -torch.backends.cudnn.benchmark = True -torch.manual_seed(54321) -use_cuda = torch.cuda.is_available() -num_gpus = torch.cuda.device_count() -print(" > Using CUDA: ", use_cuda) -print(" > Number of GPUs: ", num_gpus) + +use_cuda, num_gpus = setup_torch_training_env(True, True) def setup_loader(ap, is_val=False, verbose=False): @@ -49,10 +44,11 @@ def setup_loader(ap, is_val=False, verbose=False): pad_short=c.pad_short, conv_pad=c.conv_pad, is_training=not is_val, - return_segments=False if is_val else True, + return_segments=not is_val, use_noise_augment=c.use_noise_augment, use_cache=c.use_cache, verbose=verbose) + dataset.shuffle_mapping() # sampler = DistributedSampler(dataset) if num_gpus > 1 else None loader = DataLoader(dataset, batch_size=1 if is_val else c.batch_size, @@ -81,11 +77,11 @@ def format_data(data): return c_G, x_G, c_D, x_D # return a whole audio segment - c, x = data + co, x = data if use_cuda: - c = c.cuda(non_blocking=True) + co = co.cuda(non_blocking=True) x = x.cuda(non_blocking=True) - return c, x + return co, x, None, None def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, @@ -306,7 +302,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): start_time = time.time() # format data - c_G, y_G = format_data(data) + c_G, y_G, _, _ = format_data(data) loader_time = time.time() - end_time global_step += 1 @@ -416,7 +412,7 @@ def main(args): # pylint: disable=redefined-outer-name optimizer_gen.load_state_dict(checkpoint['optimizer']) model_disc.load_state_dict(checkpoint['model_disc']) optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) - except: + except KeyError: print(" > Partial model initialization.") model_dict = model_gen.state_dict() model_dict = set_init_dict(model_dict, checkpoint['model'], c) diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py index 4fe132bb..ff7edfd0 100644 --- a/vocoder/utils/console_logger.py +++ b/vocoder/utils/console_logger.py @@ -91,7 +91,7 @@ class ConsoleLogger(): sign = '' elif diff > 0: color = tcolors.FAIL - sing = '+' + sign = '+' log_text += "{}{}:{} {:.5f} {}({}{:.5f})\n".format(indent, key, color, value, tcolors.ENDC, sign, diff) self.old_eval_loss_dict = avg_loss_dict print(log_text, flush=True) diff --git a/vocoder/utils/io.py b/vocoder/utils/io.py index 9526b9db..b6ea7484 100644 --- a/vocoder/utils/io.py +++ b/vocoder/utils/io.py @@ -2,7 +2,6 @@ import os import torch import datetime - def save_model(model, optimizer, model_disc, optimizer_disc, current_step, epoch, output_path, **kwargs): model_state = model.state_dict() From dfce9ab9b72344eab6269515de3e66d943603557 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 2 Jun 2020 23:58:18 +0200 Subject: [PATCH 105/185] espeak install travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 645f9861..83ba25a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ language: python git: quiet: true +before_install: + - sudo apt-get update + - sudo apt-get -y install espeak + matrix: include: - name: "Lint check" From 34eacb6383cbf185ecd70e1679a8bb5e0956973e Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 3 Jun 2020 12:15:48 +0200 Subject: [PATCH 106/185] reset loss weights --- vocoder/configs/melgan_config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index 4aeba82e..bdfdf88a 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -54,11 +54,11 @@ "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators - "stft_loss_weight": 1, - "subband_stft_loss_weight": 1, + "stft_loss_weight": 0.5, + "subband_stft_loss_weight": 0.5, "mse_gan_loss_weight": 2.5, "hinge_gan_loss_weight": 2.5, - "feat_match_loss_weight": 10.0, + "feat_match_loss_weight": 25, "stft_loss_params": { "n_ffts": [1024, 2048, 512], From 6b1de26869251a3f0af0d22f9f1fe23d0556cc76 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 3 Jun 2020 12:16:08 +0200 Subject: [PATCH 107/185] correct loss normalization and function refactoring --- vocoder/layers/losses.py | 141 +++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 64 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 1c3d4442..fb4e85d4 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -6,6 +6,7 @@ from torch.nn import functional as F class TorchSTFT(): def __init__(self, n_fft, hop_length, win_length, window='hann_window'): + """ Torch based STFT operation """ self.n_fft = n_fft self.hop_length = hop_length self.win_length = win_length @@ -33,6 +34,7 @@ class TorchSTFT(): class STFTLoss(nn.Module): + """ Single scale STFT Loss """ def __init__(self, n_fft, hop_length, win_length): super(STFTLoss, self).__init__() self.n_fft = n_fft @@ -50,6 +52,7 @@ class STFTLoss(nn.Module): return loss_mag, loss_sc class MultiScaleSTFTLoss(torch.nn.Module): + """ Multi scale STFT loss """ def __init__(self, n_ffts=(1024, 2048, 512), hop_lengths=(120, 240, 50), @@ -73,6 +76,7 @@ class MultiScaleSTFTLoss(torch.nn.Module): class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): + """ Multiscale STFT loss for multi band model outputs """ def forward(self, y_hat, y): y_hat = y_hat.view(-1, 1, y_hat.shape[2]) y = y.view(-1, 1, y.shape[2]) @@ -121,16 +125,62 @@ class MelganFeatureLoss(nn.Module): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): loss_feats += torch.mean(torch.abs(fake_feat - real_feat)) + loss_feats /= len(fake_feats) + len(real_feats) return loss_feats -################################## +##################################### # LOSS WRAPPERS +##################################### + + +def _apply_G_adv_loss(scores_fake, loss_func): + """ Compute G adversarial loss function + and normalize values """ + adv_loss = 0 + if isinstance(scores_fake, list): + for score_fake in scores_fake: + fake_loss = loss_func(score_fake) + adv_loss += fake_loss + adv_loss /= len(scores_fake) + else: + fake_loss = loss_func(scores_fake) + adv_loss = fake_loss + return adv_loss + + +def _apply_D_loss(scores_fake, scores_real, loss_func): + """ Compute D loss func and normalize loss values """ + loss = 0 + real_loss = 0 + fake_loss = 0 + if isinstance(scores_fake, list): + # multi-scale loss + for score_fake, score_real in zip(scores_fake, scores_real): + total_loss, real_loss, fake_loss = loss_func(score_fake, score_real) + loss += total_loss + real_loss += real_loss + fake_loss += fake_loss + # normalize loss values with number of scales + loss /= len(scores_fake) + real_loss /= len(scores_real) + fake_loss /= len(scores_fake) + else: + # single scale loss + total_loss, real_loss, fake_loss = loss_func(scores_fake, scores_real) + loss = total_loss + return loss, real_loss, fake_loss + + +################################## +# MODEL LOSSES ################################## class GeneratorLoss(nn.Module): def __init__(self, C): + """ Compute Generator Loss values depending on training + configuration """ super(GeneratorLoss, self).__init__() assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ " [!] Cannot use HingeGANLoss and MSEGANLoss together." @@ -159,7 +209,8 @@ class GeneratorLoss(nn.Module): self.feat_match_loss = MelganFeatureLoss() def forward(self, y_hat=None, y=None, scores_fake=None, feats_fake=None, feats_real=None, y_hat_sub=None, y_sub=None): - loss = 0 + gen_loss = 0 + adv_loss = 0 return_dict = {} # STFT Loss @@ -167,50 +218,41 @@ class GeneratorLoss(nn.Module): stft_loss_mg, stft_loss_sc = self.stft_loss(y_hat.squeeze(1), y.squeeze(1)) return_dict['G_stft_loss_mg'] = stft_loss_mg return_dict['G_stft_loss_sc'] = stft_loss_sc - loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) + gen_loss += self.stft_loss_weight * (stft_loss_mg + stft_loss_sc) # subband STFT Loss if self.use_subband_stft_loss: subband_stft_loss_mg, subband_stft_loss_sc = self.subband_stft_loss(y_hat_sub, y_sub) return_dict['G_subband_stft_loss_mg'] = subband_stft_loss_mg return_dict['G_subband_stft_loss_sc'] = subband_stft_loss_sc - loss += self.subband_stft_loss_weight * (subband_stft_loss_mg + subband_stft_loss_sc) + gen_loss += self.subband_stft_loss_weight * (subband_stft_loss_mg + subband_stft_loss_sc) - # Fake Losses + # multiscale MSE adversarial loss if self.use_mse_gan_loss and scores_fake is not None: - mse_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake in scores_fake: - fake_loss = self.mse_loss(score_fake) - mse_fake_loss += fake_loss - else: - fake_loss = self.mse_loss(scores_fake) - mse_fake_loss = fake_loss + mse_fake_loss = _apply_G_adv_loss(scores_fake, self.mse_loss) return_dict['G_mse_fake_loss'] = mse_fake_loss - loss += self.mse_gan_loss_weight * mse_fake_loss + adv_loss += self.mse_gan_loss_weight * mse_fake_loss + # multiscale Hinge adversarial loss if self.use_hinge_gan_loss and not scores_fake is not None: - hinge_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake in scores_fake: - fake_loss = self.hinge_loss(score_fake) - hinge_fake_loss += fake_loss - else: - fake_loss = self.hinge_loss(scores_fake) - hinge_fake_loss = fake_loss + hinge_fake_loss = _apply_G_adv_loss(scores_fake, self.hinge_loss) return_dict['G_hinge_fake_loss'] = hinge_fake_loss - loss += self.hinge_gan_loss_weight * hinge_fake_loss + adv_loss += self.hinge_gan_loss_weight * hinge_fake_loss # Feature Matching Loss if self.use_feat_match_loss and not feats_fake: feat_match_loss = self.feat_match_loss(feats_fake, feats_real) return_dict['G_feat_match_loss'] = feat_match_loss - loss += self.feat_match_loss_weight * feat_match_loss - return_dict['G_loss'] = loss + adv_loss += self.feat_match_loss_weight * feat_match_loss + return_dict['G_loss'] = gen_loss + adv_loss + return_dict['G_gen_loss'] = gen_loss + return_dict['G_adv_loss'] = adv_loss return return_dict class DiscriminatorLoss(nn.Module): + """ Compute Discriminator Loss values depending on training + configuration """ def __init__(self, C): super(DiscriminatorLoss, self).__init__() assert not(C.use_mse_gan_loss and C.use_hinge_gan_loss),\ @@ -219,9 +261,6 @@ class DiscriminatorLoss(nn.Module): self.use_mse_gan_loss = C.use_mse_gan_loss self.use_hinge_gan_loss = C.use_hinge_gan_loss - self.mse_gan_loss_weight = C.mse_gan_loss_weight - self.hinge_gan_loss_weight = C.hinge_gan_loss_weight - if C.use_mse_gan_loss: self.mse_loss = MSEDLoss() if C.use_hinge_gan_loss: @@ -232,44 +271,18 @@ class DiscriminatorLoss(nn.Module): return_dict = {} if self.use_mse_gan_loss: - mse_gan_loss = 0 - mse_gan_real_loss = 0 - mse_gan_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake, score_real in zip(scores_fake, scores_real): - total_loss, real_loss, fake_loss = self.mse_loss(score_fake, score_real) - mse_gan_loss += total_loss - mse_gan_real_loss += real_loss - mse_gan_fake_loss += fake_loss - else: - total_loss, real_loss, fake_loss = self.mse_loss(scores_fake, scores_real) - mse_gan_loss = total_loss - mse_gan_real_loss = real_loss - mse_gan_fake_loss = fake_loss - return_dict['D_mse_gan_loss'] = mse_gan_loss - return_dict['D_mse_gan_real_loss'] = mse_gan_real_loss - return_dict['D_mse_gan_fake_loss'] = mse_gan_fake_loss - loss += self.mse_gan_loss_weight * mse_gan_loss + mse_D_loss, mse_D_real_loss, mse_D_fake_loss = _apply_D_loss(scores_fake, scores_real, self.mse_loss) + return_dict['D_mse_gan_loss'] = mse_D_loss + return_dict['D_mse_gan_real_loss'] = mse_D_real_loss + return_dict['D_mse_gan_fake_loss'] = mse_D_fake_loss + loss += mse_D_loss if self.use_hinge_gan_loss: - hinge_gan_loss = 0 - hinge_gan_real_loss = 0 - hinge_gan_fake_loss = 0 - if isinstance(scores_fake, list): - for score_fake, score_real in zip(scores_fake, scores_real): - total_loss, real_loss, fake_loss = self.hinge_loss(score_fake, score_real) - hinge_gan_loss += total_loss - hinge_gan_real_loss += real_loss - hinge_gan_fake_loss += fake_loss - else: - total_loss, real_loss, fake_loss = self.hinge_loss(scores_fake, scores_real) - hinge_gan_loss = total_loss - hinge_gan_real_loss = real_loss - hinge_gan_fake_loss = fake_loss - return_dict['D_hinge_gan_loss'] = hinge_gan_loss - return_dict['D_hinge_gan_real_loss'] = hinge_gan_real_loss - return_dict['D_hinge_gan_fake_loss'] = hinge_gan_fake_loss - loss += self.hinge_gan_loss_weight * hinge_gan_loss + hinge_D_loss, hinge_D_real_loss, hinge_D_fake_loss = _apply_D_loss(scores_fake, scores_real, self.hinge_loss) + return_dict['D_hinge_gan_loss'] = hinge_D_loss + return_dict['D_hinge_gan_real_loss'] = hinge_D_real_loss + return_dict['D_hinge_gan_fake_loss'] = hinge_D_fake_loss + loss += hinge_D_loss return_dict['D_loss'] = loss return return_dict \ No newline at end of file From 6f4c1108f07ead33bf6da21675fdb2765e0fc133 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 3 Jun 2020 12:33:53 +0200 Subject: [PATCH 108/185] suppress pylint no-self-use for loss layers --- vocoder/layers/losses.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index fb4e85d4..22e2fb54 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -77,6 +77,7 @@ class MultiScaleSTFTLoss(torch.nn.Module): class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): """ Multiscale STFT loss for multi band model outputs """ + # pylint: disable=no-self-use def forward(self, y_hat, y): y_hat = y_hat.view(-1, 1, y_hat.shape[2]) y = y.view(-1, 1, y.shape[2]) @@ -85,6 +86,7 @@ class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake): loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) return loss_fake @@ -92,6 +94,7 @@ class MSEGLoss(nn.Module): class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake): loss_fake = torch.mean(F.relu(1. + score_fake)) return loss_fake @@ -104,6 +107,7 @@ class HingeGLoss(nn.Module): class MSEDLoss(nn.Module): """ Mean Squared Discriminator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake, score_real): loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) @@ -113,6 +117,7 @@ class MSEDLoss(nn.Module): class HingeDLoss(nn.Module): """ Hinge Discriminator Loss """ + # pylint: disable=no-self-use def forward(self, score_fake, score_real): loss_real = torch.mean(F.relu(1. - score_real)) loss_fake = torch.mean(F.relu(1. + score_fake)) @@ -121,6 +126,7 @@ class HingeDLoss(nn.Module): class MelganFeatureLoss(nn.Module): + # pylint: disable=no-self-use def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): From 8dc1d6a208e19b919da76fcef75632b29a4bcaf4 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 02:58:25 +0200 Subject: [PATCH 109/185] update README.md --- README.md | 8 +++++--- vocoder/train.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7d9884b0..20799943 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,11 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- [Details...](https://github.com/mozilla/TTS/wiki/Mean-Opinion-Score-Results) ## Features -- High performance Text2Speech models on Torch and Tensorflow 2.0. -- High performance Speaker Encoder to compute speaker embeddings efficiently. -- Integration with various Neural Vocoders (PWGAN, MelGAN, WaveRNN) +- High performance Deep Learning models for Text2Speech related tasks. + - Text2Speech models (Tacotron, Tacotron2). + - Speaker Encoder to compute speaker embeddings efficiently. + - Vocoder models (MelGAN, Multiband-MelGAN, GAN-TTS) +- Ability to convert Torch models to Tensorflow 2.0 for inference. - Released trained models. - Efficient training codes for PyTorch. (soon for Tensorflow 2.0) - Codes to convert Torch models to Tensorflow 2.0. diff --git a/vocoder/train.py b/vocoder/train.py index d401e72e..03e14f4a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -52,7 +52,7 @@ def setup_loader(ap, is_val=False, verbose=False): # sampler = DistributedSampler(dataset) if num_gpus > 1 else None loader = DataLoader(dataset, batch_size=1 if is_val else c.batch_size, - shuffle=False, + shuffle=True, drop_last=False, sampler=None, num_workers=c.num_val_loader_workers From 1b05bfce2e1649ead3d07dbd9b0756258c4fbb5e Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 09:51:20 +0200 Subject: [PATCH 110/185] visualization fix --- vocoder/train.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 03e14f4a..a75c6a12 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -120,11 +120,13 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, y_hat = model_G(c_G) y_hat_sub = None y_G_sub = None + y_hat_vis = y_hat # for visualization # PQMF formatting if y_hat.shape[1] > 1: y_hat_sub = y_hat y_hat = model_G.pqmf_synthesis(y_hat) + y_hat_vis = y_hat y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: @@ -265,12 +267,12 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, model_losses=loss_dict) # compute spectrograms - figures = plot_results(y_hat, y_G, ap, global_step, + figures = plot_results(y_hat_vis, y_G, ap, global_step, 'train') tb_logger.tb_train_figures(global_step, figures) # Sample audio - sample_voice = y_hat[0].squeeze(0).detach().cpu().numpy() + sample_voice = y_hat_vis[0].squeeze(0).detach().cpu().numpy() tb_logger.tb_train_audios(global_step, {'train/audio': sample_voice}, c.audio["sample_rate"]) From aa06a0609d0a8d5e5b2780ab0b6f059ae7b0398f Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:26:30 +0200 Subject: [PATCH 111/185] tacotron abstract class --- models/tacotron_abstract.py | 160 ++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 models/tacotron_abstract.py diff --git a/models/tacotron_abstract.py b/models/tacotron_abstract.py new file mode 100644 index 00000000..db6cbdee --- /dev/null +++ b/models/tacotron_abstract.py @@ -0,0 +1,160 @@ +import copy +from abc import ABC, abstractmethod + +import torch +from torch import nn + +from TTS.layers.gst_layers import GST +from TTS.utils.generic_utils import sequence_mask + + +class TacotronAbstract(ABC, nn.Module): + def __init__(self, num_chars, + num_speakers, + r, + postnet_output_dim=80, + decoder_output_dim=80, + attn_type='original', + attn_win=False, + attn_norm="softmax", + prenet_type="original", + prenet_dropout=True, + forward_attn=False, + trans_agent=False, + forward_attn_mask=False, + location_attn=True, + attn_K=5, + separate_stopnet=True, + bidirectional_decoder=False, + double_decoder_consistency=False, + ddc_r=None, + gst=False): + """ Abstract Tacotron class """ + super().__init__() + self.r = r + self.decoder_output_dim = decoder_output_dim + self.postnet_output_dim = postnet_output_dim + self.gst = gst + self.num_speakers = num_speakers + self.bidirectional_decoder = bidirectional_decoder + self.double_decoder_consistency = double_decoder_consistency + self.ddc_r = ddc_r + + # layers + self.embedding = None + self.encoder = None + self.decoder = None + self.postnet = None + + # global style token + if self.gst: + gst_embedding_dim = None + self.gst_layer = None + + ############################# + # INIT FUNCTIONS + ############################# + + def _init_states(self): + self.speaker_embeddings = None + self.speaker_embeddings_projected = None + + def _init_backward_decoder(self): + self.decoder_backward = copy.deepcopy(self.decoder) + + def _init_coarse_decoder(self): + self.coarse_decoder = copy.deepcopy(self.decoder) + self.coarse_decoder.r_init = self.ddc_r + self.coarse_decoder.set_r(self.ddc_r) + + ############################# + # CORE FUNCTIONS + ############################# + + @abstractmethod + def forward(self): + pass + + @abstractmethod + def inference(self): + pass + + ############################# + # COMMON COMPUTE FUNCTIONS + ############################# + + def compute_masks(self, text_lengths, mel_lengths): + """Compute masks against sequence paddings.""" + # B x T_in_max (boolean) + device = text_lengths.device + input_mask = sequence_mask(text_lengths).to(device) + output_mask = None + if mel_lengths is not None: + max_len = mel_lengths.max() + r = self.decoder.r + max_len = max_len + (r - (max_len % r)) if max_len % r > 0 else max_len + output_mask = sequence_mask(mel_lengths, max_len=max_len).to(device) + return input_mask, output_mask + + def _backward_pass(self, mel_specs, encoder_outputs, mask): + """ Run backwards decoder """ + decoder_outputs_b, alignments_b, _ = self.decoder_backward( + encoder_outputs, torch.flip(mel_specs, dims=(1,)), mask, + self.speaker_embeddings_projected) + decoder_outputs_b = decoder_outputs_b.transpose(1, 2).contiguous() + return decoder_outputs_b, alignments_b + + def _coarse_decoder_pass(self, mel_specs, encoder_outputs, alignments, + input_mask): + """ Double Decoder Consistency """ + T = mel_specs.shape[1] + if T % self.coarse_decoder.r > 0: + padding_size = self.coarse_decoder.r - (T % self.coarse_decoder.r) + mel_specs = torch.nn.functional.pad(mel_specs, + (0, 0, 0, padding_size, 0, 0)) + decoder_outputs_backward, alignments_backward, _ = self.coarse_decoder( + encoder_outputs.detach(), mel_specs, input_mask) + scale_factor = self.decoder.r_init / self.decoder.r + alignments_backward = torch.nn.functional.interpolate( + alignments_backward.transpose(1, 2), + size=alignments.shape[1], + mode='nearest').transpose(1, 2) + decoder_outputs_backward = decoder_outputs_backward.transpose(1, 2) + decoder_outputs_backward = decoder_outputs_backward[:, :T, :] + return decoder_outputs_backward, alignments_backward + + ############################# + # EMBEDDING FUNCTIONS + ############################# + + def compute_speaker_embedding(self, speaker_ids): + """ Compute speaker embedding vectors """ + if hasattr(self, "speaker_embedding") and speaker_ids is None: + raise RuntimeError( + " [!] Model has speaker embedding layer but speaker_id is not provided" + ) + if hasattr(self, "speaker_embedding") and speaker_ids is not None: + self.speaker_embeddings = self.speaker_embedding(speaker_ids).unsqueeze(1) + if hasattr(self, "speaker_project_mel") and speaker_ids is not None: + self.speaker_embeddings_projected = self.speaker_project_mel( + self.speaker_embeddings).squeeze(1) + + def compute_gst(self, inputs, mel_specs): + """ Compute global style token """ + gst_outputs = self.gst_layer(mel_specs) + inputs = self._add_speaker_embedding(inputs, gst_outputs) + return inputs + + @staticmethod + def _add_speaker_embedding(outputs, speaker_embeddings): + speaker_embeddings_ = speaker_embeddings.expand( + outputs.size(0), outputs.size(1), -1) + outputs = outputs + speaker_embeddings_ + return outputs + + @staticmethod + def _concat_speaker_embedding(outputs, speaker_embeddings): + speaker_embeddings_ = speaker_embeddings.expand( + outputs.size(0), outputs.size(1), -1) + outputs = torch.cat([outputs, speaker_embeddings_], dim=-1) + return outputs From ac24bdfddda30b2b35cd860be6073d412cb2e96d Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:26:51 +0200 Subject: [PATCH 112/185] update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 20799943..f6ee1ade 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- [![](https://sourcerer.io/fame/erogol/erogol/TTS/images/0)](https://sourcerer.io/fame/erogol/erogol/TTS/links/0)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/1)](https://sourcerer.io/fame/erogol/erogol/TTS/links/1)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/2)](https://sourcerer.io/fame/erogol/erogol/TTS/links/2)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/3)](https://sourcerer.io/fame/erogol/erogol/TTS/links/3)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/4)](https://sourcerer.io/fame/erogol/erogol/TTS/links/4)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/5)](https://sourcerer.io/fame/erogol/erogol/TTS/links/5)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/6)](https://sourcerer.io/fame/erogol/erogol/TTS/links/6)[![](https://sourcerer.io/fame/erogol/erogol/TTS/images/7)](https://sourcerer.io/fame/erogol/erogol/TTS/links/7) -## TTS Performance +## TTS Performance

[Details...](https://github.com/mozilla/TTS/wiki/Mean-Opinion-Score-Results) @@ -19,8 +19,9 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- ## Features - High performance Deep Learning models for Text2Speech related tasks. - Text2Speech models (Tacotron, Tacotron2). - - Speaker Encoder to compute speaker embeddings efficiently. + - Speaker Encoder to compute speaker embeddings efficiently. - Vocoder models (MelGAN, Multiband-MelGAN, GAN-TTS) +- Support for multi-speaker TTS training. - Ability to convert Torch models to Tensorflow 2.0 for inference. - Released trained models. - Efficient training codes for PyTorch. (soon for Tensorflow 2.0) @@ -86,7 +87,7 @@ Audio length is approximately 6 secs. ## Datasets and Data-Loading -TTS provides a generic dataloder easy to use for new datasets. You need to write an preprocessor function to integrate your own dataset.Check ```datasets/preprocess.py``` to see some examples. After the function, you need to set ```dataset``` field in ```config.json```. Do not forget other data related fields too. +TTS provides a generic dataloder easy to use for new datasets. You need to write an preprocessor function to integrate your own dataset.Check ```datasets/preprocess.py``` to see some examples. After the function, you need to set ```dataset``` field in ```config.json```. Do not forget other data related fields too. Some of the open-sourced datasets that we successfully applied TTS, are linked below. @@ -98,9 +99,9 @@ Some of the open-sourced datasets that we successfully applied TTS, are linked b - [Spanish](https://drive.google.com/file/d/1Sm_zyBo67XHkiFhcRSQ4YaHPYM0slO_e/view?usp=sharing) - thx! @carlfm01 ## Training and Fine-tuning LJ-Speech -Here you can find a [CoLab](https://gist.github.com/erogol/97516ad65b44dbddb8cd694953187c5b) notebook for a hands-on example, training LJSpeech. Or you can manually follow the guideline below. +Here you can find a [CoLab](https://gist.github.com/erogol/97516ad65b44dbddb8cd694953187c5b) notebook for a hands-on example, training LJSpeech. Or you can manually follow the guideline below. -To start with, split ```metadata.csv``` into train and validation subsets respectively ```metadata_train.csv``` and ```metadata_val.csv```. Note that for text-to-speech, validation performance might be misleading since the loss value does not directly measure the voice quality to the human ear and it also does not measure the attention module performance. Therefore, running the model with new sentences and listening to the results is the best way to go. +To start with, split ```metadata.csv``` into train and validation subsets respectively ```metadata_train.csv``` and ```metadata_val.csv```. Note that for text-to-speech, validation performance might be misleading since the loss value does not directly measure the voice quality to the human ear and it also does not measure the attention module performance. Therefore, running the model with new sentences and listening to the results is the best way to go. ``` shuf metadata.csv > metadata_shuf.csv @@ -139,10 +140,10 @@ cardboardlinter --refspec master ``` ## Collaborative Experimentation Guide -If you like to use TTS to try a new idea and like to share your experiments with the community, we urge you to use the following guideline for a better collaboration. +If you like to use TTS to try a new idea and like to share your experiments with the community, we urge you to use the following guideline for a better collaboration. (If you have an idea for better collaboration, let us know) - Create a new branch. -- Open an issue pointing your branch. +- Open an issue pointing your branch. - Explain your experiment. - Share your results as you proceed. (Tensorboard log files, audio results, visuals etc.) - Use LJSpeech dataset (for English) if you like to compare results with the released models. (It is the most open scalable dataset for quick experimentation) From cd93b7b3515f6c1a3f47055df5b5018e6f9b0de8 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:27:06 +0200 Subject: [PATCH 113/185] update model config.json with double decoder consistency --- config.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.json b/config.json index 32debf86..74021970 100644 --- a/config.json +++ b/config.json @@ -96,6 +96,8 @@ "transition_agent": false, // enable/disable transition agent of forward attention. "location_attn": true, // enable_disable location sensitive attention. It is enabled for TACOTRON by default. "bidirectional_decoder": false, // use https://arxiv.org/abs/1907.09006. Use it, if attention does not work well with your dataset. + "double_decoder_consistency": true, // use DDC explained here https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency-draft/ + "ddc_r": 7, // reduction rate for coarse decoder. // STOPNET "stopnet": true, // Train stopnet predicting the end of synthesis. From 23f65df6c6cbe9ee20547841c8d40e0a87b2c736 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:27:40 +0200 Subject: [PATCH 114/185] add DDC loss --- layers/losses.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/layers/losses.py b/layers/losses.py index 608e247d..f7745b6e 100644 --- a/layers/losses.py +++ b/layers/losses.py @@ -184,7 +184,7 @@ class TacotronLoss(torch.nn.Module): def forward(self, postnet_output, decoder_output, mel_input, linear_input, stopnet_output, stopnet_target, output_lens, decoder_b_output, - alignments, alignment_lens, input_lens): + alignments, alignment_lens, alignments_backwards, input_lens): return_dict = {} # decoder and postnet losses @@ -226,6 +226,15 @@ class TacotronLoss(torch.nn.Module): return_dict['decoder_b_loss'] = decoder_b_loss return_dict['decoder_c_loss'] = decoder_c_loss + # double decoder consistency loss (if enabled) + if self.config.double_decoder_consistency: + decoder_b_loss = self.criterion(decoder_b_output, mel_input, output_lens) + # decoder_c_loss = torch.nn.functional.l1_loss(decoder_b_output, decoder_output) + attention_c_loss = torch.nn.functional.l1_loss(alignments, alignments_backwards) + loss += decoder_b_loss + attention_c_loss + return_dict['decoder_coarse_loss'] = decoder_b_loss + return_dict['decoder_ddc_loss'] = attention_c_loss + # guided attention loss (if enabled) if self.config.ga_alpha > 0: ga_loss = self.criterion_ga(alignments, input_lens, alignment_lens) From 9559e3fc308d70c029b1d703d1eeb06295d4bee3 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:28:16 +0200 Subject: [PATCH 115/185] inherit TacotronAbstact with both tacotron and tacotron2 --- models/tacotron.py | 135 ++++++++++++++++++------------------------- models/tacotron2.py | 136 ++++++++++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 129 deletions(-) diff --git a/models/tacotron.py b/models/tacotron.py index fba82b1b..c526374a 100644 --- a/models/tacotron.py +++ b/models/tacotron.py @@ -1,23 +1,21 @@ # coding: utf-8 import torch -import copy from torch import nn -from TTS.layers.tacotron import Encoder, Decoder, PostCBHG -from TTS.utils.generic_utils import sequence_mask + from TTS.layers.gst_layers import GST +from TTS.layers.tacotron import Decoder, Encoder, PostCBHG +from TTS.models.tacotron_abstract import TacotronAbstract -class Tacotron(nn.Module): +class Tacotron(TacotronAbstract): def __init__(self, num_chars, num_speakers, r=5, postnet_output_dim=1025, decoder_output_dim=80, - memory_size=5, attn_type='original', attn_win=False, - gst=False, attn_norm="sigmoid", prenet_type="original", prenet_dropout=True, @@ -27,38 +25,41 @@ class Tacotron(nn.Module): location_attn=True, attn_K=5, separate_stopnet=True, - bidirectional_decoder=False): - super(Tacotron, self).__init__() - self.r = r - self.decoder_output_dim = decoder_output_dim - self.postnet_output_dim = postnet_output_dim - self.gst = gst - self.num_speakers = num_speakers - self.bidirectional_decoder = bidirectional_decoder - decoder_dim = 512 if num_speakers > 1 else 256 - encoder_dim = 512 if num_speakers > 1 else 256 + bidirectional_decoder=False, + double_decoder_consistency=False, + ddc_r=None, + gst=False, + memory_size=5): + super(Tacotron, + self).__init__(num_chars, num_speakers, r, postnet_output_dim, + decoder_output_dim, attn_type, attn_win, + attn_norm, prenet_type, prenet_dropout, + forward_attn, trans_agent, forward_attn_mask, + location_attn, attn_K, separate_stopnet, + bidirectional_decoder, double_decoder_consistency, + ddc_r, gst) + decoder_in_features = 512 if num_speakers > 1 else 256 + encoder_in_features = 512 if num_speakers > 1 else 256 + speaker_embedding_dim = 256 proj_speaker_dim = 80 if num_speakers > 1 else 0 - # embedding layer + # base model layers self.embedding = nn.Embedding(num_chars, 256, padding_idx=0) self.embedding.weight.data.normal_(0, 0.3) - # boilerplate model - self.encoder = Encoder(encoder_dim) - self.decoder = Decoder(decoder_dim, decoder_output_dim, r, memory_size, attn_type, attn_win, + self.encoder = Encoder(encoder_in_features) + self.decoder = Decoder(decoder_in_features, decoder_output_dim, r, memory_size, attn_type, attn_win, attn_norm, prenet_type, prenet_dropout, forward_attn, trans_agent, forward_attn_mask, location_attn, attn_K, separate_stopnet, proj_speaker_dim) - if self.bidirectional_decoder: - self.decoder_backward = copy.deepcopy(self.decoder) self.postnet = PostCBHG(decoder_output_dim) self.last_linear = nn.Linear(self.postnet.cbhg.gru_features * 2, postnet_output_dim) # speaker embedding layers if num_speakers > 1: - self.speaker_embedding = nn.Embedding(num_speakers, 256) + self.speaker_embedding = nn.Embedding(num_speakers, speaker_embedding_dim) self.speaker_embedding.weight.data.normal_(0, 0.3) self.speaker_project_mel = nn.Sequential( - nn.Linear(256, proj_speaker_dim), nn.Tanh()) + nn.Linear(speaker_embedding_dim, proj_speaker_dim), nn.Tanh()) self.speaker_embeddings = None self.speaker_embeddings_projected = None # global style token layers @@ -68,28 +69,15 @@ class Tacotron(nn.Module): num_heads=4, num_style_tokens=10, embedding_dim=gst_embedding_dim) + # backward pass decoder + if self.bidirectional_decoder: + self._init_backward_decoder() + # setup DDC + if self.double_decoder_consistency: + self._init_coarse_decoder() - def _init_states(self): - self.speaker_embeddings = None - self.speaker_embeddings_projected = None - def compute_speaker_embedding(self, speaker_ids): - if hasattr(self, "speaker_embedding") and speaker_ids is None: - raise RuntimeError( - " [!] Model has speaker embedding layer but speaker_id is not provided" - ) - if hasattr(self, "speaker_embedding") and speaker_ids is not None: - self.speaker_embeddings = self._compute_speaker_embedding( - speaker_ids) - self.speaker_embeddings_projected = self.speaker_project_mel( - self.speaker_embeddings).squeeze(1) - - def compute_gst(self, inputs, mel_specs): - gst_outputs = self.gst_layer(mel_specs) - inputs = self._add_speaker_embedding(inputs, gst_outputs) - return inputs - - def forward(self, characters, text_lengths, mel_specs, speaker_ids=None): + def forward(self, characters, text_lengths, mel_specs, mel_lengths=None, speaker_ids=None): """ Shapes: - characters: B x T_in @@ -98,45 +86,59 @@ class Tacotron(nn.Module): - speaker_ids: B x 1 """ self._init_states() - mask = sequence_mask(text_lengths).to(characters.device) + input_mask, output_mask = self.compute_masks(text_lengths, mel_lengths) # B x T_in x embed_dim inputs = self.embedding(characters) # B x speaker_embed_dim - self.compute_speaker_embedding(speaker_ids) + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) if self.num_speakers > 1: # B x T_in x embed_dim + speaker_embed_dim inputs = self._concat_speaker_embedding(inputs, self.speaker_embeddings) - # B x T_in x encoder_dim + # B x T_in x encoder_in_features encoder_outputs = self.encoder(inputs) + # sequence masking + encoder_outputs = encoder_outputs * input_mask.unsqueeze(2).expand_as(encoder_outputs) + # global style token if self.gst: # B x gst_dim encoder_outputs = self.compute_gst(encoder_outputs, mel_specs) if self.num_speakers > 1: encoder_outputs = self._concat_speaker_embedding( encoder_outputs, self.speaker_embeddings) - # decoder_outputs: B x decoder_dim x T_out - # alignments: B x T_in x encoder_dim + # decoder_outputs: B x decoder_in_features x T_out + # alignments: B x T_in x encoder_in_features # stop_tokens: B x T_in decoder_outputs, alignments, stop_tokens = self.decoder( - encoder_outputs, mel_specs, mask, + encoder_outputs, mel_specs, input_mask, self.speaker_embeddings_projected) - # B x T_out x decoder_dim + # sequence masking + if output_mask is not None: + decoder_outputs = decoder_outputs * output_mask.unsqueeze(1).expand_as(decoder_outputs) + # B x T_out x decoder_in_features postnet_outputs = self.postnet(decoder_outputs) + # sequence masking + if output_mask is not None: + postnet_outputs = postnet_outputs * output_mask.unsqueeze(2).expand_as(postnet_outputs) # B x T_out x posnet_dim postnet_outputs = self.last_linear(postnet_outputs) - # B x T_out x decoder_dim + # B x T_out x decoder_in_features decoder_outputs = decoder_outputs.transpose(1, 2).contiguous() if self.bidirectional_decoder: - decoder_outputs_backward, alignments_backward = self._backward_inference(mel_specs, encoder_outputs, mask) + decoder_outputs_backward, alignments_backward = self._backward_pass(mel_specs, encoder_outputs, input_mask) return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward + if self.double_decoder_consistency: + decoder_outputs_backward, alignments_backward = self._coarse_decoder_pass(mel_specs, encoder_outputs, alignments, input_mask) + return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward return decoder_outputs, postnet_outputs, alignments, stop_tokens @torch.no_grad() def inference(self, characters, speaker_ids=None, style_mel=None): inputs = self.embedding(characters) self._init_states() - self.compute_speaker_embedding(speaker_ids) + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) if self.num_speakers > 1: inputs = self._concat_speaker_embedding(inputs, self.speaker_embeddings) @@ -152,28 +154,3 @@ class Tacotron(nn.Module): postnet_outputs = self.last_linear(postnet_outputs) decoder_outputs = decoder_outputs.transpose(1, 2) return decoder_outputs, postnet_outputs, alignments, stop_tokens - - def _backward_inference(self, mel_specs, encoder_outputs, mask): - decoder_outputs_b, alignments_b, _ = self.decoder_backward( - encoder_outputs, torch.flip(mel_specs, dims=(1,)), mask, - self.speaker_embeddings_projected) - decoder_outputs_b = decoder_outputs_b.transpose(1, 2).contiguous() - return decoder_outputs_b, alignments_b - - def _compute_speaker_embedding(self, speaker_ids): - speaker_embeddings = self.speaker_embedding(speaker_ids) - return speaker_embeddings.unsqueeze_(1) - - @staticmethod - def _add_speaker_embedding(outputs, speaker_embeddings): - speaker_embeddings_ = speaker_embeddings.expand( - outputs.size(0), outputs.size(1), -1) - outputs = outputs + speaker_embeddings_ - return outputs - - @staticmethod - def _concat_speaker_embedding(outputs, speaker_embeddings): - speaker_embeddings_ = speaker_embeddings.expand( - outputs.size(0), outputs.size(1), -1) - outputs = torch.cat([outputs, speaker_embeddings_], dim=-1) - return outputs diff --git a/models/tacotron2.py b/models/tacotron2.py index 3e7adfca..bbce4be9 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -1,13 +1,15 @@ -import copy -import torch from math import sqrt + +import torch from torch import nn -from TTS.layers.tacotron2 import Encoder, Decoder, Postnet -from TTS.utils.generic_utils import sequence_mask + +from TTS.layers.gst_layers import GST +from TTS.layers.tacotron2 import Decoder, Encoder, Postnet +from TTS.models.tacotron_abstract import TacotronAbstract # TODO: match function arguments with tacotron -class Tacotron2(nn.Module): +class Tacotron2(TacotronAbstract): def __init__(self, num_chars, num_speakers, @@ -25,16 +27,22 @@ class Tacotron2(nn.Module): location_attn=True, attn_K=5, separate_stopnet=True, - bidirectional_decoder=False): - super(Tacotron2, self).__init__() - self.postnet_output_dim = postnet_output_dim - self.decoder_output_dim = decoder_output_dim - self.r = r - self.bidirectional_decoder = bidirectional_decoder - decoder_dim = 512 if num_speakers > 1 else 512 - encoder_dim = 512 if num_speakers > 1 else 512 + bidirectional_decoder=False, + double_decoder_consistency=False, + ddc_r=None, + gst=False): + super(Tacotron2, + self).__init__(num_chars, num_speakers, r, postnet_output_dim, + decoder_output_dim, attn_type, attn_win, + attn_norm, prenet_type, prenet_dropout, + forward_attn, trans_agent, forward_attn_mask, + location_attn, attn_K, separate_stopnet, + bidirectional_decoder, double_decoder_consistency, + ddc_r, gst) + decoder_in_features = 512 if num_speakers > 1 else 512 + encoder_in_features = 512 if num_speakers > 1 else 512 proj_speaker_dim = 80 if num_speakers > 1 else 0 - # embedding layer + # base layers self.embedding = nn.Embedding(num_chars, 512, padding_idx=0) std = sqrt(2.0 / (num_chars + 512)) val = sqrt(3.0) * std # uniform bounds for std @@ -42,20 +50,25 @@ class Tacotron2(nn.Module): if num_speakers > 1: self.speaker_embedding = nn.Embedding(num_speakers, 512) self.speaker_embedding.weight.data.normal_(0, 0.3) - self.speaker_embeddings = None - self.speaker_embeddings_projected = None - self.encoder = Encoder(encoder_dim) - self.decoder = Decoder(decoder_dim, self.decoder_output_dim, r, attn_type, attn_win, + self.encoder = Encoder(encoder_in_features) + self.decoder = Decoder(decoder_in_features, self.decoder_output_dim, r, attn_type, attn_win, attn_norm, prenet_type, prenet_dropout, forward_attn, trans_agent, forward_attn_mask, location_attn, attn_K, separate_stopnet, proj_speaker_dim) - if self.bidirectional_decoder: - self.decoder_backward = copy.deepcopy(self.decoder) self.postnet = Postnet(self.postnet_output_dim) - - def _init_states(self): - self.speaker_embeddings = None - self.speaker_embeddings_projected = None + # global style token layers + if self.gst: + gst_embedding_dim = encoder_in_features + self.gst_layer = GST(num_mel=80, + num_heads=4, + num_style_tokens=10, + embedding_dim=gst_embedding_dim) + # backward pass decoder + if self.bidirectional_decoder: + self._init_backward_decoder() + # setup DDC + if self.double_decoder_consistency: + self._init_coarse_decoder() @staticmethod def shape_outputs(mel_outputs, mel_outputs_postnet, alignments): @@ -63,31 +76,60 @@ class Tacotron2(nn.Module): mel_outputs_postnet = mel_outputs_postnet.transpose(1, 2) return mel_outputs, mel_outputs_postnet, alignments - def forward(self, text, text_lengths, mel_specs=None, speaker_ids=None): + def forward(self, text, text_lengths, mel_specs=None, mel_lengths=None, speaker_ids=None): self._init_states() # compute mask for padding - mask = sequence_mask(text_lengths).to(text.device) + # B x T_in_max (boolean) + input_mask, output_mask = self.compute_masks(text_lengths, mel_lengths) + # B x D_embed x T_in_max embedded_inputs = self.embedding(text).transpose(1, 2) + # B x T_in_max x D_en encoder_outputs = self.encoder(embedded_inputs, text_lengths) - encoder_outputs = self._add_speaker_embedding(encoder_outputs, - speaker_ids) + # adding speaker embeddding to encoder output + # TODO: multi-speaker + # B x speaker_embed_dim + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) + if self.num_speakers > 1: + # B x T_in x embed_dim + speaker_embed_dim + encoder_outputs = self._add_speaker_embedding(encoder_outputs, + self.speaker_embeddings) + encoder_outputs = encoder_outputs * input_mask.unsqueeze(2).expand_as(encoder_outputs) + # global style token + if self.gst: + # B x gst_dim + encoder_outputs = self.compute_gst(encoder_outputs, mel_specs) + # B x mel_dim x T_out -- B x T_out//r x T_in -- B x T_out//r decoder_outputs, alignments, stop_tokens = self.decoder( - encoder_outputs, mel_specs, mask) + encoder_outputs, mel_specs, input_mask) + # sequence masking + if mel_lengths is not None: + decoder_outputs = decoder_outputs * output_mask.unsqueeze(1).expand_as(decoder_outputs) + # B x mel_dim x T_out postnet_outputs = self.postnet(decoder_outputs) - postnet_outputs = decoder_outputs + postnet_outputs + # sequence masking + if output_mask is not None: + postnet_outputs = postnet_outputs * output_mask.unsqueeze(1).expand_as(postnet_outputs) + # B x T_out x mel_dim -- B x T_out x mel_dim -- B x T_out//r x T_in decoder_outputs, postnet_outputs, alignments = self.shape_outputs( decoder_outputs, postnet_outputs, alignments) if self.bidirectional_decoder: - decoder_outputs_backward, alignments_backward = self._backward_inference(mel_specs, encoder_outputs, mask) + decoder_outputs_backward, alignments_backward = self._backward_pass(mel_specs, encoder_outputs, input_mask) return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward + if self.double_decoder_consistency: + decoder_outputs_backward, alignments_backward = self._coarse_decoder_pass(mel_specs, encoder_outputs, alignments, input_mask) + return decoder_outputs, postnet_outputs, alignments, stop_tokens, decoder_outputs_backward, alignments_backward return decoder_outputs, postnet_outputs, alignments, stop_tokens @torch.no_grad() def inference(self, text, speaker_ids=None): embedded_inputs = self.embedding(text).transpose(1, 2) encoder_outputs = self.encoder.inference(embedded_inputs) - encoder_outputs = self._add_speaker_embedding(encoder_outputs, - speaker_ids) + if speaker_ids is not None: + self.compute_speaker_embedding(speaker_ids) + if self.num_speakers > 1: + encoder_outputs = self._add_speaker_embedding(encoder_outputs, + self.speaker_embeddings) mel_outputs, alignments, stop_tokens = self.decoder.inference( encoder_outputs) mel_outputs_postnet = self.postnet(mel_outputs) @@ -112,22 +154,16 @@ class Tacotron2(nn.Module): mel_outputs, mel_outputs_postnet, alignments) return mel_outputs, mel_outputs_postnet, alignments, stop_tokens - def _backward_inference(self, mel_specs, encoder_outputs, mask): - decoder_outputs_b, alignments_b, _ = self.decoder_backward( - encoder_outputs, torch.flip(mel_specs, dims=(1,)), mask, - self.speaker_embeddings_projected) - decoder_outputs_b = decoder_outputs_b.transpose(1, 2) - return decoder_outputs_b, alignments_b - def _add_speaker_embedding(self, encoder_outputs, speaker_ids): - if hasattr(self, "speaker_embedding") and speaker_ids is None: - raise RuntimeError(" [!] Model has speaker embedding layer but speaker_id is not provided") - if hasattr(self, "speaker_embedding") and speaker_ids is not None: - speaker_embeddings = self.speaker_embedding(speaker_ids) + def _speaker_embedding_pass(self, encoder_outputs, speaker_ids): + # TODO: multi-speaker + # if hasattr(self, "speaker_embedding") and speaker_ids is None: + # raise RuntimeError(" [!] Model has speaker embedding layer but speaker_id is not provided") + # if hasattr(self, "speaker_embedding") and speaker_ids is not None: - speaker_embeddings.unsqueeze_(1) - speaker_embeddings = speaker_embeddings.expand(encoder_outputs.size(0), - encoder_outputs.size(1), - -1) - encoder_outputs = encoder_outputs + speaker_embeddings - return encoder_outputs + # speaker_embeddings = speaker_embeddings.expand(encoder_outputs.size(0), + # encoder_outputs.size(1), + # -1) + # encoder_outputs = encoder_outputs + speaker_embeddings + # return encoder_outputs + pass From 596251558175aa8d7f57e1983430e8c9ed172fe3 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:28:55 +0200 Subject: [PATCH 116/185] update dummy model config --- tests/outputs/dummy_model_config.json | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/outputs/dummy_model_config.json b/tests/outputs/dummy_model_config.json index 2f56c6ce..d301b61a 100644 --- a/tests/outputs/dummy_model_config.json +++ b/tests/outputs/dummy_model_config.json @@ -4,7 +4,7 @@ "audio":{ // Audio processing parameters - "num_mels": 80, // size of the mel spec frame. + "num_mels": 80, // size of the mel spec frame. "num_freq": 1025, // number of stft frequency levels. Size of the linear spectogram frame. "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. "frame_length_ms": 50, // stft window length in ms. @@ -31,19 +31,19 @@ "reinit_layers": [], - "model": "Tacotron2", // one of the model in models/ + "model": "Tacotron2", // one of the model in models/ "grad_clip": 1, // upper limit for gradients for clipping. "epochs": 1000, // total number of epochs to train. "lr": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. "lr_decay": false, // if true, Noam learning rate decaying is applied through training. "warmup_steps": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "windowing": false, // Enables attention windowing. Used only in eval mode. - "memory_size": 5, // ONLY TACOTRON - memory queue size used to queue network predictions to feed autoregressive connection. Useful if r < 5. + "memory_size": 5, // ONLY TACOTRON - memory queue size used to queue network predictions to feed autoregressive connection. Useful if r < 5. "attention_norm": "sigmoid", // softmax or sigmoid. Suggested to use softmax for Tacotron2 and sigmoid for Tacotron. "prenet_type": "original", // ONLY TACOTRON2 - "original" or "bn". - "prenet_dropout": true, // ONLY TACOTRON2 - enable/disable dropout at prenet. + "prenet_dropout": true, // ONLY TACOTRON2 - enable/disable dropout at prenet. "use_forward_attn": true, // ONLY TACOTRON2 - if it uses forward attention. In general, it aligns faster. - "forward_attn_mask": false, + "forward_attn_mask": false, "attention_type": "original", "attention_heads": 5, "bidirectional_decoder": false, @@ -51,13 +51,15 @@ "location_attn": false, // ONLY TACOTRON2 - enable_disable location sensitive attention. It is enabled for TACOTRON by default. "loss_masking": true, // enable / disable loss masking against the sequence padding. "enable_eos_bos_chars": false, // enable/disable beginning of sentence and end of sentence chars. - "stopnet": true, // Train stopnet predicting the end of synthesis. + "stopnet": true, // Train stopnet predicting the end of synthesis. "separate_stopnet": true, // Train stopnet seperately if 'stopnet==true'. It prevents stopnet loss to influence the rest of the model. It causes a better model, but it trains SLOWER. "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. - "use_gst": false, - + "use_gst": false, + "double_decoder_consistency": true, // use DDC explained here https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency-draft/ + "ddc_r": 7, // reduction rate for coarse decoder. + "batch_size": 32, // Batch size for training. Lower values than 32 might cause hard to learn attention. - "eval_batch_size":16, + "eval_batch_size":16, "r": 1, // Number of frames to predict for step. "wd": 0.000001, // Weight decay weight. "checkpoint": true, // If true, it saves checkpoints per "save_step" From fbf1689d18adb28215c85d69a3a8e239740bdfc1 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:29:37 +0200 Subject: [PATCH 117/185] update model tests for ddc --- tests/test_tacotron2_model.py | 2 +- tests/test_tacotron_model.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_tacotron2_model.py b/tests/test_tacotron2_model.py index eb91b3cc..cf1d0778 100644 --- a/tests/test_tacotron2_model.py +++ b/tests/test_tacotron2_model.py @@ -51,7 +51,7 @@ class TacotronTrainTest(unittest.TestCase): optimizer = optim.Adam(model.parameters(), lr=c.lr) for i in range(5): mel_out, mel_postnet_out, align, stop_tokens = model.forward( - input, input_lengths, mel_spec, speaker_ids) + input, input_lengths, mel_spec, mel_lengths, speaker_ids) assert torch.sigmoid(stop_tokens).data.max() <= 1.0 assert torch.sigmoid(stop_tokens).data.min() >= 0.0 optimizer.zero_grad() diff --git a/tests/test_tacotron_model.py b/tests/test_tacotron_model.py index 7053a580..2bbb3c8d 100644 --- a/tests/test_tacotron_model.py +++ b/tests/test_tacotron_model.py @@ -66,7 +66,7 @@ class TacotronTrainTest(unittest.TestCase): optimizer = optim.Adam(model.parameters(), lr=c.lr) for _ in range(5): mel_out, linear_out, align, stop_tokens = model.forward( - input_dummy, input_lengths, mel_spec, speaker_ids) + input_dummy, input_lengths, mel_spec, mel_lengths, speaker_ids) optimizer.zero_grad() loss = criterion(mel_out, mel_spec, mel_lengths) stop_loss = criterion_st(stop_tokens, stop_targets) @@ -95,6 +95,7 @@ class TacotronGSTTrainTest(unittest.TestCase): mel_spec = torch.rand(8, 120, c.audio['num_mels']).to(device) linear_spec = torch.rand(8, 120, c.audio['num_freq']).to(device) mel_lengths = torch.randint(20, 120, (8, )).long().to(device) + mel_lengths[-1] = 120 stop_targets = torch.zeros(8, 120, 1).float().to(device) speaker_ids = torch.randint(0, 5, (8, )).long().to(device) @@ -130,7 +131,7 @@ class TacotronGSTTrainTest(unittest.TestCase): optimizer = optim.Adam(model.parameters(), lr=c.lr) for _ in range(10): mel_out, linear_out, align, stop_tokens = model.forward( - input_dummy, input_lengths, mel_spec, speaker_ids) + input_dummy, input_lengths, mel_spec, mel_lengths, speaker_ids) optimizer.zero_grad() loss = criterion(mel_out, mel_spec, mel_lengths) stop_loss = criterion_st(stop_tokens, stop_targets) From 4aaf57b50b7d806dfddc22d49d8ffc0ff3d9f137 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:30:12 +0200 Subject: [PATCH 118/185] train.py update for DDC --- train.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 5a345b59..612ee8a6 100644 --- a/train.py +++ b/train.py @@ -158,13 +158,14 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, optimizer_st.zero_grad() # forward pass model - if c.bidirectional_decoder: + if c.bidirectional_decoder or c.double_decoder_consistency: decoder_output, postnet_output, alignments, stop_tokens, decoder_backward_output, alignments_backward = model( - text_input, text_lengths, mel_input, speaker_ids=speaker_ids) + text_input, text_lengths, mel_input, mel_lengths, speaker_ids=speaker_ids) else: decoder_output, postnet_output, alignments, stop_tokens = model( - text_input, text_lengths, mel_input, speaker_ids=speaker_ids) + text_input, text_lengths, mel_input, mel_lengths, speaker_ids=speaker_ids) decoder_backward_output = None + alignments_backward = None # set the alignment lengths wrt reduction factor for guided attention if mel_lengths.max() % model.decoder.r != 0: @@ -176,7 +177,8 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, loss_dict = criterion(postnet_output, decoder_output, mel_input, linear_input, stop_tokens, stop_targets, mel_lengths, decoder_backward_output, - alignments, alignment_lengths, text_lengths) + alignments, alignment_lengths, alignments_backward, + text_lengths) if c.bidirectional_decoder: keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_backward_loss'].item(), 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) From 01339e94a5e43275875db2823dfad206346dd996 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:30:43 +0200 Subject: [PATCH 119/185] setup_model update following TacotronAbstract --- utils/generic_utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index f7c04859..6d347bcd 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -161,13 +161,16 @@ def setup_model(num_chars, num_speakers, c): location_attn=c.location_attn, attn_K=c.attention_heads, separate_stopnet=c.separate_stopnet, - bidirectional_decoder=c.bidirectional_decoder) + bidirectional_decoder=c.bidirectional_decoder, + double_decoder_consistency=c.double_decoder_consistency, + ddc_r=c.ddc_r) elif c.model.lower() == "tacotron2": model = MyModel(num_chars=num_chars, num_speakers=num_speakers, r=c.r, postnet_output_dim=c.audio['num_mels'], decoder_output_dim=c.audio['num_mels'], + gst=c.use_gst, attn_type=c.attention_type, attn_win=c.windowing, attn_norm=c.attention_norm, @@ -179,7 +182,9 @@ def setup_model(num_chars, num_speakers, c): location_attn=c.location_attn, attn_K=c.attention_heads, separate_stopnet=c.separate_stopnet, - bidirectional_decoder=c.bidirectional_decoder) + bidirectional_decoder=c.bidirectional_decoder, + double_decoder_consistency=c.double_decoder_consistency, + ddc_r=c.ddc_r) return model class KeepAverage(): From 9f5f3910e4d1f4882d625fa4e7faf6716a73182c Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:31:17 +0200 Subject: [PATCH 120/185] check DDC parameters in config.json --- utils/generic_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/generic_utils.py b/utils/generic_utils.py index 6d347bcd..e3daf574 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -319,6 +319,8 @@ def check_config(c): _check_argument('transition_agent', c, restricted=True, val_type=bool) _check_argument('location_attn', c, restricted=True, val_type=bool) _check_argument('bidirectional_decoder', c, restricted=True, val_type=bool) + _check_argument('double_decoder_consistency', c, restricted=True, val_type=bool) + _check_argument('ddc_r', c, restricted='double_decoder_consistency' in c.keys(), min_val=1, max_val=7, val_type=int) # stopnet _check_argument('stopnet', c, restricted=True, val_type=bool) From 16eb15a5fff436dd0f48fb96cc11dd252301a4b1 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 4 Jun 2020 14:58:18 +0200 Subject: [PATCH 121/185] lint updates --- models/tacotron_abstract.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/models/tacotron_abstract.py b/models/tacotron_abstract.py index db6cbdee..75a1a5cd 100644 --- a/models/tacotron_abstract.py +++ b/models/tacotron_abstract.py @@ -4,12 +4,12 @@ from abc import ABC, abstractmethod import torch from torch import nn -from TTS.layers.gst_layers import GST from TTS.utils.generic_utils import sequence_mask class TacotronAbstract(ABC, nn.Module): - def __init__(self, num_chars, + def __init__(self, + num_chars, num_speakers, r, postnet_output_dim=80, @@ -31,6 +31,7 @@ class TacotronAbstract(ABC, nn.Module): gst=False): """ Abstract Tacotron class """ super().__init__() + self.num_chars = num_chars self.r = r self.decoder_output_dim = decoder_output_dim self.postnet_output_dim = postnet_output_dim @@ -39,6 +40,17 @@ class TacotronAbstract(ABC, nn.Module): self.bidirectional_decoder = bidirectional_decoder self.double_decoder_consistency = double_decoder_consistency self.ddc_r = ddc_r + self.attn_type = attn_type + self.attn_win = attn_win + self.attn_norm = attn_norm + self.prenet_type = prenet_type + self.prenet_dropout = prenet_dropout + self.forward_attn = forward_attn + self.trans_agent = trans_agent + self.forward_attn_mask = forward_attn_mask + self.location_attn = location_attn + self.attn_K = attn_K + self.separate_stopnet = separate_stopnet # layers self.embedding = None @@ -48,9 +60,16 @@ class TacotronAbstract(ABC, nn.Module): # global style token if self.gst: - gst_embedding_dim = None self.gst_layer = None + # model states + self.speaker_embeddings = None + self.speaker_embeddings_projected = None + + # additional layers + self.decoder_backward = None + self.coarse_decoder = None + ############################# # INIT FUNCTIONS ############################# @@ -114,7 +133,7 @@ class TacotronAbstract(ABC, nn.Module): (0, 0, 0, padding_size, 0, 0)) decoder_outputs_backward, alignments_backward, _ = self.coarse_decoder( encoder_outputs.detach(), mel_specs, input_mask) - scale_factor = self.decoder.r_init / self.decoder.r + # scale_factor = self.decoder.r_init / self.decoder.r alignments_backward = torch.nn.functional.interpolate( alignments_backward.transpose(1, 2), size=alignments.shape[1], @@ -141,6 +160,7 @@ class TacotronAbstract(ABC, nn.Module): def compute_gst(self, inputs, mel_specs): """ Compute global style token """ + # pylint: disable=not-callable gst_outputs = self.gst_layer(mel_specs) inputs = self._add_speaker_embedding(inputs, gst_outputs) return inputs From acb367be263e40ebbc6771ed7ed3ac37fd4f92ae Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:23:11 +0200 Subject: [PATCH 122/185] bug fix vocoder training --- vocoder/layers/losses.py | 4 ++-- vocoder/train.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 22e2fb54..a24b129c 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -199,8 +199,8 @@ class GeneratorLoss(nn.Module): self.stft_loss_weight = C.stft_loss_weight self.subband_stft_loss_weight = C.subband_stft_loss_weight - self.mse_gan_loss_weight = C.mse_gan_loss_weight - self.hinge_gan_loss_weight = C.hinge_gan_loss_weight + self.mse_gan_loss_weight = C.mse_G_loss_weight + self.hinge_gan_loss_weight = C.hinge_G_loss_weight self.feat_match_loss_weight = C.feat_match_loss_weight if C.use_stft_loss: diff --git a/vocoder/train.py b/vocoder/train.py index a75c6a12..d1e6befe 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -173,7 +173,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, loss_dict = dict() for key, value in loss_G_dict.items(): - loss_dict[key] = value.item() + if isinstance(value, int): + loss_dict[key] = value + else: + loss_dict[key] = value.item() ############################## # DISCRIMINATOR From 06d3eb42cbe7607fedd744ad5e3d6988045a102b Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:25:53 +0200 Subject: [PATCH 123/185] bug fix for rwd discriminator --- vocoder/train.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index d1e6befe..82f3bee6 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -327,8 +327,12 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): y_hat = model_G.pqmf_synthesis(y_hat) y_G_sub = model_G.pqmf_analysis(y_G) - D_out_fake = model_D(y_hat) + if len(signature(model_D.forward).parameters) == 2: + D_out_fake = model_D(y_hat, c_G) + else: + D_out_fake = model_D(y_hat) D_out_real = None + if c.use_feat_match_loss: with torch.no_grad(): D_out_real = model_D(y_G) From d7022a33b3a528117dba5c87820fbe67fff0e37e Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:27:09 +0200 Subject: [PATCH 124/185] correct name --- vocoder/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index 82f3bee6..2c3a2e0a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -363,7 +363,7 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): for key, value in loss_G_dict.items(): update_eval_values['avg_' + key] = value.item() update_eval_values['avg_loader_time'] = loader_time - update_eval_values['avgP_step_time'] = step_time + update_eval_values['avg_step_time'] = step_time keep_avg.update_values(update_eval_values) # print eval stats From 2b377b548758939f2158c746d58ae16a7ff1c465 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 13:28:16 +0200 Subject: [PATCH 125/185] model config update --- .../multiband-melgan_and_rwd_config.json | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index 9aeb7933..c783877d 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -49,21 +49,28 @@ // LOSS PARAMETERS "use_stft_loss": true, + "use_subband_stft_loss": true, "use_mse_gan_loss": true, "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators - "stft_loss_weight": 1, + "stft_loss_weight": 0.5, + "subband_stft_loss_weight": 0.5, "mse_gan_loss_weight": 2.5, - "hinge_gan_loss_weight": 1, - "feat_match_loss_weight": 10.0, + "hinge_gan_loss_weight": 2.5, + "feat_match_loss_weight": 25.0, "stft_loss_params": { "n_ffts": [1024, 2048, 512], "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240] }, - "target_loss": "avg_G_loss", // loss value to pick the best model + "subband_stft_loss_params":{ + "n_ffts": [384, 683, 171], + "hop_lengths": [30, 60, 10], + "win_lengths": [150, 300, 60] + }, + "target_loss": "avg_G_loss", // DISCRIMINATOR // "discriminator_model": "melgan_multiscale_discriminator", @@ -85,7 +92,7 @@ // GENERATOR "generator_model": "multiband_melgan_generator", "generator_model_params": { - "upsample_factors":[2 ,2, 4, 4], + "upsample_factors":[8, 4, 2], "num_res_blocks": 4 }, @@ -111,7 +118,7 @@ "noam_schedule": false, // use noam warmup and lr schedule. "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "warmup_steps_disc": 4000, - "epochs": 1000, // total number of epochs to train. + "epochs": 100000, // total number of epochs to train. "wd": 0.000001, // Weight decay weight. "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. "lr_disc": 0.0001, @@ -131,6 +138,6 @@ "eval_split_size": 10, // PATHS - "output_path": "/home/erogol/Models/LJSpeech/" + "output_path": "/data/rw/home/Trainings/" } From d2cfab71d3fa8beca43904cf9380e7386a15f253 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 5 Jun 2020 14:47:25 +0200 Subject: [PATCH 126/185] bug fix for DDC model eval run --- train.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 612ee8a6..13bda5ef 100644 --- a/train.py +++ b/train.py @@ -331,13 +331,14 @@ def evaluate(model, criterion, ap, global_step, epoch): assert mel_input.shape[1] % model.decoder.r == 0 # forward pass model - if c.bidirectional_decoder: + if c.bidirectional_decoder or c.double_decoder_consistency: decoder_output, postnet_output, alignments, stop_tokens, decoder_backward_output, alignments_backward = model( text_input, text_lengths, mel_input, speaker_ids=speaker_ids) else: decoder_output, postnet_output, alignments, stop_tokens = model( text_input, text_lengths, mel_input, speaker_ids=speaker_ids) decoder_backward_output = None + alignments_backward = None # set the alignment lengths wrt reduction factor for guided attention if mel_lengths.max() % model.decoder.r != 0: @@ -349,7 +350,8 @@ def evaluate(model, criterion, ap, global_step, epoch): loss_dict = criterion(postnet_output, decoder_output, mel_input, linear_input, stop_tokens, stop_targets, mel_lengths, decoder_backward_output, - alignments, alignment_lengths, text_lengths) + alignments, alignment_lengths, alignments_backward, + text_lengths) if c.bidirectional_decoder: keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_b_loss'].item(), 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) From b736c6cdacf5e41ec78fb9c847e91975aebfa26c Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 6 Jun 2020 12:59:59 +0200 Subject: [PATCH 127/185] bug fix for TTS model restore --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 13bda5ef..a47828e0 100644 --- a/train.py +++ b/train.py @@ -542,7 +542,7 @@ def main(args): # pylint: disable=redefined-outer-name except: print(" > Partial model initialization.") model_dict = model.state_dict() - model_dict = set_init_dict(model_dict, checkpoint, c) + model_dict = set_init_dict(model_dict, checkpoint['model'], c) model.load_state_dict(model_dict) del model_dict for group in optimizer.param_groups: From 1daba4371dc0b29e907e43f88ad372b87d9f510b Mon Sep 17 00:00:00 2001 From: erogol Date: Sat, 6 Jun 2020 13:00:46 +0200 Subject: [PATCH 128/185] bug fix vocoder model restore --- vocoder/configs/multiband-melgan_and_rwd_config.json | 4 ++-- vocoder/train.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index c783877d..736f3459 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -56,8 +56,8 @@ "stft_loss_weight": 0.5, "subband_stft_loss_weight": 0.5, - "mse_gan_loss_weight": 2.5, - "hinge_gan_loss_weight": 2.5, + "mse_G_loss_weight": 2.5, + "hinge_G_loss_weight": 2.5, "feat_match_loss_weight": 25.0, "stft_loss_params": { diff --git a/vocoder/train.py b/vocoder/train.py index 2c3a2e0a..05805c68 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -421,7 +421,7 @@ def main(args): # pylint: disable=redefined-outer-name optimizer_gen.load_state_dict(checkpoint['optimizer']) model_disc.load_state_dict(checkpoint['model_disc']) optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) - except KeyError: + except RuntimeError: print(" > Partial model initialization.") model_dict = model_gen.state_dict() model_dict = set_init_dict(model_dict, checkpoint['model'], c) From 78d43664a151a3ef53fdd16315dced3661ea1080 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 8 Jun 2020 03:22:17 +0200 Subject: [PATCH 129/185] bug fix and var renaming --- models/tacotron2.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/models/tacotron2.py b/models/tacotron2.py index bbce4be9..bce21e9e 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -107,6 +107,7 @@ class Tacotron2(TacotronAbstract): decoder_outputs = decoder_outputs * output_mask.unsqueeze(1).expand_as(decoder_outputs) # B x mel_dim x T_out postnet_outputs = self.postnet(decoder_outputs) + postnet_outputs = decoder_outputs + postnet_outputs # sequence masking if output_mask is not None: postnet_outputs = postnet_outputs * output_mask.unsqueeze(1).expand_as(postnet_outputs) @@ -130,13 +131,13 @@ class Tacotron2(TacotronAbstract): if self.num_speakers > 1: encoder_outputs = self._add_speaker_embedding(encoder_outputs, self.speaker_embeddings) - mel_outputs, alignments, stop_tokens = self.decoder.inference( + decoder_outputs, alignments, stop_tokens = self.decoder.inference( encoder_outputs) - mel_outputs_postnet = self.postnet(mel_outputs) - mel_outputs_postnet = mel_outputs + mel_outputs_postnet - mel_outputs, mel_outputs_postnet, alignments = self.shape_outputs( - mel_outputs, mel_outputs_postnet, alignments) - return mel_outputs, mel_outputs_postnet, alignments, stop_tokens + postnet_outputs = self.postnet(decoder_outputs) + postnet_outputs = decoder_outputs + postnet_outputs + decoder_outputs, postnet_outputs, alignments = self.shape_outputs( + decoder_outputs, postnet_outputs, alignments) + return decoder_outputs, postnet_outputs, alignments, stop_tokens def inference_truncated(self, text, speaker_ids=None): """ From 55b8952c3d216fbf644e850fb319adfd89b56c13 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 8 Jun 2020 10:43:09 +0200 Subject: [PATCH 130/185] run D in eval --- vocoder/configs/melgan_config.json | 4 +-- vocoder/train.py | 47 +++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json index bdfdf88a..0b6b16db 100644 --- a/vocoder/configs/melgan_config.json +++ b/vocoder/configs/melgan_config.json @@ -56,8 +56,8 @@ "stft_loss_weight": 0.5, "subband_stft_loss_weight": 0.5, - "mse_gan_loss_weight": 2.5, - "hinge_gan_loss_weight": 2.5, + "mse_G_loss_weight": 2.5, + "hinge_G_loss_weight": 2.5, "feat_match_loss_weight": 25, "stft_loss_params": { diff --git a/vocoder/train.py b/vocoder/train.py index 05805c68..54b36e6b 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -181,7 +181,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, ############################## # DISCRIMINATOR ############################## - if global_step > c.steps_to_start_discriminator: + if global_step >= c.steps_to_start_discriminator: # discriminator pass with torch.no_grad(): y_hat = model_G(c_D) @@ -295,7 +295,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, @torch.no_grad() -def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): +def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch): data_loader = setup_loader(ap, is_val=True, verbose=(epoch == 0)) model_G.eval() model_D.eval() @@ -355,13 +355,52 @@ def evaluate(model_G, criterion_G, model_D, ap, global_step, epoch): for key, value in loss_G_dict.items(): loss_dict[key] = value.item() + ############################## + # DISCRIMINATOR + ############################## + + if global_step >= c.steps_to_start_discriminator: + # discriminator pass + with torch.no_grad(): + y_hat = model_G(c_G) + + # PQMF formatting + if y_hat.shape[1] > 1: + y_hat = model_G.pqmf_synthesis(y_hat) + + # run D with or without cond. features + if len(signature(model_D.forward).parameters) == 2: + D_out_fake = model_D(y_hat.detach(), c_G) + D_out_real = model_D(y_G, c_G) + else: + D_out_fake = model_D(y_hat.detach()) + D_out_real = model_D(y_G) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + scores_real, feats_real = None, None + else: + scores_real, feats_real = D_out_real + else: + scores_fake = D_out_fake + scores_real = D_out_real + + # compute losses + loss_D_dict = criterion_D(scores_fake, scores_real) + + for key, value in loss_D_dict.items(): + loss_dict[key] = value.item() + + step_time = time.time() - start_time epoch_time += step_time # update avg stats update_eval_values = dict() - for key, value in loss_G_dict.items(): - update_eval_values['avg_' + key] = value.item() + for key, value in loss_dict.items(): + update_eval_values['avg_' + key] = value update_eval_values['avg_loader_time'] = loader_time update_eval_values['avg_step_time'] = step_time keep_avg.update_values(update_eval_values) From f0616a3b2473c3d0196289cd0a1c5be9a120845a Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 8 Jun 2020 10:45:38 +0200 Subject: [PATCH 131/185] linter fix --- models/tacotron2.py | 2 +- train.py | 2 +- vocoder/train.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/models/tacotron2.py b/models/tacotron2.py index bce21e9e..46b915b5 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -130,7 +130,7 @@ class Tacotron2(TacotronAbstract): self.compute_speaker_embedding(speaker_ids) if self.num_speakers > 1: encoder_outputs = self._add_speaker_embedding(encoder_outputs, - self.speaker_embeddings) + self.speaker_embeddings) decoder_outputs, alignments, stop_tokens = self.decoder.inference( encoder_outputs) postnet_outputs = self.postnet(decoder_outputs) diff --git a/train.py b/train.py index a47828e0..a5f3d2e7 100644 --- a/train.py +++ b/train.py @@ -350,7 +350,7 @@ def evaluate(model, criterion, ap, global_step, epoch): loss_dict = criterion(postnet_output, decoder_output, mel_input, linear_input, stop_tokens, stop_targets, mel_lengths, decoder_backward_output, - alignments, alignment_lengths, alignments_backward, + alignments, alignment_lengths, alignments_backward, text_lengths) if c.bidirectional_decoder: keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_b_loss'].item(), diff --git a/vocoder/train.py b/vocoder/train.py index 54b36e6b..259c5eb7 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -519,7 +519,7 @@ def main(args): # pylint: disable=redefined-outer-name model_disc, criterion_disc, optimizer_disc, scheduler_gen, scheduler_disc, ap, global_step, epoch) - eval_avg_loss_dict = evaluate(model_gen, criterion_gen, model_disc, ap, + eval_avg_loss_dict = evaluate(model_gen, criterion_gen, model_disc, criterion_disc, ap, global_step, epoch) c_logger.print_epoch_end(epoch, eval_avg_loss_dict) target_loss = eval_avg_loss_dict[c.target_loss] From 9913724a70ae66b109f2ac83ca6e42a2545536f8 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:01:13 +0200 Subject: [PATCH 132/185] TTS config update for using DDC --- config.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.json b/config.json index 74021970..5e10c535 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "model": "Tacotron2", - "run_name": "ljspeech", - "run_description": "tacotron2", + "run_name": "ljspeech-ddc-bn", + "run_description": "tacotron2 with ddc and batch-normalization", // AUDIO PARAMETERS "audio":{ @@ -83,8 +83,8 @@ // TACOTRON PRENET "memory_size": -1, // ONLY TACOTRON - size of the memory queue used fro storing last decoder predictions for auto-regression. If < 0, memory queue is disabled and decoder only uses the last prediction frame. - "prenet_type": "original", // "original" or "bn". - "prenet_dropout": true, // enable/disable dropout at prenet. + "prenet_type": "bn", // "original" or "bn". + "prenet_dropout": false, // enable/disable dropout at prenet. // ATTENTION "attention_type": "original", // 'original' or 'graves' @@ -124,7 +124,7 @@ // PHONEMES "phoneme_cache_path": "/media/erogol/data_ssd2/mozilla_us_phonemes_3", // phoneme computation is slow, therefore, it caches results in the given folder. - "use_phonemes": false, // use phonemes instead of raw characters. It is suggested for better pronounciation. + "use_phonemes": true, // use phonemes instead of raw characters. It is suggested for better pronounciation. "phoneme_language": "en-us", // depending on your target language, pick one from https://github.com/bootphon/phonemizer#languages // MULTI-SPEAKER and GST From 0245a2e25891b16e3be11630ec0d74459f9c5768 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:01:34 +0200 Subject: [PATCH 133/185] change alignment_score to alignment_error --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index a5f3d2e7..869557e6 100644 --- a/train.py +++ b/train.py @@ -291,7 +291,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, "loss_postnet": keep_avg['avg_postnet_loss'], "loss_decoder": keep_avg['avg_decoder_loss'], "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_score": keep_avg['avg_align_error'], + "alignment_error": keep_avg['avg_align_error'], "epoch_time": epoch_time } if c.ga_alpha > 0: @@ -413,7 +413,7 @@ def evaluate(model, criterion, ap, global_step, epoch): "loss_postnet": keep_avg['avg_postnet_loss'], "loss_decoder": keep_avg['avg_decoder_loss'], "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_score": keep_avg['avg_align_error'], + "alignment_error": keep_avg['avg_align_error'], } if c.bidirectional_decoder: From f9698af06ec037ef61e6ecbabed396db5b60b24a Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:02:05 +0200 Subject: [PATCH 134/185] correction for vocoder configs --- vocoder/configs/melgan_config.json | 145 ------------------ .../multiband-melgan_and_rwd_config.json | 2 +- 2 files changed, 1 insertion(+), 146 deletions(-) delete mode 100644 vocoder/configs/melgan_config.json diff --git a/vocoder/configs/melgan_config.json b/vocoder/configs/melgan_config.json deleted file mode 100644 index 0b6b16db..00000000 --- a/vocoder/configs/melgan_config.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "run_name": "melgan", - "run_description": "melgan initial run", - - // AUDIO PARAMETERS - "audio":{ - // stft parameters - "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. - "win_length": 1024, // stft window length in ms. - "hop_length": 256, // stft window hop-lengh in ms. - "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. - "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. - - // Audio processing parameters - "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. - "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. - "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. - - // Silence trimming - "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) - "trim_db": 60, // threshold for timming silence. Set this according to your dataset. - - // Griffin-Lim - "power": 1.5, // value to sharpen wav signals after GL algorithm. - "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. - - // MelSpectrogram parameters - "num_mels": 80, // size of the mel spec frame. - "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! - "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! - - // Normalization parameters - "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. - "min_level_db": -100, // lower bound for normalization - "symmetric_norm": true, // move normalization to range [-1, 1] - "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] - "clip_norm": true, // clip normalized values into the range. - "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored - }, - - // DISTRIBUTED TRAINING - // "distributed":{ - // "backend": "nccl", - // "url": "tcp:\/\/localhost:54321" - // }, - - // MODEL PARAMETERS - "use_pqmf": true, - - // LOSS PARAMETERS - "use_stft_loss": true, - "use_subband_stft_loss": true, - "use_mse_gan_loss": true, - "use_hinge_gan_loss": false, - "use_feat_match_loss": false, // use only with melgan discriminators - - "stft_loss_weight": 0.5, - "subband_stft_loss_weight": 0.5, - "mse_G_loss_weight": 2.5, - "hinge_G_loss_weight": 2.5, - "feat_match_loss_weight": 25, - - "stft_loss_params": { - "n_ffts": [1024, 2048, 512], - "hop_lengths": [120, 240, 50], - "win_lengths": [600, 1200, 240] - }, - "subband_stft_loss_params":{ - "n_ffts": [384, 683, 171], - "hop_lengths": [30, 60, 10], - "win_lengths": [150, 300, 60] - }, - - "target_loss": "avg_G_loss", // loss value to pick the best model - - // DISCRIMINATOR - "discriminator_model": "melgan_multiscale_discriminator", - "discriminator_model_params":{ - "base_channels": 16, - "max_channels":1024, - "downsample_factors":[4, 4, 4, 4] - }, - "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 - - // "discriminator_model": "random_window_discriminator", - // "discriminator_model_params":{ - // "uncond_disc_donwsample_factors": [8, 4], - // "cond_disc_downsample_factors": [[8, 4, 2, 2, 2], [8, 4, 2, 2], [8, 4, 2], [8, 4], [4, 2, 2]], - // "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], - // "window_sizes": [512, 1024, 2048, 4096, 8192] - // }, - - - // GENERATOR - "generator_model": "multiband_melgan_generator", - "generator_model_params": { - "upsample_factors":[2 ,2, 4, 4], - "num_res_blocks": 4 - }, - - // DATASET - "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", - "seq_len": 16384, - "pad_short": 2000, - "conv_pad": 0, - "use_noise_augment": true, - "use_cache": true, - - "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. - - // TRAINING - "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. - - // VALIDATION - "run_eval": true, - "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. - "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. - - // OPTIMIZER - "noam_schedule": false, // use noam warmup and lr schedule. - "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "warmup_steps_disc": 4000, - "epochs": 1000, // total number of epochs to train. - "wd": 0.000001, // Weight decay weight. - "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. - "lr_disc": 0.0001, - "gen_clip_grad": 10.0, - "disc_clip_grad": 10.0, - - // TENSORBOARD and LOGGING - "print_step": 25, // Number of steps to log traning on console. - "print_eval": false, // If True, it prints intermediate loss values in evalulation. - "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. - "checkpoint": true, // If true, it saves checkpoints per "save_step" - "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. - - // DATA LOADING - "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. - "num_val_loader_workers": 4, // number of evaluation data loader processes. - "eval_split_size": 10, - - // PATHS - "output_path": "/home/erogol/Models/LJSpeech/" -} - diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index 736f3459..f4b91aae 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -79,7 +79,7 @@ // "max_channels":1024, // "downsample_factors":[4, 4, 4, 4] // }, - "steps_to_start_discriminator": 100000, // steps required to start GAN trainining.1 + "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 "discriminator_model": "random_window_discriminator", "discriminator_model_params":{ From c866f23af654ef7c874977b94365556093baffcf Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:02:28 +0200 Subject: [PATCH 135/185] remove weight norm for melgan generator --- vocoder/models/melgan_generator.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py index 1e47816d..e69e6ef3 100644 --- a/vocoder/models/melgan_generator.py +++ b/vocoder/models/melgan_generator.py @@ -87,3 +87,12 @@ class MelganGenerator(nn.Module): (self.inference_padding, self.inference_padding), 'replicate') return self.layers(cond_features) + + def remove_weight_norm(self): + for _, layer in enumerate(self.layers): + if len(layer.state_dict()) != 0: + try: + nn.utils.remove_weight_norm(layer) + except ValueError: + layer.remove_weight_norm() + From 1dfafe003da30679887b523f4a76635d256b969a Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:02:55 +0200 Subject: [PATCH 136/185] fix multiband melgan inference --- vocoder/models/multiband_melgan_generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vocoder/models/multiband_melgan_generator.py b/vocoder/models/multiband_melgan_generator.py index 8feacd25..15e7426e 100644 --- a/vocoder/models/multiband_melgan_generator.py +++ b/vocoder/models/multiband_melgan_generator.py @@ -29,10 +29,11 @@ class MultibandMelganGenerator(MelganGenerator): def pqmf_synthesis(self, x): return self.pqmf_layer.synthesis(x) + @torch.no_grad() def inference(self, cond_features): cond_features = cond_features.to(self.layers[1].weight.device) cond_features = torch.nn.functional.pad( cond_features, (self.inference_padding, self.inference_padding), 'replicate') - return self.pqmf.synthesis(self.layers(cond_features)) + return self.pqmf_synthesis(self.layers(cond_features)) From 74e6e29479fe7a05ade55441ef939d593651aef2 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:03:37 +0200 Subject: [PATCH 137/185] add lr schedulers for generator and discriminator --- vocoder/train.py | 56 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 259c5eb7..c563dff0 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -107,10 +107,6 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, global_step += 1 - # get current learning rates - current_lr_G = list(optimizer_G.param_groups)[0]['lr'] - current_lr_D = list(optimizer_D.param_groups)[0]['lr'] - ############################## # GENERATOR ############################## @@ -166,9 +162,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, torch.nn.utils.clip_grad_norm_(model_G.parameters(), c.gen_clip_grad) optimizer_G.step() - - # setup lr - if c.noam_schedule: + if scheduler_G is not None: scheduler_G.step() loss_dict = dict() @@ -221,9 +215,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, torch.nn.utils.clip_grad_norm_(model_D.parameters(), c.disc_clip_grad) optimizer_D.step() - - # setup lr - if c.noam_schedule: + if c.scheduler_D is not None: scheduler_D.step() for key, value in loss_D_dict.items(): @@ -232,6 +224,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, step_time = time.time() - start_time epoch_time += step_time + # get current learning rates + current_lr_G = list(optimizer_G.param_groups)[0]['lr'] + current_lr_D = list(optimizer_D.param_groups)[0]['lr'] + # update avg stats update_train_values = dict() for key, value in loss_dict.items(): @@ -244,7 +240,8 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if global_step % c.print_step == 0: c_logger.print_train_step(batch_n_iter, num_iter, global_step, step_time, loader_time, current_lr_G, - loss_dict, keep_avg.avg_values) + current_lr_D, loss_dict, + keep_avg.avg_values) # plot step stats if global_step % 10 == 0: @@ -262,8 +259,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # save model save_checkpoint(model_G, optimizer_G, + scheduler_G, model_D, optimizer_D, + scheduler_D, global_step, epoch, OUT_PATH, @@ -434,6 +433,7 @@ def main(args): # pylint: disable=redefined-outer-name # setup audio processor ap = AudioProcessor(**c.audio) + # DISTRUBUTED # if num_gpus > 1: # init_distributed(args.rank, num_gpus, args.group_id, @@ -449,6 +449,12 @@ def main(args): # pylint: disable=redefined-outer-name lr=c.lr_disc, weight_decay=0) + # schedulers + scheduler_gen = getattr(torch.optim.lr_scheduler, c.lr_scheduler_gen) + scheduler_disc = getattr(torch.optim.lr_scheduler, c.lr_scheduler_disc) + scheduler_gen = scheduler_gen(optimizer_gen, **c.lr_scheduler_gen_params) + scheduler_disc = scheduler_disc(optimizer_disc, **c.lr_scheduler_disc_params) + # setup criterion criterion_gen = GeneratorLoss(c) criterion_disc = DiscriminatorLoss(c) @@ -456,12 +462,26 @@ def main(args): # pylint: disable=redefined-outer-name if args.restore_path: checkpoint = torch.load(args.restore_path, map_location='cpu') try: + print(" > Restoring Generator Model...") model_gen.load_state_dict(checkpoint['model']) + print(" > Restoring Generator Optimizer...") optimizer_gen.load_state_dict(checkpoint['optimizer']) + print(" > Restoring Discriminator Model...") model_disc.load_state_dict(checkpoint['model_disc']) + print(" > Restoring Discriminator Optimizer...") optimizer_disc.load_state_dict(checkpoint['optimizer_disc']) + if 'scheduler' in checkpoint: + print(" > Restoring Generator LR Scheduler...") + scheduler_gen.load_state_dict(checkpoint['scheduler']) + # NOTE: Not sure if necessary + scheduler_gen.optimizer = optimizer_gen + if 'scheduler_disc' in checkpoint: + print(" > Restoring Discriminator LR Scheduler...") + scheduler_disc.load_state_dict(checkpoint['scheduler_disc']) + scheduler_disc.optimizer = optimizer_disc except RuntimeError: - print(" > Partial model initialization.") + # retore only matching layers. + print(" > Partial model initialization...") model_dict = model_gen.state_dict() model_dict = set_init_dict(model_dict, checkpoint['model'], c) model_gen.load_state_dict(model_dict) @@ -494,16 +514,6 @@ def main(args): # pylint: disable=redefined-outer-name # if num_gpus > 1: # model = apply_gradient_allreduce(model) - if c.noam_schedule: - scheduler_gen = NoamLR(optimizer_gen, - warmup_steps=c.warmup_steps_gen, - last_epoch=args.restore_step - 1) - scheduler_disc = NoamLR(optimizer_disc, - warmup_steps=c.warmup_steps_gen, - last_epoch=args.restore_step - 1) - else: - scheduler_gen, scheduler_disc = None, None - num_params = count_parameters(model_gen) print(" > Generator has {} parameters".format(num_params), flush=True) num_params = count_parameters(model_disc) @@ -526,9 +536,11 @@ def main(args): # pylint: disable=redefined-outer-name best_loss = save_best_model(target_loss, best_loss, model_gen, + scheduler_gen, optimizer_gen, model_disc, optimizer_disc, + scheduler_disc, global_step, epoch, OUT_PATH, From ecff45369b852579bddb53f7b1b540587e8786b3 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:04:02 +0200 Subject: [PATCH 138/185] print lrg and lrD --- vocoder/utils/console_logger.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py index ff7edfd0..50882160 100644 --- a/vocoder/utils/console_logger.py +++ b/vocoder/utils/console_logger.py @@ -15,8 +15,8 @@ tcolors = AttrDict({ class ConsoleLogger(): + # TODO: merge this with TTS ConsoleLogger def __init__(self): - # TODO: color code for value changes # use these to compare values between iterations self.old_train_loss_dict = None self.old_epoch_loss_dict = None @@ -36,7 +36,7 @@ class ConsoleLogger(): print(f"\n{tcolors.BOLD} > TRAINING ({self.get_time()}) {tcolors.ENDC}") def print_train_step(self, batch_steps, step, global_step, - step_time, loader_time, lr, + step_time, loader_time, lrG, lrD, loss_dict, avg_loss_dict): indent = " | > " print() @@ -48,7 +48,7 @@ class ConsoleLogger(): log_text += "{}{}: {:.5f} ({:.5f})\n".format(indent, key, value, avg_loss_dict[f'avg_{key}']) else: log_text += "{}{}: {:.5f} \n".format(indent, key, value) - log_text += f"{indent}step_time: {step_time:.2f}\n{indent}loader_time: {loader_time:.2f}\n{indent}lr: {lr:.5f}" + log_text += f"{indent}step_time: {step_time:.2f}\n{indent}loader_time: {loader_time:.2f}\n{indent}lrG: {lrG}\n{indent}lrD: {lrD}" print(log_text, flush=True) # pylint: disable=unused-argument From 0fa17bd9bb60d02b5156f853dff3785d2b1a0cae Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:04:16 +0200 Subject: [PATCH 139/185] save schedulers with checkpoints --- vocoder/utils/io.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/vocoder/utils/io.py b/vocoder/utils/io.py index b6ea7484..9d350238 100644 --- a/vocoder/utils/io.py +++ b/vocoder/utils/io.py @@ -2,18 +2,27 @@ import os import torch import datetime -def save_model(model, optimizer, model_disc, optimizer_disc, current_step, - epoch, output_path, **kwargs): + +def save_model(model, optimizer, scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, output_path, **kwargs): model_state = model.state_dict() - model_disc_state = model_disc.state_dict() - optimizer_state = optimizer.state_dict() if optimizer is not None else None - optimizer_disc_state = optimizer_disc.state_dict( - ) if optimizer_disc is not None else None + model_disc_state = model_disc.state_dict()\ + if model_disc is not None else None + optimizer_state = optimizer.state_dict()\ + if optimizer is not None else None + optimizer_disc_state = optimizer_disc.state_dict()\ + if optimizer_disc is not None else None + scheduler_state = scheduler.state_dict()\ + if scheduler is not None else None + scheduler_disc_state = scheduler_disc.state_dict()\ + if scheduler_disc is not None else None state = { 'model': model_state, 'optimizer': optimizer_state, + 'scheduler': scheduler_state, 'model_disc': model_disc_state, 'optimizer_disc': optimizer_disc_state, + 'scheduler_disc': scheduler_disc_state, 'step': current_step, 'epoch': epoch, 'date': datetime.date.today().strftime("%B %d, %Y"), @@ -22,26 +31,29 @@ def save_model(model, optimizer, model_disc, optimizer_disc, current_step, torch.save(state, output_path) -def save_checkpoint(model, optimizer, model_disc, optimizer_disc, current_step, - epoch, output_folder, **kwargs): +def save_checkpoint(model, optimizer, scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, output_folder, + **kwargs): file_name = 'checkpoint_{}.pth.tar'.format(current_step) checkpoint_path = os.path.join(output_folder, file_name) print(" > CHECKPOINT : {}".format(checkpoint_path)) - save_model(model, optimizer, model_disc, optimizer_disc, current_step, - epoch, checkpoint_path, **kwargs) + save_model(model, optimizer, scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, checkpoint_path, **kwargs) -def save_best_model(target_loss, best_loss, model, optimizer, model_disc, - optimizer_disc, current_step, epoch, output_folder, - **kwargs): +def save_best_model(target_loss, best_loss, model, optimizer, scheduler, + model_disc, optimizer_disc, scheduler_disc, current_step, + epoch, output_folder, **kwargs): if target_loss < best_loss: file_name = 'best_model.pth.tar' checkpoint_path = os.path.join(output_folder, file_name) print(" > BEST MODEL : {}".format(checkpoint_path)) save_model(model, optimizer, + scheduler, model_disc, optimizer_disc, + scheduler_disc, current_step, epoch, checkpoint_path, From 8a201c92c6a86915a36febca586d991cf5db3f22 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:05:02 +0200 Subject: [PATCH 140/185] multiband melga nconfig --- vocoder/configs/multiband_melgan_config.json | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 vocoder/configs/multiband_melgan_config.json diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json new file mode 100644 index 00000000..3a5f0673 --- /dev/null +++ b/vocoder/configs/multiband_melgan_config.json @@ -0,0 +1,150 @@ +{ + "run_name": "multiband-melgan", + "run_description": "multiband melgan", + + // AUDIO PARAMETERS + "audio":{ + // stft parameters + "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "win_length": 1024, // stft window length in ms. + "hop_length": 256, // stft window hop-lengh in ms. + "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. + "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. + + // Audio processing parameters + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. + "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + + // Silence trimming + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "trim_db": 60, // threshold for timming silence. Set this according to your dataset. + + // Griffin-Lim + "power": 1.5, // value to sharpen wav signals after GL algorithm. + "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. + + // MelSpectrogram parameters + "num_mels": 80, // size of the mel spec frame. + "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + + // Normalization parameters + "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. + "min_level_db": -100, // lower bound for normalization + "symmetric_norm": true, // move normalization to range [-1, 1] + "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] + "clip_norm": true, // clip normalized values into the range. + "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + }, + + // DISTRIBUTED TRAINING + // "distributed":{ + // "backend": "nccl", + // "url": "tcp:\/\/localhost:54321" + // }, + + // MODEL PARAMETERS + "use_pqmf": true, + + // LOSS PARAMETERS + "use_stft_loss": true, + "use_subband_stft_loss": true, + "use_mse_gan_loss": true, + "use_hinge_gan_loss": false, + "use_feat_match_loss": false, // use only with melgan discriminators + + // loss weights + "stft_loss_weight": 0.5, + "subband_stft_loss_weight": 0.5, + "mse_G_loss_weight": 2.5, + "hinge_G_loss_weight": 2.5, + "feat_match_loss_weight": 25, + + // multiscale stft loss parameters + "stft_loss_params": { + "n_ffts": [1024, 2048, 512], + "hop_lengths": [120, 240, 50], + "win_lengths": [600, 1200, 240] + }, + + // subband multiscale stft loss parameters + "subband_stft_loss_params":{ + "n_ffts": [384, 683, 171], + "hop_lengths": [30, 60, 10], + "win_lengths": [150, 300, 60] + }, + + "target_loss": "avg_G_loss", // loss value to pick the best model to save after each epoch + + // DISCRIMINATOR + "discriminator_model": "melgan_multiscale_discriminator", + "discriminator_model_params":{ + "base_channels": 16, + "max_channels":1024, + "downsample_factors":[4, 4, 4, 4] + }, + "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 + + // GENERATOR + "generator_model": "multiband_melgan_generator", + "generator_model_params": { + "upsample_factors":[8, 4, 2], + "num_res_blocks": 4 + }, + + // DATASET + "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", + "seq_len": 16384, + "pad_short": 2000, + "conv_pad": 0, + "use_noise_augment": false, + "use_cache": true, + + "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. + + // TRAINING + "batch_size": 64, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'. + + // VALIDATION + "run_eval": true, + "test_delay_epochs": 10, //Until attention is aligned, testing only wastes computation time. + "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. + + // OPTIMIZER + "noam_schedule": false, // use noam warmup and lr schedule. + "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" + "warmup_steps_disc": 4000, + "epochs": 10000, // total number of epochs to train. + "wd": 0.0, // Weight decay weight. + "gen_clip_grad": -1, // Generator gradient clipping threshold. Apply gradient clipping if > 0 + "disc_clip_grad": -1, // Discriminator gradient clipping threshold. + "lr_scheduler_gen": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_gen_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_scheduler_disc": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_disc_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_gen": 1e-4, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 1e-4, + + // TENSORBOARD and LOGGING + "print_step": 25, // Number of steps to log traning on console. + "print_eval": false, // If True, it prints loss values for each step in eval run. + "save_step": 25000, // Number of training steps expected to plot training stats on TB and save model checkpoints. + "checkpoint": true, // If true, it saves checkpoints per "save_step" + "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. + + // DATA LOADING + "num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values. + "num_val_loader_workers": 4, // number of evaluation data loader processes. + "eval_split_size": 10, + + // PATHS + "output_path": "/home/erogol/Models/LJSpeech/" +} + From 8a931e705cf7ba8bdb13e505df8ba9705f3a423a Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 9 Jun 2020 23:14:10 +0200 Subject: [PATCH 141/185] q --- .../multiband-melgan_and_rwd_config.json | 52 +++++++++++-------- vocoder/train.py | 2 +- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/vocoder/configs/multiband-melgan_and_rwd_config.json b/vocoder/configs/multiband-melgan_and_rwd_config.json index f4b91aae..0b751854 100644 --- a/vocoder/configs/multiband-melgan_and_rwd_config.json +++ b/vocoder/configs/multiband-melgan_and_rwd_config.json @@ -1,6 +1,6 @@ { "run_name": "multiband-melgan-rwd", - "run_description": "multibadn melgan with random window discriminator", + "run_description": "multiband melgan with random window discriminator from https://arxiv.org/pdf/1909.11646.pdf", // AUDIO PARAMETERS "audio":{ @@ -54,33 +54,30 @@ "use_hinge_gan_loss": false, "use_feat_match_loss": false, // use only with melgan discriminators + // loss weights "stft_loss_weight": 0.5, "subband_stft_loss_weight": 0.5, "mse_G_loss_weight": 2.5, "hinge_G_loss_weight": 2.5, - "feat_match_loss_weight": 25.0, + "feat_match_loss_weight": 25, + // multiscale stft loss parameters "stft_loss_params": { "n_ffts": [1024, 2048, 512], "hop_lengths": [120, 240, 50], "win_lengths": [600, 1200, 240] }, + + // subband multiscale stft loss parameters "subband_stft_loss_params":{ "n_ffts": [384, 683, 171], "hop_lengths": [30, 60, 10], "win_lengths": [150, 300, 60] }, - "target_loss": "avg_G_loss", + + "target_loss": "avg_G_loss", // loss value to pick the best model to save after each epoch // DISCRIMINATOR - // "discriminator_model": "melgan_multiscale_discriminator", - // "discriminator_model_params":{ - // "base_channels": 16, - // "max_channels":1024, - // "downsample_factors":[4, 4, 4, 4] - // }, - "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 - "discriminator_model": "random_window_discriminator", "discriminator_model_params":{ "uncond_disc_donwsample_factors": [8, 4], @@ -88,6 +85,7 @@ "cond_disc_out_channels": [[128, 128, 256, 256], [128, 256, 256], [128, 256], [256], [128, 256]], "window_sizes": [512, 1024, 2048, 4096, 8192] }, + "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 // GENERATOR "generator_model": "multiband_melgan_generator", @@ -97,11 +95,11 @@ }, // DATASET - "data_path": "/root/LJSpeech-1.1/wavs/", + "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", "seq_len": 16384, "pad_short": 2000, "conv_pad": 0, - "use_noise_augment": true, + "use_noise_augment": false, "use_cache": true, "reinit_layers": [], // give a list of layer names to restore from the given checkpoint. If not defined, it reloads all heuristically matching layers. @@ -118,17 +116,27 @@ "noam_schedule": false, // use noam warmup and lr schedule. "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "warmup_steps_disc": 4000, - "epochs": 100000, // total number of epochs to train. - "wd": 0.000001, // Weight decay weight. - "lr_gen": 0.0001, // Initial learning rate. If Noam decay is active, maximum learning rate. - "lr_disc": 0.0001, - "gen_clip_grad": 10.0, - "disc_clip_grad": 10.0, + "epochs": 10000, // total number of epochs to train. + "wd": 0.0, // Weight decay weight. + "gen_clip_grad": -1, // Generator gradient clipping threshold. Apply gradient clipping if > 0 + "disc_clip_grad": -1, // Discriminator gradient clipping threshold. + "lr_scheduler_gen": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_gen_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_scheduler_disc": "MultiStepLR", // one of the schedulers from https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate + "lr_scheduler_disc_params": { + "gamma": 0.5, + "milestones": [100000, 200000, 300000, 400000, 500000, 600000] + }, + "lr_gen": 1e-4, // Initial learning rate. If Noam decay is active, maximum learning rate. + "lr_disc": 1e-4, // TENSORBOARD and LOGGING "print_step": 25, // Number of steps to log traning on console. - "print_eval": false, // If True, it prints intermediate loss values in evalulation. - "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. + "print_eval": false, // If True, it prints loss values for each step in eval run. + "save_step": 25000, // Number of training steps expected to plot training stats on TB and save model checkpoints. "checkpoint": true, // If true, it saves checkpoints per "save_step" "tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging. @@ -138,6 +146,6 @@ "eval_split_size": 10, // PATHS - "output_path": "/data/rw/home/Trainings/" + "output_path": "/home/erogol/Models/LJSpeech/" } diff --git a/vocoder/train.py b/vocoder/train.py index c563dff0..a8a8f011 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -215,7 +215,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, torch.nn.utils.clip_grad_norm_(model_D.parameters(), c.disc_clip_grad) optimizer_D.step() - if c.scheduler_D is not None: + if scheduler_D is not None: scheduler_D.step() for key, value in loss_D_dict.items(): From 9b15331eeb4fbe70ef169ada72c59ebb3be67f4e Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:45:43 +0200 Subject: [PATCH 142/185] better stats logging for TTS training --- train.py | 132 +++++++++++++++++++------------------------------------ 1 file changed, 45 insertions(+), 87 deletions(-) diff --git a/train.py b/train.py index 869557e6..51c73a9f 100644 --- a/train.py +++ b/train.py @@ -119,21 +119,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, verbose=(epoch == 0)) model.train() epoch_time = 0 - train_values = { - 'avg_postnet_loss': 0, - 'avg_decoder_loss': 0, - 'avg_stopnet_loss': 0, - 'avg_align_error': 0, - 'avg_step_time': 0, - 'avg_loader_time': 0 - } - if c.bidirectional_decoder: - train_values['avg_decoder_b_loss'] = 0 # decoder backward loss - train_values['avg_decoder_c_loss'] = 0 # decoder consistency loss - if c.ga_alpha > 0: - train_values['avg_ga_loss'] = 0 # guidede attention loss keep_avg = KeepAverage() - keep_avg.add_values(train_values) if use_cuda: batch_n_iter = int( len(data_loader.dataset) / (c.batch_size * num_gpus)) @@ -179,11 +165,6 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, mel_lengths, decoder_backward_output, alignments, alignment_lengths, alignments_backward, text_lengths) - if c.bidirectional_decoder: - keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_backward_loss'].item(), - 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) - if c.ga_alpha > 0: - keep_avg.update_values({'avg_ga_loss': loss_dict['ga_loss'].item()}) # backward pass loss_dict['loss'].backward() @@ -193,7 +174,6 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # compute alignment error (the lower the better ) align_error = 1 - alignment_diagonal_score(alignments) - keep_avg.update_value('avg_align_error', align_error) loss_dict['align_error'] = align_error # backpass and check the grad norm for stop loss @@ -208,23 +188,6 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, step_time = time.time() - start_time epoch_time += step_time - # update avg stats - update_train_values = { - 'avg_postnet_loss': float(loss_dict['postnet_loss'].item()), - 'avg_decoder_loss': float(loss_dict['decoder_loss'].item()), - 'avg_stopnet_loss': loss_dict['stopnet_loss'].item() \ - if isinstance(loss_dict['stopnet_loss'], float) else float(loss_dict['stopnet_loss'].item()), - 'avg_step_time': step_time, - 'avg_loader_time': loader_time - } - keep_avg.update_values(update_train_values) - - if global_step % c.print_step == 0: - c_logger.print_train_step(batch_n_iter, num_iter, global_step, - avg_spec_length, avg_text_length, - step_time, loader_time, current_lr, - loss_dict, keep_avg.avg_values) - # aggregate losses from processes if num_gpus > 1: loss_dict['postnet_loss'] = reduce_tensor(loss_dict['postnet_loss'].data, num_gpus) @@ -232,6 +195,30 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, loss_dict['loss'] = reduce_tensor(loss_dict['loss'] .data, num_gpus) loss_dict['stopnet_loss'] = reduce_tensor(loss_dict['stopnet_loss'].data, num_gpus) if c.stopnet else loss_dict['stopnet_loss'] + # detach loss values + loss_dict_new = dict() + for key, value in loss_dict.items(): + if isinstance(value, int) or isinstance(value, float): + loss_dict_new[key] = value + else: + loss_dict_new[key] = value.item() + loss_dict = loss_dict_new + + # update avg stats + update_train_values = dict() + for key, value in loss_dict.items(): + update_train_values['avg_' + key] = value + update_train_values['avg_loader_time'] = loader_time + update_train_values['avg_step_time'] = step_time + keep_avg.update_values(update_train_values) + + # print training progress + if global_step % c.print_step == 0: + c_logger.print_train_step(batch_n_iter, num_iter, global_step, + avg_spec_length, avg_text_length, + step_time, loader_time, current_lr, + loss_dict, keep_avg.avg_values) + if args.rank == 0: # Plot Training Iter Stats # reduce TB load @@ -266,7 +253,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, "alignment": plot_alignment(align_img), } - if c.bidirectional_decoder: + if c.bidirectional_decoder or c.double_decoder_consistency: figures["alignment_backward"] = plot_alignment(alignments_backward[0].data.cpu().numpy()) tb_logger.tb_train_figures(global_step, figures) @@ -286,16 +273,8 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # Plot Epoch Stats if args.rank == 0: - # Plot Training Epoch Stats - epoch_stats = { - "loss_postnet": keep_avg['avg_postnet_loss'], - "loss_decoder": keep_avg['avg_decoder_loss'], - "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_error": keep_avg['avg_align_error'], - "epoch_time": epoch_time - } - if c.ga_alpha > 0: - epoch_stats['guided_attention_loss'] = keep_avg['avg_ga_loss'] + epoch_stats = {"epoch_time": epoch_time} + epoch_stats.update(keep_avg.avg_values) tb_logger.tb_train_epoch_stats(global_step, epoch_stats) if c.tb_model_param_stats: tb_logger.tb_model_weights(model, global_step) @@ -307,20 +286,7 @@ def evaluate(model, criterion, ap, global_step, epoch): data_loader = setup_loader(ap, model.decoder.r, is_val=True) model.eval() epoch_time = 0 - eval_values_dict = { - 'avg_postnet_loss': 0, - 'avg_decoder_loss': 0, - 'avg_stopnet_loss': 0, - 'avg_align_error': 0 - } - if c.bidirectional_decoder: - eval_values_dict['avg_decoder_b_loss'] = 0 # decoder backward loss - eval_values_dict['avg_decoder_c_loss'] = 0 # decoder consistency loss - if c.ga_alpha > 0: - eval_values_dict['avg_ga_loss'] = 0 # guidede attention loss keep_avg = KeepAverage() - keep_avg.add_values(eval_values_dict) - c_logger.print_eval_start() if data_loader is not None: for num_iter, data in enumerate(data_loader): @@ -352,11 +318,6 @@ def evaluate(model, criterion, ap, global_step, epoch): mel_lengths, decoder_backward_output, alignments, alignment_lengths, alignments_backward, text_lengths) - if c.bidirectional_decoder: - keep_avg.update_values({'avg_decoder_b_loss': loss_dict['decoder_b_loss'].item(), - 'avg_decoder_c_loss': loss_dict['decoder_c_loss'].item()}) - if c.ga_alpha > 0: - keep_avg.update_values({'avg_ga_loss': loss_dict['ga_loss'].item()}) # step time step_time = time.time() - start_time @@ -364,7 +325,7 @@ def evaluate(model, criterion, ap, global_step, epoch): # compute alignment score align_error = 1 - alignment_diagonal_score(alignments) - keep_avg.update_value('avg_align_error', align_error) + loss_dict['align_error'] = align_error # aggregate losses from processes if num_gpus > 1: @@ -373,14 +334,20 @@ def evaluate(model, criterion, ap, global_step, epoch): if c.stopnet: loss_dict['stopnet_loss'] = reduce_tensor(loss_dict['stopnet_loss'].data, num_gpus) - keep_avg.update_values({ - 'avg_postnet_loss': - float(loss_dict['postnet_loss'].item()), - 'avg_decoder_loss': - float(loss_dict['decoder_loss'].item()), - 'avg_stopnet_loss': - float(loss_dict['stopnet_loss'].item()), - }) + # detach loss values + loss_dict_new = dict() + for key, value in loss_dict.items(): + if isinstance(value, int) or isinstance(value, float): + loss_dict_new[key] = value + else: + loss_dict_new[key] = value.item() + loss_dict = loss_dict_new + + # update avg stats + update_train_values = dict() + for key, value in loss_dict.items(): + update_train_values['avg_' + key] = value + keep_avg.update_values(update_train_values) if c.print_eval: c_logger.print_eval_step(num_iter, loss_dict, keep_avg.avg_values) @@ -409,20 +376,11 @@ def evaluate(model, criterion, ap, global_step, epoch): c.audio["sample_rate"]) # Plot Validation Stats - epoch_stats = { - "loss_postnet": keep_avg['avg_postnet_loss'], - "loss_decoder": keep_avg['avg_decoder_loss'], - "stopnet_loss": keep_avg['avg_stopnet_loss'], - "alignment_error": keep_avg['avg_align_error'], - } - if c.bidirectional_decoder: - epoch_stats['loss_decoder_backward'] = keep_avg['avg_decoder_b_loss'] + if c.bidirectional_decoder or c.double_decoder_consistency: align_b_img = alignments_backward[idx].data.cpu().numpy() - eval_figures['alignment_backward'] = plot_alignment(align_b_img) - if c.ga_alpha > 0: - epoch_stats['guided_attention_loss'] = keep_avg['avg_ga_loss'] - tb_logger.tb_eval_stats(global_step, epoch_stats) + eval_figures['alignment2'] = plot_alignment(align_b_img) + tb_logger.tb_eval_stats(global_step, keep_avg.avg_values) tb_logger.tb_eval_figures(global_step, eval_figures) if args.rank == 0 and epoch > c.test_delay_epochs: From 0a8e4cf9d6a902dc386d3f8fa170836ec8ccd187 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:51:59 +0200 Subject: [PATCH 143/185] new config argument to plot tb figures at training --- config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 5e10c535..53b12fe1 100644 --- a/config.json +++ b/config.json @@ -104,7 +104,8 @@ "separate_stopnet": true, // Train stopnet seperately if 'stopnet==true'. It prevents stopnet loss to influence the rest of the model. It causes a better model, but it trains SLOWER. // TENSORBOARD and LOGGING - "print_step": 25, // Number of steps to log traning on console. + "print_step": 25, // Number of steps to log training on console. + "tb_plot_step:": 100, // Number of steps to plot TB training figures. "print_eval": false, // If True, it prints intermediate loss values in evalulation. "save_step": 10000, // Number of training steps expected to save traninpg stats and checkpoints. "checkpoint": true, // If true, it saves checkpoints per "save_step" From b3efbbf54b9a1ad84bbd73f9270847e838f2c6a8 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:52:31 +0200 Subject: [PATCH 144/185] bug fix --- train.py | 5 ++--- utils/generic_utils.py | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 51c73a9f..02f28c1d 100644 --- a/train.py +++ b/train.py @@ -222,15 +222,14 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, if args.rank == 0: # Plot Training Iter Stats # reduce TB load - if global_step % 10 == 0: + if global_step % c.tb_plot_step == 0: iter_stats = { - "loss_posnet": loss_dict['postnet_loss'].item(), - "loss_decoder": loss_dict['decoder_loss'].item(), "lr": current_lr, "grad_norm": grad_norm, "grad_norm_st": grad_norm_st, "step_time": step_time } + iter_stats.update(loss_dict) tb_logger.tb_train_iter_stats(global_step, iter_stats) if global_step % c.save_step == 0: diff --git a/utils/generic_utils.py b/utils/generic_utils.py index e3daf574..c50f8060 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -328,6 +328,7 @@ def check_config(c): # tensorboard _check_argument('print_step', c, restricted=True, val_type=int, min_val=1) + _check_argument('tb_plot_step', c, restricted=True, val_type=int, min_val=1) _check_argument('save_step', c, restricted=True, val_type=int, min_val=1) _check_argument('checkpoint', c, restricted=True, val_type=bool) _check_argument('tb_model_param_stats', c, restricted=True, val_type=bool) From ddfede1f52191fd9568a9fe5c178b2147b6e0b3e Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:55:37 +0200 Subject: [PATCH 145/185] restore vocoder scheduler if it is in checkpoint --- vocoder/train.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index a8a8f011..091a6932 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -450,10 +450,14 @@ def main(args): # pylint: disable=redefined-outer-name weight_decay=0) # schedulers - scheduler_gen = getattr(torch.optim.lr_scheduler, c.lr_scheduler_gen) - scheduler_disc = getattr(torch.optim.lr_scheduler, c.lr_scheduler_disc) - scheduler_gen = scheduler_gen(optimizer_gen, **c.lr_scheduler_gen_params) - scheduler_disc = scheduler_disc(optimizer_disc, **c.lr_scheduler_disc_params) + scheduler_gen = None + scheduler_disc = None + if 'lr_scheduler_gen' in c: + scheduler_gen = getattr(torch.optim.lr_scheduler, c.lr_scheduler_gen) + scheduler_gen = scheduler_gen(optimizer_gen, **c.lr_scheduler_gen_params) + if 'lr_scheduler_disc' in c: + scheduler_disc = getattr(torch.optim.lr_scheduler, c.lr_scheduler_disc) + scheduler_disc = scheduler_disc(optimizer_disc, **c.lr_scheduler_disc_params) # setup criterion criterion_gen = GeneratorLoss(c) From e8a59db839acc151ac2e20e5cdbd9bf6dc494dda Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 10 Jun 2020 13:57:49 +0200 Subject: [PATCH 146/185] linter fix --- train.py | 4 ++-- vocoder/train.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 02f28c1d..f6d73a4a 100644 --- a/train.py +++ b/train.py @@ -198,7 +198,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # detach loss values loss_dict_new = dict() for key, value in loss_dict.items(): - if isinstance(value, int) or isinstance(value, float): + if isinstance(value, (int, float)): loss_dict_new[key] = value else: loss_dict_new[key] = value.item() @@ -336,7 +336,7 @@ def evaluate(model, criterion, ap, global_step, epoch): # detach loss values loss_dict_new = dict() for key, value in loss_dict.items(): - if isinstance(value, int) or isinstance(value, float): + if isinstance(value, (int, float)): loss_dict_new[key] = value else: loss_dict_new[key] = value.item() diff --git a/vocoder/train.py b/vocoder/train.py index 091a6932..ce8f111a 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -17,7 +17,7 @@ from TTS.utils.generic_utils import (KeepAverage, count_parameters, from TTS.utils.io import copy_config_file, load_config from TTS.utils.radam import RAdam from TTS.utils.tensorboard_logger import TensorboardLogger -from TTS.utils.training import setup_torch_training_env, NoamLR +from TTS.utils.training import setup_torch_training_env from TTS.vocoder.datasets.gan_dataset import GANDataset from TTS.vocoder.datasets.preprocess import load_wav_data # from distribute import (DistributedSampler, apply_gradient_allreduce, From b8766c05cea3c3767157ed7540a12f9f572aee55 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 11 Jun 2020 10:48:20 +0200 Subject: [PATCH 147/185] bug fix --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index f6d73a4a..8581132a 100644 --- a/train.py +++ b/train.py @@ -237,7 +237,7 @@ def train(model, criterion, optimizer, optimizer_st, scheduler, # save model save_checkpoint(model, optimizer, global_step, epoch, model.decoder.r, OUT_PATH, optimizer_st=optimizer_st, - model_loss=loss_dict['postnet_loss'].item()) + model_loss=loss_dict['postnet_loss']) # Diagnostic visualizations const_spec = postnet_output[0].data.cpu().numpy() From 9e71d4d66d5126a13f881f42f6e80504ca0ee560 Mon Sep 17 00:00:00 2001 From: erogol Date: Thu, 11 Jun 2020 12:42:13 +0200 Subject: [PATCH 148/185] reformatting vocoder training and disable G_adv eval if step < d_training --- vocoder/train.py | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index ce8f111a..74b3e759 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -112,7 +112,6 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, ############################## # generator pass - optimizer_G.zero_grad() y_hat = model_G(c_G) y_hat_sub = None y_G_sub = None @@ -121,8 +120,8 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # PQMF formatting if y_hat.shape[1] > 1: y_hat_sub = y_hat - y_hat = model_G.pqmf_synthesis(y_hat) y_hat_vis = y_hat + y_hat = model_G.pqmf_synthesis(y_hat) y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: @@ -142,12 +141,11 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if isinstance(D_out_fake, tuple): scores_fake, feats_fake = D_out_fake if D_out_real is None: - scores_real, feats_real = None, None + feats_real = None else: - scores_real, feats_real = D_out_real + _, feats_real = D_out_real else: scores_fake = D_out_fake - scores_real = D_out_real else: scores_fake, feats_fake, feats_real = None, None, None @@ -157,6 +155,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, loss_G = loss_G_dict['G_loss'] # optimizer generator + optimizer_G.zero_grad() loss_G.backward() if c.gen_clip_grad > 0: torch.nn.utils.clip_grad_norm_(model_G.parameters(), @@ -184,8 +183,6 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, if y_hat.shape[1] > 1: y_hat = model_G.pqmf_synthesis(y_hat) - optimizer_D.zero_grad() - # run D with or without cond. features if len(signature(model_D.forward).parameters) == 2: D_out_fake = model_D(y_hat.detach(), c_D) @@ -210,6 +207,7 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, loss_D = loss_D_dict['D_loss'] # optimizer discriminator + optimizer_D.zero_grad() loss_D.backward() if c.disc_clip_grad > 0: torch.nn.utils.clip_grad_norm_(model_D.parameters(), @@ -326,25 +324,30 @@ def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch) y_hat = model_G.pqmf_synthesis(y_hat) y_G_sub = model_G.pqmf_analysis(y_G) - if len(signature(model_D.forward).parameters) == 2: - D_out_fake = model_D(y_hat, c_G) - else: - D_out_fake = model_D(y_hat) - D_out_real = None - if c.use_feat_match_loss: - with torch.no_grad(): - D_out_real = model_D(y_G) + if global_step > c.steps_to_start_discriminator: - # format D outputs - if isinstance(D_out_fake, tuple): - scores_fake, feats_fake = D_out_fake - if D_out_real is None: - feats_real = None + if len(signature(model_D.forward).parameters) == 2: + D_out_fake = model_D(y_hat, c_G) else: - _, feats_real = D_out_real + D_out_fake = model_D(y_hat) + D_out_real = None + + if c.use_feat_match_loss: + with torch.no_grad(): + D_out_real = model_D(y_G) + + # format D outputs + if isinstance(D_out_fake, tuple): + scores_fake, feats_fake = D_out_fake + if D_out_real is None: + feats_real = None + else: + _, feats_real = D_out_real + else: + scores_fake = D_out_fake else: - scores_fake = D_out_fake + scores_fake, feats_fake, feats_real = None, None, None # compute losses loss_G_dict = criterion_G(y_hat, y_G, scores_fake, feats_fake, From 28ee6af06c4e7cac09f6bd9fa8b34db57acc1746 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 11:12:57 +0200 Subject: [PATCH 149/185] enable loading precomputed vocoder dataset --- vocoder/datasets/gan_dataset.py | 25 +++++++++++++++++++------ vocoder/datasets/preprocess.py | 21 +++++++++++++++++++++ vocoder/train.py | 4 ++-- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/vocoder/datasets/gan_dataset.py b/vocoder/datasets/gan_dataset.py index 5e410151..55513e7d 100644 --- a/vocoder/datasets/gan_dataset.py +++ b/vocoder/datasets/gan_dataset.py @@ -28,6 +28,7 @@ class GANDataset(Dataset): self.ap = ap self.item_list = items + self.compute_feat = not isinstance(items[0], (tuple, list)) self.seq_len = seq_len self.hop_len = hop_len self.pad_short = pad_short @@ -77,14 +78,26 @@ class GANDataset(Dataset): def load_item(self, idx): """ load (audio, feat) couple """ - wavpath = self.item_list[idx] - # print(wavpath) + if self.compute_feat: + # compute features from wav + wavpath = self.item_list[idx] + # print(wavpath) - if self.use_cache and self.cache[idx] is not None: - audio, mel = self.cache[idx] + if self.use_cache and self.cache[idx] is not None: + audio, mel = self.cache[idx] + else: + audio = self.ap.load_wav(wavpath) + mel = self.ap.melspectrogram(audio) else: - audio = self.ap.load_wav(wavpath) - mel = self.ap.melspectrogram(audio) + + # load precomputed features + wavpath, feat_path = self.item_list[idx] + + if self.use_cache and self.cache[idx] is not None: + audio, mel = self.cache[idx] + else: + audio = self.ap.load_wav(wavpath) + mel = np.load(feat_path) if len(audio) < self.seq_len + self.pad_short: audio = np.pad(audio, (0, self.seq_len + self.pad_short - len(audio)), \ diff --git a/vocoder/datasets/preprocess.py b/vocoder/datasets/preprocess.py index 01e01e3e..be60c13a 100644 --- a/vocoder/datasets/preprocess.py +++ b/vocoder/datasets/preprocess.py @@ -1,5 +1,6 @@ import glob import os +from pathlib import Path import numpy as np @@ -9,8 +10,28 @@ def find_wav_files(data_path): return wav_paths +def find_feat_files(data_path): + feat_paths = glob.glob(os.path.join(data_path, '**', '*.npy'), recursive=True) + return feat_paths + + def load_wav_data(data_path, eval_split_size): wav_paths = find_wav_files(data_path) np.random.seed(0) np.random.shuffle(wav_paths) return wav_paths[:eval_split_size], wav_paths[eval_split_size:] + + +def load_wav_feat_data(data_path, feat_path, eval_split_size): + wav_paths = sorted(find_wav_files(data_path)) + feat_paths = sorted(find_feat_files(feat_path)) + assert len(wav_paths) == len(feat_paths) + for wav, feat in zip(wav_paths, feat_paths): + wav_name = Path(wav).stem + feat_name = Path(feat).stem + assert wav_name == feat_name + + items = list(zip(wav_paths, feat_paths)) + np.random.seed(0) + np.random.shuffle(items) + return items[:eval_split_size], items[eval_split_size:] diff --git a/vocoder/train.py b/vocoder/train.py index 74b3e759..4d1b1029 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -19,7 +19,7 @@ from TTS.utils.radam import RAdam from TTS.utils.tensorboard_logger import TensorboardLogger from TTS.utils.training import setup_torch_training_env from TTS.vocoder.datasets.gan_dataset import GANDataset -from TTS.vocoder.datasets.preprocess import load_wav_data +from TTS.vocoder.datasets.preprocess import load_wav_data, load_wav_feat_data # from distribute import (DistributedSampler, apply_gradient_allreduce, # init_distributed, reduce_tensor) from TTS.vocoder.layers.losses import DiscriminatorLoss, GeneratorLoss @@ -543,8 +543,8 @@ def main(args): # pylint: disable=redefined-outer-name best_loss = save_best_model(target_loss, best_loss, model_gen, - scheduler_gen, optimizer_gen, + scheduler_gen, model_disc, optimizer_disc, scheduler_disc, From b62ad06f4cf67cb1db5da20c72ea1bda7819f33a Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 11:37:32 +0200 Subject: [PATCH 150/185] bug fix --- vocoder/utils/console_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/utils/console_logger.py b/vocoder/utils/console_logger.py index 50882160..4f44986c 100644 --- a/vocoder/utils/console_logger.py +++ b/vocoder/utils/console_logger.py @@ -84,7 +84,7 @@ class ConsoleLogger(): color = '' sign = '+' diff = 0 - if self.old_eval_loss_dict is not None: + if self.old_eval_loss_dict is not None and key in self.old_eval_loss_dict: diff = value - self.old_eval_loss_dict[key] if diff < 0: color = tcolors.OKGREEN From bc69a54f44f066589b460a5e8def4a57acb921db Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 11:54:54 +0200 Subject: [PATCH 151/185] visualization bug fix --- vocoder/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/train.py b/vocoder/train.py index 4d1b1029..326bd90e 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -120,8 +120,8 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, # PQMF formatting if y_hat.shape[1] > 1: y_hat_sub = y_hat - y_hat_vis = y_hat y_hat = model_G.pqmf_synthesis(y_hat) + y_hat_vis = y_hat y_G_sub = model_G.pqmf_analysis(y_G) if global_step > c.steps_to_start_discriminator: From 369a91291469a6284b921fb4f4b9a66a3095136c Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 12:11:23 +0200 Subject: [PATCH 152/185] more comments to audio.py --- utils/audio.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/audio.py b/utils/audio.py index 13eab3d6..f941f609 100644 --- a/utils/audio.py +++ b/utils/audio.py @@ -57,8 +57,10 @@ class AudioProcessor(object): self.stats_path = stats_path # setup stft parameters if hop_length is None: + # compute stft parameters from given time values self.n_fft, self.hop_length, self.win_length = self._stft_parameters() else: + # use stft parameters from config file self.hop_length = hop_length self.win_length = win_length self.n_fft = (self.num_freq - 1) * 2 From 5547ddeb618eb9d8b3dbbee5b4313dc697d78b09 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 19:32:49 +0200 Subject: [PATCH 153/185] update vocoder loss implemenatations and fix MSEDLoss --- vocoder/layers/losses.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index a24b129c..4774ab4e 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -88,7 +88,7 @@ class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ # pylint: disable=no-self-use def forward(self, score_fake): - loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + loss_fake = F.mse_loss(score_fake, score_fake.new_ones(score_fake.shape)) return loss_fake @@ -96,7 +96,8 @@ class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ # pylint: disable=no-self-use def forward(self, score_fake): - loss_fake = torch.mean(F.relu(1. + score_fake)) + # TODO: this might be wrong + loss_fake = torch.mean(F.relu(1. - score_fake)) return loss_fake @@ -107,10 +108,14 @@ class HingeGLoss(nn.Module): class MSEDLoss(nn.Module): """ Mean Squared Discriminator Loss """ + def __init__(self,): + super(MSEDLoss, self).__init__() + self.loss_func = nn.MSELoss() + # pylint: disable=no-self-use def forward(self, score_fake, score_real): - loss_real = torch.mean(torch.sum(torch.pow(score_real - 1.0, 2), dim=[1, 2])) - loss_fake = torch.mean(torch.sum(torch.pow(score_fake, 2), dim=[1, 2])) + loss_real = self.loss_func(score_real, score_real.new_ones(score_real.shape)) + loss_fake = self.loss_func(score_fake, score_fake.new_zeros(score_fake.shape)) loss_d = loss_real + loss_fake return loss_d, loss_real, loss_fake @@ -126,11 +131,15 @@ class HingeDLoss(nn.Module): class MelganFeatureLoss(nn.Module): + def __init__(self,): + super(MelganFeatureLoss, self).__init__() + self.loss_func = nn.L1Loss() + # pylint: disable=no-self-use def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): - loss_feats += torch.mean(torch.abs(fake_feat - real_feat)) + loss_feats += self.loss_func(fake_feats, real_feats) loss_feats /= len(fake_feats) + len(real_feats) return loss_feats From 8f72ad900ad1d1727a119326cd21ea4a84b3074d Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 19:50:07 +0200 Subject: [PATCH 154/185] remove redundant params in vocoder config file --- vocoder/configs/multiband_melgan_config.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json index 3a5f0673..164fe037 100644 --- a/vocoder/configs/multiband_melgan_config.json +++ b/vocoder/configs/multiband_melgan_config.json @@ -20,9 +20,6 @@ "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) "trim_db": 60, // threshold for timming silence. Set this according to your dataset. - // Griffin-Lim - "power": 1.5, // value to sharpen wav signals after GL algorithm. - "griffin_lim_iters": 60,// #griffin-lim iterations. 30-60 is a good range. Larger the value, slower the generation. // MelSpectrogram parameters "num_mels": 80, // size of the mel spec frame. From 3c20afa1c98beb292055a493b8957526346cebf3 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 12 Jun 2020 20:55:06 +0200 Subject: [PATCH 155/185] do not call .item() if returned loss is not torch type --- vocoder/train.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/vocoder/train.py b/vocoder/train.py index 326bd90e..41b3c1ec 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -217,7 +217,10 @@ def train(model_G, criterion_G, optimizer_G, model_D, criterion_D, optimizer_D, scheduler_D.step() for key, value in loss_D_dict.items(): - loss_dict[key] = value.item() + if isinstance(value, (int, float)): + loss_dict[key] = value + else: + loss_dict[key] = value.item() step_time = time.time() - start_time epoch_time += step_time @@ -355,7 +358,10 @@ def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch) loss_dict = dict() for key, value in loss_G_dict.items(): - loss_dict[key] = value.item() + if isinstance(value, (int, float)): + loss_dict[key] = value + else: + loss_dict[key] = value.item() ############################## # DISCRIMINATOR @@ -393,7 +399,10 @@ def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch) loss_D_dict = criterion_D(scores_fake, scores_real) for key, value in loss_D_dict.items(): - loss_dict[key] = value.item() + if isinstance(value, (int, float)): + loss_dict[key] = value + else: + loss_dict[key] = value.item() step_time = time.time() - start_time From 98fd3b53f293e6908509982f22b4ad8479a566b5 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 15 Jun 2020 11:28:27 +0200 Subject: [PATCH 156/185] load mel features if 'feature_path' is provided --- vocoder/configs/multiband_melgan_config.json | 2 +- vocoder/train.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json index 164fe037..81048e31 100644 --- a/vocoder/configs/multiband_melgan_config.json +++ b/vocoder/configs/multiband_melgan_config.json @@ -111,7 +111,7 @@ // OPTIMIZER "noam_schedule": false, // use noam warmup and lr schedule. "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "warmup_steps_disc": 4000, + "warmup_steps_disc": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "epochs": 10000, // total number of epochs to train. "wd": 0.0, // Weight decay weight. "gen_clip_grad": -1, // Generator gradient clipping threshold. Apply gradient clipping if > 0 diff --git a/vocoder/train.py b/vocoder/train.py index 41b3c1ec..fd44c470 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -441,7 +441,12 @@ def evaluate(model_G, criterion_G, model_D, criterion_D, ap, global_step, epoch) def main(args): # pylint: disable=redefined-outer-name # pylint: disable=global-variable-undefined global train_data, eval_data - eval_data, train_data = load_wav_data(c.data_path, c.eval_split_size) + print(f" > Loading wavs from: {c.data_path}") + if c.feature_path is not None: + print(f" > Loading features from: {c.feature_path}") + eval_data, train_data = load_wav_feat_data(c.data_path, c.feature_path, c.eval_split_size) + else: + eval_data, train_data = load_wav_data(c.data_path, c.eval_split_size) # setup audio processor ap = AudioProcessor(**c.audio) From 460d0675a6657f4037d38340ed7b997eb90ef593 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 15 Jun 2020 11:47:59 +0200 Subject: [PATCH 157/185] bug fix for vocoder feature macthing loss --- vocoder/layers/losses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 4774ab4e..22237077 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -139,7 +139,7 @@ class MelganFeatureLoss(nn.Module): def forward(self, fake_feats, real_feats): loss_feats = 0 for fake_feat, real_feat in zip(fake_feats, real_feats): - loss_feats += self.loss_func(fake_feats, real_feats) + loss_feats += self.loss_func(fake_feat, real_feat) loss_feats /= len(fake_feats) + len(real_feats) return loss_feats From c90145eef91350e476d64070fd63001ea646c097 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 15 Jun 2020 14:16:31 +0200 Subject: [PATCH 158/185] add feature path to vocder config --- vocoder/configs/multiband_melgan_config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json index 81048e31..7ba48854 100644 --- a/vocoder/configs/multiband_melgan_config.json +++ b/vocoder/configs/multiband_melgan_config.json @@ -92,6 +92,7 @@ // DATASET "data_path": "/home/erogol/Data/LJSpeech-1.1/wavs/", + "feature_path": null, "seq_len": 16384, "pad_short": 2000, "conv_pad": 0, From f3d4d1f83178e6c8519905400c58b1f52dda1d58 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 15 Jun 2020 19:26:26 +0200 Subject: [PATCH 159/185] bug fix init AudioProcessor in train.py --- vocoder/train.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vocoder/train.py b/vocoder/train.py index 144d63c3..fd44c470 100644 --- a/vocoder/train.py +++ b/vocoder/train.py @@ -448,6 +448,9 @@ def main(args): # pylint: disable=redefined-outer-name else: eval_data, train_data = load_wav_data(c.data_path, c.eval_split_size) + # setup audio processor + ap = AudioProcessor(**c.audio) + # DISTRUBUTED # if num_gpus > 1: # init_distributed(args.rank, num_gpus, args.group_id, From f18f6e6d3e8473d0ffcceb3a7108e1cdfa197558 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 16 Jun 2020 12:33:36 +0200 Subject: [PATCH 160/185] plot spectrograms undenormalized if no ap is provided --- utils/visual.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/utils/visual.py b/utils/visual.py index 87fbc8e4..3d95c2e3 100644 --- a/utils/visual.py +++ b/utils/visual.py @@ -27,14 +27,15 @@ def plot_alignment(alignment, info=None, fig_size=(16, 10), title=None): return fig -def plot_spectrogram(linear_output, audio, fig_size=(16, 10)): - if isinstance(linear_output, torch.Tensor): - linear_output_ = linear_output.detach().cpu().numpy().squeeze() +def plot_spectrogram(spectrogram, ap=None, fig_size=(16, 10)): + if isinstance(spectrogram, torch.Tensor): + spectrogram_ = spectrogram.detach().cpu().numpy().squeeze() else: - linear_output_ = linear_output - spectrogram = audio._denormalize(linear_output_.T) # pylint: disable=protected-access + spectrogram_ = spectrogram + if ap is not None: + spectrogram_ = ap._denormalize(spectrogram_.T) # pylint: disable=protected-access fig = plt.figure(figsize=fig_size) - plt.imshow(spectrogram, aspect="auto", origin="lower") + plt.imshow(spectrogram_, aspect="auto", origin="lower") plt.colorbar() plt.tight_layout() return fig From 0de38c261769a1f184c906589882a8fe79951a4a Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 16 Jun 2020 12:34:10 +0200 Subject: [PATCH 161/185] fixing naming convention in vocoder losses --- vocoder/layers/losses.py | 14 +++++++------- vocoder/utils/generic_utils.py | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index 22237077..fe13fa8a 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -87,17 +87,17 @@ class MultiScaleSubbandSTFTLoss(MultiScaleSTFTLoss): class MSEGLoss(nn.Module): """ Mean Squared Generator Loss """ # pylint: disable=no-self-use - def forward(self, score_fake): - loss_fake = F.mse_loss(score_fake, score_fake.new_ones(score_fake.shape)) + def forward(self, score_real): + loss_fake = F.mse_loss(score_real, score_real.new_ones(score_real.shape)) return loss_fake class HingeGLoss(nn.Module): """ Hinge Discriminator Loss """ # pylint: disable=no-self-use - def forward(self, score_fake): + def forward(self, score_real): # TODO: this might be wrong - loss_fake = torch.mean(F.relu(1. - score_fake)) + loss_fake = torch.mean(F.relu(1. - score_real)) return loss_fake @@ -172,7 +172,7 @@ def _apply_D_loss(scores_fake, scores_real, loss_func): if isinstance(scores_fake, list): # multi-scale loss for score_fake, score_real in zip(scores_fake, scores_real): - total_loss, real_loss, fake_loss = loss_func(score_fake, score_real) + total_loss, real_loss, fake_loss = loss_func(score_fake=score_fake, score_real=score_real) loss += total_loss real_loss += real_loss fake_loss += fake_loss @@ -286,14 +286,14 @@ class DiscriminatorLoss(nn.Module): return_dict = {} if self.use_mse_gan_loss: - mse_D_loss, mse_D_real_loss, mse_D_fake_loss = _apply_D_loss(scores_fake, scores_real, self.mse_loss) + mse_D_loss, mse_D_real_loss, mse_D_fake_loss = _apply_D_loss(scores_fake=scores_fake, scores_real=scores_real, self.mse_loss) return_dict['D_mse_gan_loss'] = mse_D_loss return_dict['D_mse_gan_real_loss'] = mse_D_real_loss return_dict['D_mse_gan_fake_loss'] = mse_D_fake_loss loss += mse_D_loss if self.use_hinge_gan_loss: - hinge_D_loss, hinge_D_real_loss, hinge_D_fake_loss = _apply_D_loss(scores_fake, scores_real, self.hinge_loss) + hinge_D_loss, hinge_D_real_loss, hinge_D_fake_loss = _apply_D_loss(scores_fake=scores_fake, scores_real=scores_real, self.hinge_loss) return_dict['D_hinge_gan_loss'] = hinge_D_loss return_dict['D_hinge_gan_real_loss'] = hinge_D_real_loss return_dict['D_hinge_gan_fake_loss'] = hinge_D_fake_loss diff --git a/vocoder/utils/generic_utils.py b/vocoder/utils/generic_utils.py index 179c4064..80c97f1a 100644 --- a/vocoder/utils/generic_utils.py +++ b/vocoder/utils/generic_utils.py @@ -29,9 +29,9 @@ def plot_results(y_hat, y, ap, global_step, name_prefix): plt.close() figures = { - name_prefix + "/spectrogram/fake": plot_spectrogram(spec_fake, ap), - name_prefix + "spectrogram/real": plot_spectrogram(spec_real, ap), - name_prefix + "spectrogram/diff": plot_spectrogram(spec_diff, ap), + name_prefix + "spectrogram/fake": plot_spectrogram(spec_fake), + name_prefix + "spectrogram/real": plot_spectrogram(spec_real), + name_prefix + "spectrogram/diff": plot_spectrogram(spec_diff), name_prefix + "speech_comparison": fig_wave, } return figures From 6948e4ce386a3e7215adb7b2e4be0aa5dfb1bf28 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 16 Jun 2020 12:35:28 +0200 Subject: [PATCH 162/185] change sample data --- tests/data/ljspeech/wavs/LJ001-0001.wav | Bin 309040 -> 425830 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/data/ljspeech/wavs/LJ001-0001.wav b/tests/data/ljspeech/wavs/LJ001-0001.wav index a4662ab0cb12f959da2c50d7f3c273d583fc6128..a274be89422809113adc336e624afeb255cdc67a 100644 GIT binary patch literal 425830 zcmY(rWtiJI+cqpaoJ=xdnoNeV?Ub3@Ei*GS;}*8e%*@Qp%&=vqZ95QV=ESyMP4DOX z@kNL2fGu65OR~>X>Ds1c%Yh4+pjXqLEk;h5o-PCcV5nsF1mLf;0N_9fh7XxOq#ioQ z3N6rqHVbq?H}s+sf?>1~u>3qaDlAkuXk!B|-~j>PgJh8O=RFHB0qxH@sDc0A3qzmi z=(qBMqpR6y5xUMN&l3G5&wY73`ZHQEdcj>whi7Kga)R%={yH zxz21<%4;dtvAp*3*2?7sAcn4u!XT0@fNbSMmh(U-+LylzpzlLS@(?OfnE0brc{}A- zm$&dgnONxE|7!j7HLAD#Sbk2qZa6A5bSCzv{c;)pcQrs7lv}ObmVD$30T3ZyihvmT zM2J2mA&D92%JNsaJw`Q`1F*HFHdM@)I)Avw#XWg^-B=W*tr-3Upo)_8he-UX$M;qFlsCfQZHiT>&`M=ix=d*Ha{ZIOGzm{9Cd`}@c%k5h( zS-HLb=f(0Pj@m4bi}E-u*PMl}D7SLC#o-?tVIYkBNFaG2qyZQ7!*VNx(Qi@IN6LL3 zg>2wOpGALklYkT;M>QlMAJxG}=jxE1l2Fa%l1hODq@tRws5UzCjuRS?e0FF?J?;T~ z1E0WC@De--AHnPJ415cJK_lD`OJFhl0zaU$qDXJ?A2|s)3}k}FU<5G0%}Dx8AO+n) zb)ZGL|7fFV)%lxwCRQzcF;Rg$Nxdc3Bi9{Fd`>JUuSZUVABUHP2gWufj>Txi zQlO?bQLV6l!7Hpaegrh7x#=qGAT5)*kk*vmmbr#Ko_my2hpA^!bPF{fjs+zIlj=pW zNDtYJI1nXco8z4$Jz{x8II)AgP6Bc?^icDO1JpN|Po=Gblme@^f5`GH#@hB*PlOaisrX18vsw>%(st)H+Ecgz7hciHb z&=5?<9KZ)LOomMZXTVi(AN&OK!4ImWSOa>1ncyOlas|8sP9P6GMp<++7!7X0?(i<$hprETPjESC z4I0DB;0f#kU%?`{k21m4;1L*s-9^$ALm8M455TFg9mN5)K{a?4GT|)v2DC!;EAW2U zSL{2@jVZArFrT_e-J%9lRjI)!LVAJipp0^mr${l305+xueSjTwMLD1vj8MZ-R93|z zU@|y>YVQty!=~^Mv_lpc03N{g@HpCDKo$D_C(Oi70t3)sarheCKyk_izmN~JU>oo+ zOhu9UmfAtBqd4#(tPb+P6lBXrU=G%z76;=rx zpqfxm$sXhYYAWmpXc&$`EC)LXcftp#b{04YFl+^i;<~^Ly1)fgBP7vfxB=D&r@>{= z2J8o$z(!=t5#S*@^1%eu=1edV)Wb%DAk~zT!P&4AHHaF4dQuix22O!%s9!V(?Xb0= z6z%~opaI{h|0o~)4JSe+`lSX~4y&WHf5SPb|E>Uoz&*gl4B#o~3{2n$_z9Q8P7uW( zb%Tmfw<#vdJNZ}?6JiYP5x54gpVq6G5`KjP$}8MuMzu$NdxP?sAIWWjx8Oj~57j9| z^-Kf9P_EAfn}G^U0=ux@*kf=4`Cp1O(4z>P4$n~opaNWmYA^(S+ZGH*y~PPnz+xod zR2Zcy!dFz3$^p}nK3}k@SVOEcinN|!3uuOVNn_9uvSBME{}K2JZbG?qGB^$A!iJy- z#bA4sKbxRfdyV8Ah2kt9>_fTrJBnBmWz5YGg8|ga02Fy|QCt)7C5ok&fPq!Ro`K%L zgfwagDuZfZE|`bB+z0h&Hp-9RAQRk$jZi5V)LhCy^@A%R7xj(vXy}N8 z-zXwhqUd`993Tg4g`#;EHWM3w{e|UXUy*G^$h!pPM%taAW>HhAMJQe#P(LXX^@fU3 zjgha1!-Z(%=?Z3`D1HTAg0J8|;6;7lF<64+Yl{47g8!ko{DNX?7d(cnb{oaPzet<= zXq1b?r|={i1L9~L?1((@3slC$7z^WLQILvtM?Hy!ZN|=_vI?7zZ9`ilEFBYIx4}R( zn(csUc!H`#O()&NGNL=tk&qEoB8|`z(ZsLB@x+$IuEfT~%><7aM1+V_WN)f9%tX2H zBQ_N;#i!6t(QLFO^aT9|<2rLFtB{?=*}@5OYH(X|M{&j6F`R2`C+jFPk8zN87P|<4 zkp)Dj_&?ELcu#0?uyvr5|F)0oo98{~mHBr0cKS;L)k5>a2O_tkhhy#ICGpdVRRl?# zCU2v>*$X_vI?!4%Fm{}KN$^!XNv=>|Nfo8P%aCOyWff)?rT@?zR}PbC_$!%jU}UYGw=aBj#KqC%%aobci>KXM~lKc0vm zPFzAd=Tld40cWH5VoFBVh=LXs?^LK%I5aOUdvhi;^H}DzY%1H8xi$5kbPh*B?)D9^ zPS8y&zWb}%uh+k1#gj^GrMq;^4MR=Y)*24nJ=VL#KRYlpcrmml9E6uW#D1h5Sb7? z7_AYh86F#|6j<*+do{Ol_Q3RaX(H_@O{%twc2{cc zRI93&G+n@AbWM!&54WWlR+bf%-PRAXba1S5H}~dwb~vZoPMCxSsbRfwq*dz94&0Ai zil-)4$2qYF;TfSG!G?jW!Dy&{Y#c~1nf;XgC(eC&G_ z2JzGJ)iF_ITyTN^mhY(VAAgllQDk63h6h+B$w2v1(>ncNCNsmJRcSL*wy3{rR;7Y; zL*}WB=4t$t-=g;HS#U{cj$7hbVXbQGnU`5oxkiZi`2|D{W6X+|7E-ATaG))>97UZxkmr`!Z>{4+>XToRD8J zyMJn1$+e^m)-|jOs014jAigkc@UC@!vvx9#F;q9G4F`>FEMsi-oju%{UYc)*Zq1WkMOMU%=5nWw)b@njfxtH2Fy#milQI#`f`(WiL91PqG+cbl2tozamDNk+jHAx zPF2kjMz{g`WUvS_$osJyk->qUo?@rc&O_F_Yie!kVP0;f>_c70JyKt7Uw{8Y|5U%p zzscXscfcF+W_V)WypTEa4C}x>mwZuPPf;S(N}Efs%OWX9vS9AM3ZV+-oUs`()mLGR zH=XqmZ;oB3N@Lu}4gYxe0q1c09qT;H9&>f`Xv;ZUb*IU#_V)Kx^U-~yd_TQ;zJb1N zzKXsh{$k%R|DnjTcnY19^h?-AUQw1V87_V$8KQWtJ&}8}U~#2w6((i(PFo?*7WCs@ zXY|DTV>PL=SXN|>e}Vg@~Wi=GXBt1lvMAM|*)TvpedCLlCR@jz%IU_sug>1NROp=f( z!yi%?Vr|3WfY$rBd#lrLtzd~8W5##p8ukjVbMAlLHC$_45mzfOD{v@KJ6Jbx!rR>Y z-tG3(3EhlOXN=_^7w?d{#Jfc);$O0snyFcT&1$Ou>p1Ga@-bUVAK5t|RIg-6j)K_{&dQP}s;Nqvs zc$#h*>+(+&oXOA2UzXKVb6(y+beEgLeu3`xIwu-N(}H>axYzHvYB^*YWTv^+zDl}6JVItld8lRN zJTE9Hm|8d^e@I4ebxZj(;amRFq)zmegfOzhyVIp|t+8J<)iRFN|JEHgRYf_po9U5Z zuVJX=np5oU>HX!a?w#a&~;~*cqa25-7bR^GZ(3c&TM+<}6`h^};&^ z6AJ`chg1vX|A>bs^F$V2Caoe>5Pj?y`6+iLYs_$?Y*k5;u9dME#d2#?is`qdk@K^= zg`4dPI;GC9?ixOm?}aZZQb?_%t3(k=v81l-i1?c*u6UYyJ-u~7S;b=&ZdCY|TSrqQ z&y&m+xP@Di_cNP-n=xMSpufof+11FVH+|Pz^^c4!6WyTKoi4kkFE%f73~@Jh^>bfw zEpV;z-0*a9Kk_b&{zpyXSVWV=lVw`@XQ@FkFZD#aBzJSg#+9gwyb8L^pX%m{9TJ;F zD&52{U~s6>k*dKPevkX9?UZq)uCK0GU(tBb&{vQt)2xFXBkfOZqwJaXLg!5P za(9`hF!GuhMz;wTCNB}Ml~ol#mpxU#&>qgYP>HHMr?ReSNA70rGxd2{BWXL?9f6JU z5HyWl4!;i1^1pR`vwYMaD%-3p(685BC~H}|w^U~6YMJj)xvo1lJI^?H&Nr?lE}6Tt z|5j`TRhg5S{4V)|{HH`Jd8K%v+LfMGz$$7{G_hz+LAOkx-J_nR%v2tis=2G^KI*U7 z&{*S8miMB=YT9C`W7w>h>Kd2sEdE;Dxa@+lvyHOj_T$zx+f~~-M}d2vtJourNE5mA zQob~~p|qE5x@eHJNZBQIWG=4~y=Ypc6BSnG=4UiXJEiHSwka_*+`CO5fko!hX)qvF)~fw7G1!Gv>&4O1%xkJfc18gW#la zube66i1QTv)vq&D1=B0!R(M?y$rEJtNdKPRLt9s~R6dm3ntqT+I% zZmwtQZ5Ubh?DxrE3x7W@-D6Bxa&676LhD-lCr4-3O1IP5+C4BdDXziy^FztiqzTzO z;b!R+^}X~vdFBcaE9@*dSx}JEAuX zyqhL1Fbu3eQY(X3j17?$L={-IC=J8t_z`!@mGw!{6qYwB9^FyaF6_* zCXzlg`*iNl?7BJga@iUGY8I!?Q*o7jWPEN{=5AUBH94V({0`LiH}Lbk9GBJJ(frnM z)9}gA+oZ8 zP?g;%4bRx3IjEQ?E#r0M?&pRXjqrWsw3s3|%IkJiG!HahC>vR-*DcfUGfps<7`qy` z8LWm$md%z-%WZ3OtKQbZcPzpri`WwG18%nPF2BF1rE;$3S6bT~enGAL-4!3^-^=(r z`&#-Y)o0mBem?s%cL8e)Z3Q-yh(yl@8+bR_ZWu4>$YNUA^0Mo?b4H~h$6(hp4D&5@ z(a2e7^I7w(CWp^2jrOB`=GNn=lEcE$D63pZk*3$tybVFq~)y773JO1u2R+z z-{NiJ)#XxjI=&s=OQ<4N-!|tU%SS`3)KRjzEJruTpwugMm-JfwK$Fcp&15mVt<9{1 ztlhoULZ8SRoFlA7+;7Q`h3{om)UFhUHY0amempO$LiN0@xw3-WnQHY1S%2XwKE{8~ ztUzO7K5}cUcVLsJy8WDak6u~YwQOPFf-+1{MtIi2#Kq4FtLocUedUpYZOP25O0hF8X}LDy41VyS_J zzW2^CmaB$R-DQ2T?v}oB+5OTa1IIq)PZksel z@FI5U zTX}O;U-cc$v$UNVtc*oz`Keb^eyE=+8_SK7<&q51+@#U$xA-rzG&Um$yh8Uy=L&lY z>glH~C#@Qr*jn4V$+pnm!%^E|vbT3AT?zMe&lz8{;Dbo-#0v5XY>b~^j^W(qr3;!0 zM@xXhqgtlEn({&;OWmZ|qyDIztk@{8Eaix*B%exp&8f|FVmqi@LL93W8t*^tHF$WQ z4X(c(YwYJyHvVcOti!DXtxc>QtN}|`+dKOJXCHTOuQr$ztwNlHGx1>z8e7SmAjlSH z%Z2K_sV~!NXUxesnsGYgP`WqmS!!8|QuSF{QPeQ$1gkF%gIyEnBL3iJUmG_I<>x4x z0jLd8{TKaCeP4YoeM0BaH!wak#Vx=tb6xOt4!2J1g~xFPb1|ni9~U*39adFMU6uYb z<5K2~tlimNa(-v4vwvqiO}m@YT^

=l)=@v0H>7mWgJuOT2YmGi<=T(XdH(r)*H! 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 X!?&c0&tuxMijB9q4^us!wT# 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�LI#YTvzcVN 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�R|NX8i1PjG$)V?EFy2g8$+n+Td9Z2j|caHcoH!jxwM;QDE_rV9C4&d; zNx6k;%R6!k=B8})`b(%clJRQ) z&v7Z9`62XxlX$P5AQxFcN|n*0D}k`p7VW$N43JW|qPZBs*Ky@P@uYm9xam_?r|Km43!wlOBPwEKH zaI?_%w?Qvh;EBH>;+mOnXHK({s>p` z1y3nP{eVc@2QVV4;yf`MPxdHU^)A{kA2oiFU<#PQGG0?jCdR$qa!-X8Zc0r&AA?jQhq+!eIPZk#SMumZI}KYd3O65054VOHORRe%R? zzIiBi$+)pse8$Z46|9>( zm}l1F73TbZ&pd&A-z(IheML*IMH_d;{MG_ryP@a)i+1aQQBf2W!`5U)WQZo9JuhMe z4@1S(7R+fbu#0j*?s2K-FxGy8+Vd1w&;XRX%^2M;@R5U==TF?p-xv`|cpjxt=W7Sg zvM8Q%2fW%h%mlA6LMMZ|v;%AGHQdQ`{A&<;%yC@R|9G3%(U+g%961s9)dPLbfM?1f zTeTDPq2sukb9k-`&;ws#HJXa+`V+5|inXyS+Hf-JdnaIZIEib@MXP3jYPA6G^&5Wg zIX=?CU&=xqnHR6o8T0!#+z(6qiED6UNB9==`yur6KA`MnU{`UCs7>bMeh%ZRGC&Q= zKpULLRnVYdrQ&%cV!WMJi=vmWKutQx%b+js!#GWoO)B=dLBjt|7OLCO57^IW};vc0kW|%>k_s^&s$z-f)vD8bjlA_3#xaJ3HSIkaU zH3|`y?&$eF)J#01Q}PG2?=8_t9VIr(704e-b0R4F&{HaiC&=mKY-tXarqm)lb#KYUlPLLnpi*tyD>^+&07BXMS za?s2!C66lI(L2hh&E?ZnU*frZ1HEcKag`h^w^!z|tJHz~Iy!|t9&SyxVYW)Gh_|#y zo&eo?5uyT}EuKK#e_5$JK{Gpus?utr3j2@TT$GtMWItgLQNZd^mETWuT-hx&CO!mB|7b;eHp|nL7{t59|@t_}Hl0P%;<(1+n zss}YyjSu@Zztl3Jfx2&?^VHDZ;e+H2dNLp8#;UWVv8Zvs!cQURYkLP@N;Aw~gE3-# z!zok~=MwSUDWS4-7OH{H0hwv5&G0qhKGAGwopuAcJ-9-5PT9b()yTpL%0^xY%S<9I z;k2=w*`j6s6P2i^6-f^@$t&X>B?6ZLo{R!E_1z zOD`s$ibbfc^m*xyRDx|Mfi+GP7uvDCC`TZlyFm8}-@)0qig1CPz{%l0#1H0~ zO_fFv8|a?I7JjMvkX=Q5=5IU;DE2a6Nj%3~BHPGw)X&NSayF{#*DxnlH9Sv!rN61RbVZq_8MYN}W-Drj@>`iB zT*)NP{oA8_2E^>3~k=ld*T~7(Er3J<- z{uOePK_5(Juc$|a7EC?D!p`F>D`gEYLr2*e#9Lo=`&c0+^gwe~8KGJ3&n3DUYx)P! zGIfye%C(e6sp-^uVY8-uc(d5rvMbaxY}Gj7^l9pUf|1I3qz6+M3K4^CbULxMKiNA&lhT@@->JLqMi51^-O~jMRN1fuo zBG(6^OYSEKB;bFR|rqpL!ticEoQy9yQUsfQ!F8!VKq`y_JI-~xMtd@ z%nmH$3N=du4J5^~GT0ep*?2XNof{~kxklxMdw|9}pDvWDll`Uo>NZ3BV4TuGOZzA4 za>#1_Y5GchIbs`I0%V?Bas!LTw^?3lDi*3j-4u0XtiGbSD=?gu4D);!!fu$GCWaU%~qni3tQCz+M$7sOdYnoP?XXtdgdiaqyJ)WdY8U0ywYyw z&r993BC7Z%5DsI$b1U({yfS#7jF;C+Z8YEL-eHq)g-ZiDx;x&n7x&$>TK|as?0l^a zYAU#64awvu-&SjmJC1&D3Kve$ULpPryf7J=mN~;rZOzjiDz}j7862sZwKA%$3)F$*xxk^xNgx#mL9g+a`6>e@IP_91?l)+g!b9E8-q5 z`pqAeUaqI+byNlaP4<>H*RfK&Flx`wn%u{TnT~tpVe`{~G4#o3(@xE=qvw|P|QCkfn+WD1T5oOOC6YN;xnX72tgv0@)C+k>L zL(Td01GZ)Mw^_}V9Z|mrXSohU6tMZ(?b$=oKirF5b>gqeld>wrF4rCU26l^O-?stg zJux+Z9;CHVL%cVH!P?`b!`H>opAF@Y9ur5+e3!JsL6Zbo&*d6NlprlPA3PMkmQx-s09Es*-nyJ3s#1pP4F$ZqO zf9s_13VyF%6Kn_l{X=hGvWq4_zY!SWwPrhUUMS0?D?8OZss;H@AytL^sH~CuD~SA4 z-9ioMmb!diE7H0P{7Pw~AvbhX+MzwG9uQ^`H|Z#~kx+{1&1U*^gv->I&-0Bn(9|(; zmC~8&t{E4crtZ~F76+<#$uzzOw}+eO-ND?_l<@z}?xvQ=o0X+RUpkM75}GNejio}Y z&{+Ew5k#NZOFhT!Rfh8I7!TP)U#pCn#?kyvUF0d zsr|~Y5|(MV!JTLyNY;PQzbS2q5z0E~Uwef}b*4T|JrNi}{M6QBX#ZmAPyJx(Q7~6J zs;f*45eFhZ+<@Fk_ZNKXWG+UGRsN;>6Su?)>IY_-S{%FB?NCSQmFdc8kNltI`| z)Tch;6jDz4jeZPYCL2Ra@939gsjv~1E+VAC+Yy@|M!2M3IY8Q~%?*`TAfMer`b;OOUBt_56#X<@no4GBg?GZiXo`OfeS=#nT~zj{ zvt=DUmFy`p$n4&dn-i08Qp+P+iED_9x-@BL;0%3Aa}!FR3&L_@l5UvHhZ~ZA(=qA| z=?Xc9JtSNX$Lq>4CHMn~S!Jj%m_%{5WMG4oU%D-h?)>{M~TP&{Ap(f+fkf;>WT*xf}2>s>&pC-_;7@3VAdgrPu$W!ujwI(Gf+ZBdbM>mi&#YnmeEvj~LwA_NLL%kQy zOVyaasL@h;wI{g%F`)K}iQG<{MSOprOwdb+y4bnTLS6SkHxxx|Efbs(cTkyRH?f3r|tTG9KolJXdH%I;av#jM{}F6~rH%I= zXS0on$B26uBPLTraoUg(>sU?X;)r#Zl$hO=2Hp8eAz|Rp(-gmm7h4V*9Cw1F7iTm$S0~9G3Iof)~gfs z$ORz%*20)hf_>Ksyrm)$60k&>xu z;Yl?VnXAF%M)IhdLYk;a%35^EXsAj;@TmnDaWMhh)QR|-K_;ECy9m1GxfgsQSJe?$x}oPB9Z;LN&b*K z$i119nx>k4nyZ?w+Ku|(^n|8BGs5(jWfwF+*GxA|(~J-FXEbNHnVPLkGa{Q*sD;XU zxw^VXEFC@pox@CTe^d;=@ox$|35^U63mywE2|9hR!>t8J@K87wPI@ckTSRx|p4^7g zk#SNhbv$(u(VppaMMgt8saaHpQj_RUPL^NExx`wcq5`}pNJmthHFTiL(3hcUodajA6l=mlJ?==0lzr-U5*GH^#17? z;Z~eOy&Zf*J-xkO18;n!_YCR)j`+KTeuX#i-^Cls8+c1aFdG>Q(*+ecZJ7sb6gP;g zqz!4C>TH^qtcNL2eMB`xNi|j3PTWxU%2T8mX*WE`PD1tFD;yV`6S@&T3>VAIyh*su z4*(z7FRl}xz#U~IDkj=1>2QAhio8r!L`V~fR@4bHQH@22m-e`3{`tD9ZMU)s0qK-8%e zP$LOeiG(uiCtnTf?l|}0!rX!}uAc7u?uA~r_dn0?o^!sX{ucg0!4CX&p+MZNUL=;2 zRk)3uk?X3xuX)8LXgBG~=_cs24O@*v4Uzg&+I6U`dPAQ?rZxvN;uz%*<(zU`j1iCU z38AZ~quK`j-^}2JP(QwS*c+}akbJw)8vdb>C@c^sB0GIqlGS)(gM1n8aHHjC@GWa8 zR+Ww;nwN%oc!i=B4dN!afb~SAyoz*FIHDF(UC5zoNhN}4q4{FkYVKk)x$ScVR7eJJ$r4 z+kM+jd(Zj$`U`yN{%yfVp`ZK~DI|TAAE@c1ow0HApaZ%9r?M}o4W6R8ty!;Kpi#J~ znksPX2}858m)b~9CJ&Hxp!05tOif8;DYDSxg=+lP@HhUQU=?o(6NHjt33060M=Bv- z7B&j&rG`pNr9X1h=antUrqqx#1V-AA`1uZTy6~Tvr9xGsQj$(wF8lGSuiQd?(%WL20|1q4t#*b6CX6_1QDju2kTY3COi<&YAsx-srZypCm9I7;-!mbW)7;a! zwQDt9HOIIon(lg|ah&lh`bGs)ef@3SWBm)=dhIaHLM97YFAdoUPP2EFTC!0z@{>Xx z10Vf+1F?bP!Lp%m0Uh*xxxwn8PjHOAF68kY;deVz3aO)z?|ei3#+0J(Q?F6`mP%LQ z{$rc6Zgw@i2wluv7AF~oWwuju$R)_mcPC+EuQrql?Iio4;$H(oj* zzCg9s3-OWg0owT;Q2mB68?F^a@fj2fwV;AcK{Z)fB^rvS7jUa2lq1SbXnq9cg!&s4 z0_{+D*8nR)I`W7jqTMsp#)yt<)M3!u$;2uui}}bl=YDaQxV>zM8=$?W>7(yy{7>J& zkYu=}JEo1*mC{w$G||-LQlM*bPy{)c_y_UsP4aH(zWAAM$Zz1ysQhWgH{r8T@$nK4 ztNlS|uPT)iZ;DN%@8VIp9CFrWiPj_mWy5OZ{ZztB&Y&mLx#SppT}z&WBj-x$GWCTz zj6CaAWNA~84ap}KshP?=%zWkLk;*Z-v~*rxDmQ{&E=ksky@a6>A=VWxiM7OSaK&6C zib7p!tTa`uEXB(4@^on$R%!n~p#VAo{o)+DHJyb2TaQXYR;&&AJ5gOVLkpmVo68J% z@*a>j!mDzp_)tg@DU6@}LSJ#WzzQ?r(pgT379*rC;sF7^j#5cU17F+TSmhTekx&x# zQYRu)+z*+IrpQ_BN4~uiaxTTlq0napki%ICHPWBR0L4K8;HI+a8L&az3Ki98%~4GQ z?KPcS|J5+hSkpM);L)GgPtsr0rRWlLS(-O&kok+=MKa_NB7jVCMfriaQT!#m<9CMb zd`tdiSjV3ayU`+lp=wMgbcO@(cA=8^241=ZlqQRzg?Of1hReoYe8iGx@%|ZPD%lKu zBZInx{lOyC5?ZkToIutkzaon^3(A}E_cTA}%_u5Yei zuY0YLxrUsTNx`Yd3kCm1WuIIh{t#KhK>khmJzUbRg!+dEhV9{SC?`CD&qs}N3*iah zLzoZM-!W;8Y=$PIC~}8e)K17u+M$wRsCV#IokFG1+vs9&3C^X)VOJYVRV9sNEwVJ; zB_BJ1hfq@t!FxqYRi$U*9LyAV!~&tZ*iRfToDwqN+G<9>`6)J#wn(p~4N?Vo<8FiY z;DV9~Wk@e%=soIqoY8WL6tW8W3L~W$G#x{5Hta^eLw`xa`J^r8)Vs*ymBR^hHknA> zWv*~DIICu{wvtw(EvlQPo2nmR48TdiV(etxuP>_`ty`nrfOeb8ex%Is2_C98QHm>T zC6{0j#|d4+hHxfYVt8nJ_)54~ct^MxFNcRfc{YnLDeM)0h_}TkxuNn2yW@KBA$^Fm z_zN%h5X2^>y0ii0sroq*c%t(YT5OFN{0kWq<&l29wxmDA-s`J6mJ(WsGdy?m!mgL2>v zu?KnT$)t*|7iP=q$jax|%S2@7>+FC&ZPI zgaipt+@ZJ@=ciDhSaElXyO)+yC{my}6nA$i6qmTW`^uI74NsoXG}*m-WM zQT~$4;l@rj?=fv>E&eo`tAdTajsC{(;ScSAWm;(Rg!hm_eet)Je)2tK63EXx>SgXm z8wj4F6ZXRiZrM%Hf!8>dA5cI0qI4I_S^(?pFSMwO^ph}Fb(GJTmK$Z`AyXgAVPzs! zJOY(r7SYt5YQ>$Z&Kp-)4k)TRQ5Y{oX(6hl)Q~62$x3HU6`o5?bxm|Wx@+PL&<&%| zoG@{(^pTpb&!rRMeYB?o*wm@&ZSIa|3EAQc@ddZKTR;pY3CpF<`gvB%YR`cf@dM}sCitC_XB=x_&6A5o02k?@+E?rT~t?LTmFm+&O6 zs0+dUH3kQ`ol4>JmA;%iWs0oWs6S$xhEhE=MJ;5_$AE#f2Y0ZX6Lu0pbL+qge( zz^*SBGN?Vjg{Rwr=&mJv0MF3{BVVnwse&z$UEQ}O3HNVxK&Us z_@i2bD!;2id%Opk5K6Sw5j0bnki&X;f<73l^#BEW0Tks8uu?r(iIt$X{w5ExR81nr zt_9lW5cmEsKq4)jAO8-cKQeP_cp97Du5In{VvTVnQ!dt;BO~J-QT1@8l@J@G{%T4*F z3FbQHDD!{jbaRn;FSe!3azU=4xKR~;3Mjlf;56znk3>AP6T)lw2G_ykd5TNHTRg-v z9smW_52V^#&|?9rN%@92XE2yDKlPR}M}11Q`Tk%Ihv1{X0)6pJ5a?MDA$9~E>V@a? z5nZVxN#L3HNrS;bpORilnbo zAV?R9^TASmD=w!$L2FKcTADuhc2ur6DL$Yx-zfi6^T1^F0Vz6$s?YDKyFU!Ph$o)uJ8E{{Ljn@j?RQ1RY~6CmVGhyoVbj ztVx%O2yEp_kVx;qxot;>1hl3T+HwH|O*(ig3&@c$qMJrwY-aLz7tm;b2n+ct#cTTr zdg&_InG~|PbJ46gUO9%mt$`d@Diz09fnWNLTG%S{od7bu6_N9J5XmC5--@Q!QD=a$ zU8@#@Hg5?gXtn*cwpFe+8VC zdgS4pKp@p)Y(*e`6y)YDpB{)c|DIgW31K((@(FA30FC&9Gf5 zUD&By?Hx#+iS(8j2Hx`vEBzOJ6Lx`j^a2Om8U(YX)?|-7)q%vyLDY0T3=;GPEB}ek z5_8EA%mHUr4hlyPHp`#2j9`Sm=(0b^IFZf@9Y6`yXMNvM+qxwcu5aM`d?Qq9OYn!XwhID8<3$I#Que{f4-W=+1wah z<|wMDFXx25p`GLe`~_@RJaZYsxiJ`--;9RLMh0duwznXw9|?M~Sh$VFdB-^a(e+|O7yF^d_zvnlf!${5@56~IaB%t&RhiXTC}m9ZjOct@h}TzkrAodN0foRjWf z@MnS$hjh4taZA=Hp2E6)3qCTOXN^Wm>a$YW#7gb)aZDi0LU^?o5_AtuEanN1_>7mF z<*Dq$U(DkkSzd@I81bO>6J9r9-`-P}wA3n_rJd5r~ zaVJhJcSag0n2~V@Aq(VP0q1imGcYiAd%nB`D`sAUr+Tth0Z6KzS9)O^odg?Ju6kW! z*=H3Qyv+Aouy+^vI)u!gM)o!_(zURcHi57E5yaV_d=Er|t2-KO=kN3R`4YdqiT=N3 zm8xatDnC^qqbcl40jsSc$2YJq`AAb179)xMNX5pb@M-~Hv07fESoxvMs4X%&8!7w^ zpZ;%l{UrY$~l?Ulkc_e{N*FnI3|hBv19FoS4f{fSkovi5xn$8JicGyRoF4d zb=YY$7Wy;#mw?6{V0CZOTj(%0*h{SsC*MG9G=>=$!C<(HJ&Xor-jK?G;h+Ltv^*Fm z+llMfaeiJv|IcaXgzv;p;y|ffJj#h32X1$a@BmK9zp7r{r~IOv1kYcfF2i!37L2_1 zuBeIirTTb6BjK2(a~6Cex3CURb~b2zAFTyzwgqou3%8L)Jb4cuKrDD|5BmT3YH#ph zhvKdNqk4ewbiw-F1GC+hNMJTugkY@qUL@o;Xx0|sk?ru^{D~fRq0f%k#1o*x6ZqPI zH5`B@9l(ofNQT{7v#77(><-0(@1na#B=+(Kr`KWroyUp?a`K%+{{H}TJdF43K+9j_ z>xUwbqd{NS!v|=BH{i)xa|K(v6RSTHUD}Nec==TVBqYBf)@KVGgL=HD1ri*==fq%f zLfNkj&KC{Y@n&bO(cM-V|##v~2>|Yc=S|};4X}fSNM;E#Six#kft|0xNtuXdZ$cmTqV10vb9cu6 z6OywJZC=f*lduf}_lfx+dOI?QwtT)7BYBMF;MO0Fio>R)@|B4!cjEJhp|v}Z(FI6? zHD^>~`rah+iD%KK2KYB&f*sixe=2B2QZuHesKZJt_-+e8EY)Ttx3N9$%;2&%O<03; zj=*MD5uX*RM&&eK&3$^ZjDqcR6D0RU!2mC6iqul)PbZcjYAc-LOc@Nb%S$^8*Qtyf zPZu~fDQX!0$ulZ4+!Lq6)w)UKI9BA`Va@AlTewsGgr`Rx9p*iqUAisw!KZI8PNsX- zcJ^s8=-yId;B)E<5G56A5QujNEcQk2j&F;f$r7Bye{CjCWY@BgxfDDy7quSVm^VMQ zAij7D^R+#vVIEfRG`>YIPJy1((2BuUoWs7*RtNjo9ohI5t9TvzcZpYTB*MyNeYYT| zKI97ZS_r3ab9U$wvk&Ez{8?DajBmnTnaSBPlvAP%3;jJY%P8%h+77(79k(mK*y!%! zZoKPz(lO%awz{E=xJ;bQ2+nH*xFd*H)(~-fD(mU3$>){Rm2!}2QYd!R(KSO1VsQSu{h!cgLfhRE9|;($UJj*mGJs@WZ>aDE*5x`U2Q!0+-QhMa=^ zc&YAGPa|Xb>O43Z_4(UCJhUx%l3U3}e~W+7l2iDp){1{mA#sbj9jIiLHZhLf=;JZs zkB-=lzSxT9XjeJ%5lluyCq5VIihpAdCh|QSE0)h$(TTYJItP8%W9X9VSbL))%Rf9bFA^v|K*29*2KutYos_LB{eby7~ZodOfVx zX6*%1KaOX6Yj5E?EyT~A`E?(2wYSWvQfMnaLd*uJ96!`#SWiHLp(8D&UZsm66;K{h*yf%f`~Lipst0xK8|y*fT@w zAyx2dcXVhsR-v0v6U4-1?wVUtb>*nMMTyfA>0b6PXQ3uElDZQ2Soo}1n5f?fV_|mB zQ~lK^yuLtb#~E8pm8T{!AswVsLVYonGxRSGdW3-X#Kd}5RD8G|up)Vnk z&;h)!PV8D!EOIzjaWA>W8e%vS5|5Ag3z`wfjy1;i+6kw)6`qE@HNaK*p#2X^upf)q zjZCqp_zGLv5BqQik9;lb{)K3;J=VM>_oo~2ydP+znQ11Ls}p*u!{+`^7%KLM%jC!i zEy#w%C)T6RN?q*RZM>p=*vHZ67PxV(H@5>@ke)rvVGL*7O=MsOJF|-?S9>N2{O%yX ztIhcyE*6p{IEx(b!){E48!=2=g&$MGv#RJF)my!##xaL!u=gJzf8Sv@FZ2IH@%N&z zxVB<_aRi^`PN$;`qJmNwBm$Z~2Ody0FM6>08~1{W+L>FFAK^wU7Uzk(#O0j+j;zNB z>`J7zgpMDl;d@3Sx4ZGfykPdtAb;?;m|xvH46ouJEMQGm*^@j*A-tSSGJHdMcD_0v zd8%gg)#5c>wN~ilJK+#^t+S}&ZFR-&kHNz~Mi$S62k{S9?JeVosngll zb;3k6BU`P$4anu(qo<=VTAauJ*`s$GVPg!!L%PU%9Uzjuhwl?g2Ie1Cf)y5yFLRY_ zQ*}1Pj|}Z|&S8~^r5`zq_vANz=SFE4nQjrQDQg+RWzk&9g2LNu~>(teDk9$j5WWSD9osz2aUFXNxb!jxR2Mv)u!L06u#ngMhxGf4k1-d&uoJMbk>lOZVq|1_E$m#p?+ zheu%Z2Vz-n9kJI9eiMepbLO<%kH>M1nd`;PLMqW4Tq7**P~Ks{zZ=Ns=Ck5$Sz#Bx z@4=C4LtbJUzQ;zSemj=L1jEsa9Xp6NT_K)%j6b~#{`n}*uSz0?0i090LU-}1DC2q0 z#z*VQT&{iH{~~o#bq1dAbL{MR&JSB`jzTrWaI9f}kV$&9eyW;77H2V1*aExvBX{9* z@y@e2&#rS;Y+w{iI1j5h_g%G{tp5mpx`t=F0;XPjF_XVVW5a?t18eiIKXzs)db1uW zIEX!QWp|@E^M(=|uf~rLz`9++V&`F#ayjE8uwjkx<@eH&bFKP?*Uv&f!x?8=yyRZ^ zUBw`&s`>5P$iRt2GfmL#IbSVkKeV`-`T3BMtVMrw(Dz@Fj)m9~cSd5y(|L`p>4QJp zmi@TSY4e(07>2hu5q(~aeZIoU`>(K+yO|~AU$U_#{qXIF!3Q(&e3RGO2BfPoWABLd*JHt9^^gtFs0|SNSY{@qK&s%83V6;7o zJ$A&aeL;S(h!gdDGN?bYzmwVjV)i!x&s9R-j`Hj-aN^!!KkljaNcsYNk7vl1LR`iP zO04q?-)jMq@tX5I3ajbMJfk>0Gl&`$&6Z5bUHr5n>~#;M{yQR+21K7lJSCRjZ^QT7 z!C7`2J7mUF>%&tnGskKh^Bq~VLF{V_ev057AF*cV@#-G1vWL-$0^$)fF>-Y_t=iLD z!>TVw<}w(Y3oG3jzwsfg)Ia$eNz77?j#lRxVvxq|{QI7NXOkbC$|x@Iem(Q}f=oQ( zzc%<4&G4Cv$pzQKS_}9N!|_kPA+mS~+b$Zlf4r;!a9lrNrwdh0jpE#zhxN?- znicqf9{$T1-SJ+diPv9Y=jWg;Bk|eXS+{KLg*6_~C*-FKpZSCn^JjKwJeqe1ElVU{ zP>vu@D|;g8NXBzIB$aqfcbZn4$b1Uf`&C32Q+R!SM&-ok z*s+8DWDB~o!~3xd@5$*rXP?iKxv9QIdH|o(3QO99S^!HxuZ-p9@qgTbj76gth-*1n zHi~12NPWaSqL3_Z6jC@Rce8gzc#_~&iH9ZicJ-;R1Sv6ezicI!TFzTGS*mY-La5ua zi^?alaxqA^ayXTqASUK<6LbgkL=N>(yf~@Oe6^R4IgwL|O>|(e{!$t$C9*0{R)Wd5 zbSKvBuN!QLwSH?C=JeWicMWTw|NOQF6a*Cc&-eY;vw@qn<7#U!DON76T2i*6$T7cl zPJ=9oo>1pAPh>C5b1m{MbE}Fq+pE)sa_-o-OD{Ode6(%UynA5&#dL&D6MocopJ|FU zFP8hLIa-!5mYhy=y6+xSy1@HbYfdzcHT`3>F|Mu3tZY=(+mtV7N%?lO+`spqQfon^ zTiwDs4I|fvjS7kLU+0tL+0et{dco;m+e!NM%7_Y=!g^U7QVt~cPq>`WGkIlNudI~3 zw?#+FwpDdD&y}ZeBX$Dc+JsflL}DY!gxX*^>JV2RReqFbnEgzy#$T#Bg6()`&XU`L zGU));H&>ovnP(D>>#Igq%`hG}bvNHO&!tQ7ebXgNYvHNQYq#)#3lWRzM>WiDFu3mI za5cEC-vFvN6S?$!=z;y7c6{EI0g<1T*M^l4{ocw$!S_U!)opNj1&+nM)izZhQF zB-`z^zij)&TC@t$?XJF0!IA_D`_$&jNK3Raw_;8C)v{&fV=7Cl&YOirT1}9HDn{pBO&K0<{ygUM>^Rq?n(6QJoJ*G)PiwslHue=R z58QgYZFlMJ(9)*0!5|H(&im0%;l5?Ev3te!(wRlI3Re`iDY{e=Qjt~F#_Vg+Ot*|H zs{AUesIFdAv7u_T>5@58ehPQVnNC4&Iu)<2T>0Jfy~$$s6`tCytT8+|q;6q!bp4@G zgKDnxJLNsiW0Bh<_qMLB9e3G$Qm0hr6a{CtP8t<===0z&WpVyV4Knu^)iZiX_v{zD z>Am;+`g+@VxH(tZe9%9YVzFJjwBO{Vrh*Ek*rlLhZeaF}?CrUY3#ODrRz5WKmqX}7 zT~qF8*=1^OOr;KOEBa|SmLIGBQb+v^Fp2Z^-K6!Jt=WrRuWxdc+?~Jpj)<7upj`uV zT{)~nz*X;|o}TUl-OX;$!|d(#XH9ZxU|##wnh7nxWPkYIr>ZYL2~RV7?=Wgbj_o&G#4H@8mF@bW3fM)DW6 z74cSmb+UZX)URqz#n}p-Q8xEdO=6M$TdQ(IkfDWcoY+k}Zc3&py(g!K8aq!uNG7JnDQ}IO||__ zEBunfe4}5~`xG%aq`l87k75r$_oJ?3-NKzBZT<95Oub67a-XM+h_m^U|9sr?N)7c$MmXh1@((BSn8S9Qjvd!{2SeucIvzhi}YnWXI;A3O1Q4PGS;A* zLC4B-S_2oKfZT{R(Sz!a3vUy2-Sd>&H22$XkyK6p!+D3@d7aLvFB+3|J@L1gC7*KM z-Fjd1%hdQS*>$VtSX+E9grBZ|HTry=*P(lS54#sS+_RlyJx}Ma&8%`OTAKNNl56ai z&yBtuihGwbE_+|mwn|r}trTRqYw*!mhvx zmgyCpN(;(8<-PV#{WgXBM9;0?F`{!&q}N^7Wv=h(`FqyQ)@6w8EZs`u`+^-=Gm@)f zk9;}wG5-C;&pYCzjNi*mx(OaTYfh{a++a(C8FhNqdgy=4U37eF{iBqj?5Hvop2<9r zv?k`~PY*wC|2!>WReG2FHRXktIpSWum7$}qn5e!#xxsDfVlYSX@-*dznjjqG&U=(N z3s%Qr%jk;ek~8If)kG6ojbb5IS;a(pi4E~EOg8M zU+Uucj%>Hi3;D_WN0-AkFN9_0 zlcmKu_0vu#=wfz$YWA`86EQHF{fZN8@gQxM z@Po8R_f!fMY%HHk`I?e@v;{VK=|j#19eu`9uoFB_?<m$z2m z%1z7f6+F(&OPP_7{-xvRW}hB@{xw0$JW-TUWl+BryMayHEBr!iGeg);j_@DxlD3;F zXOq=M!WC(eE>$v7um5q`qoUar-w5s8+SCfIcdAkUhD{UBm5t81nK3lQCVq76_)k+lIwc&<98o^TVDFmh7aitVdv)Z2$dh5MLVpZe;FaJs zUGHH!R{S*QMcUNlH}RulgfHHoTg7~vbS*QhsGZTEs#ImTOg?QNp3Y<{*3Fcvgw|@f z<(;{w>`7h9=i(75NBB?fRPn6%W@WB;*}Y@fgSyWfc5Sdb+#LAS^9SeWj&~ie+Iu_9 zu^lVkHy4*S$^9?uS=x@oVev7aAAdF_)yvH^TG=MLKMfon(Jm^qt}d!Yt*1flea5(q zv-VN$m-fs*nDsVoP->$jyZH05TVt%_-=+-7u_=9GN>pRTvC=3JR5vxWKEPjFBivTM zvlJQ+nr!8twS_txLnA|$*w^e#2bXfQX1hD^Rn#vH4>y@!uS2cpelJ}%J9;=BamaT# zZy&B(W@%Y|KlgUl+zeBaRiZ=e)lY8mf24md-Yi+WjQ7h553SR`-gos9A{K5O*hTT5{9O(t^lJAGt4867#WaEr@F)tE>Hqo3zHV z$+*mT!F*NOCD`iLfT+K#U8u?{HCClbMvt*!AM5UJ=oEb{Y;WL$8Y`S`I7T?WwU4!L zW%ZBzxne~@qpSg$J5xs|4NUA3yEJZd+K_?)@&jEvS3Hp?f3O+Q)-RygoVKaO~$a%`wuk zt?l1x0iJTZ%)isurRFDEC(ejl5?7UaH~+1vovl|5r(k34J$2jH_pW!b_N-dh0Q5F+nvyEh+!U zW?5j`2IJ&!WrTK;DCq;7>>i~t6*a^^To=~rSASKbo{j#F{4qrH?(QNw$_}+0<~cO5 zIj;1r$jGmo`F(mGJwsl^O^u0<-JUkF@Eh4^zu#+PP1`zE^}5$zQ&)>P7WzxTZ|)H` zp60~-PU*iTHjjIa9S;6f^m$<1(Ue{}|Can>{z*6j!q`i&r*nssx?VW<6>HX8doC|G zUpEz5!j-$~WFb$@w(P7}T|BsIy&=`JEMjG}Tci8YQ^M~B6nLz3TJNyT@f)Ykj+3op z^*Jrr9O`6Mrn$98;1|mDQ;HCn?A^$**acDXMKF4k1w$>1A z?2-Q}tunE0T(>Vje|qpS^7FOW?a3{3!pqLevvkX?3iOKviO6G$8Ym9adFdPLh@0e2 zRJt5tIUqk!L8>UpriUd7g-4Aet!@1_M73!!rqSVg-eFt)tvxO|)pD%uJk9xn!!CUx zHX%A^bNY_tf8#4-mVf^6r7-F5Tpv?E+l`))ApZJ7F!Eej!_dybM||!$*V3J- zkaC^UrY8=GegFCHN8wZJFLUCKCOhT0lvP+7>AG13>d8SWb(IYDhR|6|=kBDLHd)zh zIV%qWGr5=hy}k0yszt^3N{sSAhm^qRIzbIKG?)|hG31Q*5!YWGw>n;SKJFB3cS!Uz zPAk5U8@>pfQCR!Blj_x~b2nm5XkhS2ziV!-Y(~iO zMOm5cQ`;u)i@P6FJ0>*tR$TwYm1*gDHsuQ}7sd6uUZRicq_k6?2#I1#>6SEGc%fXh z440>>_o$+DQhcI1nzohPDbQ6q>aTf(gr(N)6>U{ltQF#S(EW)f3_h7@+6Od6pIGL@`UZRbQg}Ms!mK zTa0pv+DsfoP4z39jcHg>WU%?I%Ps)m-q{@esRGGFB8jCW@p_hY*Ce`+!Gf{^|g)WpN+AmYqCXHr9Wh_Harz4 zDpnxqofVT>Du#*P>T+XnaY@Ms*=(EUTOQslYD3g7;m7@7c{sQ%w+nR)c9k6y>}>VP zrbXq)i@dXIq`RaXi+vO0nh=`0fto#^9RmHnuk|_NN@Se~+nQ-X#(->}^&The7AuoV zd*)n9J)3kZ-Z8E`UP+2eJ(6jiU#oPyX`8x(OkRxA&|Kd%&HO)Qg|L;{(T^nu;SfxR zL)^8^77mJ?gr)L_itUAsO9m^M_ND%nwQJU?iZq11^8MaD)@g}dl+y&a&raj*TIdEE zGfHa}ea@PjJ~m}%Y+!8fgrTWJime1Ur(FNp;g4%~ihL0^nll+H34v@f7td#MY}uS^Xs?_k1OQ}5g$=`}0*ImF10 z)KcCnE{2z#SM{veSax4K>X;Om7WiwQsMm*Jsz&ar9Wc*yyG_ET(n3S#Bw(guZX zv$Tx#l-F^~;{Qolo7T0|QSfkX5ZF8XO5}*Bvtf3@%lv0~&#h76^0##>#lOru_lNYh z$-l&Ri)$6{lK4Z)s*IPp<4V2E$F%-BM_r-X%~HU+y_L(=F(CKLg(j-C>?#je>VfgM zmud^P@}r6sh22W?RDZ|#z)Mke>Q1WLuJ$|sX*G(So>~v0#&Us8d#gd3Tjk-hW<{&A zwq*FEd=s}V{&M1zbceFN!Vu>Xf&Ie|M6QZ@AJ#Sap#N;ILib+Iq15|XS$aQbOZv{_ zqw%-mO5?KP^A{Tl)qOyIxG&ztu5C5wcgdp{=tuZ_PNfri*g9DSFQfgb++^=zg)60-;$M; zk(_)!;aTFH=8PhnGjajrw1>eMo!%SDuI6W;jkZ{2-^7mgV-(2uN9( za4UX6;@jk->B-p(3(TcWjkZd6umySQ9r+y?{%F|Y7|5|XlEYuXET;T>IU;QBeAiHwQ(n32()?U^&tIou|y5jnJx6DOp*tFY9>5j+CVM zz6o=aUZuY)-lVQ`@b{Y<_AIhjox8Q0hTaHV>2uossI!CZY3+}y21Tv1@25RT=oH&K zt{~o!@-8zZ|4eBu(|Tnz8F~+Oi)Aew(w%awa)2tP!DohP`<wAN^hidIsMM8R_rp9q8fb^u>9j`*7Ev9qU+?$lZ)~o}uoo9k=PGnSD#Fa)r#L$<_(O z6V@j-PW>bE-&~)PTUGCr_SBx9E!NX|D-+~<=CRaD?_*wS9%JrfzGQAFXRH0Vzq|`4 z)kS@2UQ+SOxJNqdP{$`UI4*cg&AWl6ULW1tI8AjJ;4C;Fa455Jm43I>ulloO2z_zi zrKBdrCR|9WpBY~2t_^nl)ptS7(c$(HA49JMt@IbX*SIfm3A9@&?lxU1w#!x1gOg?^ z98LT^X?a>&_WZ&l6%FKN!Uf4uQnYMkuO-^FscLl9Oygx!zB$!0Nd6#~Dy|@)wsMn{ zMW>xrrtFFk%V_;o$H!is{e{4n!5#s=UYFd9oi;i}xJ9@$cj$*k{AuZA{Ihsq?zPMd zDese7CvQ$!nKQFuwbQq9=&&JSooc!S?e}}`W%Rh^^2+9}cC>OxVe4$SRCB`6 z#L}dmshu(pm`8zd8Yt!8`mndA;(e?R?R3p6fX0M7vhjYqZ}?O{z+Y7Umqv z%ugPh=$6tbZDwwps-LBNrz^g1f^usHg{6hm4vG$R^gZI~?6%MPisDugpXZn9nvxM8 zoOnEWQ|id9oc!XFm&W6&1Bies;j&_orp|;-<3$1FFUzO(=>bW zl$fioM&7uFv(dNUI{mU!LZ&%hbErq{gEvLw`oUdeSD}*xf zye>uhL-^kOuwsFwuda*zc+Uc#6}~qDr}&k5T6;Bdo98BY*LL6PXt5ciOgE0MT2SOz zup`euy?NTav{@23ihD>+QRE{pI&DU~@>bzy#mBK5aa%xj*u>c29EJYCBHTOzD;Di;ov* zxw?!Ushv`;B`?X6N{(5^+O~3E?9(dfzu@~J4MO{dd=4Dpd&y<6VVWtdsCiD!jGt5Y zrAq04W^~V5pQGg`mNYY3tM$p;!0)qMH=e3|Twz_=v1*tp)ZEfEgMNl@O>d}4GKnq@ zPxO`2O<|?^U3nAJ9bv1@D31lcodT>wj|V^T``NFFXS7F=*Eshdom$x&1wXW_UP(bg zK!Gvid}^bV@rggBrxiS@9H6h~oLJ-gfF&VuHDf}rg;WGI_F3tYsE;yVDDlnPleI77 zZrY^uhIIb*$Uc+zXHiaND|x^AKdR0YT0$&SjE^eYSM{&@(fGyKyXq4?7h_E=l~f^C zir1ae|E|jyM#$L}gDO%iR=RKpuNwZo^@F>Ijt-WBruqkaclGY+dDx|sgPq}j>KRMV z%8n%kg*|ePr2UlqI$=k0>+Cbd2Klwk9k&jCH*1E3=Y>xU|21T(Z_}8m@72d-EY48yQ}Wj=UlpZKK7qfb41PGLM8<6_3rI8-1DT{S?30J zH+4sZX>yyY!m_!AcJx3$mfSY^L;8^1veH#rU;74L140gkHHg?1_I*%$?|RN}bob1W z4cZpYt zQo5+(ib+*l>Q-9ywC-oMN8eIxs2nh!to+qHNXWHTT<&-t@~a*6YhYAhxc_sn-#wex z(7APXneQ;uIzX?eH%uuNKE;3KhGf-F?~pzzt9ia{#ZzIt!%(jlK{rG01^wXr#_e1C ziTbySWExbtyezdiys&BRn=HGmXPIF+%k!5M?JajTpHaUhLmj8@q^}_^lcyNn%l%8H z7vG@T$V~dMms;*==cM8KJNg)%i}YN3B|kPvrgfIi;yl~YuD!hu`q>Bi23GpV`8M+o z^m^-gu|_kGLYHp#cMXrUO{OCipGy1+mgcn2%u4sj&MOG6tR?QZKka_NyPNlO_ij!b zZEW@X#V~D(>|wrMd8@QSxr_34<*zTCQqsA6chyJB3oTK)LoJu<)DyjIY+8P( zq*ZZM(T^q1%W^AcnJ@-uEjr=H8;jv^x91BZs%Fw% zZ)Vj1;~;Y|ez8ee3RcI3d+CF8sQ4(-LxwxS#~|tR#B$M2A7E``8|={Asjt&Z=O-@D zTsFBKb^G1*p=*g#p4}vyYkCii;kmh*nUEB-}C|J)MZplnA@B4gW2s6YN-6wVUa5de{8XbeC?_<;FlNBfK@eHqA1- zS)N(yDHqg^f-9XwG^&gaFpM^AH$0@HN1Fb*u7;Egnqx6%OCJz03#9kDWc>!Keb&2d zp3=R%4PVZ-Eo?elH@CWBus1A*1-XUpBdX9vd!byQkB7CKM_=Mx{PO-Vq;J7h0E?>b z;HGnu{FnS*UaIK8h{w=ZZ=>9uY7!?+^XOq)XliGkVvaF)w)}1p+mOvg(P8v=l~=0wscZ5OG|X3zK=ebZf8w&Ino%ir(I!mUKAU^ zYqXQnKp?*dA@d5-F*_ znCrh<{^YwMbzxN4>docZsyir+NTI3v9~k5B>ArDQcmwXVRQyXY(QV*o@K$SuTCgLy z{{=_XUD_da)2$cd;Z>do$FqU%?FLZZH6$6XMKfyZzX!X2ox9?Z)wSTj#b1KI=q$Dd zpSV(zz#rTOSG)zxxd1Neg?3)OMGraw%xfRHnS7G($MmZDjp_w`l_^?RwI=wjR^W`@ zYh}W0@@0raEUGd^enh{?;o!Zi*&%;u-KCebCoqULbcMnssTH`ajpRb-3#)X8xG%^T z8wgExE7dU~HO5sc+kjy_0xS2qxR2Uvz2E>W)vkkZ%@;Ejk^5-R?e98l z%P#GxVg(Xwj8IS4RNF+Ylh)c~@fG!NmS`81>i)=A)j0Y-%u;U1^VBP>TBtmi8i0Yy zQKHD+)D}ww+2bJX5MF?ybO7IaS_c+ixUB05e_?_&k<7duHC=wCR@*Y6ois!=N+#;Z z_mUoH9#kC?L4DK{$Fh{++Cstk_~B>Ph`U$5n{Ov?^gb z_!M7qbH(%;7151L;6TcW$i^#&Ec=yM#DSOt`4B{158VWK(QdFA!gP`19FQ~${HEz(1U1oz zD(^8O2zWGhGP0CU-f%{rhXwf>BO9PD0Qv0&lF>$3q_r2jfL1yOqvn-1M{wev zB^4BUrW7kCO4nhjJO@eIPpk`KdI1Q8M0#hR2UAp=8`E~&Vr>+E05?^eu0B_&R}uh9 zC`jxJ|D_QK!8P1CToFPT+cs?^+>F6OPp~oHss*6Fr-L=`4Nu{M@&&H4r!0b1X-FNV zO<fDi zfJ{$;?YKa@BUXXn?2I3K5d`d1aDScIiD{sLUkUC=X(;!DpXn7AM+K2@v~zSzvs0U> zEtMNeZMfkpKweLPU;Pp;?<2K_qRRhMn#kjo&Pp@28Thhh-~jt#vF6hO!X9L0H*uD@ z4#c-noS>^K)A;1Yb{bC-;Q2iU;p% zBTvz4ky{CeGm#5Q`x)r5L(D!H)cq1ra!G=%WCIgMk?8R&_657tSQsp=){#$!4^oSB zpS;3&=Jt#qv6; zcJv7PiIZ#(xrv3W&r8)=7zJW6Pl+HN%TeN}A9GK6uh!rMO%i6%rC>PT#CvTi@yHb6 zkk&%V2GO{U%F5r-O(0I}EG-vOLEpB4$FY$pcsba{1nnu@r9a`K2Z}wB*a9@XmGm#S zGda{>d873b+G>Z?Jl=hRzBXZ+huBOSkH67Rdn-=>+uKDMqPA1+D~GAcaSjgDO%;3= z=Q&+`mAZH(zo|iRy=H0s#Yp71A^m<)G{14 z)E4Uq@5J`n7-gK2B!1MnQ1_~@VT{!XVK^+wTJltKy#H|qC4%_PH;mIVsFjmpYDevp zHOhD`kqQ=b#ogTc)}$l%0-=vOUS7dYuh14*Woy0ZXTDI_tiLC8kbRUw;i?p^H;T#X zH=<~mB(#E~zt1>MJwh$bpV^-fp^Y??o=nA(to2Y7HB#4G*I#@Hi@;5Cu(E|u^$ZOD zkK#ggg*;N}rQa=i=-z8-<|Sa3M`{NITdH40i5GQ^4ABPg(X7ufb%c^H{Hl0p4Wx}? zFX5z;L8Y|&)L3*9CTU&d6Y3N^p+n*ymgdv~nyv0MJVJ}c>gKEGv=5+4Tj|%TG0Il` zGqJb2Rq1D0t*$rhGaQm`U=hCvH(CEl5?vQ9I&~$u%agi2U**-o@=&(YjtjoJaB88i z)*pk7@TXWy%hZXwCUUmrFuHaIpWu@4M#{#E@2icn^rNQEOVcWojdaWEPbpY;Q%f<= z#&#~(H4xlPzX}fwUb;IH)C-t+h|)%_@v+>6S3UxJkHV zb5ZIo{-BL857r-`qTN~XNyY2(cH&l>!-l>>h-rYjM(B&?%0ir8){3OX@_1dCK1CMw zNxFu*0m{D89MgCq$EKBTgE8AY(def?p}Q)~k)14|a)!3aaM-4s-ED)1T4_A44Hes{ zqfHa4Z0OV1PakDzYx*94ng zR<0JTb>G?r2nUE5jM@V0EBX=24!M^0)bK&~jo_k;soE=8s46&G8)|fu+w0$mnN}CA z2C0fA2sFM)_fg$e*+KYM7peb2Xk@OX7^r$Sk{ih<;@`?!X`*hIc0{*Xz9`I;&a0!v zu9}TFM0i5|w@2zVF-RGP6t9!~bRR8^wPRu(ahotl{YCC7E>U+Y_vzAdTa)Dl>NUNU z@T1fjRB*a@2}(Hujy6nKroK}?DTmefVr#13&X%i$4bneEpC6Plx~bGp@rBU4R_#nD zu?Ny`V5wT-`5F~lX%3ZW{?Km7kHI0ml@g@Cgk+@`42b%S<1Ej;V&1NPub)P>-kHj9 zxuJf9cv%`Jj#HZ{4TO8jGhIimwRwmS4pjQRr4@lZN+T{fqpibtY7Eoj zobWgHSi$>hM(rzj&v3ZrXrnkQUuqJbT7^0mKdP+|E^Q|d*BmzDb(mv5T1V=s&V^q+ zMhyVteH~`|Cv6nD?NAL?lxSAJm;Ti%mA2R_>UDs*-$Yis9bA`b^oJXQt^SMdLhC`? zzJsf>O+AL?x&veD2k`f8#A+^VLl_9%VeLHuJD#fcqL$q+!vDm(oNe9UF};WTlFw=G zNo;dmaK)!zNq55nV#V)-Xiddqi^hN1rOu`%&t0mQv}QfbS^|FG5uvV_g3o#i-#Hrm z`D=RZBnzQpEHwh|@k(Ff_4!mRIt&v-g=JZXzuAaK;6AJ++VY1(>p%xCPqNKcRE~7Q zH}+!owW;q@$jbG?w|;=Xw+O#IlsNkke80UQ_Ybi?X1FQQyzeQq`3s-#A8Ie&1ARXU zfA=q<(=Pn=SJ+ke=`J>klj9?PZ;7^DaD-t!8P>`@#^(V-zMRTaR`jC?qJl{}o`)|U z=LT@DgM>k1TVW(?9E&e}5~j`}xG>M?T$K&)S0lRbMXi*dsJU~DO#V1{EQ!>yTft`! z<*fCA!?XmScpvD02e{&+;8b)2wY@;Q$SYJ<<_;)%2Y5bnU~c^n7S$5oaTOo@8NDm1 zmHs1Q?J7SIHawCq0p3=y9nQ$K6 zwt%~zj*oi)R>Nb~(u38ugAKB#I+iBNKEzj3yrP4!)5bBA$*>mc;#l@JVS+>dFC3wNVGIn05%B@$%5HYPn(sE2 zc;zg-&w=s&+!-y@FFJT|CSOHj)fo6fjL?WYuL^G#3R#SklsSN z?&3|j6VWQv1x-Nm8?XXB`0TEH&MKZWkW51*G22L(7kd1#w)~~KYRU%K2Ctc4b=9)p zL047xvl{{jC6QI#4Ck*Iyigmsbk+RJUg(M)oRRu?z79J~=QHrleT)zt}9 zWaS6eB?P${$O_%#_ACRA#Rg8Y*}SisebEK4(g|Km6*&KY`J4mrvKJ8DOoHjsf!Ist z(}tldbCAf!>{fNHh)v}1X2C6az^JR)c&8cvckF&gFmXGf(MQm+^Ta%PMAESnAa_KWjo9k zYh=lR+5Nz-_JSe#m=#+I`=y7pQK(T^vH+fJ-{_3NK<>ouSKBPW4$R*$V( z*0y1v?ogK}015CxgO0E+>F8h}ES*iPbt5?AeUO9KUwa+8u$Glr)i!)W8}_3Ex}(4b z`VX5bYtxz^OA?lh6ljnbM zblh1rKP>lgEYTCBDp(l988rN>2G7AdzUBQ_U~q-p1{vy1# zAgptEwb#YxbmG5*$N)6P6R>3m^hm5HGo6oQtbxyWm1nL+qN;nW*5xV9c=8moB;*dT zU1yP#-mIEGmbWis%z@`!mt9?h6-eY&-(p2vu+Rsw5{p^cUpT4!Sn)lum(GE?`HKk1 z2M_5zyP1M5IEB7rl-cnYDJA?+AAC87#%0$kYDG z3hqPZ|NF|4bH#>)p}`V1;4pfSz^+wdM>CMVIp~HCD^Oj1D46j~V3mKRLP91ssXtuC z2kh}&tV0*ZxSCT&;8VM!UzhPksyhJJ;$$>osY|IL@j-QDtv7#V*fl_xy{JofiaGZ~ zZk7orU|;?Lca@3_*tg_r9Yag&GQ(zQS3|~^!k&JM%(UXn{tx*$z!|d{ZreFlvJBrV zf#@O;X1n`(LyN!Z>CyMX1GW16h^l=&$z{jCq;RRTZ+Z_&+4Zg#ojoPncYKP__^>0@@tEKx>M6j zK}dQT7IHNmGFEdRQ6ZdGBcwLMDK%T{PTz=IM5@0CbK$#3Yn5UvCF(0T@n`j>ber9Y zl^WwUE}{eZM)hx4^qO#9iN({tM0}Q@{7okX`k%^&^|AC!nkz0B{4@`IPj9sL5}MXW zeXjM8<|;0tHyTkcbW;@cXTJEYDr;9IU)3AT@VLr^Jow z6!`RKENAqMgm812brboXnkdo}S=~ZS{7L$kW>2xFuC}Fv^c^caQ5&S2X`Zj2qdC&G zWr1QVd?P_T(=S!>bh|*koVJGdBst zh}cFe<$}F5iB2Y6Y<3t=Xe}KM7mYV8v44@DYTeGzsm#sxg>b-RV->7E)5ht&<<(-D zP*?4$v$DAA&#T8wpB$8OW?{FYe7PZ9u(pghxX2@<;o34K!O-8-RoZ2xFK=hFM%ZY2 zZnafeX_=>=tF4opihHEXmU&Va!}BtO{T}TX<4UW!;(cRNLwi9rZM2$dUaKwE8`T(7 zM|;`yyBcG&%Xm&$Z+pLdlA*US)Z%3oZj1z(Gl4u(UE!{ƅF&C=B=rs{zF#5!EC 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 literal 309040 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 z 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%0DV=luwk2%4K=K+)(~hj1XQlFC*jnJZ-AhQvDPW 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 R-YUW>l8F&ZVFrl8{{f|f;(h=C From b2e9c05acc7fc5f934d5b5785b13ed1855543207 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 16 Jun 2020 13:24:59 +0200 Subject: [PATCH 163/185] losses bug fix --- vocoder/layers/losses.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index fe13fa8a..d6ffe9fe 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -286,14 +286,20 @@ class DiscriminatorLoss(nn.Module): return_dict = {} if self.use_mse_gan_loss: - mse_D_loss, mse_D_real_loss, mse_D_fake_loss = _apply_D_loss(scores_fake=scores_fake, scores_real=scores_real, self.mse_loss) + mse_D_loss, mse_D_real_loss, mse_D_fake_loss = _apply_D_loss( + scores_fake=scores_fake, + scores_real=scores_real, + loss_func=self.mse_loss) return_dict['D_mse_gan_loss'] = mse_D_loss return_dict['D_mse_gan_real_loss'] = mse_D_real_loss return_dict['D_mse_gan_fake_loss'] = mse_D_fake_loss loss += mse_D_loss if self.use_hinge_gan_loss: - hinge_D_loss, hinge_D_real_loss, hinge_D_fake_loss = _apply_D_loss(scores_fake=scores_fake, scores_real=scores_real, self.hinge_loss) + hinge_D_loss, hinge_D_real_loss, hinge_D_fake_loss = _apply_D_loss( + scores_fake=scores_fake, + scores_real=scores_real, + loss_func=self.hinge_loss) return_dict['D_hinge_gan_loss'] = hinge_D_loss return_dict['D_hinge_gan_real_loss'] = hinge_D_real_loss return_dict['D_hinge_gan_fake_loss'] = hinge_D_fake_loss From 55230bb317a8e5fd67b547b9a3a3dda3c6a71692 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 16 Jun 2020 18:53:02 +0200 Subject: [PATCH 164/185] plot spectrogram transpose fix --- utils/visual.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/visual.py b/utils/visual.py index 3d95c2e3..b4ebec9a 100644 --- a/utils/visual.py +++ b/utils/visual.py @@ -29,11 +29,11 @@ def plot_alignment(alignment, info=None, fig_size=(16, 10), title=None): def plot_spectrogram(spectrogram, ap=None, fig_size=(16, 10)): if isinstance(spectrogram, torch.Tensor): - spectrogram_ = spectrogram.detach().cpu().numpy().squeeze() + spectrogram_ = spectrogram.detach().cpu().numpy().squeeze().T else: - spectrogram_ = spectrogram + spectrogram_ = spectrogram.T if ap is not None: - spectrogram_ = ap._denormalize(spectrogram_.T) # pylint: disable=protected-access + spectrogram_ = ap._denormalize(spectrogram_) # pylint: disable=protected-access fig = plt.figure(figsize=fig_size) plt.imshow(spectrogram_, aspect="auto", origin="lower") plt.colorbar() From 82f8e9cb123abadb4dcdebc108d2f1b2f4daf6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sat, 13 Jun 2020 00:34:51 +0100 Subject: [PATCH 165/185] add tts-server executable This makes the project easier to use when installing via package manager. --- server/server.py | 6 +++++- setup.py | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/server/server.py b/server/server.py index 705937e2..593eeb18 100644 --- a/server/server.py +++ b/server/server.py @@ -76,5 +76,9 @@ def tts(): return send_file(data, mimetype='audio/wav') -if __name__ == '__main__': +def main(): app.run(debug=args.debug, host='0.0.0.0', port=args.port) + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index a7840568..96032de0 100644 --- a/setup.py +++ b/setup.py @@ -75,6 +75,11 @@ setup( url='https://github.com/mozilla/TTS', description='Text to Speech with Deep Learning', license='MPL-2.0', + entry_points={ + 'console_scripts': [ + 'tts-server = TTS.server.server:main' + ] + }, package_dir={'': 'tts_namespace'}, packages=find_packages('tts_namespace'), package_data={ From df10e2a92af5fd30a4dd84b3338e38a8a9a30f10 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 17 Jun 2020 11:13:16 +0200 Subject: [PATCH 166/185] fixinf discriminator configuration --- vocoder/configs/multiband_melgan_config.json | 7 ++----- vocoder/models/melgan_multiscale_discriminator.py | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json index 7ba48854..d54c64aa 100644 --- a/vocoder/configs/multiband_melgan_config.json +++ b/vocoder/configs/multiband_melgan_config.json @@ -78,8 +78,8 @@ "discriminator_model": "melgan_multiscale_discriminator", "discriminator_model_params":{ "base_channels": 16, - "max_channels":1024, - "downsample_factors":[4, 4, 4, 4] + "max_channels":512, + "downsample_factors":[4, 4, 4] }, "steps_to_start_discriminator": 200000, // steps required to start GAN trainining.1 @@ -110,9 +110,6 @@ "test_sentences_file": null, // set a file to load sentences to be used for testing. If it is null then we use default english sentences. // OPTIMIZER - "noam_schedule": false, // use noam warmup and lr schedule. - "warmup_steps_gen": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" - "warmup_steps_disc": 4000, // Noam decay steps to increase the learning rate from 0 to "lr" "epochs": 10000, // total number of epochs to train. "wd": 0.0, // Weight decay weight. "gen_clip_grad": -1, // Generator gradient clipping threshold. Apply gradient clipping if > 0 diff --git a/vocoder/models/melgan_multiscale_discriminator.py b/vocoder/models/melgan_multiscale_discriminator.py index d77b9ceb..dbcc1f30 100644 --- a/vocoder/models/melgan_multiscale_discriminator.py +++ b/vocoder/models/melgan_multiscale_discriminator.py @@ -11,7 +11,7 @@ class MelganMultiscaleDiscriminator(nn.Module): kernel_sizes=(5, 3), base_channels=16, max_channels=1024, - downsample_factors=(4, 4, 4, 4), + downsample_factors=(4, 4, 4), pooling_kernel_size=4, pooling_stride=2, pooling_padding=1): From 25aec41626286cde412643f63068f16612db3393 Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 17 Jun 2020 13:35:37 +0200 Subject: [PATCH 167/185] README update --- vocoder/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vocoder/README.md b/vocoder/README.md index 48fc24ee..1b65f929 100644 --- a/vocoder/README.md +++ b/vocoder/README.md @@ -32,4 +32,7 @@ You can fine-tune a pre-trained model by the following command. Restoring a model starts a new training in a different output folder. It only restores model weights with the given checkpoint file. However, continuing a training starts from the same conditions the previous training run left off. -You can also follow your training runs on Tensorboard as you do with our TTS models. \ No newline at end of file +You can also follow your training runs on Tensorboard as you do with our TTS models. + +## Acknowledgement +Thanks to @kan-bayashi for his [repository](https://github.com/kan-bayashi/ParallelWaveGAN) being the start point of our work. \ No newline at end of file From 1611a7182df8efc7843ca0a4c9d4b39aeeb3a085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eren=20G=C3=B6lge?= Date: Thu, 18 Jun 2020 16:15:57 +0200 Subject: [PATCH 168/185] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jörg Thalheim --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6ee1ade..a211764c 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ Audio length is approximately 6 secs. ## Datasets and Data-Loading -TTS provides a generic dataloder easy to use for new datasets. You need to write an preprocessor function to integrate your own dataset.Check ```datasets/preprocess.py``` to see some examples. After the function, you need to set ```dataset``` field in ```config.json```. Do not forget other data related fields too. +TTS provides a generic dataloader easy to use for new datasets. You need to write an preprocessor function to integrate your own dataset.Check ```datasets/preprocess.py``` to see some examples. After the function, you need to set ```dataset``` field in ```config.json```. Do not forget other data related fields too. Some of the open-sourced datasets that we successfully applied TTS, are linked below. From 58784ad09c05a5d07d3b86cd53b89e34972e34bc Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 12:25:03 +0200 Subject: [PATCH 169/185] renaming for melgan generator --- vocoder/layers/melgan.py | 2 +- vocoder/layers/pqmf.py | 2 -- vocoder/models/melgan_generator.py | 14 +++++++------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/vocoder/layers/melgan.py b/vocoder/layers/melgan.py index 61f7a96b..58c12a2e 100644 --- a/vocoder/layers/melgan.py +++ b/vocoder/layers/melgan.py @@ -21,7 +21,7 @@ class ResidualStack(nn.Module): nn.Conv1d(channels, channels, kernel_size=kernel_size, - dilation=layer_padding, + dilation=layer_dilation, bias=True)), nn.LeakyReLU(0.2), weight_norm( diff --git a/vocoder/layers/pqmf.py b/vocoder/layers/pqmf.py index 3985aad4..ef5a3507 100644 --- a/vocoder/layers/pqmf.py +++ b/vocoder/layers/pqmf.py @@ -1,5 +1,3 @@ -"""Pseudo QMF modules.""" - import numpy as np import torch import torch.nn.functional as F diff --git a/vocoder/models/melgan_generator.py b/vocoder/models/melgan_generator.py index e69e6ef3..01b52ea8 100644 --- a/vocoder/models/melgan_generator.py +++ b/vocoder/models/melgan_generator.py @@ -77,16 +77,16 @@ class MelganGenerator(nn.Module): ] self.layers = nn.Sequential(*layers) - def forward(self, cond_features): - return self.layers(cond_features) + def forward(self, c): + return self.layers(c) - def inference(self, cond_features): - cond_features = cond_features.to(self.layers[1].weight.device) - cond_features = torch.nn.functional.pad( - cond_features, + def inference(self, c): + c = c.to(self.layers[1].weight.device) + c = torch.nn.functional.pad( + c, (self.inference_padding, self.inference_padding), 'replicate') - return self.layers(cond_features) + return self.layers(c) def remove_weight_norm(self): for _, layer in enumerate(self.layers): From 6b2ff0823924d5a5a197f4f7a07b252590826c29 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 12:25:27 +0200 Subject: [PATCH 170/185] Issue #435 - Convert melgan vocoder models to TF2.0 --- vocoder/tf/convert_melgan_torch_to_tf.py | 115 ++++++++++++++++++ vocoder/tf/layers/melgan.py | 52 ++++++++ vocoder/tf/layers/pqmf.py | 66 ++++++++++ vocoder/tf/models/melgan_generator.py | 106 ++++++++++++++++ .../tf/models/multiband_melgan_generator.py | 46 +++++++ vocoder/tf/utils/__init__.py | 0 vocoder/tf/utils/convert_torch_to_tf_utils.py | 48 ++++++++ vocoder/tf/utils/generic_utils.py | 37 ++++++ vocoder/tf/utils/io.py | 27 ++++ 9 files changed, 497 insertions(+) create mode 100644 vocoder/tf/convert_melgan_torch_to_tf.py create mode 100644 vocoder/tf/layers/melgan.py create mode 100644 vocoder/tf/layers/pqmf.py create mode 100644 vocoder/tf/models/melgan_generator.py create mode 100644 vocoder/tf/models/multiband_melgan_generator.py create mode 100644 vocoder/tf/utils/__init__.py create mode 100644 vocoder/tf/utils/convert_torch_to_tf_utils.py create mode 100644 vocoder/tf/utils/generic_utils.py create mode 100644 vocoder/tf/utils/io.py diff --git a/vocoder/tf/convert_melgan_torch_to_tf.py b/vocoder/tf/convert_melgan_torch_to_tf.py new file mode 100644 index 00000000..b767f268 --- /dev/null +++ b/vocoder/tf/convert_melgan_torch_to_tf.py @@ -0,0 +1,115 @@ +import argparse +import os +import sys +from pprint import pprint + +import numpy as np +import tensorflow as tf +import torch +from fuzzywuzzy import fuzz + +from TTS.utils.io import load_config +from TTS.vocoder.tf.models.multiband_melgan_generator import \ + MultibandMelganGenerator +from TTS.vocoder.tf.utils.convert_torch_to_tf_utils import ( + compare_torch_tf, convert_tf_name, transfer_weights_torch_to_tf) +from TTS.vocoder.tf.utils.generic_utils import \ + setup_generator as setup_tf_generator +from TTS.vocoder.tf.utils.io import save_checkpoint +from TTS.vocoder.utils.generic_utils import setup_generator + +# prevent GPU use +os.environ['CUDA_VISIBLE_DEVICES'] = '' + +# define args +parser = argparse.ArgumentParser() +parser.add_argument('--torch_model_path', + type=str, + help='Path to target torch model to be converted to TF.') +parser.add_argument('--config_path', + type=str, + help='Path to config file of torch model.') +parser.add_argument( + '--output_path', + type=str, + help='path to output file including file name to save TF model.') +args = parser.parse_args() + +# load model config +config_path = args.config_path +c = load_config(config_path) +num_speakers = 0 + +# init torch model +model = setup_generator(c) +checkpoint = torch.load(args.torch_model_path, + map_location=torch.device('cpu')) +state_dict = checkpoint['model'] +model.load_state_dict(state_dict) +model.remove_weight_norm() +state_dict = model.state_dict() + +# init tf model +model_tf = setup_tf_generator(c) + +common_sufix = '/.ATTRIBUTES/VARIABLE_VALUE' +# get tf_model graph by passing an input +# B x D x T +dummy_input = tf.random.uniform((7, 80, 64)) +mel_pred = model_tf(dummy_input, training=False) + +# get tf variables +tf_vars = model_tf.weights + +# match variable names with fuzzy logic +torch_var_names = list(state_dict.keys()) +tf_var_names = [we.name for we in model_tf.weights] +for tf_name in tf_var_names: + # skip re-mapped layer names + if tf_name in [name[0] for name in var_map]: + continue + tf_name_edited = convert_tf_name(tf_name) + ratios = [ + fuzz.ratio(torch_name, tf_name_edited) + for torch_name in torch_var_names + ] + max_idx = np.argmax(ratios) + matching_name = torch_var_names[max_idx] + del torch_var_names[max_idx] + var_map.append((tf_name, matching_name)) + +# pass weights +tf_vars = transfer_weights_torch_to_tf(tf_vars, dict(var_map), state_dict) + +# Compare TF and TORCH models +# check embedding outputs +model.eval() +dummy_input_torch = torch.ones((1, 80, 10)) +dummy_input_tf = tf.convert_to_tensor(dummy_input_torch.numpy()) +dummy_input_tf = tf.transpose(dummy_input_tf, perm=[0, 2, 1]) +dummy_input_tf = tf.expand_dims(dummy_input_tf, 2) + +out_torch = model.layers[0](dummy_input_torch) +out_tf = model_tf.model_layers[0](dummy_input_tf) +out_tf_ = tf.transpose(out_tf, perm=[0, 3, 2, 1])[:, :, 0, :] + +assert compare_torch_tf(out_torch, out_tf_) < 1e-5 + +for i in range(1, len(model.layers)): + print(f"{i} -> {model.layers[i]} vs {model_tf.model_layers[i]}") + out_torch = model.layers[i](out_torch) + out_tf = model_tf.model_layers[i](out_tf) + out_tf_ = tf.transpose(out_tf, perm=[0, 3, 2, 1])[:, :, 0, :] + diff = compare_torch_tf(out_torch, out_tf_) + assert diff < 1e-5, diff + +dummy_input_torch = torch.ones((1, 80, 10)) +dummy_input_tf = tf.convert_to_tensor(dummy_input_torch.numpy()) +output_torch = model.inference(dummy_input_torch) +output_tf = model_tf(dummy_input_tf, training=False) +assert compare_torch_tf(output_torch, output_tf) < 1e-5, compare_torch_tf( + output_torch, output_tf) +# save tf model +save_checkpoint(model_tf, checkpoint['step'], checkpoint['epoch'], + args.output_path) +print(' > Model conversion is successfully completed :).') diff --git a/vocoder/tf/layers/melgan.py b/vocoder/tf/layers/melgan.py new file mode 100644 index 00000000..8625bbab --- /dev/null +++ b/vocoder/tf/layers/melgan.py @@ -0,0 +1,52 @@ +import tensorflow as tf + + +class ReflectionPad1d(tf.keras.layers.Layer): + def __init__(self, padding): + super(ReflectionPad1d, self).__init__() + self.padding = padding + + def call(self, x): + print(x.shape) + return tf.pad(x, [[0, 0], [self.padding, self.padding], [0, 0], [0, 0]], "REFLECT") + + +class ResidualStack(tf.keras.layers.Layer): + def __init__(self, channels, num_res_blocks, kernel_size, name): + super(ResidualStack, self).__init__(name=name) + + assert (kernel_size - 1) % 2 == 0, " [!] kernel_size has to be odd." + base_padding = (kernel_size - 1) // 2 + + self.blocks = [] + num_layers = 2 + for idx in range(num_res_blocks): + layer_kernel_size = kernel_size + layer_dilation = layer_kernel_size**idx + layer_padding = base_padding * layer_dilation + block = [ + tf.keras.layers.LeakyReLU(0.2), + ReflectionPad1d(layer_padding), + tf.keras.layers.Conv2D(filters=channels, + kernel_size=(kernel_size, 1), + dilation_rate=(layer_dilation, 1), + use_bias=True, + padding='valid', + name=f'blocks.{idx}.{num_layers}'), + tf.keras.layers.LeakyReLU(0.2), + tf.keras.layers.Conv2D(filters=channels, kernel_size=(1, 1), use_bias=True, name=f'blocks.{idx}.{num_layers + 2}') + ] + self.blocks.append(block) + self.shortcuts = [ + tf.keras.layers.Conv2D(channels, kernel_size=1, use_bias=True, name=f'shortcuts.{i}') + for i in range(num_res_blocks) + ] + + def call(self, x): + # breakpoint() + for block, shortcut in zip(self.blocks, self.shortcuts): + res = shortcut(x) + for layer in block: + x = layer(x) + x += res + return x \ No newline at end of file diff --git a/vocoder/tf/layers/pqmf.py b/vocoder/tf/layers/pqmf.py new file mode 100644 index 00000000..474b6e7f --- /dev/null +++ b/vocoder/tf/layers/pqmf.py @@ -0,0 +1,66 @@ +import numpy as np +import tensorflow as tf + +from scipy import signal as sig + + +class PQMF(tf.keras.layers.Layer): + def __init__(self, N=4, taps=62, cutoff=0.15, beta=9.0): + super(PQMF, self).__init__() + # define filter coefficient + self.N = N + self.taps = taps + self.cutoff = cutoff + self.beta = beta + + QMF = sig.firwin(taps + 1, cutoff, window=('kaiser', beta)) + H = np.zeros((N, len(QMF))) + G = np.zeros((N, len(QMF))) + for k in range(N): + constant_factor = (2 * k + 1) * (np.pi / + (2 * N)) * (np.arange(taps + 1) - + ((taps - 1) / 2)) + phase = (-1)**k * np.pi / 4 + H[k] = 2 * QMF * np.cos(constant_factor + phase) + + G[k] = 2 * QMF * np.cos(constant_factor - phase) + + # [N, 1, taps + 1] == [filter_width, in_channels, out_channels] + self.H = np.transpose(H[:, None, :], (2, 1, 0)).astype('float32') + self.G = np.transpose(G[None, :, :], (2, 1, 0)).astype('float32') + + # filter for downsampling & upsampling + updown_filter = np.zeros((N, N, N), dtype=np.float32) + for k in range(N): + updown_filter[0, k, k] = 1.0 + self.updown_filter = updown_filter.astype(np.float32) + + def analysis(self, x): + """ + x : B x 1 x T + """ + x = tf.transpose(x, perm=[0, 2, 1]) + x = tf.pad(x, [[0, 0], [self.taps // 2, self.taps // 2], [0, 0]]) + x = tf.nn.conv1d(x, self.H, stride=1, padding='VALID') + x = tf.nn.conv1d(x, + self.updown_filter, + stride=self.N, + padding='VALID') + x = tf.transpose(x, perm=[0, 2, 1]) + return x + + def synthesis(self, x): + """ + x : B x 1 x T + """ + x = tf.transpose(x, perm=[0, 2, 1]) + x = tf.nn.conv1d_transpose( + x, + self.updown_filter * self.N, + strides=self.N, + output_shape=(tf.shape(x)[0], tf.shape(x)[1] * self.N, + self.N)) + x = tf.pad(x, [[0, 0], [self.taps // 2, self.taps // 2], [0, 0]]) + x = tf.nn.conv1d(x, self.G, stride=1, padding="VALID") + x = tf.transpose(x, perm=[0, 2, 1]) + return x \ No newline at end of file diff --git a/vocoder/tf/models/melgan_generator.py b/vocoder/tf/models/melgan_generator.py new file mode 100644 index 00000000..db0a9675 --- /dev/null +++ b/vocoder/tf/models/melgan_generator.py @@ -0,0 +1,106 @@ +import logging +import os + +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # FATAL +logging.getLogger('tensorflow').setLevel(logging.FATAL) + +import tensorflow as tf +from TTS.vocoder.tf.layers.melgan import ResidualStack, ReflectionPad1d + + +class MelganGenerator(tf.keras.models.Model): + """ Melgan Generator TF implementation dedicated for inference with no + weight norm """ + def __init__(self, + in_channels=80, + out_channels=1, + proj_kernel=7, + base_channels=512, + upsample_factors=(8, 8, 2, 2), + res_kernel=3, + num_res_blocks=3): + super(MelganGenerator, self).__init__() + + # assert model parameters + assert (proj_kernel - + 1) % 2 == 0, " [!] proj_kernel should be an odd number." + + # setup additional model parameters + base_padding = (proj_kernel - 1) // 2 + act_slope = 0.2 + self.inference_padding = 2 + + # initial layer + self.initial_layer = [ + ReflectionPad1d(base_padding), + tf.keras.layers.Conv2D(filters=base_channels, + kernel_size=(proj_kernel, 1), + strides=1, + padding='valid', + use_bias=True, + name="1") + ] + num_layers = 3 # count number of layers for layer naming + + # upsampling layers and residual stacks + self.upsample_layers = [] + for idx, upsample_factor in enumerate(upsample_factors): + layer_out_channels = base_channels // (2**(idx + 1)) + layer_filter_size = upsample_factor * 2 + layer_stride = upsample_factor + layer_output_padding = upsample_factor % 2 + self.upsample_layers += [ + tf.keras.layers.LeakyReLU(act_slope), + tf.keras.layers.Conv2DTranspose( + filters=layer_out_channels, + kernel_size=(layer_filter_size, 1), + strides=(layer_stride, 1), + padding='same', + # output_padding=layer_output_padding, + use_bias=True, + name=f'{num_layers}'), + ResidualStack( + channels=layer_out_channels, + num_res_blocks=num_res_blocks, + kernel_size=res_kernel, + name=f'layers.{num_layers + 1}' + ) + ] + num_layers += num_res_blocks - 1 + + self.upsample_layers += [tf.keras.layers.LeakyReLU(act_slope)] + + # final layer + self.final_layers = [ + ReflectionPad1d(base_padding), + tf.keras.layers.Conv2D(filters=out_channels, + kernel_size=(proj_kernel, 1), + use_bias=True, + name=f'layers.{num_layers + 1}'), + tf.keras.layers.Activation("tanh") + ] + + # self.initial_layer = tf.keras.models.Sequential(self.initial_layer) + # self.upsample_layers = tf.keras.models.Sequential(self.upsample_layers) + # self.final_layers = tf.keras.models.Sequential(self.final_layers) + # self.model_layers = tf.keras.models.Sequential(self.initial_layer + self.upsample_layers + self.final_layers, name="layers") + self.model_layers = self.initial_layer + self.upsample_layers + self.final_layers + + def call(self, c, training=False): + """ + c : B x C x T + """ + if training: + raise NotImplementedError() + return self.inference(c) + + def inference(self, c): + c = tf.transpose(c, perm=[0, 2, 1]) + c = tf.expand_dims(c, 2) + c = tf.pad(c, [[0, 0], [self.inference_padding, self.inference_padding], [0, 0], [0, 0]], "REFLECT") + o = c + for layer in self.model_layers: + o = layer(o) + # o = self.model_layers(c) + o = tf.transpose(o, perm=[0, 3, 2, 1]) + return o[:, :, 0, :] \ No newline at end of file diff --git a/vocoder/tf/models/multiband_melgan_generator.py b/vocoder/tf/models/multiband_melgan_generator.py new file mode 100644 index 00000000..e8599760 --- /dev/null +++ b/vocoder/tf/models/multiband_melgan_generator.py @@ -0,0 +1,46 @@ +import tensorflow as tf + +from TTS.vocoder.tf.models.melgan_generator import MelganGenerator +from TTS.vocoder.tf.layers.pqmf import PQMF + + +class MultibandMelganGenerator(MelganGenerator): + def __init__(self, + in_channels=80, + out_channels=4, + proj_kernel=7, + base_channels=384, + upsample_factors=(2, 8, 2, 2), + res_kernel=3, + num_res_blocks=3): + super(MultibandMelganGenerator, + self).__init__(in_channels=in_channels, + out_channels=out_channels, + proj_kernel=proj_kernel, + base_channels=base_channels, + upsample_factors=upsample_factors, + res_kernel=res_kernel, + num_res_blocks=num_res_blocks) + self.pqmf_layer = PQMF(N=4, taps=62, cutoff=0.15, beta=9.0) + + def pqmf_analysis(self, x): + return self.pqmf_layer.analysis(x) + + def pqmf_synthesis(self, x): + return self.pqmf_layer.synthesis(x) + + # def call(self, c, training=False): + # if training: + # raise NotImplementedError() + # return self.inference(c) + + def inference(self, c): + c = tf.transpose(c, perm=[0, 2, 1]) + c = tf.expand_dims(c, 2) + c = tf.pad(c, [[0, 0], [self.inference_padding, self.inference_padding], [0, 0], [0, 0]], "REFLECT") + o = c + for layer in self.model_layers: + o = layer(o) + o = tf.transpose(o, perm=[0, 3, 2, 1]) + o = self.pqmf_layer.synthesis(o[:, :, 0, :]) + return o diff --git a/vocoder/tf/utils/__init__.py b/vocoder/tf/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vocoder/tf/utils/convert_torch_to_tf_utils.py b/vocoder/tf/utils/convert_torch_to_tf_utils.py new file mode 100644 index 00000000..799235e3 --- /dev/null +++ b/vocoder/tf/utils/convert_torch_to_tf_utils.py @@ -0,0 +1,48 @@ +import numpy as np +import tensorflow as tf + + +def compare_torch_tf(torch_tensor, tf_tensor): + """ Compute the average absolute difference b/w torch and tf tensors """ + return abs(torch_tensor.detach().numpy() - tf_tensor.numpy()).mean() + + +def convert_tf_name(tf_name): + """ Convert certain patterns in TF layer names to Torch patterns """ + tf_name_tmp = tf_name + tf_name_tmp = tf_name_tmp.replace(':0', '') + tf_name_tmp = tf_name_tmp.replace('/forward_lstm/lstm_cell_1/recurrent_kernel', '/weight_hh_l0') + tf_name_tmp = tf_name_tmp.replace('/forward_lstm/lstm_cell_2/kernel', '/weight_ih_l1') + tf_name_tmp = tf_name_tmp.replace('/recurrent_kernel', '/weight_hh') + tf_name_tmp = tf_name_tmp.replace('/kernel', '/weight') + tf_name_tmp = tf_name_tmp.replace('/gamma', '/weight') + tf_name_tmp = tf_name_tmp.replace('/beta', '/bias') + tf_name_tmp = tf_name_tmp.replace('/', '.') + return tf_name_tmp + + +def transfer_weights_torch_to_tf(tf_vars, var_map_dict, state_dict): + """ Transfer weigths from torch state_dict to TF variables """ + print(" > Passing weights from Torch to TF ...") + for tf_var in tf_vars: + torch_var_name = var_map_dict[tf_var.name] + print(f' | > {tf_var.name} <-- {torch_var_name}') + # if tuple, it is a bias variable + if 'kernel' in tf_var.name: + torch_weight = state_dict[torch_var_name] + try: + numpy_weight = torch_weight.permute([2, 1, 0]).numpy()[:, None, :, :] + except: + breakpoint() + if 'bias' in tf_var.name: + torch_weight = state_dict[torch_var_name] + numpy_weight = torch_weight + assert np.all(tf_var.shape == numpy_weight.shape), f" [!] weight shapes does not match: {tf_var.name} vs {torch_var_name} --> {tf_var.shape} vs {numpy_weight.shape}" + tf.keras.backend.set_value(tf_var, numpy_weight) + return tf_vars + + +def load_tf_vars(model_tf, tf_vars): + for tf_var in tf_vars: + model_tf.get_layer(tf_var.name).set_weights(tf_var) + return model_tf diff --git a/vocoder/tf/utils/generic_utils.py b/vocoder/tf/utils/generic_utils.py new file mode 100644 index 00000000..b17db596 --- /dev/null +++ b/vocoder/tf/utils/generic_utils.py @@ -0,0 +1,37 @@ +import re +import importlib +import numpy as np +from matplotlib import pyplot as plt + + +def to_camel(text): + text = text.capitalize() + return re.sub(r'(?!^)_([a-zA-Z])', lambda m: m.group(1).upper(), text) + + +def setup_generator(c): + print(" > Generator Model: {}".format(c.generator_model)) + MyModel = importlib.import_module('TTS.vocoder.tf.models.' + + c.generator_model.lower()) + MyModel = getattr(MyModel, to_camel(c.generator_model)) + if c.generator_model in 'melgan_generator': + model = MyModel( + in_channels=c.audio['num_mels'], + out_channels=1, + proj_kernel=7, + base_channels=512, + upsample_factors=c.generator_model_params['upsample_factors'], + res_kernel=3, + num_res_blocks=c.generator_model_params['num_res_blocks']) + if c.generator_model in 'melgan_fb_generator': + pass + if c.generator_model in 'multiband_melgan_generator': + model = MyModel( + in_channels=c.audio['num_mels'], + out_channels=4, + proj_kernel=7, + base_channels=384, + upsample_factors=c.generator_model_params['upsample_factors'], + res_kernel=3, + num_res_blocks=c.generator_model_params['num_res_blocks']) + return model \ No newline at end of file diff --git a/vocoder/tf/utils/io.py b/vocoder/tf/utils/io.py new file mode 100644 index 00000000..d95d972c --- /dev/null +++ b/vocoder/tf/utils/io.py @@ -0,0 +1,27 @@ +import datetime +import pickle +import tensorflow as tf + + +def save_checkpoint(model, current_step, epoch, output_path, **kwargs): + """ Save TF Vocoder model """ + state = { + 'model': model.weights, + 'step': current_step, + 'epoch': epoch, + 'date': datetime.date.today().strftime("%B %d, %Y"), + } + state.update(kwargs) + pickle.dump(state, open(output_path, 'wb')) + + +def load_checkpoint(model, checkpoint_path): + """ Load TF Vocoder model """ + checkpoint = pickle.load(open(checkpoint_path, 'rb')) + chkp_var_dict = {var.name: var.numpy() for var in checkpoint['model']} + tf_vars = model.weights + for tf_var in tf_vars: + layer_name = tf_var.name + chkp_var_value = chkp_var_dict[layer_name] + tf.keras.backend.set_value(tf_var, chkp_var_value) + return model \ No newline at end of file From ce076330bf817d44bb464e66af9b020a083591f7 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 14:46:13 +0200 Subject: [PATCH 171/185] linter fixes --- vocoder/tests/test_melgan_discriminator.py | 2 +- vocoder/tf/convert_melgan_torch_to_tf.py | 7 +-- vocoder/tf/layers/melgan.py | 24 +++++---- vocoder/tf/layers/pqmf.py | 6 +-- vocoder/tf/models/melgan_generator.py | 49 +++++++++---------- .../tf/models/multiband_melgan_generator.py | 2 +- vocoder/tf/utils/convert_torch_to_tf_utils.py | 5 +- vocoder/tf/utils/generic_utils.py | 2 - 8 files changed, 46 insertions(+), 51 deletions(-) diff --git a/vocoder/tests/test_melgan_discriminator.py b/vocoder/tests/test_melgan_discriminator.py index 83acec8f..a4564b56 100644 --- a/vocoder/tests/test_melgan_discriminator.py +++ b/vocoder/tests/test_melgan_discriminator.py @@ -20,7 +20,7 @@ def test_melgan_multi_scale_discriminator(): scores, feats = model(dummy_input) assert len(scores) == 3 assert len(scores) == len(feats) - assert np.all(scores[0].shape == (4, 1, 16)) + assert np.all(scores[0].shape == (4, 1, 64)) assert np.all(feats[0][0].shape == (4, 16, 4096)) assert np.all(feats[0][1].shape == (4, 64, 1024)) assert np.all(feats[0][2].shape == (4, 256, 256)) diff --git a/vocoder/tf/convert_melgan_torch_to_tf.py b/vocoder/tf/convert_melgan_torch_to_tf.py index b767f268..1b3d687d 100644 --- a/vocoder/tf/convert_melgan_torch_to_tf.py +++ b/vocoder/tf/convert_melgan_torch_to_tf.py @@ -1,7 +1,5 @@ import argparse import os -import sys -from pprint import pprint import numpy as np import tensorflow as tf @@ -9,8 +7,6 @@ import torch from fuzzywuzzy import fuzz from TTS.utils.io import load_config -from TTS.vocoder.tf.models.multiband_melgan_generator import \ - MultibandMelganGenerator from TTS.vocoder.tf.utils.convert_torch_to_tf_utils import ( compare_torch_tf, convert_tf_name, transfer_weights_torch_to_tf) from TTS.vocoder.tf.utils.generic_utils import \ @@ -55,7 +51,7 @@ model_tf = setup_tf_generator(c) common_sufix = '/.ATTRIBUTES/VARIABLE_VALUE' # get tf_model graph by passing an input # B x D x T -dummy_input = tf.random.uniform((7, 80, 64)) +dummy_input = tf.random.uniform((7, 80, 64), dtype=tf.float32) mel_pred = model_tf(dummy_input, training=False) # get tf variables @@ -64,6 +60,7 @@ tf_vars = model_tf.weights # match variable names with fuzzy logic torch_var_names = list(state_dict.keys()) tf_var_names = [we.name for we in model_tf.weights] +var_map = [] for tf_name in tf_var_names: # skip re-mapped layer names if tf_name in [name[0] for name in var_map]: diff --git a/vocoder/tf/layers/melgan.py b/vocoder/tf/layers/melgan.py index 8625bbab..4f195d3f 100644 --- a/vocoder/tf/layers/melgan.py +++ b/vocoder/tf/layers/melgan.py @@ -28,18 +28,24 @@ class ResidualStack(tf.keras.layers.Layer): tf.keras.layers.LeakyReLU(0.2), ReflectionPad1d(layer_padding), tf.keras.layers.Conv2D(filters=channels, - kernel_size=(kernel_size, 1), - dilation_rate=(layer_dilation, 1), - use_bias=True, - padding='valid', - name=f'blocks.{idx}.{num_layers}'), + kernel_size=(kernel_size, 1), + dilation_rate=(layer_dilation, 1), + use_bias=True, + padding='valid', + name=f'blocks.{idx}.{num_layers}'), tf.keras.layers.LeakyReLU(0.2), - tf.keras.layers.Conv2D(filters=channels, kernel_size=(1, 1), use_bias=True, name=f'blocks.{idx}.{num_layers + 2}') + tf.keras.layers.Conv2D(filters=channels, + kernel_size=(1, 1), + use_bias=True, + name=f'blocks.{idx}.{num_layers + 2}') ] self.blocks.append(block) self.shortcuts = [ - tf.keras.layers.Conv2D(channels, kernel_size=1, use_bias=True, name=f'shortcuts.{i}') - for i in range(num_res_blocks) + tf.keras.layers.Conv2D(channels, + kernel_size=1, + use_bias=True, + name=f'shortcuts.{i}') + for i in range(num_res_blocks) ] def call(self, x): @@ -47,6 +53,6 @@ class ResidualStack(tf.keras.layers.Layer): for block, shortcut in zip(self.blocks, self.shortcuts): res = shortcut(x) for layer in block: - x = layer(x) + x = layer(x) x += res return x \ No newline at end of file diff --git a/vocoder/tf/layers/pqmf.py b/vocoder/tf/layers/pqmf.py index 474b6e7f..6c47dfc4 100644 --- a/vocoder/tf/layers/pqmf.py +++ b/vocoder/tf/layers/pqmf.py @@ -40,7 +40,7 @@ class PQMF(tf.keras.layers.Layer): x : B x 1 x T """ x = tf.transpose(x, perm=[0, 2, 1]) - x = tf.pad(x, [[0, 0], [self.taps // 2, self.taps // 2], [0, 0]]) + x = tf.pad(x, [[0, 0], [self.taps // 2, self.taps // 2], [0, 0]], constant_values=0.0) x = tf.nn.conv1d(x, self.H, stride=1, padding='VALID') x = tf.nn.conv1d(x, self.updown_filter, @@ -60,7 +60,7 @@ class PQMF(tf.keras.layers.Layer): strides=self.N, output_shape=(tf.shape(x)[0], tf.shape(x)[1] * self.N, self.N)) - x = tf.pad(x, [[0, 0], [self.taps // 2, self.taps // 2], [0, 0]]) + x = tf.pad(x, [[0, 0], [self.taps // 2, self.taps // 2], [0, 0]], constant_values=0.0) x = tf.nn.conv1d(x, self.G, stride=1, padding="VALID") x = tf.transpose(x, perm=[0, 2, 1]) - return x \ No newline at end of file + return x diff --git a/vocoder/tf/models/melgan_generator.py b/vocoder/tf/models/melgan_generator.py index db0a9675..8a2a49be 100644 --- a/vocoder/tf/models/melgan_generator.py +++ b/vocoder/tf/models/melgan_generator.py @@ -8,7 +8,7 @@ import tensorflow as tf from TTS.vocoder.tf.layers.melgan import ResidualStack, ReflectionPad1d -class MelganGenerator(tf.keras.models.Model): +class MelganGenerator(tf.keras.models.Model): # pylint: disable=too-many-ancestors """ Melgan Generator TF implementation dedicated for inference with no weight norm """ def __init__(self, @@ -21,6 +21,8 @@ class MelganGenerator(tf.keras.models.Model): num_res_blocks=3): super(MelganGenerator, self).__init__() + self.in_channels = in_channels + # assert model parameters assert (proj_kernel - 1) % 2 == 0, " [!] proj_kernel should be an odd number." @@ -34,11 +36,11 @@ class MelganGenerator(tf.keras.models.Model): self.initial_layer = [ ReflectionPad1d(base_padding), tf.keras.layers.Conv2D(filters=base_channels, - kernel_size=(proj_kernel, 1), - strides=1, - padding='valid', - use_bias=True, - name="1") + kernel_size=(proj_kernel, 1), + strides=1, + padding='valid', + use_bias=True, + name="1") ] num_layers = 3 # count number of layers for layer naming @@ -48,23 +50,21 @@ class MelganGenerator(tf.keras.models.Model): layer_out_channels = base_channels // (2**(idx + 1)) layer_filter_size = upsample_factor * 2 layer_stride = upsample_factor - layer_output_padding = upsample_factor % 2 + # layer_output_padding = upsample_factor % 2 self.upsample_layers += [ tf.keras.layers.LeakyReLU(act_slope), tf.keras.layers.Conv2DTranspose( - filters=layer_out_channels, - kernel_size=(layer_filter_size, 1), - strides=(layer_stride, 1), - padding='same', - # output_padding=layer_output_padding, - use_bias=True, - name=f'{num_layers}'), - ResidualStack( - channels=layer_out_channels, - num_res_blocks=num_res_blocks, - kernel_size=res_kernel, - name=f'layers.{num_layers + 1}' - ) + filters=layer_out_channels, + kernel_size=(layer_filter_size, 1), + strides=(layer_stride, 1), + padding='same', + # output_padding=layer_output_padding, + use_bias=True, + name=f'{num_layers}'), + ResidualStack(channels=layer_out_channels, + num_res_blocks=num_res_blocks, + kernel_size=res_kernel, + name=f'layers.{num_layers + 1}') ] num_layers += num_res_blocks - 1 @@ -74,15 +74,12 @@ class MelganGenerator(tf.keras.models.Model): self.final_layers = [ ReflectionPad1d(base_padding), tf.keras.layers.Conv2D(filters=out_channels, - kernel_size=(proj_kernel, 1), - use_bias=True, - name=f'layers.{num_layers + 1}'), + kernel_size=(proj_kernel, 1), + use_bias=True, + name=f'layers.{num_layers + 1}'), tf.keras.layers.Activation("tanh") ] - # self.initial_layer = tf.keras.models.Sequential(self.initial_layer) - # self.upsample_layers = tf.keras.models.Sequential(self.upsample_layers) - # self.final_layers = tf.keras.models.Sequential(self.final_layers) # self.model_layers = tf.keras.models.Sequential(self.initial_layer + self.upsample_layers + self.final_layers, name="layers") self.model_layers = self.initial_layer + self.upsample_layers + self.final_layers diff --git a/vocoder/tf/models/multiband_melgan_generator.py b/vocoder/tf/models/multiband_melgan_generator.py index e8599760..d3e1c754 100644 --- a/vocoder/tf/models/multiband_melgan_generator.py +++ b/vocoder/tf/models/multiband_melgan_generator.py @@ -4,7 +4,7 @@ from TTS.vocoder.tf.models.melgan_generator import MelganGenerator from TTS.vocoder.tf.layers.pqmf import PQMF -class MultibandMelganGenerator(MelganGenerator): +class MultibandMelganGenerator(MelganGenerator): # pylint: disable=too-many-ancestors def __init__(self, in_channels=80, out_channels=4, diff --git a/vocoder/tf/utils/convert_torch_to_tf_utils.py b/vocoder/tf/utils/convert_torch_to_tf_utils.py index 799235e3..25139cc3 100644 --- a/vocoder/tf/utils/convert_torch_to_tf_utils.py +++ b/vocoder/tf/utils/convert_torch_to_tf_utils.py @@ -30,10 +30,7 @@ def transfer_weights_torch_to_tf(tf_vars, var_map_dict, state_dict): # if tuple, it is a bias variable if 'kernel' in tf_var.name: torch_weight = state_dict[torch_var_name] - try: - numpy_weight = torch_weight.permute([2, 1, 0]).numpy()[:, None, :, :] - except: - breakpoint() + numpy_weight = torch_weight.permute([2, 1, 0]).numpy()[:, None, :, :] if 'bias' in tf_var.name: torch_weight = state_dict[torch_var_name] numpy_weight = torch_weight diff --git a/vocoder/tf/utils/generic_utils.py b/vocoder/tf/utils/generic_utils.py index b17db596..580a3738 100644 --- a/vocoder/tf/utils/generic_utils.py +++ b/vocoder/tf/utils/generic_utils.py @@ -1,7 +1,5 @@ import re import importlib -import numpy as np -from matplotlib import pyplot as plt def to_camel(text): From aad51bc4f9f3f9970a8773c1fc8416c418f33574 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 14:52:43 +0200 Subject: [PATCH 172/185] readme update --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a211764c..57a979d7 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- - Speaker Encoder to compute speaker embeddings efficiently. - Vocoder models (MelGAN, Multiband-MelGAN, GAN-TTS) - Support for multi-speaker TTS training. +- Support for Multi-GPUs training. - Ability to convert Torch models to Tensorflow 2.0 for inference. -- Released trained models. -- Efficient training codes for PyTorch. (soon for Tensorflow 2.0) -- Codes to convert Torch models to Tensorflow 2.0. -- Detailed training anlaysis on console and Tensorboard. +- Released pre-trained models. +- Fast and efficient model training. +- Detailed training logs on console and Tensorboard. - Tools to curate Text2Speech datasets under```dataset_analysis```. - Demo server for model testing. - Notebooks for extensive model benchmarking. From de7ed4176c190d54fc3d68ec4624e8664fdd55f3 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 15:56:02 +0200 Subject: [PATCH 173/185] README directory structure --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 57a979d7..df143174 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,22 @@ Or you can use ```requirements.txt``` to install the requirements only. ```pip install -r requirements.txt``` +### Directory Structure +``` +|- TTS/ +| |- train.py (train your TTS model.) +| |- distribute.py (train your TTS model using Multiple GPUs) +| |- config.json (TTS model configuration file) +| |- tf (Tensorflow 2 utilities and model implementations) +| |- layers/ (model layer definitions) +| |- models/ (model definitions) +| |- notebooks/ (Jupyter Notebooks for model evaluation and parameter selection) +| |- data_analysis/ (TTS Dataset analysis tools and notebooks.) +| |- utils/ (TTS utilities -io, visualization, data processing etc.-) +| |- speaker_encoder/ (Speaker Encoder implementation with the same folder structure.) +| |- vocoder/ (Vocoder implementations with the same folder structure.) +``` + ### Docker A barebone `Dockerfile` exists at the root of the project, which should let you quickly setup the environment. By default, it will start the server and let you query it. Make sure to use `nvidia-docker` to use your GPUs. Make sure you follow the instructions in the [`server README`](server/README.md) before you build your image so that the server can find the model within the image. From 4b99eacb38d9983271610947267063cfd39606a6 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 16:51:48 +0200 Subject: [PATCH 174/185] README update add models and method section --- speaker_encoder/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/speaker_encoder/README.md b/speaker_encoder/README.md index 38b4bb1b..b6f541f8 100644 --- a/speaker_encoder/README.md +++ b/speaker_encoder/README.md @@ -1,16 +1,16 @@ -### Speaker embedding (Experimental) +### Speaker Encoder This is an implementation of https://arxiv.org/abs/1710.10467. This model can be used for voice and speaker embedding. With the code here you can generate d-vectors for both multi-speaker and single-speaker TTS datasets, then visualise and explore them along with the associated audio files in an interactive chart. -Below is an example showing embedding results of various speakers. You can generate the same plot with the provided notebook as demonstrated in [this video](https://youtu.be/KW3oO7JVa7Q). +Below is an example showing embedding results of various speakers. You can generate the same plot with the provided notebook as demonstrated in [this video](https://youtu.be/KW3oO7JVa7Q). ![](umap.png) Download a pretrained model from [Released Models](https://github.com/mozilla/TTS/wiki/Released-Models) page. -To run the code, you need to follow the same flow as in TTS. +To run the code, you need to follow the same flow as in TTS. - Define 'config.json' for your needs. Note that, audio parameters should match your TTS model. - Example training call ```python speaker_encoder/train.py --config_path speaker_encoder/config.json --data_path ~/Data/Libri-TTS/train-clean-360``` From ec7aa4496eb83f1a9d6acef0f8f4e183dbaa4aa8 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 16:53:37 +0200 Subject: [PATCH 175/185] README updates added models and method ssection --- README.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index df143174..bf25c558 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,7 @@ -This project is a part of [Mozilla Common Voice](https://voice.mozilla.org/en). TTS aims a deep learning based Text2Speech engine, low in cost and high in quality. To begin with, you can hear a sample generated voice from [here](https://soundcloud.com/user-565970875/commonvoice-loc-sens-attn). - -TTS includes two different model implementations which are based on [Tacotron](https://arxiv.org/abs/1703.10135) and [Tacotron2](https://arxiv.org/abs/1712.05884). Tacotron is smaller, efficient and easier to train but Tacotron2 provides better results, especially when it is combined with a Neural vocoder. Therefore, choose depending on your project requirements. +This project is a part of [Mozilla Common Voice](https://voice.mozilla.org/en). TTS aims a deep learning based Text2Speech engine, low in cost and high in quality. To begin with, you can hear a sample synthesized voice from [here](https://soundcloud.com/user-565970875/commonvoice-loc-sens-attn). If you are new, you can also find [here](http://www.erogol.com/text-speech-deep-learning-architectures/) a brief post about TTS architectures and their comparisons. @@ -16,6 +14,27 @@ If you are new, you can also find [here](http://www.erogol.com/text-speech-deep- [Details...](https://github.com/mozilla/TTS/wiki/Mean-Opinion-Score-Results) +## Provided Models and Methods +Text-to-Spectrogram: +- Tacotron: [paper](https://arxiv.org/abs/1703.10135) +- Tacotron2: [paper](https://arxiv.org/abs/1712.05884) + +Attention Methods: +- Guided Attention [paper](https://arxiv.org/abs/1710.08969) +- Forward Backward Decoding [paper](https://arxiv.org/abs/1907.09006) +- Graves Attention [paper](https://arxiv.org/abs/1907.09006) +- Double Decoder Consistency [blog](https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency/) + +Speaker Encoder: +- GE2E: [paper](https://arxiv.org/abs/1710.10467) + +Vocoders: +- MelGAN: [paper](https://arxiv.org/abs/1710.10467) +- MultiBandMelGAN: [paper](https://arxiv.org/abs/2005.05106) +- GAN-TTS discriminators: [paper](https://arxiv.org/abs/1909.11646) + +You can also help us implement more models. Some TTS related work can be found [here](https://github.com/erogol/TTS-papers). + ## Features - High performance Deep Learning models for Text2Speech related tasks. - Text2Speech models (Tacotron, Tacotron2). @@ -56,7 +75,7 @@ Or you can use ```requirements.txt``` to install the requirements only. | |- train.py (train your TTS model.) | |- distribute.py (train your TTS model using Multiple GPUs) | |- config.json (TTS model configuration file) -| |- tf (Tensorflow 2 utilities and model implementations) +| |- tf/ (Tensorflow 2 utilities and model implementations) | |- layers/ (model layer definitions) | |- models/ (model definitions) | |- notebooks/ (Jupyter Notebooks for model evaluation and parameter selection) From d587094dc522aa420f309831346133b593ae8766 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 19 Jun 2020 16:55:44 +0200 Subject: [PATCH 176/185] formatting fix --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bf25c558..13d6bcfc 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,10 @@ Text-to-Spectrogram: - Tacotron2: [paper](https://arxiv.org/abs/1712.05884) Attention Methods: -- Guided Attention [paper](https://arxiv.org/abs/1710.08969) -- Forward Backward Decoding [paper](https://arxiv.org/abs/1907.09006) -- Graves Attention [paper](https://arxiv.org/abs/1907.09006) -- Double Decoder Consistency [blog](https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency/) +- Guided Attention: [paper](https://arxiv.org/abs/1710.08969) +- Forward Backward Decoding: [paper](https://arxiv.org/abs/1907.09006) +- Graves Attention: [paper](https://arxiv.org/abs/1907.09006) +- Double Decoder Consistency: [blog](https://erogol.com/solving-attention-problems-of-tts-models-with-double-decoder-consistency/) Speaker Encoder: - GE2E: [paper](https://arxiv.org/abs/1710.10467) From dbb4bd884a8745181dee3111d0ad1ab48cd82050 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 22 Jun 2020 14:52:23 +0200 Subject: [PATCH 177/185] print more info in compute_statistics.py --- compute_statistics.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compute_statistics.py b/compute_statistics.py index 9cd073cd..f718cde3 100755 --- a/compute_statistics.py +++ b/compute_statistics.py @@ -63,6 +63,11 @@ def main(): stats['linear_mean'] = linear_mean stats['linear_std'] = linear_scale + print(f' > Avg mel spec mean: {mel_mean.mean()}') + print(f' > Avg mel spec scale: {mel_scale.mean()}') + print(f' > Avg linear spec mean: {linear_mean.mean()}') + print(f' > Avg lienar spec scale: {linear_scale.mean()}') + # set default config values for mean-var scaling CONFIG.audio['stats_path'] = output_file_path CONFIG.audio['signal_norm'] = True @@ -73,6 +78,7 @@ def main(): del CONFIG.audio['clip_norm'] stats['audio_config'] = CONFIG.audio np.save(output_file_path, stats, allow_pickle=True) + print(f' > scale_stats.npy is saved to {output_file_path}') if __name__ == "__main__": From 18d4ed3dc42184295e269f9acb7567b94d312921 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 22 Jun 2020 14:52:45 +0200 Subject: [PATCH 178/185] replace n_fft with fft_size --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 53b12fe1..bdeecdea 100644 --- a/config.json +++ b/config.json @@ -6,7 +6,7 @@ // AUDIO PARAMETERS "audio":{ // stft parameters - "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "fft_size": 1024, // number of stft frequency levels. Size of the linear spectogram frame. "win_length": 1024, // stft window length in ms. "hop_length": 256, // stft window hop-lengh in ms. "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. From 70c83671e68b0b73bf41605ed91b7134e1cba159 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 22 Jun 2020 14:54:23 +0200 Subject: [PATCH 179/185] init coarse decoder with argument list --- models/tacotron.py | 16 ++++++++++------ models/tacotron2.py | 5 ++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/models/tacotron.py b/models/tacotron.py index c526374a..ba42610c 100644 --- a/models/tacotron.py +++ b/models/tacotron.py @@ -46,11 +46,11 @@ class Tacotron(TacotronAbstract): self.embedding = nn.Embedding(num_chars, 256, padding_idx=0) self.embedding.weight.data.normal_(0, 0.3) self.encoder = Encoder(encoder_in_features) - self.decoder = Decoder(decoder_in_features, decoder_output_dim, r, memory_size, attn_type, attn_win, - attn_norm, prenet_type, prenet_dropout, - forward_attn, trans_agent, forward_attn_mask, - location_attn, attn_K, separate_stopnet, - proj_speaker_dim) + self.decoder = Decoder(decoder_in_features, decoder_output_dim, r, + memory_size, attn_type, attn_win, attn_norm, + prenet_type, prenet_dropout, forward_attn, + trans_agent, forward_attn_mask, location_attn, + attn_K, separate_stopnet, proj_speaker_dim) self.postnet = PostCBHG(decoder_output_dim) self.last_linear = nn.Linear(self.postnet.cbhg.gru_features * 2, postnet_output_dim) @@ -74,7 +74,11 @@ class Tacotron(TacotronAbstract): self._init_backward_decoder() # setup DDC if self.double_decoder_consistency: - self._init_coarse_decoder() + self.coarse_decoder = Decoder( + decoder_in_features, decoder_output_dim, ddc_r, memory_size, + attn_type, attn_win, attn_norm, prenet_type, prenet_dropout, + forward_attn, trans_agent, forward_attn_mask, location_attn, + attn_K, separate_stopnet, proj_speaker_dim) def forward(self, characters, text_lengths, mel_specs, mel_lengths=None, speaker_ids=None): diff --git a/models/tacotron2.py b/models/tacotron2.py index 46b915b5..7a56212d 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -68,7 +68,10 @@ class Tacotron2(TacotronAbstract): self._init_backward_decoder() # setup DDC if self.double_decoder_consistency: - self._init_coarse_decoder() + self.coarse_decoder = Decoder(decoder_in_features, self.decoder_output_dim, ddc_r, attn_type, attn_win, + attn_norm, prenet_type, prenet_dropout, + forward_attn, trans_agent, forward_attn_mask, + location_attn, attn_K, separate_stopnet, proj_speaker_dim) @staticmethod def shape_outputs(mel_outputs, mel_outputs_postnet, alignments): From 2f3f43844e80306a5d83e42101cfa5e937ef4583 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 22 Jun 2020 14:55:11 +0200 Subject: [PATCH 180/185] spec_gain fft_size and stft_pad_mode parameters for audio_processor --- train.py | 3 --- utils/audio.py | 28 +++++++++++++++------------- utils/generic_utils.py | 5 +++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/train.py b/train.py index 8581132a..bdafaeba 100644 --- a/train.py +++ b/train.py @@ -473,8 +473,6 @@ def main(args): # pylint: disable=redefined-outer-name model = setup_model(num_chars, num_speakers, c) - print(" | > Num output units : {}".format(ap.num_freq), flush=True) - params = set_weight_decay(model, c.wd) optimizer = RAdam(params, lr=c.lr, weight_decay=0) if c.stopnet and c.separate_stopnet: @@ -542,7 +540,6 @@ def main(args): # pylint: disable=redefined-outer-name if c.bidirectional_decoder: model.decoder_backward.set_r(r) print("\n > Number of output frames:", model.decoder.r) - train_avg_loss_dict, global_step = train(model, criterion, optimizer, optimizer_st, scheduler, ap, global_step, epoch) diff --git a/utils/audio.py b/utils/audio.py index f941f609..31c065ff 100644 --- a/utils/audio.py +++ b/utils/audio.py @@ -17,7 +17,7 @@ class AudioProcessor(object): hop_length=None, win_length=None, ref_level_db=None, - num_freq=None, + fft_size=1024, power=None, preemphasis=0.0, signal_norm=None, @@ -25,6 +25,8 @@ class AudioProcessor(object): max_norm=None, mel_fmin=None, mel_fmax=None, + spec_gain=20, + stft_pad_mode='reflect', clip_norm=True, griffin_lim_iters=None, do_trim_silence=False, @@ -41,7 +43,7 @@ class AudioProcessor(object): self.frame_shift_ms = frame_shift_ms self.frame_length_ms = frame_length_ms self.ref_level_db = ref_level_db - self.num_freq = num_freq + self.fft_size = fft_size self.power = power self.preemphasis = preemphasis self.griffin_lim_iters = griffin_lim_iters @@ -49,6 +51,8 @@ class AudioProcessor(object): self.symmetric_norm = symmetric_norm self.mel_fmin = mel_fmin or 0 self.mel_fmax = mel_fmax + self.spec_gain = float(spec_gain) + self.stft_pad_mode = 'reflect' self.max_norm = 1.0 if max_norm is None else float(max_norm) self.clip_norm = clip_norm self.do_trim_silence = do_trim_silence @@ -58,12 +62,11 @@ class AudioProcessor(object): # setup stft parameters if hop_length is None: # compute stft parameters from given time values - self.n_fft, self.hop_length, self.win_length = self._stft_parameters() + self.hop_length, self.win_length = self._stft_parameters() else: # use stft parameters from config file self.hop_length = hop_length self.win_length = win_length - self.n_fft = (self.num_freq - 1) * 2 assert min_level_db != 0.0, " [!] min_level_db is 0" members = vars(self) for key, value in members.items(): @@ -86,19 +89,18 @@ class AudioProcessor(object): assert self.mel_fmax <= self.sample_rate // 2 return librosa.filters.mel( self.sample_rate, - self.n_fft, + self.fft_size, n_mels=self.num_mels, fmin=self.mel_fmin, fmax=self.mel_fmax) def _stft_parameters(self, ): """Compute necessary stft parameters with given time values""" - n_fft = (self.num_freq - 1) * 2 factor = self.frame_length_ms / self.frame_shift_ms assert (factor).is_integer(), " [!] frame_shift_ms should divide frame_length_ms" hop_length = int(self.frame_shift_ms / 1000.0 * self.sample_rate) win_length = int(hop_length * factor) - return n_fft, hop_length, win_length + return hop_length, win_length ### normalization ### def _normalize(self, S): @@ -110,7 +112,7 @@ class AudioProcessor(object): if hasattr(self, 'mel_scaler'): if S.shape[0] == self.num_mels: return self.mel_scaler.transform(S.T).T - elif S.shape[0] == self.n_fft / 2: + elif S.shape[0] == self.fft_size / 2: return self.linear_scaler.transform(S.T).T else: raise RuntimeError(' [!] Mean-Var stats does not match the given feature dimensions.') @@ -139,7 +141,7 @@ class AudioProcessor(object): if hasattr(self, 'mel_scaler'): if S_denorm.shape[0] == self.num_mels: return self.mel_scaler.inverse_transform(S_denorm.T).T - elif S_denorm.shape[0] == self.n_fft / 2: + elif S_denorm.shape[0] == self.fft_size / 2: return self.linear_scaler.inverse_transform(S_denorm.T).T else: raise RuntimeError(' [!] Mean-Var stats does not match the given feature dimensions.') @@ -184,11 +186,11 @@ class AudioProcessor(object): ### DB and AMP conversion ### # pylint: disable=no-self-use def _amp_to_db(self, x): - return 20 * np.log10(np.maximum(1e-5, x)) + return self.spec_gain * np.log10(np.maximum(1e-5, x)) # pylint: disable=no-self-use def _db_to_amp(self, x): - return np.power(10.0, x * 0.05) + return np.power(10.0, x / self.spec_gain) ### Preemphasis ### def apply_preemphasis(self, x): @@ -254,10 +256,10 @@ class AudioProcessor(object): def _stft(self, y): return librosa.stft( y=y, - n_fft=self.n_fft, + n_fft=self.fft_size, hop_length=self.hop_length, win_length=self.win_length, - pad_mode='constant' + pad_mode=self.stft_pad_mode, ) def _istft(self, y): diff --git a/utils/generic_utils.py b/utils/generic_utils.py index c50f8060..c806bdf3 100644 --- a/utils/generic_utils.py +++ b/utils/generic_utils.py @@ -146,7 +146,7 @@ def setup_model(num_chars, num_speakers, c): model = MyModel(num_chars=num_chars, num_speakers=num_speakers, r=c.r, - postnet_output_dim=c.audio['num_freq'], + postnet_output_dim=int(c.audio['fft_size'] / 2 + 1), decoder_output_dim=c.audio['num_mels'], gst=c.use_gst, memory_size=c.memory_size, @@ -252,7 +252,7 @@ def check_config(c): # audio processing parameters _check_argument('num_mels', c['audio'], restricted=True, val_type=int, min_val=10, max_val=2056) - _check_argument('num_freq', c['audio'], restricted=True, val_type=int, min_val=128, max_val=4058) + _check_argument('fft_size', c['audio'], restricted=True, val_type=int, min_val=128, max_val=4058) _check_argument('sample_rate', c['audio'], restricted=True, val_type=int, min_val=512, max_val=100000) _check_argument('frame_length_ms', c['audio'], restricted=True, val_type=float, min_val=10, max_val=1000, alternative='win_length') _check_argument('frame_shift_ms', c['audio'], restricted=True, val_type=float, min_val=1, max_val=1000, alternative='hop_length') @@ -278,6 +278,7 @@ def check_config(c): _check_argument('clip_norm', c['audio'], restricted=True, val_type=bool) _check_argument('mel_fmin', c['audio'], restricted=True, val_type=float, min_val=0.0, max_val=1000) _check_argument('mel_fmax', c['audio'], restricted=True, val_type=float, min_val=500.0) + _check_argument('spec_gain', c['audio'], restricted=True, val_type=float, min_val=1, max_val=100) _check_argument('do_trim_silence', c['audio'], restricted=True, val_type=bool) _check_argument('trim_db', c['audio'], restricted=True, val_type=int) From 1324117703da659316163109556a5016862a8b07 Mon Sep 17 00:00:00 2001 From: erogol Date: Mon, 22 Jun 2020 14:56:12 +0200 Subject: [PATCH 181/185] update multiband melgan for mean-scale normalization and new audio parameters --- vocoder/configs/multiband_melgan_config.json | 15 +++++++-------- vocoder/layers/losses.py | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/vocoder/configs/multiband_melgan_config.json b/vocoder/configs/multiband_melgan_config.json index d54c64aa..a89d43bb 100644 --- a/vocoder/configs/multiband_melgan_config.json +++ b/vocoder/configs/multiband_melgan_config.json @@ -1,11 +1,10 @@ { "run_name": "multiband-melgan", - "run_description": "multiband melgan", + "run_description": "multiband melgan mean-var scaling", // AUDIO PARAMETERS "audio":{ - // stft parameters - "num_freq": 513, // number of stft frequency levels. Size of the linear spectogram frame. + "fft_size": 1024, // number of stft frequency levels. Size of the linear spectogram frame. "win_length": 1024, // stft window length in ms. "hop_length": 256, // stft window hop-lengh in ms. "frame_length_ms": null, // stft window length in ms.If null, 'win_length' is used. @@ -14,17 +13,17 @@ // Audio processing parameters "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. - "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. + "ref_level_db": 0, // reference level db, theoretically 20db is the sound of air. // Silence trimming "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) "trim_db": 60, // threshold for timming silence. Set this according to your dataset. - // MelSpectrogram parameters "num_mels": 80, // size of the mel spec frame. - "mel_fmin": 0.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! - "mel_fmax": 8000.0, // maximum freq level for mel-spec. Tune for dataset!! + "mel_fmin": 50.0, // minimum freq level for mel-spec. ~50 for male and ~95 for female voices. Tune for dataset!! + "mel_fmax": 7600.0, // maximum freq level for mel-spec. Tune for dataset!! + "spec_gain": 1.0, // scaler value appplied after log transform of spectrogram. // Normalization parameters "signal_norm": true, // normalize spec values. Mean-Var normalization if 'stats_path' is defined otherwise range normalization defined by the other params. @@ -32,7 +31,7 @@ "symmetric_norm": true, // move normalization to range [-1, 1] "max_norm": 4.0, // scale normalization to range [-max_norm, max_norm] or [0, max_norm] "clip_norm": true, // clip normalized values into the range. - "stats_path": null // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored + "stats_path": "/home/erogol/Data/LJSpeech-1.1/scale_stats.npy" // DO NOT USE WITH MULTI_SPEAKER MODEL. scaler stats file computed by 'compute_statistics.py'. If it is defined, mean-std based notmalization is used and other normalization params are ignored }, // DISTRIBUTED TRAINING diff --git a/vocoder/layers/losses.py b/vocoder/layers/losses.py index d6ffe9fe..431f7f45 100644 --- a/vocoder/layers/losses.py +++ b/vocoder/layers/losses.py @@ -20,7 +20,7 @@ class TorchSTFT(): self.win_length, self.window, center=True, - pad_mode="constant", # compatible with audio.py + pad_mode="reflect", # compatible with audio.py normalized=False, onesided=True) M = o[:, :, :, 0] From ccba431cdac1e6f44bd39b83d6a8ebdd166992a5 Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 23 Jun 2020 13:29:55 +0200 Subject: [PATCH 182/185] handling dates better with the text cleaner --- models/tacotron2.py | 3 - utils/text/__init__.py | 1 - utils/text/cleaners.py | 2 +- utils/text/number_norm.py | 149 +++++++-------------- vocoder/tests/test_melgan_discriminator.py | 2 +- 5 files changed, 49 insertions(+), 108 deletions(-) diff --git a/models/tacotron2.py b/models/tacotron2.py index 7a56212d..d9570f8d 100644 --- a/models/tacotron2.py +++ b/models/tacotron2.py @@ -44,9 +44,6 @@ class Tacotron2(TacotronAbstract): proj_speaker_dim = 80 if num_speakers > 1 else 0 # base layers self.embedding = nn.Embedding(num_chars, 512, padding_idx=0) - std = sqrt(2.0 / (num_chars + 512)) - val = sqrt(3.0) * std # uniform bounds for std - self.embedding.weight.data.uniform_(-val, val) if num_speakers > 1: self.speaker_embedding = nn.Embedding(num_speakers, 512) self.speaker_embedding.weight.data.normal_(0, 0.3) diff --git a/utils/text/__init__.py b/utils/text/__init__.py index 79069192..41aa6778 100644 --- a/utils/text/__init__.py +++ b/utils/text/__init__.py @@ -77,7 +77,6 @@ def phoneme_to_sequence(text, cleaner_names, language, enable_eos_bos=False, tp= _phonemes_to_id = {s: i for i, s in enumerate(_phonemes)} sequence = [] - text = text.replace(":", "") clean_text = _clean_text(text, cleaner_names) to_phonemes = text2phone(clean_text, language) if to_phonemes is None: diff --git a/utils/text/cleaners.py b/utils/text/cleaners.py index 35da8aef..f0a66f57 100644 --- a/utils/text/cleaners.py +++ b/utils/text/cleaners.py @@ -71,7 +71,7 @@ def remove_aux_symbols(text): def replace_symbols(text): text = text.replace(';', ',') text = text.replace('-', ' ') - text = text.replace(':', ' ') + text = text.replace(':', ',') text = text.replace('&', 'and') return text diff --git a/utils/text/number_norm.py b/utils/text/number_norm.py index d3d9a46b..54fa1093 100644 --- a/utils/text/number_norm.py +++ b/utils/text/number_norm.py @@ -1,127 +1,72 @@ +# -*- coding: utf-8 -*- +""" from https://github.com/keithito/tacotron """ + +import inflect import re + +_inflect = inflect.engine() _comma_number_re = re.compile(r'([0-9][0-9\,]+[0-9])') _decimal_number_re = re.compile(r'([0-9]+\.[0-9]+)') _pounds_re = re.compile(r'£([0-9\,]*[0-9]+)') _dollars_re = re.compile(r'\$([0-9\.\,]*[0-9]+)') -_ordinal_re = re.compile(r'([0-9]+)(st|nd|rd|th)') +_ordinal_re = re.compile(r'[0-9]+(st|nd|rd|th)') _number_re = re.compile(r'[0-9]+') -_units = [ - '', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', - 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', - 'seventeen', 'eighteen', 'nineteen' -] - -_tens = [ - '', - 'ten', - 'twenty', - 'thirty', - 'forty', - 'fifty', - 'sixty', - 'seventy', - 'eighty', - 'ninety', -] - -_digit_groups = [ - '', - 'thousand', - 'million', - 'billion', - 'trillion', - 'quadrillion', -] - -_ordinal_suffixes = [ - ('one', 'first'), - ('two', 'second'), - ('three', 'third'), - ('five', 'fifth'), - ('eight', 'eighth'), - ('nine', 'ninth'), - ('twelve', 'twelfth'), - ('ty', 'tieth'), -] - def _remove_commas(m): - return m.group(1).replace(',', '') + return m.group(1).replace(',', '') def _expand_decimal_point(m): - return m.group(1).replace('.', ' point ') + return m.group(1).replace('.', ' point ') def _expand_dollars(m): - match = m.group(1) - parts = match.split('.') - if len(parts) > 2: - return match + ' dollars' # Unexpected format - dollars = int(parts[0]) if parts[0] else 0 - cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0 - if dollars and cents: - dollar_unit = 'dollar' if dollars == 1 else 'dollars' - cent_unit = 'cent' if cents == 1 else 'cents' - return '%s %s, %s %s' % (dollars, dollar_unit, cents, cent_unit) - if dollars: - dollar_unit = 'dollar' if dollars == 1 else 'dollars' - return '%s %s' % (dollars, dollar_unit) - if cents: - cent_unit = 'cent' if cents == 1 else 'cents' - return '%s %s' % (cents, cent_unit) + match = m.group(1) + parts = match.split('.') + if len(parts) > 2: + return match + ' dollars' # Unexpected format + dollars = int(parts[0]) if parts[0] else 0 + cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0 + if dollars and cents: + dollar_unit = 'dollar' if dollars == 1 else 'dollars' + cent_unit = 'cent' if cents == 1 else 'cents' + return '%s %s, %s %s' % (dollars, dollar_unit, cents, cent_unit) + elif dollars: + dollar_unit = 'dollar' if dollars == 1 else 'dollars' + return '%s %s' % (dollars, dollar_unit) + elif cents: + cent_unit = 'cent' if cents == 1 else 'cents' + return '%s %s' % (cents, cent_unit) + else: return 'zero dollars' -def _standard_number_to_words(n, digit_group): - parts = [] - if n >= 1000: - # Format next higher digit group. - parts.append(_standard_number_to_words(n // 1000, digit_group + 1)) - n = n % 1000 - - if n >= 100: - parts.append('%s hundred' % _units[n // 100]) - if n % 100 >= len(_units): - parts.append(_tens[(n % 100) // 10]) - parts.append(_units[(n % 100) % 10]) - else: - parts.append(_units[n % 100]) - if n > 0: - parts.append(_digit_groups[digit_group]) - return ' '.join([x for x in parts if x]) - - -def _number_to_words(n): - # Handle special cases first, then go to the standard case: - if n >= 1000000000000000000: - return str(n) # Too large, just return the digits - if n == 0: - return 'zero' - if n % 100 == 0 and n % 1000 != 0 and n < 3000: - return _standard_number_to_words(n // 100, 0) + ' hundred' - return _standard_number_to_words(n, 0) +def _expand_ordinal(m): + return _inflect.number_to_words(m.group(0)) def _expand_number(m): - return _number_to_words(int(m.group(0))) - - -def _expand_ordinal(m): - num = _number_to_words(int(m.group(1))) - for suffix, replacement in _ordinal_suffixes: - if num.endswith(suffix): - return num[:-len(suffix)] + replacement - return num + 'th' + num = int(m.group(0)) + if num > 1000 and num < 3000: + if num == 2000: + return 'two thousand' + elif num > 2000 and num < 2010: + return 'two thousand ' + _inflect.number_to_words(num % 100) + elif num % 100 == 0: + return _inflect.number_to_words(num // 100) + ' hundred' + else: + return _inflect.number_to_words(num, andword='', zero='oh', group=2).replace(', ', ' ') + else: + return _inflect.number_to_words(num, andword='') def normalize_numbers(text): - text = re.sub(_comma_number_re, _remove_commas, text) - text = re.sub(_pounds_re, r'\1 pounds', text) - text = re.sub(_dollars_re, _expand_dollars, text) - text = re.sub(_decimal_number_re, _expand_decimal_point, text) - text = re.sub(_ordinal_re, _expand_ordinal, text) - text = re.sub(_number_re, _expand_number, text) - return text + text = re.sub(_comma_number_re, _remove_commas, text) + text = re.sub(_pounds_re, r'\1 pounds', text) + text = re.sub(_dollars_re, _expand_dollars, text) + text = re.sub(_decimal_number_re, _expand_decimal_point, text) + text = re.sub(_ordinal_re, _expand_ordinal, text) + text = re.sub(_number_re, _expand_number, text) + return text \ No newline at end of file diff --git a/vocoder/tests/test_melgan_discriminator.py b/vocoder/tests/test_melgan_discriminator.py index a4564b56..a89dad5e 100644 --- a/vocoder/tests/test_melgan_discriminator.py +++ b/vocoder/tests/test_melgan_discriminator.py @@ -23,4 +23,4 @@ def test_melgan_multi_scale_discriminator(): assert np.all(scores[0].shape == (4, 1, 64)) assert np.all(feats[0][0].shape == (4, 16, 4096)) assert np.all(feats[0][1].shape == (4, 64, 1024)) - assert np.all(feats[0][2].shape == (4, 256, 256)) + assert np.all(feats[0][2].shape == (4, 256, 256)) \ No newline at end of file From 216bba97599af72e3e2b8dabf58fe865ed30fd0b Mon Sep 17 00:00:00 2001 From: erogol Date: Tue, 23 Jun 2020 21:55:51 +0200 Subject: [PATCH 183/185] add new test sentence --- layers/custom_layers.py | 24 ------------------------ train.py | 5 +++-- 2 files changed, 3 insertions(+), 26 deletions(-) delete mode 100644 layers/custom_layers.py diff --git a/layers/custom_layers.py b/layers/custom_layers.py deleted file mode 100644 index 72668c97..00000000 --- a/layers/custom_layers.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: utf-8 -# import torch -# from torch import nn - -# class StopProjection(nn.Module): -# r""" Simple projection layer to predict the "stop token" - -# Args: -# in_features (int): size of the input vector -# out_features (int or list): size of each output vector. aka number -# of predicted frames. -# """ - -# def __init__(self, in_features, out_features): -# super(StopProjection, self).__init__() -# self.linear = nn.Linear(in_features, out_features) -# self.dropout = nn.Dropout(0.5) -# self.sigmoid = nn.Sigmoid() - -# def forward(self, inputs): -# out = self.dropout(inputs) -# out = self.linear(out) -# out = self.sigmoid(out) -# return out diff --git a/train.py b/train.py index bdafaeba..189a6baa 100644 --- a/train.py +++ b/train.py @@ -333,7 +333,7 @@ def evaluate(model, criterion, ap, global_step, epoch): if c.stopnet: loss_dict['stopnet_loss'] = reduce_tensor(loss_dict['stopnet_loss'].data, num_gpus) - # detach loss values + # detach loss values loss_dict_new = dict() for key, value in loss_dict.items(): if isinstance(value, (int, float)): @@ -388,7 +388,8 @@ def evaluate(model, criterion, ap, global_step, epoch): "It took me quite a long time to develop a voice, and now that I have it I'm not going to be silent.", "Be a voice, not an echo.", "I'm sorry Dave. I'm afraid I can't do that.", - "This cake is great. It's so delicious and moist." + "This cake is great. It's so delicious and moist.", + "Prior to November 22, 1963." ] else: with open(c.test_sentences_file, "r") as f: From 77c962561ec8d68b5690756d3301438f966e3e4d Mon Sep 17 00:00:00 2001 From: erogol Date: Wed, 24 Jun 2020 12:18:13 +0200 Subject: [PATCH 184/185] resolve config comments --- config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index bdeecdea..77a223dc 100644 --- a/config.json +++ b/config.json @@ -13,12 +13,12 @@ "frame_shift_ms": null, // stft window hop-lengh in ms. If null, 'hop_length' is used. // Audio processing parameters - "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled. + "sample_rate": 22050, // DATASET-RELATED: wav sample-rate. "preemphasis": 0.0, // pre-emphasis to reduce spec noise and make it more structured. If 0.0, no -pre-emphasis. "ref_level_db": 20, // reference level db, theoretically 20db is the sound of air. // Silence trimming - "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (false), TWEB (false), Nancy (true) + "do_trim_silence": true,// enable trimming of slience of audio as you load it. LJspeech (true), TWEB (false), Nancy (true) "trim_db": 60, // threshold for timming silence. Set this according to your dataset. // Griffin-Lim @@ -89,7 +89,7 @@ // ATTENTION "attention_type": "original", // 'original' or 'graves' "attention_heads": 4, // number of attention heads (only for 'graves') - "attention_norm": "sigmoid", // softmax or sigmoid. Suggested to use softmax for Tacotron2 and sigmoid for Tacotron. + "attention_norm": "sigmoid", // softmax or sigmoid. "windowing": false, // Enables attention windowing. Used only in eval mode. "use_forward_attn": false, // if it uses forward attention. In general, it aligns faster. "forward_attn_mask": false, // Additional masking forcing monotonicity only in eval mode. From b1935c97fa1175908c579a4db06214174253f5f4 Mon Sep 17 00:00:00 2001 From: erogol Date: Fri, 26 Jun 2020 14:35:40 +0200 Subject: [PATCH 185/185] update server to enable native vocoder inference and remove pwgan support --- server/server.py | 12 ++++++++++ server/synthesizer.py | 46 ++++++++++++++++++++++++++----------- server/templates/index.html | 8 +++---- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/server/server.py b/server/server.py index 593eeb18..43f1b3c4 100644 --- a/server/server.py +++ b/server/server.py @@ -21,6 +21,8 @@ def create_argparser(): parser.add_argument('--pwgan_lib_path', type=str, default=None, help='path to ParallelWaveGAN project folder to be imported. If this is not passed, model uses Griffin-Lim for synthesis.') parser.add_argument('--pwgan_file', type=str, default=None, help='path to ParallelWaveGAN checkpoint file.') parser.add_argument('--pwgan_config', type=str, default=None, help='path to ParallelWaveGAN config file.') + parser.add_argument('--vocoder_config', type=str, default=None, help='path to TTS.vocoder config file.') + parser.add_argument('--vocoder_checkpoint', type=str, default=None, help='path to TTS.vocoder checkpoint file.') parser.add_argument('--port', type=int, default=5002, help='port to listen on.') parser.add_argument('--use_cuda', type=convert_boolean, default=False, help='true to use CUDA.') parser.add_argument('--debug', type=convert_boolean, default=False, help='true to enable Flask debug mode.') @@ -35,6 +37,11 @@ embedded_tts_folder = os.path.join(embedded_models_folder, 'tts') tts_checkpoint_file = os.path.join(embedded_tts_folder, 'checkpoint.pth.tar') tts_config_file = os.path.join(embedded_tts_folder, 'config.json') +embedded_vocoder_folder = os.path.join(embedded_models_folder, 'vocoder') +vocoder_checkpoint_file = os.path.join(embedded_vocoder_folder, 'checkpoint.pth.tar') +vocoder_config_file = os.path.join(embedded_vocoder_folder, 'config.json') + +# These models are soon to be deprecated embedded_wavernn_folder = os.path.join(embedded_models_folder, 'wavernn') wavernn_checkpoint_file = os.path.join(embedded_wavernn_folder, 'checkpoint.pth.tar') wavernn_config_file = os.path.join(embedded_wavernn_folder, 'config.json') @@ -50,6 +57,11 @@ if not args.tts_checkpoint and os.path.isfile(tts_checkpoint_file): args.tts_checkpoint = tts_checkpoint_file if not args.tts_config and os.path.isfile(tts_config_file): args.tts_config = tts_config_file +if not args.vocoder_checkpoint and os.path.isfile(tts_checkpoint_file): + args.tts_checkpoint = tts_checkpoint_file +if not args.vocoder_config and os.path.isfile(tts_config_file): + args.tts_config = tts_config_file + if not args.wavernn_file and os.path.isfile(wavernn_checkpoint_file): args.wavernn_file = wavernn_checkpoint_file if not args.wavernn_config and os.path.isfile(wavernn_config_file): diff --git a/server/synthesizer.py b/server/synthesizer.py index c6fde902..d85bbebc 100644 --- a/server/synthesizer.py +++ b/server/synthesizer.py @@ -1,6 +1,7 @@ import io import re import sys +import time import numpy as np import torch @@ -10,6 +11,7 @@ from TTS.utils.audio import AudioProcessor from TTS.utils.io import load_config from TTS.utils.generic_utils import setup_model from TTS.utils.speakers import load_speaker_mapping +from TTS.vocoder.utils.generic_utils import setup_generator # pylint: disable=unused-wildcard-import # pylint: disable=wildcard-import from TTS.utils.synthesis import * @@ -34,6 +36,8 @@ class Synthesizer(object): assert torch.cuda.is_available(), "CUDA is not availabe on this machine." self.load_tts(self.config.tts_checkpoint, self.config.tts_config, self.config.use_cuda) + if self.config.vocoder_checkpoint: + self.load_vocoder(self.config.vocoder_checkpoint, self.config.vocoder_config, self.config.use_cuda) if self.config.wavernn_lib_path: self.load_wavernn(self.config.wavernn_lib_path, self.config.wavernn_file, self.config.wavernn_config, self.config.use_cuda) @@ -77,6 +81,19 @@ class Synthesizer(object): self.tts_model.decoder.max_decoder_steps = 3000 if 'r' in cp: self.tts_model.decoder.set_r(cp['r']) + print(f" > model reduction factor: {cp['r']}") + + def load_vocoder(self, model_file, model_config, use_cuda): + self.vocoder_config = load_config(model_config) + self.vocoder_model = setup_generator(self.vocoder_config) + self.vocoder_model.load_state_dict(torch.load(model_file, map_location="cpu")["model"]) + self.vocoder_model.remove_weight_norm() + self.vocoder_model.inference_padding = 0 + self.vocoder_config = load_config(model_config) + + if use_cuda: + self.vocoder_model.cuda() + self.vocoder_model.eval() def load_wavernn(self, lib_path, model_file, model_config, use_cuda): # TODO: set a function in wavernn code base for model setup and call it here. @@ -171,6 +188,7 @@ class Synthesizer(object): return sentences def tts(self, text, speaker_id=None): + start_time = time.time() wavs = [] sens = self.split_into_sentences(text) print(sens) @@ -184,29 +202,25 @@ class Synthesizer(object): inputs = numpy_to_torch(inputs, torch.long, cuda=self.use_cuda) inputs = inputs.unsqueeze(0) # synthesize voice - decoder_output, postnet_output, alignments, stop_tokens = run_model_torch( - self.tts_model, inputs, self.tts_config, False, speaker_id, None) + decoder_output, postnet_output, alignments, stop_tokens = run_model_torch(self.tts_model, inputs, self.tts_config, False, speaker_id, None) # convert outputs to numpy - postnet_output, decoder_output, _, _ = parse_outputs_torch( - postnet_output, decoder_output, alignments, stop_tokens) - - if self.pwgan: - vocoder_input = torch.FloatTensor(postnet_output.T).unsqueeze(0) + if self.vocoder_model: + vocoder_input = postnet_output[0].transpose(0, 1).unsqueeze(0) + wav = self.vocoder_model.inference(vocoder_input) if self.use_cuda: - vocoder_input.cuda() - wav = self.pwgan.inference(vocoder_input, hop_size=self.ap.hop_length) + wav = wav.cpu().numpy() + else: + wav = wav.numpy() + wav = wav.flatten() elif self.wavernn: vocoder_input = None if self.tts_config.model == "Tacotron": vocoder_input = torch.FloatTensor(self.ap.out_linear_to_mel(linear_spec=postnet_output.T).T).T.unsqueeze(0) else: - vocoder_input = torch.FloatTensor(postnet_output.T).unsqueeze(0) - + vocoder_input = postnet_output[0].transpose(0, 1).unsqueeze(0) if self.use_cuda: vocoder_input.cuda() wav = self.wavernn.generate(vocoder_input, batched=self.config.is_wavernn_batched, target=11000, overlap=550) - else: - wav = inv_spectrogram(postnet_output, self.ap, self.tts_config) # trim silence wav = trim_silence(wav, self.ap) @@ -215,4 +229,10 @@ class Synthesizer(object): out = io.BytesIO() self.save_wav(wavs, out) + + # compute stats + process_time = time.time() - start_time + audio_time = len(wavs) / self.tts_config.audio['sample_rate'] + print(f" > Processing time: {process_time}") + print(f" > Real-time factor: {process_time / audio_time}") return out diff --git a/server/templates/index.html b/server/templates/index.html index d1bde024..45b874a9 100644 --- a/server/templates/index.html +++ b/server/templates/index.html @@ -8,10 +8,10 @@ - Mozillia - Text2Speech engine + Mozilla - Text2Speech engine - @@ -27,7 +27,7 @@ - + Fork me on GitHub @@ -60,7 +60,7 @@

Mozilla TTS

- +