mirror of https://github.com/coqui-ai/TTS.git
refactor and fix compat issues for speaker encoder
This commit is contained in:
parent
540d811dd5
commit
f9001a4bdd
|
@ -11,10 +11,10 @@ import torch
|
||||||
from torch.utils.data import DataLoader
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
from TTS.speaker_encoder.dataset import MyDataset
|
from TTS.speaker_encoder.dataset import MyDataset
|
||||||
from TTS.speaker_encoder.generic_utils import save_best_model
|
from TTS.speaker_encoder.utils.generic_utils import save_best_model
|
||||||
from TTS.speaker_encoder.losses import GE2ELoss, AngleProtoLoss
|
from TTS.speaker_encoder.losses import GE2ELoss, AngleProtoLoss
|
||||||
from TTS.speaker_encoder.model import SpeakerEncoder
|
from TTS.speaker_encoder.model import SpeakerEncoder
|
||||||
from TTS.speaker_encoder.visual import plot_embeddings
|
from TTS.speaker_encoder.utils.visual import plot_embeddings
|
||||||
from TTS.tts.datasets.preprocess import load_meta_data
|
from TTS.tts.datasets.preprocess import load_meta_data
|
||||||
from TTS.utils.generic_utils import (
|
from TTS.utils.generic_utils import (
|
||||||
create_experiment_folder, get_git_branch, remove_experiment_folder,
|
create_experiment_folder, get_git_branch, remove_experiment_folder,
|
||||||
|
|
|
@ -7,8 +7,8 @@ from tqdm import tqdm
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from TTS.speaker_encoder.model import SpeakerEncoder
|
from TTS.speaker_encoder.model import SpeakerEncoder
|
||||||
from TTS.tts.utils.audio import AudioProcessor
|
from TTS.utils.audio import AudioProcessor
|
||||||
from TTS.tts.utils.generic_utils import load_config
|
from TTS.utils.io import load_config
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Compute embedding vectors for each wav file in a dataset. ')
|
description='Compute embedding vectors for each wav file in a dataset. ')
|
||||||
|
@ -80,7 +80,7 @@ if args.use_cuda:
|
||||||
model.cuda()
|
model.cuda()
|
||||||
|
|
||||||
for idx, wav_file in enumerate(tqdm(wav_files)):
|
for idx, wav_file in enumerate(tqdm(wav_files)):
|
||||||
mel_spec = ap.melspectrogram(ap.load_wav(wav_file)).T
|
mel_spec = ap.melspectrogram(ap.load_wav(wav_file, sr=ap.sample_rate)).T
|
||||||
mel_spec = torch.FloatTensor(mel_spec[None, :, :])
|
mel_spec = torch.FloatTensor(mel_spec[None, :, :])
|
||||||
if args.use_cuda:
|
if args.use_cuda:
|
||||||
mel_spec = mel_spec.cuda()
|
mel_spec = mel_spec.cuda()
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
|
|
||||||
{
|
|
||||||
"run_name": "Model compatible to CorentinJ/Real-Time-Voice-Cloning",
|
|
||||||
"run_description": "train speaker encoder with voxceleb1, voxceleb2 and libriSpeech ",
|
|
||||||
"audio":{
|
|
||||||
// Audio processing parameters
|
|
||||||
"num_mels": 40, // size of the mel spec frame.
|
|
||||||
"fft_size": 400, // number of stft frequency levels. Size of the linear spectogram frame.
|
|
||||||
"sample_rate": 16000, // DATASET-RELATED: wav sample-rate. If different than the original data, it is resampled.
|
|
||||||
"win_length": 400, // stft window length in ms.
|
|
||||||
"hop_length": 160, // 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.
|
|
||||||
"preemphasis": 0.98, // 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": 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": 4.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": false, // 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.
|
|
||||||
},
|
|
||||||
"reinit_layers": [],
|
|
||||||
"loss": "ge2e", // "ge2e" to use Generalized End-to-End loss and "angleproto" to use Angular Prototypical loss (new SOTA)
|
|
||||||
"grad_clip": 3.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.
|
|
||||||
"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"
|
|
||||||
"tb_model_param_stats": false, // true, plots param stats per layer on tensorboard. Might be memory consuming, but good for debugging.
|
|
||||||
"steps_plot_stats": 10, // number of steps to plot embeddings.
|
|
||||||
"num_speakers_in_batch": 32, // Batch size for training. Lower values than 32 might cause hard to learn attention. It is overwritten by 'gradual_training'.
|
|
||||||
"num_loader_workers": 4, // number of training data loader processes. Don't set it too big. 4-8 are good values.
|
|
||||||
"wd": 0.000001, // Weight decay weight.
|
|
||||||
"checkpoint": true, // If true, it saves checkpoints per "save_step"
|
|
||||||
"save_step": 1000, // Number of training steps expected to save traning stats and checkpoints.
|
|
||||||
"print_step": 1, // Number of steps to log traning on console.
|
|
||||||
"output_path": "../../checkpoints/voxceleb_librispeech/speaker_encoder/", // DATASET-RELATED: output path for all training outputs.
|
|
||||||
"model": {
|
|
||||||
"input_dim": 40,
|
|
||||||
"proj_dim": 256,
|
|
||||||
"lstm_dim": 256,
|
|
||||||
"num_lstm_layers": 3,
|
|
||||||
"use_lstm_with_projection": false
|
|
||||||
},
|
|
||||||
"datasets":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "vctk",
|
|
||||||
"path": "../../../datasets/VCTK-Corpus-removed-silence/",
|
|
||||||
"meta_file_train": null,
|
|
||||||
"meta_file_val": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import os
|
|
||||||
import datetime
|
|
||||||
import torch
|
|
||||||
|
|
||||||
|
|
||||||
def save_checkpoint(model, optimizer, model_loss, out_path,
|
|
||||||
current_step, epoch):
|
|
||||||
checkpoint_path = 'checkpoint_{}.pth.tar'.format(current_step)
|
|
||||||
checkpoint_path = os.path.join(out_path, checkpoint_path)
|
|
||||||
print(" | | > Checkpoint saving : {}".format(checkpoint_path))
|
|
||||||
|
|
||||||
new_state_dict = model.state_dict()
|
|
||||||
state = {
|
|
||||||
'model': new_state_dict,
|
|
||||||
'optimizer': optimizer.state_dict() if optimizer is not None else None,
|
|
||||||
'step': current_step,
|
|
||||||
'epoch': epoch,
|
|
||||||
'loss': model_loss,
|
|
||||||
'date': datetime.date.today().strftime("%B %d, %Y"),
|
|
||||||
}
|
|
||||||
torch.save(state, checkpoint_path)
|
|
||||||
|
|
||||||
|
|
||||||
def save_best_model(model, optimizer, model_loss, best_loss, out_path,
|
|
||||||
current_step):
|
|
||||||
if model_loss < best_loss:
|
|
||||||
new_state_dict = model.state_dict()
|
|
||||||
state = {
|
|
||||||
'model': new_state_dict,
|
|
||||||
'optimizer': optimizer.state_dict(),
|
|
||||||
'step': current_step,
|
|
||||||
'loss': model_loss,
|
|
||||||
'date': datetime.date.today().strftime("%B %d, %Y"),
|
|
||||||
}
|
|
||||||
best_loss = model_loss
|
|
||||||
bestmodel_path = 'best_model.pth.tar'
|
|
||||||
bestmodel_path = os.path.join(out_path, bestmodel_path)
|
|
||||||
print("\n > BEST MODEL ({0:.5f}) : {1:}".format(
|
|
||||||
model_loss, bestmodel_path))
|
|
||||||
torch.save(state, bestmodel_path)
|
|
||||||
return best_loss
|
|
|
@ -1,46 +0,0 @@
|
||||||
import umap
|
|
||||||
import numpy as np
|
|
||||||
import matplotlib
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
matplotlib.use("Agg")
|
|
||||||
|
|
||||||
|
|
||||||
colormap = (
|
|
||||||
np.array(
|
|
||||||
[
|
|
||||||
[76, 255, 0],
|
|
||||||
[0, 127, 70],
|
|
||||||
[255, 0, 0],
|
|
||||||
[255, 217, 38],
|
|
||||||
[0, 135, 255],
|
|
||||||
[165, 0, 165],
|
|
||||||
[255, 167, 255],
|
|
||||||
[0, 255, 255],
|
|
||||||
[255, 96, 38],
|
|
||||||
[142, 76, 0],
|
|
||||||
[33, 0, 127],
|
|
||||||
[0, 0, 0],
|
|
||||||
[183, 183, 183],
|
|
||||||
],
|
|
||||||
dtype=np.float,
|
|
||||||
)
|
|
||||||
/ 255
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def plot_embeddings(embeddings, num_utter_per_speaker):
|
|
||||||
embeddings = embeddings[: 10 * num_utter_per_speaker]
|
|
||||||
model = umap.UMAP()
|
|
||||||
projection = model.fit_transform(embeddings)
|
|
||||||
num_speakers = embeddings.shape[0] // num_utter_per_speaker
|
|
||||||
ground_truth = np.repeat(np.arange(num_speakers), num_utter_per_speaker)
|
|
||||||
colors = [colormap[i] for i in ground_truth]
|
|
||||||
|
|
||||||
fig, ax = plt.subplots(figsize=(16, 10))
|
|
||||||
_ = ax.scatter(projection[:, 0], projection[:, 1], c=colors)
|
|
||||||
plt.gca().set_aspect("equal", "datalim")
|
|
||||||
plt.title("UMAP projection")
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig("umap")
|
|
||||||
return fig
|
|
Loading…
Reference in New Issue