#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys import os import argparse import torch # load coqui-ai/trainer libraries from trainer import Trainer, TrainerArgs # load coqui-ai/TTS libraries from TTS.tts.configs.shared_configs import BaseDatasetConfig from TTS.tts.configs.vits_config import VitsConfig from TTS.tts.datasets import load_tts_samples from TTS.tts.models.vits import Vits, VitsArgs, VitsAudioConfig # # parse command line arguments # def parse_cmdline_args(): parser = argparse.ArgumentParser( description = "Code to clone a voice from a given set of voice samples and a multi-speaker baseline model") parser.add_argument("--baseline_model_path", type = str, required = True, help = "Path to multi-speaker baseline model (VITS model)") parser.add_argument("--speaker_dataset_path", type = str, required = True, help = "Path to voice cloning dataset") parser.add_argument("--speaker_embeddings_path", type = str, required = True, help = "Path to speaker's embeddings file") parser.add_argument("--output_path", type = str, default = "results/cloned-voices", help = "Path to store trained / generated assets") parser.add_argument("--batch_size", type = int, default = 96, # 96 is suitable for AWS g5 instances help = "Batch size for training run") parser.add_argument("--max_epochs", type = int, default = 200, # 200 for batch_size 96 (with the 22.050 sampling rate multi-speaker model help = "Maximum number of epochs for training run") # 2000 for batch_size 64 and 1500 for batch_size 96 (with the initial 16k sampling rate VCTK 0.80 model) parser.add_argument("--use_cpu", default = False, action = "store_true", # untested!!! help = "Signal that CPU should be used even if a CUDA-device is available") parser.add_argument("--output_format", type = str, choices = ["txt", "json"], default = "txt", help = "Output format; available choices include 'txt' for human readible text and 'json' for JSON formatting") return parser.parse_args() # # main training method (voice cloning) # def main(args): if args.output_format == "txt": print("Commencing training of a new multi-speaker potion-voice baseline model:") print("") print(" + Baseline multi-speaker model path: {}" . format(args.baseline_model_path)) print(" + Voice training dataset path : {}" . format(args.speaker_dataset_path)) print(" + Speaker embeddings path : {}" . format(args.speaker_embeddings_path)) print(" + Output path : {}" . format(args.output_path)) print(" + Batch size : {}" . format(args.batch_size)) print(" + Training runs (max epochs) : {}" . format(args.max_epochs)) print("") # determine whether CUDA support is available and set device parameters accordingly use_cuda = torch.cuda.is_available() if args.output_format == "txt": print(" + CUDA availability : {}" . format(use_cuda)) if args.use_cpu: device = "cpu" device_torch = False elif use_cuda: device = "cuda" device_torch = torch.device("cuda") else: device = "cpu" device_torch = False if args.output_format == "txt": print(" + Compute device used : {}" . format(device)) print("") # define training data set dataset_config = BaseDatasetConfig(formatter = "vctk_old", language = "en-us", path = args.speaker_dataset_path) # set VITS training parameters audio_config = VitsAudioConfig( sample_rate = 22050, win_length = 1024, hop_length = 256, num_mels = 80, mel_fmin = 0, mel_fmax = None, ) vitsArgs = VitsArgs( use_speaker_embedding = False, use_d_vector_file = True, d_vector_file = [args.speaker_embeddings_path], d_vector_dim = 512, num_layers_text_encoder = 10 ) config = VitsConfig( model_args = vitsArgs, audio = audio_config, run_name = "vits_potion_clone", use_speaker_embedding = False, use_d_vector_file = True, d_vector_file = [args.speaker_embeddings_path], d_vector_dim = 512, batch_size = args.batch_size, eval_batch_size = 8, batch_group_size = 0, # changing this to 5 (VITS training default) slows training down, but doesn't have any positive training effects num_loader_workers = 4, num_eval_loader_workers = 4, run_eval = True, eval_split_size = 2, # fix size of eval dataset (default 1% approach requires at least 100 voice samples!) test_delay_epochs = -1, epochs = args.max_epochs, text_cleaner = "english_cleaners", use_phonemes = False, phoneme_language = "en-us", phoneme_cache_path = os.path.join(args.output_path, "phoneme_cache"), compute_input_seq_cache = True, print_step = 50, print_eval = True, mixed_precision = True, max_text_len = 325, output_path = args.output_path, save_checkpoints = True, save_step = 200, datasets = [dataset_config], cudnn_benchmark = False, #characters = { # "pad": "_", # "eos": "&", # "bos": "*", # "characters": "!¡'(),-.:;¿?abcdefghijklmnopqrstuvwxyz «°±µ»$%&‘’‚“`”„", # "punctuations": "!¡'(),-.:;¿? ", # "phonemes": None, # "unique": True #}, test_sentences = [ ["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."], ["Prior to November 22, 1963."], ["Hey! Sandra."], ["Hey! Andrew."], ["Hey, Michelle."], ["Hey! George."], ["Hey there, Rachel."] ] ) # load training samples train_samples, eval_samples = load_tts_samples(config.datasets, eval_split = True, eval_split_max_size = config.eval_split_max_size, eval_split_size = config.eval_split_size) # init VITS model model = Vits.init_from_config(config) # init voice cloning trainer = Trainer( TrainerArgs(restore_path = args.baseline_model_path, use_ddp = False), config, args.output_path, model = model, train_samples = train_samples, eval_samples = eval_samples ) # trigger voice cloning (aka single speaker training) try: trainer.fit() except (KeyboardInterrupt, SystemExit): print("Training stopped manually (via keyboard interrupt)! Bye.") exit(0) # determine required adjustment for speech synthesizing (i.e., the scaling factor for the duration predictor) # take the duration of the test sentence and calculate the difference to corresponding reference samples # set config.model_args["length_scale"] accordingly and save the updated config asset # exit gracefully if args.output_format == "txt": print("") print("Completed voice cloning. The resulting model(s) can be found at:") print(" --> {}" . format(args.output_path)) print("") print("Done; bye.") print("") if __name__ == "__main__": # parse command line arguments args = parse_cmdline_args() # clear command line arguments to avoid triggering argparse features part of Trainer / coqpit imports # Traceback (most recent call last): # File "train_multispeaker_baseline_model.py", line 208, in # main(args) # File "train_multispeaker_baseline_model.py", line 177, in main # trainer = Trainer( # File "/home/ubuntu/dev/potion-voice_venv/lib/python3.8/site-packages/trainer/trainer.py", line 360, in __init__ # config, new_fields = self.init_training(args, coqpit_overrides, config) # File "/home/ubuntu/dev/potion-voice_venv/lib/python3.8/site-packages/trainer/trainer.py", line 594, in init_training # config.parse_known_args(coqpit_overrides, relaxed_parser=True) # File "/home/ubuntu/dev/potion-voice_venv/lib/python3.8/site-packages/coqpit/coqpit.py", line 843, in parse_known_args # parser = self.init_argparse(arg_prefix=arg_prefix, relaxed_parser=relaxed_parser) # File "/home/ubuntu/dev/potion-voice_venv/lib/python3.8/site-packages/coqpit/coqpit.py", line 881, in init_argparse # _init_argparse( # File "/home/ubuntu/dev/potion-voice_venv/lib/python3.8/site-packages/coqpit/coqpit.py", line 529, in _init_argparse # parser = _init_argparse( # File "/home/ubuntu/dev/potion-voice_venv/lib/python3.8/site-packages/coqpit/coqpit.py", line 550, in _init_argparse # return default.init_argparse( # AttributeError: 'str' object has no attribute 'init_argparse' sys.argv = [sys.argv[0]] # ensure the output path exists os.makedirs(args.output_path, exist_ok = True) main(args) ### USAGE: ### $ python3 TTS/TTS/bin/resample.py --input_dir voice_dataset_path/person_82/wav48/1 --output_sr 16000 ### $ python3 clone_voice.py [with argument]