2018-05-03 22:16:32 +00:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tacotron 2 inference code \n",
"Edit the variables **checkpoint_path** and **text** to match yours and run the entire code to generate plots of mel outputs, alignments and audio synthesis from the generated mel-spectrogram using Griffin-Lim."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Import libraries and setup matplotlib"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": true
},
"outputs": [
],
"source": [
"import matplotlib\n",
"matplotlib.use(\"Agg\")\n",
"import matplotlib.pylab as plt\n",
"import IPython.display as ipd\n",
"\n",
"import numpy as np\n",
"import torch\n",
"\n",
"from hparams import create_hparams\n",
"from model import Tacotron2\n",
"from layers import TacotronSTFT\n",
"from audio_processing import griffin_lim\n",
"from train import load_model\n",
"from text import text_to_sequence\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"def plot_data(data, figsize=(16, 4)):\n",
" fig, axes = plt.subplots(1, len(data), figsize=figsize)\n",
" for i in range(len(data)):\n",
" axes[i].imshow(data[i], aspect='auto', origin='bottom', \n",
" interpolation='none')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Setup hparams"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"INFO:tensorflow:Parsing command line hparams: distributed_run=False,mask_padding=False\n"
]
}
],
"source": [
"hparams = create_hparams(\"distributed_run=False,mask_padding=False\")\n",
"hparams.sampling_rate = 22050\n",
"hparams.filter_length = 1024\n",
"hparams.hop_length = 256\n",
"hparams.win_length = 1024"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Load model from checkpoint"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [],
"source": [
"checkpoint_path = \"/home/scratch.adlr-gcf/audio_denoising/runs/TTS-Tacotron2-LJS-MSE-DRC-NoMaskPadding-Unsorted-Distributed-22khz/checkpoint_15500\"\n",
"model = load_model(hparams)\n",
2018-05-06 00:23:11 +00:00
"model.load_state_dict({k.replace('module.',''):v for k,v in torch.load(checkpoint_path)['state_dict'].items()})\n",
2018-05-03 22:16:32 +00:00
"model = model.module\n",
"_ = model.eval()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Prepare text input"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [],
"source": [
"text = \"This is an example of text to speech synthesis after 14 hours training.\"\n",
"sequence = np.array(text_to_sequence(text, ['english_cleaners']))[None, :]\n",
"sequence = torch.autograd.Variable(\n",
" torch.from_numpy(sequence)).cuda().long()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Decode text input and plot results"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<matplotlib.figure.Figure at 0x7fff5b0fa780>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"mel_outputs, mel_outputs_postnet, _, alignments = model.inference(sequence)\n",
"plot_data((mel_outputs.data.cpu().numpy()[0],\n",
" mel_outputs_postnet.data.cpu().numpy()[0],\n",
" alignments.data.cpu().numpy()[0].T))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Load TacotronSTFT and convert mel-spectrogram to spectrogram"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [],
"source": [
"taco_stft = TacotronSTFT(\n",
" hparams.filter_length, hparams.hop_length, hparams.win_length, \n",
" sampling_rate=hparams.sampling_rate)\n",
"mel_decompress = taco_stft.spectral_de_normalize(mel_outputs_postnet)\n",
"mel_decompress = mel_decompress.transpose(1, 2).data.cpu()\n",
"spec_from_mel_scaling = 1000\n",
"spec_from_mel = torch.mm(mel_decompress[0], taco_stft.mel_basis)\n",
"spec_from_mel = spec_from_mel.transpose(0, 1).unsqueeze(0)\n",
"spec_from_mel = spec_from_mel * spec_from_mel_scaling"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Synthesize audio from spectrogram using the Griffin-Lim algorithm"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
],
"source": [
"waveform = griffin_lim(torch.autograd.Variable(spec_from_mel[:, :, :-1]), \n",
" taco_stft.stft_fn, 60)"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <audio controls=\"controls\" >\n",
" <source src=\"data:audio/wav;base64,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
" Your browser does not support the audio element.\n",
" </audio>\n",
" "
],
"text/plain": [
"<IPython.lib.display.Audio object>"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ipd.Audio(waveform[0].data.cpu().numpy(), rate=hparams.sampling_rate) "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}