227 lines
9.8 KiB
Python
227 lines
9.8 KiB
Python
#!/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 <module>
|
|
# 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]
|