├── demo.wav ├── tensorboard.png ├── .gitmodules ├── Dockerfile ├── requirements.txt ├── multiproc.py ├── loss_function.py ├── text ├── symbols.py ├── LICENSE ├── cmudict.py ├── numbers.py ├── cleaners.py ├── __init__.py ├── ko_dictionary.py └── korean.py ├── utils.py ├── skip_short_clip.py ├── LICENSE ├── merge_m2m_metadatas.py ├── preprocess_audio.py ├── plotting_utils.py ├── logger.py ├── README.md ├── hparams.py ├── audio_processing.py ├── layers.py ├── filelists ├── kss_val_filelist.txt ├── nam-h_val_filelist.txt ├── ljs_audio_text_val_filelist.txt ├── kss_test_filelist.txt └── nam-h_test_filelist.txt ├── data_utils.py ├── loss_scaler.py ├── stft.py ├── prepare_training_data.py ├── inference.py ├── distributed.py ├── GTA.py ├── train.py ├── fp16_optimizer.py └── model.py /demo.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yeongtae/tacotron2/HEAD/demo.wav -------------------------------------------------------------------------------- /tensorboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yeongtae/tacotron2/HEAD/tensorboard.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "waveglow"] 2 | path = waveglow 3 | url = https://github.com/Yeongtae/waveglow 4 | branch = master 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pytorch/pytorch:0.4_cuda9_cudnn7 2 | RUN pip install numpy scipy matplotlib librosa==0.6.0 tensorflow tensorboardX inflect==0.2.5 Unidecode==1.0.22 jupyter 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | tensorflow==1.13.1 2 | inflect==0.2.5 3 | pytorch==1.0.1 4 | librosa==0.6.0 5 | scipy==1.0.0 6 | tensorboardX==1.1 7 | Unidecode==1.0.22 8 | pillow 9 | nltk==3.3 10 | jamo==0.4.1 11 | -------------------------------------------------------------------------------- /multiproc.py: -------------------------------------------------------------------------------- 1 | import time 2 | import torch 3 | import sys 4 | import subprocess 5 | 6 | argslist = list(sys.argv)[1:] 7 | num_gpus = torch.cuda.device_count() 8 | argslist.append('--n_gpus={}'.format(num_gpus)) 9 | workers = [] 10 | job_id = time.strftime("%Y_%m_%d-%H%M%S") 11 | argslist.append("--group_name=group_{}".format(job_id)) 12 | 13 | for i in range(num_gpus): 14 | argslist.append('--rank={}'.format(i)) 15 | stdout = None if i == 0 else open("logs/{}_GPU_{}.log".format(job_id, i), 16 | "w") 17 | print(argslist) 18 | p = subprocess.Popen([str(sys.executable)]+argslist, stdout=stdout) 19 | workers.append(p) 20 | argslist = argslist[:-1] 21 | 22 | for p in workers: 23 | p.wait() 24 | -------------------------------------------------------------------------------- /loss_function.py: -------------------------------------------------------------------------------- 1 | from torch import nn 2 | 3 | 4 | class Tacotron2Loss(nn.Module): 5 | def __init__(self): 6 | super(Tacotron2Loss, self).__init__() 7 | 8 | def forward(self, model_output, targets): 9 | mel_target, gate_target = targets[0], targets[1] 10 | mel_target.requires_grad = False 11 | gate_target.requires_grad = False 12 | gate_target = gate_target.view(-1, 1) 13 | 14 | mel_out, mel_out_postnet, gate_out, _ = model_output 15 | gate_out = gate_out.view(-1, 1) 16 | mel_loss = nn.MSELoss()(mel_out, mel_target) + \ 17 | nn.MSELoss()(mel_out_postnet, mel_target) 18 | gate_loss = nn.BCEWithLogitsLoss()(gate_out, gate_target) 19 | return mel_loss + gate_loss 20 | -------------------------------------------------------------------------------- /text/symbols.py: -------------------------------------------------------------------------------- 1 | """ from https://github.com/keithito/tacotron """ 2 | 3 | ''' 4 | Defines the set of symbols used in text input to the model. 5 | 6 | The default is a set of ASCII characters that works well for English or text that has been run through Unidecode. For other data, you can modify _characters. See TRAINING_DATA.md for details. ''' 7 | from text import cmudict 8 | from text.korean import ALL_SYMBOLS_1 9 | 10 | _pad = '_' 11 | _punctuation = '!\'(),.:;? ' 12 | _special = '-' 13 | _letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 14 | 15 | # Prepend "@" to ARPAbet symbols to ensure uniqueness (some are the same as uppercase letters): 16 | _arpabet = ['@' + s for s in cmudict.valid_symbols] 17 | 18 | # Export all symbols: 19 | eng_symbols = [_pad] + list(_special) + list(_punctuation) + list(_letters) + _arpabet 20 | kor_symbols = ALL_SYMBOLS_1 21 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.io.wavfile import read 3 | import librosa 4 | import torch 5 | 6 | max_wav_value=32768.0 7 | 8 | def get_mask_from_lengths(lengths): 9 | max_len = torch.max(lengths).item() 10 | ids = torch.arange(0, max_len, out=torch.cuda.LongTensor(max_len)) 11 | mask = (ids < lengths.unsqueeze(1)).byte() 12 | return mask 13 | 14 | 15 | def load_wav_to_torch(full_path): 16 | sampling_rate, data = read(full_path) 17 | return torch.FloatTensor(data.astype(np.float32)), sampling_rate 18 | 19 | 20 | def load_filepaths_and_text(filename, split="|"): 21 | with open(filename, encoding='utf-8') as f: 22 | filepaths_and_text = [line.strip().split(split) for line in f] 23 | return filepaths_and_text 24 | 25 | 26 | def to_gpu(x): 27 | x = x.contiguous() 28 | 29 | if torch.cuda.is_available(): 30 | x = x.cuda(non_blocking=True) 31 | return torch.autograd.Variable(x) 32 | -------------------------------------------------------------------------------- /text/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Keith Ito 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /skip_short_clip.py: -------------------------------------------------------------------------------- 1 | import librosa 2 | import argparse 3 | 4 | sr = 22050 5 | max_wav_value=32768.0 6 | trim_fft_size = 1024 7 | trim_hop_size = 256 8 | trim_top_db = 23 9 | 10 | def preprocess_audio(file_name): 11 | f = open(file_name,'r',encoding='utf-8') 12 | R = f.readlines() 13 | f.close() 14 | 15 | L = [] 16 | for i, r in enumerate(R): 17 | wav_file = r.split('|')[0] 18 | data, sampling_rate = librosa.core.load(wav_file, sr) 19 | if(len(data) >= 14848): 20 | L.append(r) 21 | 22 | skiped_file_name = file_name.split('.')[0]+'_skiped.txt' 23 | f = open(skiped_file_name,'w',encoding='utf-8') 24 | f.writelines(L) 25 | f.close() 26 | 27 | if __name__ == "__main__": 28 | """ 29 | usage 30 | python preprocess_audio.py -f=filelists/nam-h_test_filelist.txt,filelists/nam-h_train_filelist.txt,filelists/nam-h_val_filelist.txt -s=3 31 | """ 32 | parser = argparse.ArgumentParser() 33 | parser.add_argument('-f', '--file_name', type=str, 34 | help='map.txt file name') 35 | args = parser.parse_args() 36 | 37 | preprocess_audio(args.file_name) 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, NVIDIA Corporation 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /merge_m2m_metadatas.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import argparse 3 | import os 4 | 5 | def merge(source_metadata, target_metadata, out_dir=''): 6 | concatinated_metas = [] 7 | with open(source_metadata, 'r', encoding='utf-8') as file: 8 | source_metas = file.readlines() 9 | with open(target_metadata, 'r', encoding='utf-8') as file: 10 | target_metas = file.readlines() 11 | print(len(source_metas),len(target_metas)) 12 | with open(os.path.join(out_dir,'vc_metadata.csv'),'w',encoding='utf-8') as file: 13 | for source_meta in source_metas: 14 | s_mel_path, s_text = source_meta.strip().split('|') 15 | for i, target_meta in enumerate(target_metas): 16 | t_mel_path, t_text = target_meta.strip().split('|') 17 | if(t_text in s_text and s_text in t_text): 18 | concatinated_metas.append("{}|{}|{}|{}\n".format(s_mel_path,s_text,t_mel_path,t_text)) 19 | target_metas.pop(i) 20 | break 21 | file.writelines(concatinated_metas) 22 | pass 23 | 24 | if __name__ == "__main__": 25 | """ 26 | usage 27 | python merge_m2m_metadatas.py --out_dir=. --source_metadata=park_inference/metadata.csv --target_metadata=park_m2m/metadata.csv 28 | """ 29 | parser = argparse.ArgumentParser() 30 | parser.add_argument('-o', '--out_dir', default='',type=str, help='output path for voice conversion metadata') 31 | parser.add_argument('-s', '--source_metadata', type=str, help='source melspectrogram dataset meta') 32 | parser.add_argument('-t', '--target_metadata', type=str, help='target melspectrogram dataset meta') 33 | args = parser.parse_args() 34 | merge(args.source_metadata, args.target_metadata, args.out_dir) -------------------------------------------------------------------------------- /preprocess_audio.py: -------------------------------------------------------------------------------- 1 | from scipy.io.wavfile import write 2 | import librosa 3 | import numpy as np 4 | import argparse 5 | 6 | sr = 22050 7 | max_wav_value=32768.0 8 | trim_fft_size = 1024 9 | trim_hop_size = 256 10 | trim_top_db = 23 11 | 12 | def preprocess_audio(file_list, silence_audio_size): 13 | for F in file_list: 14 | f = open(F) 15 | R = f.readlines() 16 | f.close() 17 | print('='*5+F+'='*5) 18 | 19 | for i, r in enumerate(R): 20 | wav_file = r.split('|')[0] 21 | data, sampling_rate = librosa.core.load(wav_file, sr) 22 | data = data / np.abs(data).max() *0.999 23 | data_= librosa.effects.trim(data, top_db= trim_top_db, frame_length=trim_fft_size, hop_length=trim_hop_size)[0] 24 | data_ = data_*max_wav_value 25 | data_ = np.append(data_, [0.]*silence_audio_size) 26 | data_ = data_.astype(dtype=np.int16) 27 | write(wav_file, sr, data_) 28 | #print(len(data),len(data_)) 29 | if(i%100 == 0): 30 | print (i) 31 | 32 | if __name__ == "__main__": 33 | """ 34 | usage 35 | python preprocess_audio.py -f=filelists/nam-h_test_filelist.txt,filelists/nam-h_train_filelist.txt,filelists/nam-h_val_filelist.txt -s=3 36 | """ 37 | parser = argparse.ArgumentParser() 38 | parser.add_argument('-f', '--file_list', type=str, 39 | help='file list to preprocess') 40 | parser.add_argument('-s', '--silence_mel_padding', type=int, default=0, 41 | help='silence audio size is hop_length * silence mel padding') 42 | args = parser.parse_args() 43 | file_list = args.file_list.split(',') 44 | silence_audio_size = trim_hop_size * args.silence_mel_padding 45 | preprocess_audio(file_list, silence_audio_size) 46 | -------------------------------------------------------------------------------- /plotting_utils.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | matplotlib.use("Agg") 3 | import matplotlib.pylab as plt 4 | import numpy as np 5 | 6 | 7 | def save_figure_to_numpy(fig): 8 | # save it to a numpy array. 9 | data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='') 10 | data = data.reshape(fig.canvas.get_width_height()[::-1] + (3,)) 11 | return data 12 | 13 | 14 | def plot_alignment_to_numpy(alignment, info=None): 15 | fig, ax = plt.subplots(figsize=(6, 4)) 16 | im = ax.imshow(alignment, aspect='auto', origin='lower', 17 | interpolation='none') 18 | fig.colorbar(im, ax=ax) 19 | xlabel = 'Decoder timestep' 20 | if info is not None: 21 | xlabel += '\n\n' + info 22 | plt.xlabel(xlabel) 23 | plt.ylabel('Encoder timestep') 24 | plt.tight_layout() 25 | 26 | fig.canvas.draw() 27 | data = save_figure_to_numpy(fig) 28 | plt.close() 29 | return data 30 | 31 | 32 | def plot_spectrogram_to_numpy(spectrogram): 33 | fig, ax = plt.subplots(figsize=(12, 3)) 34 | im = ax.imshow(spectrogram, aspect="auto", origin="lower", 35 | interpolation='none') 36 | plt.colorbar(im, ax=ax) 37 | plt.xlabel("Frames") 38 | plt.ylabel("Channels") 39 | plt.tight_layout() 40 | 41 | fig.canvas.draw() 42 | data = save_figure_to_numpy(fig) 43 | plt.close() 44 | return data 45 | 46 | 47 | def plot_gate_outputs_to_numpy(gate_targets, gate_outputs): 48 | fig, ax = plt.subplots(figsize=(12, 3)) 49 | ax.scatter(range(len(gate_targets)), gate_targets, alpha=0.5, 50 | color='green', marker='+', s=1, label='target') 51 | ax.scatter(range(len(gate_outputs)), gate_outputs, alpha=0.5, 52 | color='red', marker='.', s=1, label='predicted') 53 | 54 | plt.xlabel("Frames (Green target, Red predicted)") 55 | plt.ylabel("Gate State") 56 | plt.tight_layout() 57 | 58 | fig.canvas.draw() 59 | data = save_figure_to_numpy(fig) 60 | plt.close() 61 | return data 62 | -------------------------------------------------------------------------------- /logger.py: -------------------------------------------------------------------------------- 1 | import random 2 | import torch.nn.functional as F 3 | from tensorboardX import SummaryWriter 4 | from plotting_utils import plot_alignment_to_numpy, plot_spectrogram_to_numpy 5 | from plotting_utils import plot_gate_outputs_to_numpy 6 | 7 | 8 | class Tacotron2Logger(SummaryWriter): 9 | def __init__(self, logdir): 10 | super(Tacotron2Logger, self).__init__(logdir) 11 | 12 | def log_training(self, reduced_loss, grad_norm, learning_rate, duration, 13 | iteration): 14 | self.add_scalar("training.loss", reduced_loss, iteration) 15 | self.add_scalar("grad.norm", grad_norm, iteration) 16 | self.add_scalar("learning.rate", learning_rate, iteration) 17 | self.add_scalar("duration", duration, iteration) 18 | 19 | def log_validation(self, reduced_loss, model, y, y_pred, iteration): 20 | self.add_scalar("validation.loss", reduced_loss, iteration) 21 | _, mel_outputs, gate_outputs, alignments = y_pred 22 | mel_targets, gate_targets = y 23 | 24 | # plot distribution of parameters 25 | for tag, value in model.named_parameters(): 26 | tag = tag.replace('.', '/') 27 | self.add_histogram(tag, value.data.cpu().numpy(), iteration) 28 | 29 | # plot alignment, mel target and predicted, gate target and predicted 30 | idx = random.randint(0, alignments.size(0) - 1) 31 | self.add_image( 32 | "alignment", 33 | plot_alignment_to_numpy(alignments[idx].data.cpu().numpy().T), 34 | iteration) 35 | self.add_image( 36 | "mel_target", 37 | plot_spectrogram_to_numpy(mel_targets[idx].data.cpu().numpy()), 38 | iteration) 39 | self.add_image( 40 | "mel_predicted", 41 | plot_spectrogram_to_numpy(mel_outputs[idx].data.cpu().numpy()), 42 | iteration) 43 | self.add_image( 44 | "gate", 45 | plot_gate_outputs_to_numpy( 46 | gate_targets[idx].data.cpu().numpy(), 47 | F.sigmoid(gate_outputs[idx]).data.cpu().numpy()), 48 | iteration) 49 | -------------------------------------------------------------------------------- /text/cmudict.py: -------------------------------------------------------------------------------- 1 | """ from https://github.com/keithito/tacotron """ 2 | 3 | import re 4 | 5 | 6 | valid_symbols = [ 7 | 'AA', 'AA0', 'AA1', 'AA2', 'AE', 'AE0', 'AE1', 'AE2', 'AH', 'AH0', 'AH1', 'AH2', 8 | 'AO', 'AO0', 'AO1', 'AO2', 'AW', 'AW0', 'AW1', 'AW2', 'AY', 'AY0', 'AY1', 'AY2', 9 | 'B', 'CH', 'D', 'DH', 'EH', 'EH0', 'EH1', 'EH2', 'ER', 'ER0', 'ER1', 'ER2', 'EY', 10 | 'EY0', 'EY1', 'EY2', 'F', 'G', 'HH', 'IH', 'IH0', 'IH1', 'IH2', 'IY', 'IY0', 'IY1', 11 | 'IY2', 'JH', 'K', 'L', 'M', 'N', 'NG', 'OW', 'OW0', 'OW1', 'OW2', 'OY', 'OY0', 12 | 'OY1', 'OY2', 'P', 'R', 'S', 'SH', 'T', 'TH', 'UH', 'UH0', 'UH1', 'UH2', 'UW', 13 | 'UW0', 'UW1', 'UW2', 'V', 'W', 'Y', 'Z', 'ZH' 14 | ] 15 | 16 | _valid_symbol_set = set(valid_symbols) 17 | 18 | 19 | class CMUDict: 20 | '''Thin wrapper around CMUDict data. http://www.speech.cs.cmu.edu/cgi-bin/cmudict''' 21 | def __init__(self, file_or_path, keep_ambiguous=True): 22 | if isinstance(file_or_path, str): 23 | with open(file_or_path, encoding='latin-1') as f: 24 | entries = _parse_cmudict(f) 25 | else: 26 | entries = _parse_cmudict(file_or_path) 27 | if not keep_ambiguous: 28 | entries = {word: pron for word, pron in entries.items() if len(pron) == 1} 29 | self._entries = entries 30 | 31 | 32 | def __len__(self): 33 | return len(self._entries) 34 | 35 | 36 | def lookup(self, word): 37 | '''Returns list of ARPAbet pronunciations of the given word.''' 38 | return self._entries.get(word.upper()) 39 | 40 | 41 | 42 | _alt_re = re.compile(r'\([0-9]+\)') 43 | 44 | 45 | def _parse_cmudict(file): 46 | cmudict = {} 47 | for line in file: 48 | if len(line) and (line[0] >= 'A' and line[0] <= 'Z' or line[0] == "'"): 49 | parts = line.split(' ') 50 | word = re.sub(_alt_re, '', parts[0]) 51 | pronunciation = _get_pronunciation(parts[1]) 52 | if pronunciation: 53 | if word in cmudict: 54 | cmudict[word].append(pronunciation) 55 | else: 56 | cmudict[word] = [pronunciation] 57 | return cmudict 58 | 59 | 60 | def _get_pronunciation(s): 61 | parts = s.strip().split(' ') 62 | for part in parts: 63 | if part not in _valid_symbol_set: 64 | return None 65 | return ' '.join(parts) 66 | -------------------------------------------------------------------------------- /text/numbers.py: -------------------------------------------------------------------------------- 1 | """ from https://github.com/keithito/tacotron """ 2 | 3 | import inflect 4 | import re 5 | 6 | 7 | _inflect = inflect.engine() 8 | _comma_number_re = re.compile(r'([0-9][0-9\,]+[0-9])') 9 | _decimal_number_re = re.compile(r'([0-9]+\.[0-9]+)') 10 | _pounds_re = re.compile(r'£([0-9\,]*[0-9]+)') 11 | _dollars_re = re.compile(r'\$([0-9\.\,]*[0-9]+)') 12 | _ordinal_re = re.compile(r'[0-9]+(st|nd|rd|th)') 13 | _number_re = re.compile(r'[0-9]+') 14 | 15 | 16 | def _remove_commas(m): 17 | return m.group(1).replace(',', '') 18 | 19 | 20 | def _expand_decimal_point(m): 21 | return m.group(1).replace('.', ' point ') 22 | 23 | 24 | def _expand_dollars(m): 25 | match = m.group(1) 26 | parts = match.split('.') 27 | if len(parts) > 2: 28 | return match + ' dollars' # Unexpected format 29 | dollars = int(parts[0]) if parts[0] else 0 30 | cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0 31 | if dollars and cents: 32 | dollar_unit = 'dollar' if dollars == 1 else 'dollars' 33 | cent_unit = 'cent' if cents == 1 else 'cents' 34 | return '%s %s, %s %s' % (dollars, dollar_unit, cents, cent_unit) 35 | elif dollars: 36 | dollar_unit = 'dollar' if dollars == 1 else 'dollars' 37 | return '%s %s' % (dollars, dollar_unit) 38 | elif cents: 39 | cent_unit = 'cent' if cents == 1 else 'cents' 40 | return '%s %s' % (cents, cent_unit) 41 | else: 42 | return 'zero dollars' 43 | 44 | 45 | def _expand_ordinal(m): 46 | return _inflect.number_to_words(m.group(0)) 47 | 48 | 49 | def _expand_number(m): 50 | num = int(m.group(0)) 51 | if num > 1000 and num < 3000: 52 | if num == 2000: 53 | return 'two thousand' 54 | elif num > 2000 and num < 2010: 55 | return 'two thousand ' + _inflect.number_to_words(num % 100) 56 | elif num % 100 == 0: 57 | return _inflect.number_to_words(num // 100) + ' hundred' 58 | else: 59 | return _inflect.number_to_words(num, andword='', zero='oh', group=2).replace(', ', ' ') 60 | else: 61 | return _inflect.number_to_words(num, andword='') 62 | 63 | 64 | def normalize_numbers(text): 65 | text = re.sub(_comma_number_re, _remove_commas, text) 66 | text = re.sub(_pounds_re, r'\1 pounds', text) 67 | text = re.sub(_dollars_re, _expand_dollars, text) 68 | text = re.sub(_decimal_number_re, _expand_decimal_point, text) 69 | text = re.sub(_ordinal_re, _expand_ordinal, text) 70 | text = re.sub(_number_re, _expand_number, text) 71 | return text 72 | -------------------------------------------------------------------------------- /text/cleaners.py: -------------------------------------------------------------------------------- 1 | """ from https://github.com/keithito/tacotron """ 2 | 3 | ''' 4 | Cleaners are transformations that run over the input text at both training and eval time. 5 | 6 | Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners" 7 | hyperparameter. Some cleaners are English-specific. You'll typically want to use: 8 | 1. "english_cleaners" for English text 9 | 2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using 10 | the Unidecode library (https://pypi.python.org/pypi/Unidecode) 11 | 3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update 12 | the symbols in symbols.py to match your data). 13 | ''' 14 | 15 | import re 16 | from unidecode import unidecode 17 | from text.numbers import normalize_numbers 18 | from text.korean import tokenize as ko_tokenize 19 | 20 | 21 | # Regular expression matching whitespace: 22 | _whitespace_re = re.compile(r'\s+') 23 | 24 | # List of (regular expression, replacement) pairs for abbreviations: 25 | _abbreviations = [(re.compile('\\b%s\\.' % x[0], re.IGNORECASE), x[1]) for x in [ 26 | ('mrs', 'misess'), 27 | ('mr', 'mister'), 28 | ('dr', 'doctor'), 29 | ('st', 'saint'), 30 | ('co', 'company'), 31 | ('jr', 'junior'), 32 | ('maj', 'major'), 33 | ('gen', 'general'), 34 | ('drs', 'doctors'), 35 | ('rev', 'reverend'), 36 | ('lt', 'lieutenant'), 37 | ('hon', 'honorable'), 38 | ('sgt', 'sergeant'), 39 | ('capt', 'captain'), 40 | ('esq', 'esquire'), 41 | ('ltd', 'limited'), 42 | ('col', 'colonel'), 43 | ('ft', 'fort'), 44 | ]] 45 | 46 | 47 | def expand_abbreviations(text): 48 | for regex, replacement in _abbreviations: 49 | text = re.sub(regex, replacement, text) 50 | return text 51 | 52 | 53 | def expand_numbers(text): 54 | return normalize_numbers(text) 55 | 56 | 57 | def lowercase(text): 58 | return text.lower() 59 | 60 | 61 | def collapse_whitespace(text): 62 | return re.sub(_whitespace_re, ' ', text) 63 | 64 | 65 | def convert_to_ascii(text): 66 | return unidecode(text) 67 | 68 | 69 | def basic_cleaners(text): 70 | '''Basic pipeline that lowercases and collapses whitespace without transliteration.''' 71 | text = lowercase(text) 72 | text = collapse_whitespace(text) 73 | return text 74 | 75 | 76 | def transliteration_cleaners(text): 77 | '''Pipeline for non-English text that transliterates to ASCII.''' 78 | text = convert_to_ascii(text) 79 | text = lowercase(text) 80 | text = collapse_whitespace(text) 81 | return text 82 | 83 | 84 | def english_cleaners(text): 85 | '''Pipeline for English text, including number and abbreviation expansion.''' 86 | text = convert_to_ascii(text) 87 | text = lowercase(text) 88 | text = expand_numbers(text) 89 | text = expand_abbreviations(text) 90 | text = collapse_whitespace(text) 91 | return text 92 | 93 | def korean_cleaners(text): 94 | '''Pipeline for Korean text, including number and abbreviation expansion.''' 95 | text = ko_tokenize(text, as_id=False) 96 | #print(text) 97 | return text -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tacotron 2 (without wavenet) 2 | 3 | PyTorch implementation of [Natural TTS Synthesis By Conditioning 4 | Wavenet On Mel Spectrogram Predictions](https://arxiv.org/pdf/1712.05884.pdf). 5 | 6 | This implementation includes **distributed** and **fp16** support 7 | and uses the [LJSpeech dataset](https://keithito.com/LJ-Speech-Dataset/). 8 | 9 | Distributed and FP16 support relies on work by Christian Sarofeen and NVIDIA's 10 | [Apex Library](https://github.com/nvidia/apex). 11 | 12 | Visit our [website] for audio samples using our published [Tacotron 2] and 13 | [WaveGlow] models. 14 | 15 | ![Alignment, Predicted Mel Spectrogram, Target Mel Spectrogram](tensorboard.png) 16 | 17 | 18 | ## Pre-requisites 19 | 1. NVIDIA GPU + CUDA cuDNN 20 | 21 | ## Setup 22 | 1. Download and extract the [LJ Speech dataset](https://keithito.com/LJ-Speech-Dataset/) 23 | 2. Clone this repo: `git clone https://github.com/NVIDIA/tacotron2.git` 24 | 3. CD into this repo: `cd tacotron2` 25 | 4. Initialize submodule: `git submodule init; git submodule update` 26 | 5. Update .wav paths: `sed -i -- 's,DUMMY,ljs_dataset_folder/wavs,g' filelists/*.txt` 27 | - Alternatively, set `load_mel_from_disk=True` in `hparams.py` and update mel-spectrogram paths 28 | 6. Install [PyTorch 1.0] 29 | 7. Install python requirements or build docker image 30 | - Install python requirements: `pip install -r requirements.txt` 31 | 32 | ## Training 33 | 1. `python train.py --output_directory=outdir --log_directory=logdir` 34 | 2. (OPTIONAL) `tensorboard --logdir=outdir/logdir` 35 | 36 | ## Multi-GPU (distributed) and FP16 Training 37 | 1. `python -m multiproc train.py --output_directory=outdir --log_directory=logdir --hparams=distributed_run=True,fp16_run=True` 38 | 39 | ## Inference demo 40 | 1. Download our published [Tacotron 2] model 41 | 2. Download our published [WaveGlow] model 42 | 3. `jupyter notebook --ip=127.0.0.1 --port=31337` 43 | 4. Load inference.ipynb 44 | 45 | N.b. When performing Mel-Spectrogram to Audio synthesis, make sure Tacotron 2 46 | and the Mel decoder were trained on the same mel-spectrogram representation. 47 | 48 | 49 | ## Related repos 50 | [WaveGlow](https://github.com/NVIDIA/WaveGlow) Faster than real time Flow-based 51 | Generative Network for Speech Synthesis 52 | 53 | [nv-wavenet](https://github.com/NVIDIA/nv-wavenet/) Faster than real time 54 | WaveNet. 55 | 56 | ## Acknowledgements 57 | This implementation uses code from the following repos: [Keith 58 | Ito](https://github.com/keithito/tacotron/), [Prem 59 | Seetharaman](https://github.com/pseeth/pytorch-stft) as described in our code. 60 | 61 | We are inspired by [Ryuchi Yamamoto's](https://github.com/r9y9/tacotron_pytorch) 62 | Tacotron PyTorch implementation. 63 | 64 | We are thankful to the Tacotron 2 paper authors, specially Jonathan Shen, Yuxuan 65 | Wang and Zongheng Yang. 66 | 67 | 68 | [WaveGlow]: https://drive.google.com/file/d/1cjKPHbtAMh_4HTHmuIGNkbOkPBD9qwhj/view?usp=sharing 69 | [Tacotron 2]: https://drive.google.com/file/d/1c5ZTuT7J08wLUoVZ2KkUs_VdZuJ86ZqA/view?usp=sharing 70 | [pytorch 1.0]: https://github.com/pytorch/pytorch#installation 71 | [website]: https://nv-adlr.github.io/WaveGlow 72 | -------------------------------------------------------------------------------- /hparams.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | def create_hparams(hparams_string=None, verbose=False): 4 | """Create model hyperparameters. Parse nondefault from given string.""" 5 | 6 | hparams = tf.contrib.training.HParams( 7 | ################################ 8 | # Experiment Parameters # 9 | ################################ 10 | epochs=270, 11 | iters_per_checkpoint=500, 12 | seed=1234, 13 | dynamic_loss_scaling=True, 14 | fp16_run=False, 15 | distributed_run=False, 16 | 17 | dist_backend="nccl", 18 | dist_url="tcp://localhost:54321", 19 | cudnn_enabled=True, 20 | cudnn_benchmark=False, 21 | 22 | ################################ 23 | # Data Parameters # 24 | ################################ 25 | load_mel_from_disk=False, 26 | training_files='filelists/kss_train_filelist.txt', 27 | validation_files='filelists/kss_val_filelist.txt', 28 | text_cleaners=['english_cleaners'], # english_cleaners, korean_cleaners 29 | sort_by_length=False, 30 | 31 | ################################ 32 | # Audio Parameters # 33 | ################################ 34 | max_wav_value=32768.0, 35 | sampling_rate=22050, 36 | filter_length=1024, 37 | hop_length=256, # number audio of frames between stft colmns, default win_length/4 38 | win_length=1024, # win_length int <= n_ftt: fft window size (frequency domain), defaults to win_length = n_fft 39 | n_mel_channels=80, 40 | mel_fmin=0.0, 41 | mel_fmax=8000.0, 42 | 43 | ################################ 44 | # Model Parameters # 45 | ################################ 46 | n_symbols = 149, # set 80 if u use korean_cleaners. set 149 if u use english_cleaners 47 | symbols_embedding_dim=512, 48 | 49 | # Encoder parameters 50 | encoder_kernel_size=5, 51 | encoder_n_convolutions=3, 52 | encoder_embedding_dim=512, 53 | 54 | # Decoder parameters 55 | n_frames_per_step=1, # currently only 1 is supported 56 | decoder_rnn_dim=1024, 57 | prenet_dim=256, 58 | max_decoder_steps=1000, 59 | gate_threshold=0.5, 60 | p_attention_dropout=0.1, 61 | p_decoder_dropout=0.1, 62 | 63 | # Attention parameters 64 | attention_rnn_dim=1024, 65 | attention_dim=128, 66 | 67 | # Location Layer parameters 68 | attention_location_n_filters=32, 69 | attention_location_kernel_size=31, 70 | 71 | # Mel-post processing network parameters 72 | postnet_embedding_dim=512, 73 | postnet_kernel_size=5, 74 | postnet_n_convolutions=5, 75 | 76 | ################################ 77 | # Optimization Hyperparameters # 78 | ################################ 79 | use_saved_learning_rate=False, 80 | learning_rate=1e-3, 81 | weight_decay=1e-6, 82 | grad_clip_thresh=1.0, 83 | batch_size=64, 84 | mask_padding=True # set model's padded outputs to padded values 85 | ) 86 | 87 | if hparams_string: 88 | tf.logging.info('Parsing command line hparams: %s', hparams_string) 89 | hparams.parse(hparams_string) 90 | 91 | if verbose: 92 | tf.logging.info('Final parsed hparams: %s', hparams.values()) 93 | 94 | return hparams 95 | -------------------------------------------------------------------------------- /audio_processing.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from scipy.signal import get_window 4 | import librosa.util as librosa_util 5 | 6 | 7 | def window_sumsquare(window, n_frames, hop_length=200, win_length=800, 8 | n_fft=800, dtype=np.float32, norm=None): 9 | """ 10 | # from librosa 0.6 11 | Compute the sum-square envelope of a window function at a given hop length. 12 | 13 | This is used to estimate modulation effects induced by windowing 14 | observations in short-time fourier transforms. 15 | 16 | Parameters 17 | ---------- 18 | window : string, tuple, number, callable, or list-like 19 | Window specification, as in `get_window` 20 | 21 | n_frames : int > 0 22 | The number of analysis frames 23 | 24 | hop_length : int > 0 25 | The number of samples to advance between frames 26 | 27 | win_length : [optional] 28 | The length of the window function. By default, this matches `n_fft`. 29 | 30 | n_fft : int > 0 31 | The length of each analysis frame. 32 | 33 | dtype : np.dtype 34 | The data type of the output 35 | 36 | Returns 37 | ------- 38 | wss : np.ndarray, shape=`(n_fft + hop_length * (n_frames - 1))` 39 | The sum-squared envelope of the window function 40 | """ 41 | if win_length is None: 42 | win_length = n_fft 43 | 44 | n = n_fft + hop_length * (n_frames - 1) 45 | x = np.zeros(n, dtype=dtype) 46 | 47 | # Compute the squared window at the desired length 48 | win_sq = get_window(window, win_length, fftbins=True) 49 | win_sq = librosa_util.normalize(win_sq, norm=norm)**2 50 | win_sq = librosa_util.pad_center(win_sq, n_fft) 51 | 52 | # Fill the envelope 53 | for i in range(n_frames): 54 | sample = i * hop_length 55 | x[sample:min(n, sample + n_fft)] += win_sq[:max(0, min(n_fft, n - sample))] 56 | return x 57 | 58 | 59 | def griffin_lim(magnitudes, stft_fn, n_iters=30): 60 | """ 61 | PARAMS 62 | ------ 63 | magnitudes: spectrogram magnitudes 64 | stft_fn: STFT class with transform (STFT) and inverse (ISTFT) methods 65 | """ 66 | 67 | angles = np.angle(np.exp(2j * np.pi * np.random.rand(*magnitudes.size()))) 68 | angles = angles.astype(np.float32) 69 | angles = torch.autograd.Variable(torch.from_numpy(angles)) 70 | signal = stft_fn.inverse(magnitudes, angles).squeeze(1) 71 | 72 | for i in range(n_iters): 73 | _, angles = stft_fn.transform(signal) 74 | signal = stft_fn.inverse(magnitudes, angles).squeeze(1) 75 | return signal 76 | 77 | def mel_normalize(x, max_abs_value=4.0, min_level_db=-100): 78 | return torch.clamp((2*max_abs_value)*(x - min_level_db)/(-min_level_db) - max_abs_value, 79 | min=-max_abs_value, max = max_abs_value) 80 | 81 | def mel_denormalize(x, max_abs_value=4.0, min_level_db=-100): 82 | return (torch.clamp(x, min=-max_abs_value, max = max_abs_value) + max_abs_value)*(-min_level_db)/(2*max_abs_value) + min_level_db 83 | 84 | def dynamic_range_compression(x, C=20, clip_val=1e-5): 85 | """ 86 | PARAMS 87 | ------ 88 | C: compression factor 89 | """ 90 | return torch.log10(torch.clamp(x, min=clip_val)) * C 91 | 92 | 93 | def dynamic_range_decompression(x, C=20): 94 | """ 95 | PARAMS 96 | ------ 97 | C: compression factor used to compress 98 | """ 99 | return torch.pow(10, x/C) 100 | -------------------------------------------------------------------------------- /text/__init__.py: -------------------------------------------------------------------------------- 1 | """ from https://github.com/keithito/tacotron """ 2 | import re 3 | from text import cleaners 4 | from text.symbols import eng_symbols, kor_symbols 5 | from hparams import create_hparams 6 | 7 | hparam = create_hparams() 8 | cleaner_names = hparam.text_cleaners 9 | 10 | # Mappings from symbol to numeric ID and vice versa: 11 | symbols = "" 12 | _symbol_to_id = {} 13 | _id_to_symbol = {} 14 | 15 | # Regular expression matching text enclosed in curly braces: 16 | _curly_re = re.compile(r'(.*?)\{(.+?)\}(.*)') 17 | 18 | def change_symbol(cleaner_names): 19 | symbols = "" 20 | global _symbol_to_id 21 | global _id_to_symbol 22 | if cleaner_names == ["english_cleaners"]: symbols = eng_symbols 23 | if cleaner_names == ["korean_cleaners"]: symbols = kor_symbols 24 | 25 | _symbol_to_id = {s: i for i, s in enumerate(symbols)} 26 | _id_to_symbol = {i: s for i, s in enumerate(symbols)} 27 | 28 | change_symbol(cleaner_names) 29 | 30 | def text_to_sequence(text, cleaner_names): 31 | '''Converts a string of text to a sequence of IDs corresponding to the symbols in the text. 32 | 33 | The text can optionally have ARPAbet sequences enclosed in curly braces embedded 34 | in it. For example, "Turn left on {HH AW1 S S T AH0 N} Street." 35 | 36 | Args: 37 | text: string to convert to a sequence 38 | cleaner_names: names of the cleaner functions to run the text through 39 | 40 | Returns: 41 | List of integers corresponding to the symbols in the text 42 | ''' 43 | sequence = [] 44 | change_symbol(cleaner_names) 45 | # Check for curly braces and treat their contents as ARPAbet: 46 | while len(text): 47 | m = _curly_re.match(text) 48 | try: 49 | if not m: 50 | sequence += _symbols_to_sequence(_clean_text(text, cleaner_names)) 51 | break 52 | sequence += _symbols_to_sequence(_clean_text(m.group(1), cleaner_names)) 53 | sequence += _arpabet_to_sequence(m.group(2)) 54 | text = m.group(3) 55 | except: 56 | print(text) 57 | exit() 58 | # Append EOS token 59 | if cleaner_names == ["korean_cleaners"]: sequence.append(_symbol_to_id['~']) 60 | return sequence 61 | 62 | 63 | def sequence_to_text(sequence): 64 | '''Converts a sequence of IDs back to a string''' 65 | result = '' 66 | for symbol_id in sequence: 67 | if symbol_id in _id_to_symbol: 68 | s = _id_to_symbol[symbol_id] 69 | # Enclose ARPAbet back in curly braces: 70 | if len(s) > 1 and s[0] == '@': 71 | s = '{%s}' % s[1:] 72 | result += s 73 | return result.replace('}{', ' ') 74 | 75 | 76 | def _clean_text(text, cleaner_names): 77 | for name in cleaner_names: 78 | cleaner = getattr(cleaners, name) 79 | if not cleaner: 80 | raise Exception('Unknown cleaner: %s' % name) 81 | text = cleaner(text) 82 | return text 83 | 84 | 85 | def _symbols_to_sequence(symbols): 86 | return [_symbol_to_id[s] for s in symbols if _should_keep_symbol(s)] 87 | 88 | 89 | def _arpabet_to_sequence(text): 90 | return _symbols_to_sequence(['@' + s for s in text.split()]) 91 | 92 | 93 | def _should_keep_symbol(s): 94 | return s in _symbol_to_id and s is not '_' and s is not '~' 95 | 96 | if __name__ == "__main__": 97 | print(text_to_sequence('this is test sentence.? ', ['english_cleaners'])) 98 | print(text_to_sequence('테스트 문장입니다.? ', ['korean_cleaners'])) 99 | print(_clean_text('AB테스트 문장입니다.? ', ['korean_cleaners'])) 100 | print(_clean_text('mp3 파일을 홈페이지에서 다운로드 받으시기 바랍니다.',['korean_cleaners'])) 101 | print(_clean_text("마가렛 대처의 별명은 '철의 여인'이었다.", ['korean_cleaners'])) 102 | print(_clean_text("제 전화번호는 01012345678이에요.", ['korean_cleaners'])) 103 | print(_clean_text("‘아줌마’는 결혼한 여자를 뜻한다.", ['korean_cleaners'])) 104 | print(text_to_sequence("‘아줌마’는 결혼한 여자를 뜻한다.", ['korean_cleaners'])) 105 | 106 | -------------------------------------------------------------------------------- /layers.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from librosa.filters import mel as librosa_mel_fn 3 | from audio_processing import dynamic_range_compression, dynamic_range_decompression, mel_normalize, mel_denormalize 4 | from stft import STFT 5 | 6 | 7 | class LinearNorm(torch.nn.Module): 8 | def __init__(self, in_dim, out_dim, bias=True, w_init_gain='linear'): 9 | super(LinearNorm, self).__init__() 10 | self.linear_layer = torch.nn.Linear(in_dim, out_dim, bias=bias) 11 | 12 | torch.nn.init.xavier_uniform_( 13 | self.linear_layer.weight, 14 | gain=torch.nn.init.calculate_gain(w_init_gain)) 15 | 16 | def forward(self, x): 17 | return self.linear_layer(x) 18 | 19 | 20 | class ConvNorm(torch.nn.Module): 21 | def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, 22 | padding=None, dilation=1, bias=True, w_init_gain='linear'): 23 | super(ConvNorm, self).__init__() 24 | if padding is None: 25 | assert(kernel_size % 2 == 1) 26 | padding = int(dilation * (kernel_size - 1) / 2) 27 | 28 | self.conv = torch.nn.Conv1d(in_channels, out_channels, 29 | kernel_size=kernel_size, stride=stride, 30 | padding=padding, dilation=dilation, 31 | bias=bias) 32 | 33 | torch.nn.init.xavier_uniform_( 34 | self.conv.weight, gain=torch.nn.init.calculate_gain(w_init_gain)) 35 | 36 | def forward(self, signal): 37 | conv_signal = self.conv(signal) 38 | return conv_signal 39 | 40 | 41 | class TacotronSTFT(torch.nn.Module): 42 | def __init__(self, filter_length=1024, hop_length=256, win_length=1024, 43 | n_mel_channels=80, sampling_rate=22050, mel_fmin=0.0, 44 | mel_fmax=8000.0): 45 | super(TacotronSTFT, self).__init__() 46 | self.n_mel_channels = n_mel_channels 47 | self.sampling_rate = sampling_rate 48 | self.stft_fn = STFT(filter_length, hop_length, win_length) 49 | mel_basis = librosa_mel_fn( 50 | sampling_rate, filter_length, n_mel_channels, mel_fmin, mel_fmax) 51 | mel_basis = torch.from_numpy(mel_basis).float() 52 | self.register_buffer('mel_basis', mel_basis) 53 | 54 | def spectral_normalize(self, magnitudes): 55 | output = dynamic_range_compression(magnitudes) 56 | return output 57 | 58 | def spectral_de_normalize(self, magnitudes): 59 | output = dynamic_range_decompression(magnitudes) 60 | return output 61 | 62 | def mel_spectrogram(self, y, ref_level_db = 20, magnitude_power=1.5): 63 | """Computes mel-spectrograms from a batch of waves 64 | PARAMS 65 | ------ 66 | y: Variable(torch.FloatTensor) with shape (B, T) in range [-1, 1] 67 | 68 | RETURNS 69 | ------- 70 | mel_output: torch.FloatTensor of shape (B, n_mel_channels, T) 71 | """ 72 | assert(torch.min(y.data) >= -1) 73 | assert(torch.max(y.data) <= 1) 74 | 75 | #print('y' ,y.max(), y.mean(), y.min()) 76 | magnitudes, phases = self.stft_fn.transform(y) 77 | magnitudes = magnitudes.data 78 | #print('stft_fn', magnitudes.max(), magnitudes.mean(), magnitudes.min()) 79 | mel_output = torch.matmul(self.mel_basis, torch.abs(magnitudes)**magnitude_power) 80 | #print('_linear_to_mel', mel_output.max(), mel_output.mean(), mel_output.min()) 81 | mel_output = self.spectral_normalize(mel_output) - ref_level_db 82 | #print('_amp_to_db', mel_output.max(), mel_output.mean(), mel_output.min()) 83 | mel_output = mel_normalize(mel_output) 84 | #print('_normalize', mel_output.max(), mel_output.mean(), mel_output.min()) 85 | #spec = mel_denormalize(mel_output) 86 | #print('_denormalize', spec.max(), spec.mean(), spec.min()) 87 | #spec = self.spectral_de_normalize(spec + ref_level_db)**(1/magnitude_power) 88 | #print('db_to_amp', spec.max(), spec.mean(), spec.min()) 89 | return mel_output 90 | -------------------------------------------------------------------------------- /filelists/kss_val_filelist.txt: -------------------------------------------------------------------------------- 1 | kss/wavs/4/4_5162.wav|한국에서는 택시에서 무료로 통역 서비스를 제공해요. 2 | kss/wavs/4/4_5341.wav|이건 완전한 문장이 아닌데요. 3 | kss/wavs/4/4_1123.wav|우리 회사에 지원한 동기가 무엇입니까? 4 | kss/wavs/3/3_0292.wav|수업 시간 내내 졸았어요. 5 | kss/wavs/3/3_1693.wav|그것은 부정할 수 없는 사실이다. 6 | kss/wavs/2/2_0436.wav|저는 최근 반 년 동안 거의 매일 묽은 변을 봤어요. 7 | kss/wavs/4/4_3185.wav|머리 조심 8 | kss/wavs/4/4_3859.wav|내년에 대학에 갈 거니? 9 | kss/wavs/3/3_2849.wav|멜로디가 귀에 익어요. 10 | kss/wavs/1/1_0354.wav|몸을 옆으로 기울여 보세요. 11 | kss/wavs/3/3_1356.wav|살이 진짜 많이 빠졌군요. 12 | kss/wavs/3/3_2567.wav|아동 노동이 금지되어 있음을 모르는 사람들도 있어요. 13 | kss/wavs/4/4_3922.wav|파리가 방 안을 날아다니고 있어요. 14 | kss/wavs/4/4_4867.wav|컴퓨터 속을 봐야 할 것 같습니다. 15 | kss/wavs/2/2_0453.wav|학생이 수업 시간에 질문을 하는 것이 바람직합니다. 16 | kss/wavs/3/3_2895.wav|그녀의 소설은 모든 등장인물들이 저마다의 개성을 갖고 있다. 17 | kss/wavs/4/4_3083.wav|이제부터는 어려운 부분만 집중적으로 공부할 필요가 있어요. 18 | kss/wavs/3/3_4079.wav|즉시 집으로 가라! 19 | kss/wavs/4/4_5240.wav|요즘 십대들은 개성이 뚜렷해요. 20 | kss/wavs/4/4_3672.wav|저는 목요일마다 집을 치워요. 21 | kss/wavs/4/4_2862.wav|이게 내가 가진 전부야. 22 | kss/wavs/4/4_0512.wav|제가 어릴 때 부모님이 이혼했어요. 23 | kss/wavs/4/4_1835.wav|이 노트북은 꽤 고급이야. 24 | kss/wavs/3/3_4622.wav|언어가 시간에 따라 변화한다는 것은 명백한 사실이다. 25 | kss/wavs/3/3_2251.wav|이번 여름에 부모님이랑 여행 갈 계획이에요. 26 | kss/wavs/2/2_0253.wav|다양한 의견을 듣는 것은 중요합니다. 27 | kss/wavs/3/3_0247.wav|나는 비린 생선들을 좋아하지 않는다. 28 | kss/wavs/3/3_4469.wav|한국은 천연자원이 풍부하지 않습니다. 29 | kss/wavs/4/4_4567.wav|그 버스는 우리 집 바로 앞에 서요. 30 | kss/wavs/3/3_3828.wav|빛은 소리보다 훨씬 빨리 이동한다. 31 | kss/wavs/3/3_2350.wav|나는 발이 손이 되도록 빌었지만 소용없었다. 32 | kss/wavs/3/3_0741.wav|상처 부위에 매일 이 연고를 바르세요. 33 | kss/wavs/4/4_1845.wav|저는 현대 소설보다 고전을 좋아해요. 34 | kss/wavs/3/3_2151.wav|금연 구역 35 | kss/wavs/4/4_3001.wav|아직도 그 생각을 하면 슬퍼져요. 36 | kss/wavs/3/3_0064.wav|저는 부산에서 태어났지만 서울에서 자랐어요. 37 | kss/wavs/4/4_0684.wav|서태지는 음악의 천재예요. 38 | kss/wavs/3/3_1393.wav|저는 손톱을 물어 뜨는 나쁜 습관이 있어요. 39 | kss/wavs/1/1_0769.wav|그녀의 소식을 들으니 마음이 놓였다. 40 | kss/wavs/4/4_1734.wav|기초 자료를 수집하는 중입니다. 41 | kss/wavs/4/4_2673.wav|자기 운명은 자기가 만들어 나가는 거예요. 42 | kss/wavs/3/3_3629.wav|책을 구입하기 전에 목차를 꼭 확인해라. 43 | kss/wavs/3/3_0876.wav|대학에 안 간 것이 원통해요. 44 | kss/wavs/4/4_1255.wav|그 꼬마가 어느새 커서 어른이 되었구나. 45 | kss/wavs/3/3_4990.wav|굵 46 | kss/wavs/4/4_1472.wav|가능성이 어느 정도라고 생각합니까? 47 | kss/wavs/2/2_0368.wav|조금만 참아. 방학이 머지않았어. 48 | kss/wavs/2/2_1094.wav|모두가 지쳤지만, 그에게서는 피로한 기색을 찾아볼 수 없었다. 49 | kss/wavs/4/4_1883.wav|현재 공사는 어느 정도 되었나요? 50 | kss/wavs/4/4_0774.wav|추가 비용은 없습니다. 51 | kss/wavs/4/4_2483.wav|환경을 생각해서 일회용품의 사용을 줄여야 합니다. 52 | kss/wavs/4/4_1768.wav|김이랑 김치랑 밥 먹어. 53 | kss/wavs/4/4_2687.wav|엄마는 피아노를 잘 치세요. 54 | kss/wavs/4/4_5320.wav|내가 그렇게 우스워 보여? 55 | kss/wavs/1/1_0205.wav|창문을 좀 닫아도 될까요? 56 | kss/wavs/1/1_0894.wav|영화가 막 시작하려고 합니다. 57 | kss/wavs/2/2_0101.wav|제 입장이 좀 곤란한데요. 58 | kss/wavs/2/2_1132.wav|모두 떠나고 나니 마음이 황량했다. 59 | kss/wavs/3/3_2143.wav|서울은 한국의 수도다. 60 | kss/wavs/4/4_3678.wav|잠이 모자라서 피곤해요. 61 | kss/wavs/3/3_0345.wav|저희 아빠는 집에서 살림을 하세요. 62 | kss/wavs/3/3_0522.wav|내가 짐을 들 테니 당신이 아이 좀 안아요. 63 | kss/wavs/4/4_4463.wav|전 대통령의 사망 소식에 전 국민이 슬픔에 잠겨 있다. 64 | kss/wavs/4/4_1922.wav|저는 고등학교에서 국어를 가르칩니다. 65 | kss/wavs/2/2_1091.wav|몹시 피곤해 보이시네요. 좀 쉬세요. 66 | kss/wavs/4/4_1470.wav|나는 네 가는 손가락이 부러워. 67 | kss/wavs/1/1_0748.wav|참을 수 있는 한계를 넘어섰어요. 68 | kss/wavs/1/1_0634.wav|그 사람 정말 말랐어. 69 | kss/wavs/4/4_4791.wav|내일 신체검사가 있어. 70 | kss/wavs/4/4_1480.wav|그 계약서에 강제로 서명하지 않으셔도 됩니다. 71 | kss/wavs/2/2_0717.wav|그것 참 안됐네요. 72 | kss/wavs/1/1_0360.wav|가을은 일 년 중 공부하기에 제일 좋은 계절이다. 73 | kss/wavs/4/4_3540.wav|엄마는 싼 옷만 입으세요. 74 | kss/wavs/4/4_2928.wav|저는 제 분야에서 전문가가 되고 싶습니다. 75 | kss/wavs/4/4_0283.wav|아버지는 밭에 씨를 뿌리고 계세요. 76 | kss/wavs/3/3_4547.wav|무려 천 명이나 모였어요. 77 | kss/wavs/4/4_0056.wav|앞문하고 뒷문 둘 다 잠갔지? 78 | kss/wavs/3/3_0212.wav|그는 열쇠 구멍을 통해 훔쳐보다가 잡혔다. 79 | kss/wavs/4/4_2835.wav|수술 절차는 꽤 간단해요. 80 | kss/wavs/3/3_1454.wav|그날 집에 있기로 한 것은 현명한 선택이었다. 81 | kss/wavs/3/3_3231.wav|최대한 빨리 대책을 세워야 한다. 82 | kss/wavs/4/4_5054.wav|저는 오늘 쉬는 날이에요. 83 | kss/wavs/2/2_0320.wav|왜 밖이 이렇게 떠들썩해? 84 | kss/wavs/3/3_4612.wav|최대한 협조하겠습니다. 85 | kss/wavs/4/4_1538.wav|지금은 배가 안 고파요. 게다가 라면도 별로 안 좋아하고요. 86 | kss/wavs/4/4_2816.wav|잘못을 저질렀으면 벌을 받아야지. 87 | kss/wavs/4/4_3730.wav|이 가방은 제가 들기에는 너무 무거워요. 88 | kss/wavs/4/4_2805.wav|저것 좀 봐. 89 | kss/wavs/3/3_4123.wav|이것을 최후의 수단으로 남겨두세요. 90 | kss/wavs/4/4_0716.wav|엄마, 내일 친구 집에 가서 놀아도 돼요? 91 | kss/wavs/3/3_1292.wav|내 신세가 참 불쌍해요. 92 | kss/wavs/4/4_0182.wav|나는 작년에 박사 학위를 받았다. 93 | kss/wavs/4/4_2518.wav|저는 오늘 아침에 우유를 세 잔이나 마셨어요. 94 | kss/wavs/3/3_0715.wav|어제 아들이 학교에서 의식을 잃고 쓰러졌어요. 95 | kss/wavs/3/3_5005.wav|보이 96 | kss/wavs/2/2_0493.wav|밥을 먹고 나면 늘 배가 더부룩하게 불러요. 97 | kss/wavs/4/4_3717.wav|싸움 구경을 하려고 사람들이 모여들었다. 98 | kss/wavs/4/4_2960.wav|그 사람은 고개를 저으면서 거절했어요. 99 | kss/wavs/3/3_1825.wav|뭐 때문에 늦었어? 100 | kss/wavs/4/4_4674.wav|숙제는 스스로 해라. 101 | -------------------------------------------------------------------------------- /filelists/nam-h_val_filelist.txt: -------------------------------------------------------------------------------- 1 | nam-h/wavs/4/0000162.wav|대중은 알 권리가 있다. 2 | nam-h/wavs/6/0000119.wav|저를 알아보시겠어요? 3 | nam-h/wavs/1/0000824.wav|저는 늘 그 사람이 하는 일에 만족합니다. 4 | nam-h/wavs/9/0000605.wav|저는 먹여 살릴 식구가 많아요. 5 | nam-h/wavs/1/0000803.wav|지금 울고 싶은 심정이야. 6 | nam-h/wavs/8/0000778.wav|자유롭게 질문해 주세요. 7 | nam-h/wavs/5/0000601.wav|말을 안 하는 게 말을 잘하는 것보다 훨씬 더 어려워요. 8 | nam-h/wavs/3/0000200.wav|그 아파트는 방이 세 개고 거실이 한 개다. 9 | nam-h/wavs/5/0000244.wav|지금껏 어디에 있었어? 10 | nam-h/wavs/2/0000158.wav|최선을 다해 돕겠습니다. 11 | nam-h/wavs/0/0000732.wav|의지가 약해서 담배를 못 끊겠어요. 12 | nam-h/wavs/3/0000371.wav|저는 약혼을 했지만 약혼녀를 정말로 얼마나 사랑하는지 모르겠어요. 13 | nam-h/wavs/1/0000792.wav|일하면서 스트레스를 많이 받으세요? 14 | nam-h/wavs/12/0000433.wav|우산 가져오는 걸 잊어버렸어. 15 | nam-h/wavs/6/0000441.wav|맥주는 보리로 만들어요. 16 | nam-h/wavs/7/0000065.wav|물은 100도에서 끓어요. 17 | nam-h/wavs/11/0000131.wav|요즘은 바빠서 운동할 틈이 없어요. 18 | nam-h/wavs/4/0000815.wav|우주의 기원을 이해하는 것은 인류의 오랜 소망 중 하나다. 19 | nam-h/wavs/8/0000465.wav|11월 8일은 저희 결혼 기념일이에요. 20 | nam-h/wavs/9/0000588.wav|제 기억이 맞다면, 첫째, 셋째 수요일에 쉬어요. 21 | nam-h/wavs/0/0000419.wav|비가 와서 마당의 잡초가 무성하게 자랐다. 22 | nam-h/wavs/9/0000402.wav|구두가 너무 꽉 껴요. 23 | nam-h/wavs/6/0000192.wav|보내 주신 제품에서 몇 가지 문제가 발견되었습니다. 24 | nam-h/wavs/5/0000600.wav|이번 겨울은 비교적 따뜻하다. 25 | nam-h/wavs/3/0000949.wav|제 친구 하나가 작년에 호주로 이민을 갔어요. 26 | nam-h/wavs/7/0000997.wav|2002년 월드컵 때 수많은 시민들이 시청 앞 광장에 모였어요. 27 | nam-h/wavs/3/0000089.wav|저는 자주 그 카페에서 시간을 보냅니다. 28 | nam-h/wavs/3/0000854.wav|그녀는 가수가 되기 위해 서울에 왔다. 29 | nam-h/wavs/6/0000684.wav|서태지는 음악의 천재예요. 30 | nam-h/wavs/12/0000853.wav|회사 건너편에 새로 생긴 커피숍 가 봤니? 31 | nam-h/wavs/1/0000750.wav|배탈이 나서 밤새 설사를 했어요. 32 | nam-h/wavs/10/0000167.wav|가격이 얼마나 올랐어요? 33 | nam-h/wavs/1/0000030.wav|기혼이세요, 미혼이세요? 34 | nam-h/wavs/12/0000080.wav|이틀 동안 차를 빌리고 싶은데요. 35 | nam-h/wavs/7/0000030.wav|김, 오이, 당근, 계란 등의 재료가 다 있습니다. 36 | nam-h/wavs/2/0000226.wav|그는 자신이 원하는 바를 이루기 위해 늘 최선을 다한다. 37 | nam-h/wavs/8/0000456.wav|교사는 학생들을 올바른 길로 이끌어야 합니다. 38 | nam-h/wavs/6/0000049.wav|조수미는 세계적으로 알려진 음악가다. 39 | nam-h/wavs/6/0000341.wav|요즘 인기 있는 브랜드를 추천해 주실 수 있나요? 40 | nam-h/wavs/1/0000213.wav|도와 드릴까요? 아뇨, 그냥 둘러보는 거예요. 41 | nam-h/wavs/3/0000768.wav|이번에는 체력 훈련에 중점을 두었습니다. 42 | nam-h/wavs/10/0000832.wav|기차가 십 분 후에 출발합니다. 43 | nam-h/wavs/0/0000122.wav|나이를 여쭤 봐도 괜찮을까요? 44 | nam-h/wavs/9/0000088.wav|제가 지름길을 알고 있어요. 45 | nam-h/wavs/5/0000561.wav|약간 비싼데요. 46 | nam-h/wavs/1/0000633.wav|왜 자꾸 내 뒤를 따라다니는 거야? 47 | nam-h/wavs/5/0000955.wav|들어와서 커피 한 잔 해. 48 | nam-h/wavs/0/0000645.wav|시원한 물 좀 드릴까요? 49 | nam-h/wavs/5/0000368.wav|그는 자신의 모습을 거울에 비춰 보았다. 50 | nam-h/wavs/7/0000876.wav|공장 내에서는 사진을 찍을 수 없습니다. 51 | nam-h/wavs/1/0000776.wav|저는 왼쪽 뺨에 흉터가 있어요. 52 | nam-h/wavs/12/0000808.wav|벚꽃이 활짝 폈다. 53 | nam-h/wavs/6/0000247.wav|그냥 방바닥 긁고 있어요. 54 | nam-h/wavs/5/0000329.wav|선생님은 우리에게 책상 줄을 반듯하게 맞추도록 시켰다. 55 | nam-h/wavs/0/0000687.wav|커피가 너무 써. 56 | nam-h/wavs/6/0000118.wav|연극이 몇 시에 시작하는지 알아봐야겠다. 57 | nam-h/wavs/1/0000009.wav|저는 별명으로 불리는 게 싫어요. 58 | nam-h/wavs/0/0000967.wav|아무리 조심해도 지나치지 않아요. 59 | nam-h/wavs/5/0000021.wav|결혼 10주년 60 | nam-h/wavs/11/0000562.wav|당신이 여성으로서는 처음 뽑힌 거라고 들었습니다. 61 | nam-h/wavs/2/0000682.wav|도대체 무슨 말이야? 62 | nam-h/wavs/12/0000759.wav|할아버지는 그런 일을 하시기에는 너무 늙으셨어. 63 | nam-h/wavs/12/0000222.wav|무거운 것을 들다 허리를 삐끗했다. 64 | nam-h/wavs/2/0000763.wav|세상을 저주한다고 무슨 소용이 있어? 65 | nam-h/wavs/8/0000227.wav|할아버지, 여기 들어오시면 안 됩니다. 66 | nam-h/wavs/3/0000594.wav|저는 버스로 출퇴근해요. 67 | nam-h/wavs/2/0000599.wav|아까 길에서 외국인이 말을 걸어 와서 당황했어요. 68 | nam-h/wavs/5/0000297.wav|그 건물은 길 건너편에 있어요. 69 | nam-h/wavs/8/0000187.wav|오늘 밤은 하늘에 별이 아주 많아. 70 | nam-h/wavs/4/0000259.wav|이제야 감을 좀 잡겠어요. 71 | nam-h/wavs/8/0000208.wav|그 사람은 한마디 말도 없이 가 버렸어요. 72 | nam-h/wavs/10/0000885.wav|아내는 결혼 전에 동네에서 미인으로 소문났었어요. 73 | nam-h/wavs/5/0000816.wav|아버지 도와 드려라. 74 | nam-h/wavs/10/0000396.wav|어제 우리 집 개가 새끼를 낳았어. 75 | nam-h/wavs/6/0000323.wav|두 팀 간의 점수가 너무 많이 벌어졌어요. 76 | nam-h/wavs/9/0000340.wav|아기는 밤 사이에 여러 번 깼어요. 77 | nam-h/wavs/3/0000800.wav|경기장 안으로 술을 가지고 들어올 수 없습니다. 78 | nam-h/wavs/1/0000084.wav|이번 주 일요일에 할머니 칠순 잔치를 합니다. 79 | nam-h/wavs/10/0000442.wav|이 서류에 사인해 주세요. 80 | nam-h/wavs/6/0000044.wav|악수는 보통 오른손으로 한다. 81 | nam-h/wavs/12/0000129.wav|갑자기 시부모님이 오셔서 모임에 참석하지 못했어요. 82 | nam-h/wavs/6/0000741.wav|최대 20학점까지 신청할 수 있습니다. 83 | nam-h/wavs/4/0000864.wav|산업 하수는 수질오염을 유발한다. 84 | nam-h/wavs/1/0000932.wav|그녀는 친한 친구가 새 자전거를 자랑하자 샘이 났다. 85 | nam-h/wavs/6/0000254.wav|저는 키가 큰 데 반해, 아버지는 키가 작으세요. 86 | nam-h/wavs/4/0000671.wav|검색 문구가 너무 길어요. 87 | nam-h/wavs/10/0000019.wav|그 사람을 보면 놀랄 거야. 88 | nam-h/wavs/8/0000263.wav|그건 초보자들이 흔히들 하는 실수야. 89 | nam-h/wavs/8/0000857.wav|어두워지기 전에 집에 가자. 90 | nam-h/wavs/7/0000919.wav|마포구청 91 | nam-h/wavs/5/0000740.wav|이사를 하면서 낡은 옷들을 모두 버렸어요. 92 | nam-h/wavs/7/0000739.wav|기대지 마시오. 93 | nam-h/wavs/0/0000104.wav|그녀는 길고 곧은 코를 갖고 있다. 94 | nam-h/wavs/7/0000679.wav|최근 감기 환자가 급증하고 있어요. 95 | nam-h/wavs/2/0000875.wav|다음 문장에서 잘못된 부분을 고치세요. 96 | nam-h/wavs/10/0000819.wav|오늘 밤은 신나게 놀자. 97 | nam-h/wavs/0/0000062.wav|오늘은 파도가 거칠어서 해변에 나가지 않았어요. 98 | nam-h/wavs/12/0000607.wav|가스 레인지 좀 켜 봐. 99 | nam-h/wavs/4/0000732.wav|강남은 언제나 붐벼요. 100 | nam-h/wavs/7/0000075.wav|시간은 되돌릴 수 없다. -------------------------------------------------------------------------------- /data_utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import numpy as np 3 | import torch 4 | import torch.utils.data 5 | 6 | import layers 7 | from utils import load_wav_to_torch, load_filepaths_and_text 8 | from text import text_to_sequence 9 | 10 | 11 | class TextMelLoader(torch.utils.data.Dataset): 12 | """ 13 | 1) loads audio,text pairs 14 | 2) normalizes text and converts them to sequences of one-hot vectors 15 | 3) computes mel-spectrograms from audio files. 16 | """ 17 | def __init__(self, audiopaths_and_text, hparams): 18 | self.audiopaths_and_text = load_filepaths_and_text(audiopaths_and_text) 19 | self.text_cleaners = hparams.text_cleaners 20 | self.max_wav_value = hparams.max_wav_value 21 | self.sampling_rate = hparams.sampling_rate 22 | self.load_mel_from_disk = hparams.load_mel_from_disk 23 | self.stft = layers.TacotronSTFT( 24 | hparams.filter_length, hparams.hop_length, hparams.win_length, 25 | hparams.n_mel_channels, hparams.sampling_rate, hparams.mel_fmin, 26 | hparams.mel_fmax) 27 | random.seed(1234) 28 | random.shuffle(self.audiopaths_and_text) 29 | 30 | def get_mel_text_pair(self, audiopath_and_text): 31 | # separate filename and text 32 | audiopath, text = audiopath_and_text[0], audiopath_and_text[1] 33 | text = self.get_text(text) # int_tensor[char_index, ....] 34 | mel = self.get_mel(audiopath) # [] 35 | return (text, mel) 36 | 37 | def get_mel(self, filename): 38 | if not self.load_mel_from_disk: 39 | audio, sampling_rate = load_wav_to_torch(filename) 40 | if sampling_rate != self.stft.sampling_rate: 41 | raise ValueError("{} {} SR doesn't match target {} SR".format( 42 | sampling_rate, self.stft.sampling_rate)) 43 | audio_norm = audio / self.max_wav_value 44 | audio_norm = audio_norm.unsqueeze(0) 45 | audio_norm = torch.autograd.Variable(audio_norm, requires_grad=False) 46 | melspec = self.stft.mel_spectrogram(audio_norm) 47 | melspec = torch.squeeze(melspec, 0) 48 | else: 49 | melspec = torch.from_numpy(np.load(filename)) 50 | assert melspec.size(0) == self.stft.n_mel_channels, ( 51 | 'Mel dimension mismatch: given {}, expected {}'.format( 52 | melspec.size(0), self.stft.n_mel_channels)) 53 | 54 | return melspec 55 | 56 | def get_text(self, text): 57 | text_norm = torch.IntTensor(text_to_sequence(text, self.text_cleaners)) 58 | return text_norm 59 | 60 | def __getitem__(self, index): 61 | return self.get_mel_text_pair(self.audiopaths_and_text[index]) 62 | 63 | def __len__(self): 64 | return len(self.audiopaths_and_text) 65 | 66 | 67 | class TextMelCollate(): 68 | """ Zero-pads model inputs and targets based on number of frames per setep 69 | """ 70 | def __init__(self, n_frames_per_step): 71 | self.n_frames_per_step = n_frames_per_step 72 | 73 | def __call__(self, batch): 74 | """Collate's training batch from normalized text and mel-spectrogram 75 | PARAMS 76 | ------ 77 | batch: [[text_normalized, mel_normalized], ...] 78 | """ 79 | # Right zero-pad all one-hot text sequences to max input length 80 | input_lengths, ids_sorted_decreasing = torch.sort( 81 | torch.LongTensor([len(x[0]) for x in batch]), 82 | dim=0, descending=True) 83 | max_input_len = input_lengths[0] 84 | 85 | text_padded = torch.LongTensor(len(batch), max_input_len) 86 | text_padded.zero_() 87 | for i in range(len(ids_sorted_decreasing)): 88 | text = batch[ids_sorted_decreasing[i]][0] 89 | text_padded[i, :text.size(0)] = text 90 | 91 | # Right zero-pad mel-spec 92 | num_mels = batch[0][1].size(0) 93 | max_target_len = max([x[1].size(1) for x in batch]) 94 | if max_target_len % self.n_frames_per_step != 0: 95 | max_target_len += self.n_frames_per_step - max_target_len % self.n_frames_per_step 96 | assert max_target_len % self.n_frames_per_step == 0 97 | 98 | # include mel padded and gate padded 99 | mel_padded = torch.FloatTensor(len(batch), num_mels, max_target_len) 100 | mel_padded.zero_() 101 | gate_padded = torch.FloatTensor(len(batch), max_target_len) 102 | gate_padded.zero_() 103 | output_lengths = torch.LongTensor(len(batch)) 104 | for i in range(len(ids_sorted_decreasing)): 105 | mel = batch[ids_sorted_decreasing[i]][1] 106 | mel_padded[i, :, :mel.size(1)] = mel 107 | gate_padded[i, mel.size(1)-1:] = 1 108 | output_lengths[i] = mel.size(1) 109 | 110 | return text_padded, input_lengths, mel_padded, gate_padded, \ 111 | output_lengths 112 | -------------------------------------------------------------------------------- /loss_scaler.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | class LossScaler: 4 | 5 | def __init__(self, scale=1): 6 | self.cur_scale = scale 7 | 8 | # `params` is a list / generator of torch.Variable 9 | def has_overflow(self, params): 10 | return False 11 | 12 | # `x` is a torch.Tensor 13 | def _has_inf_or_nan(x): 14 | return False 15 | 16 | # `overflow` is boolean indicating whether we overflowed in gradient 17 | def update_scale(self, overflow): 18 | pass 19 | 20 | @property 21 | def loss_scale(self): 22 | return self.cur_scale 23 | 24 | def scale_gradient(self, module, grad_in, grad_out): 25 | return tuple(self.loss_scale * g for g in grad_in) 26 | 27 | def backward(self, loss): 28 | scaled_loss = loss*self.loss_scale 29 | scaled_loss.backward() 30 | 31 | class DynamicLossScaler: 32 | 33 | def __init__(self, 34 | init_scale=2**32, 35 | scale_factor=2., 36 | scale_window=1000): 37 | self.cur_scale = init_scale 38 | self.cur_iter = 0 39 | self.last_overflow_iter = -1 40 | self.scale_factor = scale_factor 41 | self.scale_window = scale_window 42 | 43 | # `params` is a list / generator of torch.Variable 44 | def has_overflow(self, params): 45 | # return False 46 | for p in params: 47 | if p.grad is not None and DynamicLossScaler._has_inf_or_nan(p.grad.data): 48 | return True 49 | 50 | return False 51 | 52 | # `x` is a torch.Tensor 53 | def _has_inf_or_nan(x): 54 | cpu_sum = float(x.float().sum()) 55 | if cpu_sum == float('inf') or cpu_sum == -float('inf') or cpu_sum != cpu_sum: 56 | return True 57 | return False 58 | 59 | # `overflow` is boolean indicating whether we overflowed in gradient 60 | def update_scale(self, overflow): 61 | if overflow: 62 | #self.cur_scale /= self.scale_factor 63 | self.cur_scale = max(self.cur_scale/self.scale_factor, 1) 64 | self.last_overflow_iter = self.cur_iter 65 | else: 66 | if (self.cur_iter - self.last_overflow_iter) % self.scale_window == 0: 67 | self.cur_scale *= self.scale_factor 68 | # self.cur_scale = 1 69 | self.cur_iter += 1 70 | 71 | @property 72 | def loss_scale(self): 73 | return self.cur_scale 74 | 75 | def scale_gradient(self, module, grad_in, grad_out): 76 | return tuple(self.loss_scale * g for g in grad_in) 77 | 78 | def backward(self, loss): 79 | scaled_loss = loss*self.loss_scale 80 | scaled_loss.backward() 81 | 82 | ############################################################## 83 | # Example usage below here -- assuming it's in a separate file 84 | ############################################################## 85 | if __name__ == "__main__": 86 | import torch 87 | from torch.autograd import Variable 88 | from dynamic_loss_scaler import DynamicLossScaler 89 | 90 | # N is batch size; D_in is input dimension; 91 | # H is hidden dimension; D_out is output dimension. 92 | N, D_in, H, D_out = 64, 1000, 100, 10 93 | 94 | # Create random Tensors to hold inputs and outputs, and wrap them in Variables. 95 | x = Variable(torch.randn(N, D_in), requires_grad=False) 96 | y = Variable(torch.randn(N, D_out), requires_grad=False) 97 | 98 | w1 = Variable(torch.randn(D_in, H), requires_grad=True) 99 | w2 = Variable(torch.randn(H, D_out), requires_grad=True) 100 | parameters = [w1, w2] 101 | 102 | learning_rate = 1e-6 103 | optimizer = torch.optim.SGD(parameters, lr=learning_rate) 104 | loss_scaler = DynamicLossScaler() 105 | 106 | for t in range(500): 107 | y_pred = x.mm(w1).clamp(min=0).mm(w2) 108 | loss = (y_pred - y).pow(2).sum() * loss_scaler.loss_scale 109 | print('Iter {} loss scale: {}'.format(t, loss_scaler.loss_scale)) 110 | print('Iter {} scaled loss: {}'.format(t, loss.data[0])) 111 | print('Iter {} unscaled loss: {}'.format(t, loss.data[0] / loss_scaler.loss_scale)) 112 | 113 | # Run backprop 114 | optimizer.zero_grad() 115 | loss.backward() 116 | 117 | # Check for overflow 118 | has_overflow = DynamicLossScaler.has_overflow(parameters) 119 | 120 | # If no overflow, unscale grad and update as usual 121 | if not has_overflow: 122 | for param in parameters: 123 | param.grad.data.mul_(1. / loss_scaler.loss_scale) 124 | optimizer.step() 125 | # Otherwise, don't do anything -- ie, skip iteration 126 | else: 127 | print('OVERFLOW!') 128 | 129 | # Update loss scale for next iteration 130 | loss_scaler.update_scale(has_overflow) 131 | 132 | -------------------------------------------------------------------------------- /text/ko_dictionary.py: -------------------------------------------------------------------------------- 1 | etc_dictionary = { 2 | '2 30대': '이삼십대', 3 | '20~30대': '이삼십대', 4 | '20, 30대': '이십대 삼십대', 5 | '1+1': '원플러스원', 6 | '3에서 6개월인': '3개월에서 육개월인', 7 | 'mp3': '엠피쓰리', 8 | } 9 | 10 | english_dictionary = { 11 | 'Devsisters': '데브시스터즈', 12 | 'track': '트랙', 13 | 14 | # krbook 15 | 'LA': '엘에이', 16 | 'LG': '엘지', 17 | 'KOREA': '코리아', 18 | 'JSA': '제이에스에이', 19 | 'PGA': '피지에이', 20 | 'GA': '지에이', 21 | 'idol': '아이돌', 22 | 'KTX': '케이티엑스', 23 | 'AC': '에이씨', 24 | 'DVD': '디비디', 25 | 'US': '유에스', 26 | 'CNN': '씨엔엔', 27 | 'LPGA': '엘피지에이', 28 | 'P': '피', 29 | 'p': '피', 30 | 'L': '엘', 31 | 'l': '엘', 32 | 'T': '티', 33 | 't': '티', 34 | 'B': '비', 35 | 'b': '비', 36 | 'C': '씨', 37 | 'c': '씨', 38 | 'BIFF': '비아이에프에프', 39 | 'GV': '지비', 40 | 41 | # JTBC 42 | 'IT': '아이티', 43 | 'IQ': '아이큐', 44 | 'JTBC': '제이티비씨', 45 | 'trickle down effect': '트리클 다운 이펙트', 46 | 'trickle up effect': '트리클 업 이펙트', 47 | 'down': '다운', 48 | 'up': '업', 49 | 'FCK': '에프씨케이', 50 | 'AP': '에이피', 51 | 'WHERETHEWILDTHINGSARE': '', 52 | 'Rashomon Effect': '', 53 | 'O': '오', 54 | 'o': '오', 55 | 'OO': '오오', 56 | 'B': '비', 57 | 'b': '비', 58 | 'GDP': '지디피', 59 | 'CIPA': '씨아이피에이', 60 | 'YS': '와이에스', 61 | 'Y': '와이', 62 | 'y': '와이', 63 | 'S': '에스', 64 | 's': '에스', 65 | 'JTBC': '제이티비씨', 66 | 'PC': '피씨', 67 | 'bill': '빌', 68 | 'Halmuny': '하모니', ##### 69 | 'X': '엑스', 70 | 'SNS': '에스엔에스', 71 | 'ability': '어빌리티', 72 | 'shy': '', 73 | 'CCTV': '씨씨티비', 74 | 'IT': '아이티', 75 | 'the tenth man': '더 텐쓰 맨', #### 76 | 'L': '엘', 77 | 'PC': '피씨', 78 | 'YSDJJPMB': '', ######## 79 | 'Content Attitude Timing': '컨텐트 애티튜드 타이밍', 80 | 'CAT': '캣', 81 | 'IS': '아이에스', 82 | 'SNS': '에스엔에스', 83 | 'K': '케이', 84 | 'k': '케이', 85 | 'Y': '와이', 86 | 'y': '와이', 87 | 'KDI': '케이디아이', 88 | 'DOC': '디오씨', 89 | 'CIA': '씨아이에이', 90 | 'PBS': '피비에스', 91 | 'D': '디', 92 | 'd': '디', 93 | 'PPropertyPositionPowerPrisonP' 94 | 'S': '에스', 95 | 'francisco': '프란시스코', 96 | 'I': '아이', 97 | 'i': '아이', 98 | 'III': '아이아이', ###### 99 | 'No joke': '노 조크', 100 | 'BBK': '비비케이', 101 | 'LA': '엘에이', 102 | 'Don': '', 103 | 't worry be happy': ' 워리 비 해피', 104 | 'NO': '엔오', ##### 105 | 'it was our sky': '잇 워즈 아워 스카이', 106 | 'it is our sky': '잇 이즈 아워 스카이', #### 107 | 'NEIS': '엔이아이에스', ##### 108 | 'IMF': '아이엠에프', 109 | 'apology': '어폴로지', 110 | 'humble': '험블', 111 | 'M': '엠', 112 | 'm': '엠', 113 | 'Nowhere Man': '노웨어 맨', 114 | 'The Tenth Man': '더 텐쓰 맨', 115 | 'PBS': '피비에스', 116 | 'BBC': '비비씨', 117 | 'MRJ': '엠알제이', 118 | 'CCTV': '씨씨티비', 119 | 'Pick me up': '픽 미 업', 120 | 'DNA': '디엔에이', 121 | 'UN': '유엔', 122 | 'STOP': '스탑', ##### 123 | 'PRESS': '프레스', ##### 124 | 'not to be': '낫 투비', 125 | 'Denial': '디나이얼', 126 | 'G': '지', 127 | 'g': '지', 128 | 'IMF': '아이엠에프', 129 | 'GDP': '지디피', 130 | 'JTBC': '제이티비씨', 131 | 'Time flies like an arrow': '타임 플라이즈 라이크 언 애로우', 132 | 'DDT': '디디티', 133 | 'AI': '에이아이', 134 | 'Z': '제트', 135 | 'z': '제트', 136 | 'OECD': '오이씨디', 137 | 'N': '앤', 138 | 'n': '앤', 139 | 'A': '에이', 140 | 'a': '에이', 141 | 'MB': '엠비', 142 | 'EH': '이에이치', 143 | 'IS': '아이에스', 144 | 'TV': '티비', 145 | 'MIT': '엠아이티', 146 | 'KBO': '케이비오', 147 | 'I love America': '아이 러브 아메리카', 148 | 'SF': '에스에프', 149 | 'Q': '큐', 150 | 'q': '큐', 151 | 'KFX': '케이에프엑스', 152 | 'PM': '피엠', 153 | 'Prime Minister': '프라임 미니스터', 154 | 'Swordline': '스워드라인', 155 | 'TBS': '티비에스', 156 | 'DDT': '디디티', 157 | 'CS': '씨에스', 158 | 'Reflecting Absence': '리플렉팅 앱센스', 159 | 'PBS': '피비에스', 160 | 'Drum being beaten by everyone': '드럼 빙 비튼 바이 에브리원', 161 | 'negative pressure': '네거티브 프레셔', 162 | 'F': '에프', 163 | 'f': '에프', 164 | 'KIA': '기아', 165 | 'FTA': '에프티에이', 166 | 'Que sais-je': '', 167 | 'UFC': '유에프씨', 168 | 'P': '피', 169 | 'p': '피', 170 | 'DJ': '디제이', 171 | 'Chaebol': '채벌', 172 | 'BBC': '비비씨', 173 | 'OECD': '오이씨디', 174 | 'BC': '삐씨', 175 | 'C': '씨', 176 | 'c': '씨', 177 | 'B': '씨', 178 | 'b': '씨', 179 | 'KY': '케이와이', 180 | 'K': '케이', 181 | 'k': '케이', 182 | 'CEO': '씨이오', 183 | 'YH': '와이에치', 184 | 'IS': '아이에스', 185 | 'who are you': '후 얼 유', 186 | 'Y': '와이', 187 | 'y': '와이', 188 | 'The Devils Advocate': '더 데빌즈 어드보카트', 189 | 'YS': '와이에스', 190 | 'so sorry': '쏘 쏘리', 191 | 'Santa': '산타', 192 | 'Big Endian': '빅 엔디안', 193 | 'Small Endian': '스몰 엔디안', 194 | 'Oh Captain My Captain': '오 캡틴 마이 캡틴', 195 | 'AIB': '에이아이비', 196 | 'K': '케이', 197 | 'k': '케이', 198 | 'PBS': '피비에스', 199 | } 200 | -------------------------------------------------------------------------------- /stft.py: -------------------------------------------------------------------------------- 1 | """ 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2017, Prem Seetharaman 5 | All rights reserved. 6 | 7 | * Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, this 14 | list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from this 19 | software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | """ 32 | 33 | import torch 34 | import numpy as np 35 | import torch.nn.functional as F 36 | from torch.autograd import Variable 37 | from scipy.signal import get_window 38 | from librosa.util import pad_center, tiny 39 | from audio_processing import window_sumsquare 40 | 41 | 42 | class STFT(torch.nn.Module): 43 | """adapted from Prem Seetharaman's https://github.com/pseeth/pytorch-stft""" 44 | def __init__(self, filter_length=800, hop_length=200, win_length=800, 45 | window='hann'): 46 | super(STFT, self).__init__() 47 | self.filter_length = filter_length 48 | self.hop_length = hop_length 49 | self.win_length = win_length 50 | self.window = window 51 | self.forward_transform = None 52 | scale = self.filter_length / self.hop_length 53 | fourier_basis = np.fft.fft(np.eye(self.filter_length)) 54 | 55 | cutoff = int((self.filter_length / 2 + 1)) 56 | fourier_basis = np.vstack([np.real(fourier_basis[:cutoff, :]), 57 | np.imag(fourier_basis[:cutoff, :])]) 58 | 59 | forward_basis = torch.FloatTensor(fourier_basis[:, None, :]) 60 | inverse_basis = torch.FloatTensor( 61 | np.linalg.pinv(scale * fourier_basis).T[:, None, :]) 62 | 63 | if window is not None: 64 | assert(filter_length >= win_length) 65 | # get window and zero center pad it to filter_length 66 | fft_window = get_window(window, win_length, fftbins=True) 67 | fft_window = pad_center(fft_window, filter_length) 68 | fft_window = torch.from_numpy(fft_window).float() 69 | 70 | # window the bases 71 | forward_basis *= fft_window 72 | inverse_basis *= fft_window 73 | 74 | self.register_buffer('forward_basis', forward_basis.float()) 75 | self.register_buffer('inverse_basis', inverse_basis.float()) 76 | 77 | def transform(self, input_data): 78 | num_batches = input_data.size(0) 79 | num_samples = input_data.size(1) 80 | 81 | self.num_samples = num_samples 82 | 83 | # similar to librosa, reflect-pad the input 84 | input_data = input_data.view(num_batches, 1, num_samples) 85 | input_data = F.pad( 86 | input_data.unsqueeze(1), 87 | (int(self.filter_length / 2), int(self.filter_length / 2), 0, 0), 88 | mode='reflect') 89 | input_data = input_data.squeeze(1) 90 | 91 | forward_transform = F.conv1d( 92 | input_data, 93 | Variable(self.forward_basis, requires_grad=False), 94 | stride=self.hop_length, 95 | padding=0) 96 | 97 | cutoff = int((self.filter_length / 2) + 1) 98 | real_part = forward_transform[:, :cutoff, :] 99 | imag_part = forward_transform[:, cutoff:, :] 100 | 101 | magnitude = torch.sqrt(real_part**2 + imag_part**2) 102 | phase = torch.autograd.Variable( 103 | torch.atan2(imag_part.data, real_part.data)) 104 | 105 | return magnitude, phase 106 | 107 | def inverse(self, magnitude, phase): 108 | recombine_magnitude_phase = torch.cat( 109 | [magnitude*torch.cos(phase), magnitude*torch.sin(phase)], dim=1) 110 | 111 | inverse_transform = F.conv_transpose1d( 112 | recombine_magnitude_phase, 113 | Variable(self.inverse_basis, requires_grad=False), 114 | stride=self.hop_length, 115 | padding=0) 116 | 117 | if self.window is not None: 118 | window_sum = window_sumsquare( 119 | self.window, magnitude.size(-1), hop_length=self.hop_length, 120 | win_length=self.win_length, n_fft=self.filter_length, 121 | dtype=np.float32) 122 | # remove modulation effects 123 | approx_nonzero_indices = torch.from_numpy( 124 | np.where(window_sum > tiny(window_sum))[0]) 125 | window_sum = torch.autograd.Variable( 126 | torch.from_numpy(window_sum), requires_grad=False) 127 | inverse_transform[:, :, approx_nonzero_indices] /= window_sum[approx_nonzero_indices] 128 | 129 | # scale by hop ratio 130 | inverse_transform *= float(self.filter_length) / self.hop_length 131 | 132 | inverse_transform = inverse_transform[:, :, int(self.filter_length/2):] 133 | inverse_transform = inverse_transform[:, :, :-int(self.filter_length/2):] 134 | 135 | return inverse_transform 136 | 137 | def forward(self, input_data): 138 | self.magnitude, self.phase = self.transform(input_data) 139 | reconstruction = self.inverse(self.magnitude, self.phase) 140 | return reconstruction 141 | -------------------------------------------------------------------------------- /prepare_training_data.py: -------------------------------------------------------------------------------- 1 | from scipy.io.wavfile import write 2 | import librosa 3 | import numpy as np 4 | import argparse 5 | import os 6 | import sys 7 | from hparams import create_hparams 8 | from utils import load_wav_to_torch 9 | from layers import TacotronSTFT 10 | import torch 11 | 12 | sr = 22050 13 | max_wav_value=32768.0 14 | trim_fft_size = 1024 15 | trim_hop_size = 256 16 | trim_top_db = 23 17 | 18 | def get_audio(audio_path): 19 | data, sampling_rate = librosa.core.load(audio_path, sr) 20 | data = data / np.abs(data).max() * 0.999 21 | data_ = librosa.effects.trim(data, top_db=trim_top_db, frame_length=trim_fft_size, hop_length=trim_hop_size)[0] 22 | #print(data_.max(), data_.min()) 23 | return torch.FloatTensor(data_.astype(np.float32)) 24 | 25 | def get_mel(stft, audio): 26 | audio_norm = audio.unsqueeze(0) 27 | audio_norm = torch.autograd.Variable(audio_norm, requires_grad=False) 28 | #print(audio_norm.max(), audio_norm.min()) 29 | melspec = stft.mel_spectrogram(audio_norm) 30 | return melspec 31 | 32 | def _sign(x): 33 | #wrapper to support tensorflow tensors/numpy arrays 34 | isnumpy = isinstance(x, np.ndarray) 35 | isscalar = np.isscalar(x) 36 | return np.sign(x) 37 | 38 | 39 | def _log1p(x): 40 | #wrapper to support tensorflow tensors/numpy arrays 41 | isnumpy = isinstance(x, np.ndarray) 42 | isscalar = np.isscalar(x) 43 | return np.log1p(x) 44 | 45 | 46 | def _abs(x): 47 | #wrapper to support tensorflow tensors/numpy arrays 48 | isnumpy = isinstance(x, np.ndarray) 49 | isscalar = np.isscalar(x) 50 | return np.abs(x) 51 | 52 | 53 | def _asint(x): 54 | #wrapper to support tensorflow tensors/numpy arrays 55 | isnumpy = isinstance(x, np.ndarray) 56 | isscalar = np.isscalar(x) 57 | return x.astype(np.int) 58 | 59 | 60 | def _asfloat(x): 61 | #wrapper to support tensorflow tensors/numpy arrays 62 | isnumpy = isinstance(x, np.ndarray) 63 | isscalar = np.isscalar(x) 64 | return x.astype(np.float32) 65 | 66 | def mulaw(x, mu=256): 67 | mu = 255 68 | return _sign(x) * _log1p(mu * _abs(x)) / _log1p(mu) 69 | 70 | def mulaw_quantize(x, mu=256): 71 | mu = 255 72 | y = mulaw(x, mu) 73 | return _asint((y + 1) / 2 * mu) 74 | 75 | def save_wavenet_map(out_dir, sentences, mels, audios): 76 | """ 77 | training_data/audio/audio-1.npy|training_data/mels/mel-1.npy|||여기에서 가까운 곳에 서점이 있나요? 78 | """ 79 | with open(os.path.join(out_dir, 'map.txt'), 'w', encoding='utf-8') as file: 80 | for i in range(len(sentences)): 81 | audio_path = os.path.join(out_dir,'audio','audio-{}.npy'.format(i)) 82 | audio = audios[i].astype(dtype=np.int16) 83 | mel_path = os.path.join(out_dir, 'mels', 'mel-{}.npy'.format(i)) 84 | mel = mels[i].squeeze(0).transpose(0,1) 85 | sentence = sentences[i] 86 | np.save(audio_path, audio) 87 | np.save(mel_path, mel) 88 | str = "{}|{}|||{}\n".format(audio_path, mel_path, sentence) 89 | file.write(str) 90 | pass 91 | 92 | def save_m2m_metadata(out_dir, sentences, mels): 93 | """ 94 | training_data/audio/audio-1.npy|training_data/mels/mel-1.npy|||여기에서 가까운 곳에 서점이 있나요? 95 | """ 96 | with open(os.path.join(out_dir, 'metadata.csv'), 'w', encoding='utf-8') as file: 97 | for i in range(len(sentences)): 98 | mel_path = os.path.join(out_dir, 'mels', 'mel-{}.npy'.format(i)) 99 | mel = mels[i].squeeze(0) 100 | sentence = sentences[i] 101 | np.save(mel_path, mel) 102 | str = "{}|{}\n".format(mel_path, sentence) 103 | file.write(str) 104 | pass 105 | 106 | def prepare_training_data(hparams, out_dir, for_wavenet, for_m2m, dataset): 107 | mel_dir = os.path.join(out_dir, 'mels') 108 | wav_dir = os.path.join(out_dir, 'audio') 109 | os.makedirs(out_dir, exist_ok=True) 110 | os.makedirs(mel_dir, exist_ok=True) 111 | os.makedirs(wav_dir, exist_ok=True) 112 | 113 | metadatas = open(os.path.join(dataset,'metadata.csv'),'r',encoding='utf-8').readlines() 114 | audio_paths = [] 115 | sentences = [] 116 | mels = [] 117 | mus = [] 118 | 119 | stft = TacotronSTFT( 120 | hparams.filter_length, hparams.hop_length, hparams.win_length, 121 | hparams.n_mel_channels, hparams.sampling_rate, hparams.mel_fmin, 122 | hparams.mel_fmax) 123 | 124 | for i, m in enumerate(metadatas): 125 | audio_path, sentence = m.strip().split('|') 126 | audio_path = os.path.join(dataset, 'wavs', audio_path) 127 | sentences.append(sentence) 128 | audio_paths.append(audio_path) 129 | 130 | audio = get_audio(audio_path) 131 | #print(audio.shape, audio.max(), audio.min()) 132 | mel = get_mel(stft, audio) 133 | mels.append(mel) 134 | #print(mel.shape, mel.max(), mel.min(), mel.size(0)) 135 | 136 | audio = audio.data.cpu().numpy() 137 | #print(len(audio), hparams.hop_length * mel.size(2)) 138 | diff = len(audio) - hparams.hop_length * mel.size(2) 139 | if (diff >= 0): 140 | 141 | audio = audio[:-diff] 142 | else: 143 | audio = np.append(audio, [0.]*-diff) 144 | 145 | #print(len(audio)%hparams.hop_length ==0, len(audio)//mel.size(2) == hparams.hop_length, len(audio), len(audio)//mel.size(2)) 146 | 147 | mu = mulaw_quantize(audio) 148 | mus.append(mu) 149 | # print(mu.shape, mu.max(), mu.min()) 150 | if (i%100 == 0): 151 | print(i) 152 | 153 | if(for_wavenet): 154 | save_wavenet_map(out_dir, sentences, mels, mus) 155 | elif(for_m2m): 156 | save_m2m_metadata(out_dir, sentences, mels) 157 | 158 | pass 159 | 160 | if __name__ == "__main__": 161 | """ 162 | usage 163 | python prepare_training_data.py --dataset=nam-h --out_dir=training_data --for_wavenet 164 | python prepare_training_data.py --dataset=park --out_dir=park_m2m --for_m2m 165 | """ 166 | parser = argparse.ArgumentParser() 167 | parser.add_argument('-d', '--dataset', type=str, 168 | help='file list to preprocess') 169 | parser.add_argument('-o', '--out_dir', type=str, 170 | default='training_data', help='file list to preprocess') 171 | parser.add_argument('--hparams', type=str, 172 | required=False, help='comma separated name=value pairs') 173 | parser.add_argument('--for_wavenet', action="store_true", help='Whether to save training format for wavenet-mamah ') 174 | parser.add_argument('--for_m2m', action="store_true", help='Whether to save training format for mel to mel(voice conversion)') 175 | args = parser.parse_args() 176 | hparams = create_hparams(args.hparams) 177 | prepare_training_data(hparams, args.out_dir, args.for_wavenet, args.for_m2m, args.dataset) 178 | -------------------------------------------------------------------------------- /inference.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | matplotlib.use("Agg") 3 | import matplotlib.pylab as plt 4 | import argparse 5 | import os 6 | 7 | import numpy as np 8 | import time 9 | import torch 10 | 11 | from hparams import create_hparams 12 | from layers import TacotronSTFT 13 | from audio_processing import griffin_lim, mel_denormalize 14 | from train import load_model 15 | from text import text_to_sequence 16 | from scipy.io.wavfile import write 17 | 18 | def plot_data(data, index, output_dir="", figsize=(16, 4)): 19 | fig, axes = plt.subplots(1, len(data), figsize=figsize) 20 | for i in range(len(data)): 21 | axes[i].imshow(data[i], aspect='auto', origin='bottom', 22 | interpolation='none') 23 | plt.savefig(os.path.join(output_dir, 'sentence_{}.png'.format(index))) 24 | 25 | def generate_mels(hparams, checkpoint_path, sentences, cleaner, removing_silence_mel_padding, adding_silence_mel_padding, is_GL, output_dir=""): 26 | model = load_model(hparams) 27 | try: 28 | model = model.module 29 | except: 30 | pass 31 | model.load_state_dict({k.replace('module.', ''): v for k, v in torch.load(checkpoint_path)['state_dict'].items()}) 32 | _ = model.eval() 33 | 34 | output_mels = [] 35 | for i, s in enumerate(sentences): 36 | sequence = np.array(text_to_sequence(s, cleaner))[None, :] 37 | sequence = torch.autograd.Variable(torch.from_numpy(sequence)).cuda().long() 38 | 39 | stime = time.time() 40 | _, mel_outputs_postnet, _, alignments = model.inference(sequence) 41 | mel = mel_outputs_postnet.data.cpu().numpy()[0][:,:-removing_silence_mel_padding] 42 | mel = np.append(mel, np.ones((80,adding_silence_mel_padding),dtype=np.float32)*-4.0, axis=1) 43 | if(is_GL): 44 | plot_data((mel, 45 | alignments.data.cpu().numpy()[0].T), i, output_dir) 46 | inf_time = time.time() - stime 47 | print("{}th sentence, Infenrece time: {:.2f}s, len_mel: {}".format(i, inf_time, mel_outputs_postnet.size(2))) 48 | output_mels.append(mel) 49 | return output_mels 50 | 51 | def mels_to_wavs_GL(hparams, mels, taco_stft, output_dir="", ref_level_db = 0, magnitude_power=1.5): 52 | for i, mel in enumerate(mels): 53 | stime = time.time() 54 | mel_decompress = mel_denormalize(torch.from_numpy(mel).cuda().unsqueeze(0)) 55 | mel_decompress = taco_stft.spectral_de_normalize(mel_decompress + ref_level_db) ** (1/magnitude_power) 56 | mel_decompress_ = mel_decompress.transpose(1, 2).data.cpu() 57 | spec_from_mel_scaling = 1000 58 | spec_from_mel = torch.mm(mel_decompress_[0], taco_stft.mel_basis) 59 | spec_from_mel = spec_from_mel.transpose(0, 1).unsqueeze(0) 60 | spec_from_mel = spec_from_mel * spec_from_mel_scaling 61 | waveform = griffin_lim(torch.autograd.Variable(spec_from_mel[:, :, :]), 62 | taco_stft.stft_fn, 60) 63 | waveform = waveform[0].data.cpu().numpy() 64 | dec_time = time.time() - stime 65 | len_audio = float(len(waveform)) / float(hparams.sampling_rate) 66 | str = "{}th sentence, audio length: {:.2f} sec, mel_to_wave time: {:.2f}".format(i, len_audio, dec_time) 67 | print(str) 68 | write(os.path.join(output_dir,"sentence_{}.wav".format(i)), hparams.sampling_rate, waveform) 69 | 70 | def run(hparams, checkpoint_path, sentence_path, clenaer, removing_silence_mel_padding, adding_silence_mel_padding, is_GL, is_melout, is_metaout, output_dir): 71 | f = open(sentence_path, 'r', encoding='utf-8') 72 | sentences = [x.strip() for x in f.readlines()] 73 | print('All sentences to infer:',sentences) 74 | f.close() 75 | os.makedirs(output_dir, exist_ok=True) 76 | 77 | stft = TacotronSTFT( 78 | hparams.filter_length, hparams.hop_length, hparams.win_length, 79 | hparams.n_mel_channels, hparams.sampling_rate, hparams.mel_fmin, 80 | hparams.mel_fmax) 81 | 82 | mels = generate_mels(hparams, checkpoint_path, sentences, clenaer, removing_silence_mel_padding, adding_silence_mel_padding, is_GL, output_dir) 83 | if(is_GL): mels_to_wavs_GL(hparams, mels, stft, output_dir) 84 | 85 | mel_paths = [] 86 | if is_melout: 87 | mel_dir = os.path.join(output_dir, 'mels') 88 | os.makedirs(mel_dir, exist_ok=True) 89 | 90 | for i, mel in enumerate(mels): 91 | mel_path = os.path.join(output_dir, 'mels/', "mel-{}.npy".format(i)) 92 | mel_paths.append(mel_path) 93 | if(list(mel.shape)[1] >= hparams.max_decoder_steps - removing_silence_mel_padding): 94 | continue 95 | np.save(mel_path, mel) 96 | 97 | 98 | if is_metaout: 99 | with open(os.path.join(output_dir, 'metadata.csv'), 'w', encoding='utf-8') as file: 100 | lines = [] 101 | for i, s in enumerate(sentences): 102 | mel_path = mel_paths[i] 103 | if (list(mels[i].shape)[1] >= hparams.max_decoder_steps - removing_silence_mel_padding): 104 | continue 105 | lines.append('{}|{}\n'.format(mel_path,s)) 106 | file.writelines(lines) 107 | 108 | if __name__ == '__main__': 109 | """ 110 | usage 111 | python inference.py -o=synthesis/80000 -c=nam_h_ep8/checkpoint_80000 -s=test.txt --silence_mel_padding=3 --is_GL 112 | -> wave, figure 113 | python inference.py -o=kss_mels_given_park_text -c=kakao_kss_model_checkpoint_23500 -s=skip_review_percentile_metadata_n.csv --silence_mel_padding=3 --is_melout --is_metaout 114 | -> mels, metadata.csv 115 | """ 116 | parser = argparse.ArgumentParser() 117 | parser.add_argument('-o', '--output_directory', type=str, 118 | help='directory to save wave and fig') 119 | parser.add_argument('-c', '--checkpoint_path', type=str, default=None, 120 | required=True, help='checkpoint path') 121 | parser.add_argument('-s', '--sentence_path', type=str, default=None, 122 | required=True, help='sentence path') 123 | parser.add_argument('--removing_silence_mel_padding', type=int, default=1, 124 | help='removing existing silence_mel_padding, silence audio size is hop_length * silence mel padding') 125 | parser.add_argument('--adding_silence_mel_padding', type=int, default=0, 126 | help='adding silence_mel_padding, silence audio size is hop_length * silence mel padding') 127 | parser.add_argument('--hparams', type=str, 128 | required=False, help='comma separated name=value pairs') 129 | parser.add_argument('--is_GL', action="store_true", help='Whether to do Giffin & Lim inference or not ') 130 | parser.add_argument('--is_melout', action="store_true", help='Whether to save melspectrogram file or not ') 131 | parser.add_argument('--is_metaout', action="store_true", help='Whether to save metadata.csv file for (mel, text) tuple or not ') 132 | 133 | args = parser.parse_args() 134 | hparams = create_hparams(args.hparams) 135 | hparams.sampling_rate = 22050 136 | hparams.filter_length = 1024 137 | hparams.hop_length = 256 138 | hparams.win_length = 1024 139 | 140 | torch.backends.cudnn.enabled = hparams.cudnn_enabled 141 | torch.backends.cudnn.benchmark = hparams.cudnn_benchmark 142 | 143 | run(hparams, args.checkpoint_path, args.sentence_path, hparams.text_cleaners, args.removing_silence_mel_padding, args.adding_silence_mel_padding, args.is_GL, args.is_melout, args.is_metaout, args.output_directory) 144 | 145 | 146 | -------------------------------------------------------------------------------- /distributed.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.distributed as dist 3 | from torch.nn.modules import Module 4 | from torch.autograd import Variable 5 | 6 | def _flatten_dense_tensors(tensors): 7 | """Flatten dense tensors into a contiguous 1D buffer. Assume tensors are of 8 | same dense type. 9 | Since inputs are dense, the resulting tensor will be a concatenated 1D 10 | buffer. Element-wise operation on this buffer will be equivalent to 11 | operating individually. 12 | Arguments: 13 | tensors (Iterable[Tensor]): dense tensors to flatten. 14 | Returns: 15 | A contiguous 1D buffer containing input tensors. 16 | """ 17 | if len(tensors) == 1: 18 | return tensors[0].contiguous().view(-1) 19 | flat = torch.cat([t.contiguous().view(-1) for t in tensors], dim=0) 20 | return flat 21 | 22 | def _unflatten_dense_tensors(flat, tensors): 23 | """View a flat buffer using the sizes of tensors. Assume that tensors are of 24 | same dense type, and that flat is given by _flatten_dense_tensors. 25 | Arguments: 26 | flat (Tensor): flattened dense tensors to unflatten. 27 | tensors (Iterable[Tensor]): dense tensors whose sizes will be used to 28 | unflatten flat. 29 | Returns: 30 | Unflattened dense tensors with sizes same as tensors and values from 31 | flat. 32 | """ 33 | outputs = [] 34 | offset = 0 35 | for tensor in tensors: 36 | numel = tensor.numel() 37 | outputs.append(flat.narrow(0, offset, numel).view_as(tensor)) 38 | offset += numel 39 | return tuple(outputs) 40 | 41 | 42 | ''' 43 | This version of DistributedDataParallel is designed to be used in conjunction with the multiproc.py 44 | launcher included with this example. It assumes that your run is using multiprocess with 1 45 | GPU/process, that the model is on the correct device, and that torch.set_device has been 46 | used to set the device. 47 | 48 | Parameters are broadcasted to the other processes on initialization of DistributedDataParallel, 49 | and will be allreduced at the finish of the backward pass. 50 | ''' 51 | class DistributedDataParallel(Module): 52 | 53 | def __init__(self, module): 54 | super(DistributedDataParallel, self).__init__() 55 | #fallback for PyTorch 0.3 56 | if not hasattr(dist, '_backend'): 57 | self.warn_on_half = True 58 | else: 59 | self.warn_on_half = True if dist._backend == dist.dist_backend.GLOO else False 60 | 61 | self.module = module 62 | 63 | for p in self.module.state_dict().values(): 64 | if not torch.is_tensor(p): 65 | continue 66 | dist.broadcast(p, 0) 67 | 68 | def allreduce_params(): 69 | if(self.needs_reduction): 70 | self.needs_reduction = False 71 | buckets = {} 72 | for param in self.module.parameters(): 73 | if param.requires_grad and param.grad is not None: 74 | tp = type(param.data) 75 | if tp not in buckets: 76 | buckets[tp] = [] 77 | buckets[tp].append(param) 78 | if self.warn_on_half: 79 | if torch.cuda.HalfTensor in buckets: 80 | print("WARNING: gloo dist backend for half parameters may be extremely slow." + 81 | " It is recommended to use the NCCL backend in this case. This currently requires" + 82 | "PyTorch built from top of tree master.") 83 | self.warn_on_half = False 84 | 85 | for tp in buckets: 86 | bucket = buckets[tp] 87 | grads = [param.grad.data for param in bucket] 88 | coalesced = _flatten_dense_tensors(grads) 89 | dist.all_reduce(coalesced) 90 | coalesced /= dist.get_world_size() 91 | for buf, synced in zip(grads, _unflatten_dense_tensors(coalesced, grads)): 92 | buf.copy_(synced) 93 | 94 | for param in list(self.module.parameters()): 95 | def allreduce_hook(*unused): 96 | param._execution_engine.queue_callback(allreduce_params) 97 | if param.requires_grad: 98 | param.register_hook(allreduce_hook) 99 | 100 | def forward(self, *inputs, **kwargs): 101 | self.needs_reduction = True 102 | return self.module(*inputs, **kwargs) 103 | 104 | ''' 105 | def _sync_buffers(self): 106 | buffers = list(self.module._all_buffers()) 107 | if len(buffers) > 0: 108 | # cross-node buffer sync 109 | flat_buffers = _flatten_dense_tensors(buffers) 110 | dist.broadcast(flat_buffers, 0) 111 | for buf, synced in zip(buffers, _unflatten_dense_tensors(flat_buffers, buffers)): 112 | buf.copy_(synced) 113 | def train(self, mode=True): 114 | # Clear NCCL communicator and CUDA event cache of the default group ID, 115 | # These cache will be recreated at the later call. This is currently a 116 | # work-around for a potential NCCL deadlock. 117 | if dist._backend == dist.dist_backend.NCCL: 118 | dist._clear_group_cache() 119 | super(DistributedDataParallel, self).train(mode) 120 | self.module.train(mode) 121 | ''' 122 | ''' 123 | Modifies existing model to do gradient allreduce, but doesn't change class 124 | so you don't need "module" 125 | ''' 126 | def apply_gradient_allreduce(module): 127 | if not hasattr(dist, '_backend'): 128 | module.warn_on_half = True 129 | else: 130 | module.warn_on_half = True if dist._backend == dist.dist_backend.GLOO else False 131 | 132 | for p in module.state_dict().values(): 133 | if not torch.is_tensor(p): 134 | continue 135 | dist.broadcast(p, 0) 136 | 137 | def allreduce_params(): 138 | if(module.needs_reduction): 139 | module.needs_reduction = False 140 | buckets = {} 141 | for param in module.parameters(): 142 | if param.requires_grad and param.grad is not None: 143 | tp = type(param.data) 144 | if tp not in buckets: 145 | buckets[tp] = [] 146 | buckets[tp].append(param) 147 | if module.warn_on_half: 148 | if torch.cuda.HalfTensor in buckets: 149 | print("WARNING: gloo dist backend for half parameters may be extremely slow." + 150 | " It is recommended to use the NCCL backend in this case. This currently requires" + 151 | "PyTorch built from top of tree master.") 152 | module.warn_on_half = False 153 | 154 | for tp in buckets: 155 | bucket = buckets[tp] 156 | grads = [param.grad.data for param in bucket] 157 | coalesced = _flatten_dense_tensors(grads) 158 | dist.all_reduce(coalesced) 159 | coalesced /= dist.get_world_size() 160 | for buf, synced in zip(grads, _unflatten_dense_tensors(coalesced, grads)): 161 | buf.copy_(synced) 162 | 163 | for param in list(module.parameters()): 164 | def allreduce_hook(*unused): 165 | Variable._execution_engine.queue_callback(allreduce_params) 166 | if param.requires_grad: 167 | param.register_hook(allreduce_hook) 168 | 169 | def set_needs_reduction(self, input, output): 170 | self.needs_reduction = True 171 | 172 | module.register_forward_hook(set_needs_reduction) 173 | return module 174 | -------------------------------------------------------------------------------- /GTA.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import argparse 4 | import math 5 | from numpy import finfo 6 | import numpy as np 7 | 8 | import torch 9 | from distributed import DistributedDataParallel 10 | from torch.utils.data.distributed import DistributedSampler 11 | from torch.nn import DataParallel 12 | from torch.utils.data import DataLoader 13 | 14 | from fp16_optimizer import FP16_Optimizer 15 | 16 | from model import Tacotron2 17 | from data_utils import TextMelLoader, TextMelCollate 18 | from hparams import create_hparams 19 | 20 | def batchnorm_to_float(module): 21 | """Converts batch norm modules to FP32""" 22 | if isinstance(module, torch.nn.modules.batchnorm._BatchNorm): 23 | module.float() 24 | for child in module.children(): 25 | batchnorm_to_float(child) 26 | return module 27 | 28 | 29 | def reduce_tensor(tensor, num_gpus): 30 | rt = tensor.clone() 31 | torch.distributed.all_reduce(rt, op=torch.distributed.reduce_op.SUM) 32 | rt /= num_gpus 33 | return rt 34 | 35 | 36 | def init_distributed(hparams, n_gpus, rank, group_name): 37 | assert torch.cuda.is_available(), "Distributed mode requires CUDA." 38 | print("Initializing distributed") 39 | # Set cuda device so everything is done on the right GPU. 40 | torch.cuda.set_device(rank % torch.cuda.device_count()) 41 | # Initialize distributed communication 42 | torch.distributed.init_process_group( 43 | backend=hparams.dist_backend, init_method=hparams.dist_url, 44 | world_size=n_gpus, rank=rank, group_name=group_name) 45 | print("Done initializing distributed") 46 | 47 | 48 | def prepare_dataloaders(hparams): 49 | # Get data, data loaders and collate function ready 50 | trainset = TextMelLoader(hparams.training_files, hparams) # trainset.__getitem__(index) = (text, mel), text in [num_char], mel in [num_mel, ceil((len(audio)+1)/hop_length)] 51 | valset = TextMelLoader(hparams.validation_files, hparams) 52 | collate_fn = TextMelCollate(hparams.n_frames_per_step) # 53 | train_sampler = DistributedSampler(trainset) \ 54 | if hparams.distributed_run else None 55 | train_loader = DataLoader(trainset, num_workers=1, shuffle=False, 56 | sampler=train_sampler, 57 | batch_size=hparams.batch_size, pin_memory=False, 58 | drop_last=True, collate_fn=collate_fn) 59 | return train_loader, valset, collate_fn, trainset 60 | 61 | 62 | def load_model(hparams): 63 | model = Tacotron2(hparams).cuda() 64 | if hparams.fp16_run: 65 | model = batchnorm_to_float(model.half()) 66 | model.decoder.attention_layer.score_mask_value = float(finfo('float16').min) 67 | if hparams.distributed_run: 68 | model = DistributedDataParallel(model) 69 | elif torch.cuda.device_count() > 1: 70 | model = DataParallel(model) 71 | return model 72 | 73 | 74 | def warm_start_model(checkpoint_path, model): 75 | assert os.path.isfile(checkpoint_path) 76 | print("Warm starting model from checkpoint '{}'".format(checkpoint_path)) 77 | checkpoint_dict = torch.load(checkpoint_path, map_location='cpu') 78 | model.load_state_dict(checkpoint_dict['state_dict']) 79 | return model 80 | 81 | 82 | def GTA_Synthesis(output_directory, checkpoint_path, n_gpus, 83 | rank, group_name, hparams): 84 | 85 | if hparams.distributed_run: 86 | init_distributed(hparams, n_gpus, rank, group_name) 87 | torch.manual_seed(hparams.seed) 88 | torch.cuda.manual_seed(hparams.seed) 89 | model = load_model(hparams) 90 | train_loader, valset, collate_fn, train_set = prepare_dataloaders(hparams) 91 | # Load checkpoint if one exists 92 | assert checkpoint_path is not None 93 | if checkpoint_path is not None: 94 | model = warm_start_model(checkpoint_path, model) 95 | model.eval() 96 | if hparams.distributed_run or torch.cuda.device_count() > 1: 97 | batch_parser = model.module.parse_batch 98 | else: 99 | batch_parser = model.parse_batch 100 | # ================ MAIN TRAINNIG LOOP! =================== 101 | f = open(os.path.join(output_directory, 'map.txt'),'w', encoding='utf-8') 102 | os.makedirs(os.path.join(output_directory,'mels'), exist_ok=True) 103 | 104 | total_number_of_data = len(train_set.audiopaths_and_text) 105 | max_itter = int(total_number_of_data/hparams.batch_size) 106 | remainder_size = total_number_of_data % hparams.batch_size 107 | 108 | for i, batch in enumerate(train_loader): 109 | batch_size = hparams.batch_size if i is not max_itter else remainder_size 110 | 111 | # get wavefile path 112 | audiopaths_and_text = train_set.audiopaths_and_text[i*hparams.batch_size:i*hparams.batch_size + batch_size] 113 | audiopaths = [ x[0] for x in audiopaths_and_text] # file name list 114 | 115 | # get len texts 116 | indx_list = np.arange(i*hparams.batch_size, i*hparams.batch_size + batch_size).tolist() 117 | len_text_list = [] 118 | for batch_index in indx_list: 119 | text, _ = train_set.__getitem__(batch_index) 120 | len_text_list.append(text.size(0)) 121 | _, input_lengths, _, _, output_lengths = batch # output_lengths: orgnal mel length 122 | input_lengths_, ids_sorted_decreasing = torch.sort(torch.LongTensor(len_text_list), dim=0, descending=True) 123 | ids_sorted_decreasing = ids_sorted_decreasing.numpy() # ids_sorted_decreasing, original index 124 | 125 | org_audiopaths = [] # orgnal_file_name 126 | mel_paths = [] 127 | for k in range(batch_size): 128 | d = audiopaths[ids_sorted_decreasing[k]] 129 | org_audiopaths.append(d) 130 | mel_paths.append(d.replace('wav','mel')) 131 | 132 | x, _ = batch_parser(batch) 133 | _, mel_outputs_postnet, _, _ = model(x) 134 | mel_outputs_postnet = mel_outputs_postnet.data.cpu().numpy() 135 | 136 | for k in range(batch_size): 137 | wav_path = org_audiopaths[k] 138 | mel_path = mel_paths[k]+'.npy' 139 | map = "{}|{}\n".format(wav_path,mel_path) 140 | f.write(map) 141 | # To do: size mismatch 142 | diff = output_lengths[k] - (input_lengths[k] / hparams.hop_length) 143 | diff = diff.data.data.cpu().numpy() 144 | mel = mel_outputs_postnet[k,:,:output_lengths[k]-diff] 145 | if diff != 0: print(wav_path, input_lengths[k], output_lengths[k], mel.shape) 146 | np.save(mel_path, mel) 147 | print('compute and save GTA melspectrograms in {}th batch'.format(i)) 148 | f.close() 149 | 150 | if __name__ == '__main__': 151 | # run example 152 | # python GTA.py -o=nam-h -c=nam_h_ep8/checkpoint_50000 153 | parser = argparse.ArgumentParser() 154 | parser.add_argument('-o', '--output_directory', type=str, 155 | help='directory to save checkpoints') 156 | parser.add_argument('-c', '--checkpoint_path', type=str, default=None, 157 | required=False, help='checkpoint path') 158 | parser.add_argument('--n_gpus', type=int, default=1, 159 | required=False, help='number of gpus') 160 | parser.add_argument('--rank', type=int, default=0, 161 | required=False, help='rank of current gpu') 162 | parser.add_argument('--group_name', type=str, default='group_name', 163 | required=False, help='Distributed group name') 164 | parser.add_argument('--hparams', type=str, required=False, help='comma separated name=value pairs') 165 | 166 | args = parser.parse_args() 167 | hparams = create_hparams(args.hparams) 168 | 169 | torch.backends.cudnn.enabled = hparams.cudnn_enabled 170 | torch.backends.cudnn.benchmark = hparams.cudnn_benchmark 171 | 172 | print("FP16 Run:", hparams.fp16_run) 173 | print("Dynamic Loss Scaling:", hparams.dynamic_loss_scaling) 174 | print("Distributed Run:", hparams.distributed_run) 175 | print("cuDNN Enabled:", hparams.cudnn_enabled) 176 | print("cuDNN Benchmark:", hparams.cudnn_benchmark) 177 | 178 | GTA_Synthesis(args.output_directory, args.checkpoint_path, args.n_gpus, args.rank, args.group_name, hparams) 179 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import argparse 4 | import math 5 | from numpy import finfo 6 | 7 | import torch 8 | from distributed import apply_gradient_allreduce 9 | import torch.distributed as dist 10 | from torch.utils.data.distributed import DistributedSampler 11 | from torch.utils.data import DataLoader 12 | 13 | from fp16_optimizer import FP16_Optimizer 14 | 15 | from model import Tacotron2 16 | from data_utils import TextMelLoader, TextMelCollate 17 | from loss_function import Tacotron2Loss 18 | from logger import Tacotron2Logger 19 | from hparams import create_hparams 20 | 21 | 22 | def batchnorm_to_float(module): 23 | """Converts batch norm modules to FP32""" 24 | if isinstance(module, torch.nn.modules.batchnorm._BatchNorm): 25 | module.float() 26 | for child in module.children(): 27 | batchnorm_to_float(child) 28 | return module 29 | 30 | 31 | def reduce_tensor(tensor, n_gpus): 32 | rt = tensor.clone() 33 | dist.all_reduce(rt, op=dist.reduce_op.SUM) 34 | rt /= n_gpus 35 | return rt 36 | 37 | 38 | def init_distributed(hparams, n_gpus, rank, group_name): 39 | assert torch.cuda.is_available(), "Distributed mode requires CUDA." 40 | print("Initializing Distributed") 41 | 42 | # Set cuda device so everything is done on the right GPU. 43 | torch.cuda.set_device(rank % torch.cuda.device_count()) 44 | 45 | # Initialize distributed communication 46 | dist.init_process_group( 47 | backend=hparams.dist_backend, init_method=hparams.dist_url, 48 | world_size=n_gpus, rank=rank, group_name=group_name) 49 | 50 | print("Done initializing distributed") 51 | 52 | 53 | def prepare_dataloaders(hparams): 54 | # Get data, data loaders and collate function ready 55 | trainset = TextMelLoader(hparams.training_files, hparams) 56 | valset = TextMelLoader(hparams.validation_files, hparams) 57 | collate_fn = TextMelCollate(hparams.n_frames_per_step) 58 | 59 | train_sampler = DistributedSampler(trainset) \ 60 | if hparams.distributed_run else None 61 | 62 | train_loader = DataLoader(trainset, num_workers=1, shuffle=False, 63 | sampler=train_sampler, 64 | batch_size=hparams.batch_size, pin_memory=False, 65 | drop_last=True, collate_fn=collate_fn) 66 | return train_loader, valset, collate_fn 67 | 68 | 69 | def prepare_directories_and_logger(output_directory, log_directory, rank): 70 | if rank == 0: 71 | if not os.path.isdir(output_directory): 72 | os.makedirs(output_directory) 73 | os.chmod(output_directory, 0o775) 74 | logger = Tacotron2Logger(os.path.join(output_directory, log_directory)) 75 | else: 76 | logger = None 77 | return logger 78 | 79 | 80 | def load_model(hparams): 81 | model = Tacotron2(hparams).cuda() 82 | if hparams.fp16_run: 83 | model = batchnorm_to_float(model.half()) 84 | model.decoder.attention_layer.score_mask_value = float(finfo('float16').min) 85 | 86 | if hparams.distributed_run: 87 | model = apply_gradient_allreduce(model) 88 | 89 | return model 90 | 91 | 92 | def warm_start_model(checkpoint_path, model): 93 | assert os.path.isfile(checkpoint_path) 94 | print("Warm starting model from checkpoint '{}'".format(checkpoint_path)) 95 | checkpoint_dict = torch.load(checkpoint_path, map_location='cpu') 96 | model.load_state_dict(checkpoint_dict['state_dict']) 97 | return model 98 | 99 | 100 | def load_checkpoint(checkpoint_path, model, optimizer): 101 | assert os.path.isfile(checkpoint_path) 102 | print("Loading checkpoint '{}'".format(checkpoint_path)) 103 | checkpoint_dict = torch.load(checkpoint_path, map_location='cpu') 104 | model.load_state_dict(checkpoint_dict['state_dict']) 105 | optimizer.load_state_dict(checkpoint_dict['optimizer']) 106 | learning_rate = checkpoint_dict['learning_rate'] 107 | iteration = checkpoint_dict['iteration'] 108 | print("Loaded checkpoint '{}' from iteration {}" .format( 109 | checkpoint_path, iteration)) 110 | return model, optimizer, learning_rate, iteration 111 | 112 | 113 | def save_checkpoint(model, optimizer, learning_rate, iteration, filepath): 114 | print("Saving model and optimizer state at iteration {} to {}".format( 115 | iteration, filepath)) 116 | torch.save({'iteration': iteration, 117 | 'state_dict': model.state_dict(), 118 | 'optimizer': optimizer.state_dict(), 119 | 'learning_rate': learning_rate}, filepath) 120 | 121 | 122 | def validate(model, criterion, valset, iteration, batch_size, n_gpus, 123 | collate_fn, logger, distributed_run, rank): 124 | """Handles all the validation scoring and printing""" 125 | model.eval() 126 | with torch.no_grad(): 127 | val_sampler = DistributedSampler(valset) if distributed_run else None 128 | val_loader = DataLoader(valset, sampler=val_sampler, num_workers=1, 129 | shuffle=False, batch_size=batch_size, 130 | pin_memory=False, collate_fn=collate_fn) 131 | 132 | val_loss = 0.0 133 | for i, batch in enumerate(val_loader): 134 | x, y = model.parse_batch(batch) 135 | y_pred = model(x) 136 | loss = criterion(y_pred, y) 137 | if distributed_run: 138 | reduced_val_loss = reduce_tensor(loss.data, n_gpus).item() 139 | else: 140 | reduced_val_loss = loss.item() 141 | val_loss += reduced_val_loss 142 | val_loss = val_loss / (i + 1) 143 | 144 | model.train() 145 | if rank == 0: 146 | print("Validation loss {}: {:9f} ".format(iteration, reduced_val_loss)) 147 | logger.log_validation(reduced_val_loss, model, y, y_pred, iteration) 148 | 149 | 150 | def train(output_directory, log_directory, checkpoint_path, warm_start, n_gpus, 151 | rank, group_name, hparams): 152 | """Training and validation logging results to tensorboard and stdout 153 | 154 | Params 155 | ------ 156 | output_directory (string): directory to save checkpoints 157 | log_directory (string) directory to save tensorboard logs 158 | checkpoint_path(string): checkpoint path 159 | n_gpus (int): number of gpus 160 | rank (int): rank of current gpu 161 | hparams (object): comma separated list of "name=value" pairs. 162 | """ 163 | if hparams.distributed_run: 164 | init_distributed(hparams, n_gpus, rank, group_name) 165 | 166 | torch.manual_seed(hparams.seed) 167 | torch.cuda.manual_seed(hparams.seed) 168 | 169 | model = load_model(hparams) 170 | learning_rate = hparams.learning_rate 171 | optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, 172 | weight_decay=hparams.weight_decay) 173 | if hparams.fp16_run: 174 | optimizer = FP16_Optimizer( 175 | optimizer, dynamic_loss_scale=hparams.dynamic_loss_scaling) 176 | 177 | if hparams.distributed_run: 178 | model = apply_gradient_allreduce(model) 179 | 180 | criterion = Tacotron2Loss() 181 | 182 | logger = prepare_directories_and_logger( 183 | output_directory, log_directory, rank) 184 | 185 | train_loader, valset, collate_fn = prepare_dataloaders(hparams) 186 | 187 | # Load checkpoint if one exists 188 | iteration = 0 189 | epoch_offset = 0 190 | if checkpoint_path is not None: 191 | if warm_start: 192 | model = warm_start_model(checkpoint_path, model) 193 | else: 194 | model, optimizer, _learning_rate, iteration = load_checkpoint( 195 | checkpoint_path, model, optimizer) 196 | if hparams.use_saved_learning_rate: 197 | learning_rate = _learning_rate 198 | iteration += 1 # next iteration is iteration + 1 199 | epoch_offset = max(0, int(iteration / len(train_loader))) 200 | 201 | model.train() 202 | # ================ MAIN TRAINNIG LOOP! =================== 203 | for epoch in range(epoch_offset, hparams.epochs): 204 | print("Epoch: {}".format(epoch)) 205 | for i, batch in enumerate(train_loader): 206 | start = time.perf_counter() 207 | for param_group in optimizer.param_groups: 208 | param_group['lr'] = learning_rate 209 | 210 | model.zero_grad() 211 | x, y = model.parse_batch(batch) 212 | y_pred = model(x) 213 | 214 | loss = criterion(y_pred, y) 215 | if hparams.distributed_run: 216 | reduced_loss = reduce_tensor(loss.data, n_gpus).item() 217 | else: 218 | reduced_loss = loss.item() 219 | 220 | if hparams.fp16_run: 221 | optimizer.backward(loss) 222 | grad_norm = optimizer.clip_fp32_grads(hparams.grad_clip_thresh) 223 | else: 224 | loss.backward() 225 | grad_norm = torch.nn.utils.clip_grad_norm_( 226 | model.parameters(), hparams.grad_clip_thresh) 227 | 228 | optimizer.step() 229 | 230 | overflow = optimizer.overflow if hparams.fp16_run else False 231 | 232 | if not overflow and not math.isnan(reduced_loss) and rank == 0: 233 | duration = time.perf_counter() - start 234 | print("Train loss {} {:.6f} Grad Norm {:.6f} {:.2f}s/it".format( 235 | iteration, reduced_loss, grad_norm, duration)) 236 | logger.log_training( 237 | reduced_loss, grad_norm, learning_rate, duration, iteration) 238 | 239 | if not overflow and (iteration % hparams.iters_per_checkpoint == 0): 240 | validate(model, criterion, valset, iteration, 241 | hparams.batch_size, n_gpus, collate_fn, logger, 242 | hparams.distributed_run, rank) 243 | if rank == 0: 244 | checkpoint_path = os.path.join( 245 | output_directory, "checkpoint_{}".format(iteration)) 246 | save_checkpoint(model, optimizer, learning_rate, iteration, 247 | checkpoint_path) 248 | 249 | iteration += 1 250 | 251 | 252 | if __name__ == '__main__': 253 | parser = argparse.ArgumentParser() 254 | parser.add_argument('-o', '--output_directory', type=str, 255 | help='directory to save checkpoints') 256 | parser.add_argument('-l', '--log_directory', type=str, 257 | help='directory to save tensorboard logs') 258 | parser.add_argument('-c', '--checkpoint_path', type=str, default=None, 259 | required=False, help='checkpoint path') 260 | parser.add_argument('--warm_start', action='store_true', 261 | help='load the model only (warm start)') 262 | parser.add_argument('--n_gpus', type=int, default=1, 263 | required=False, help='number of gpus') 264 | parser.add_argument('--rank', type=int, default=0, 265 | required=False, help='rank of current gpu') 266 | parser.add_argument('--group_name', type=str, default='group_name', 267 | required=False, help='Distributed group name') 268 | parser.add_argument('--hparams', type=str, 269 | required=False, help='comma separated name=value pairs') 270 | 271 | args = parser.parse_args() 272 | hparams = create_hparams(args.hparams) 273 | 274 | torch.backends.cudnn.enabled = hparams.cudnn_enabled 275 | torch.backends.cudnn.benchmark = hparams.cudnn_benchmark 276 | 277 | print("FP16 Run:", hparams.fp16_run) 278 | print("Dynamic Loss Scaling:", hparams.dynamic_loss_scaling) 279 | print("Distributed Run:", hparams.distributed_run) 280 | print("cuDNN Enabled:", hparams.cudnn_enabled) 281 | print("cuDNN Benchmark:", hparams.cudnn_benchmark) 282 | 283 | train(args.output_directory, args.log_directory, args.checkpoint_path, 284 | args.warm_start, args.n_gpus, args.rank, args.group_name, hparams) 285 | -------------------------------------------------------------------------------- /filelists/ljs_audio_text_val_filelist.txt: -------------------------------------------------------------------------------- 1 | LJSpeech-1.1/wavs/LJ022-0023.wav|The overwhelming majority of people in this country know how to sift the wheat from the chaff in what they hear and what they read. 2 | LJSpeech-1.1/wavs/LJ043-0030.wav|If somebody did that to me, a lousy trick like that, to take my wife away, and all the furniture, I would be mad as hell, too. 3 | LJSpeech-1.1/wavs/LJ005-0201.wav|as is shown by the report of the Commissioners to inquire into the state of the municipal corporations in eighteen thirty-five. 4 | LJSpeech-1.1/wavs/LJ001-0110.wav|Even the Caslon type when enlarged shows great shortcomings in this respect: 5 | LJSpeech-1.1/wavs/LJ003-0345.wav|All the committee could do in this respect was to throw the responsibility on others. 6 | LJSpeech-1.1/wavs/LJ007-0154.wav|These pungent and well-grounded strictures applied with still greater force to the unconvicted prisoner, the man who came to the prison innocent, and still uncontaminated, 7 | LJSpeech-1.1/wavs/LJ018-0098.wav|and recognized as one of the frequenters of the bogus law-stationers. His arrest led to that of others. 8 | LJSpeech-1.1/wavs/LJ047-0044.wav|Oswald was, however, willing to discuss his contacts with Soviet authorities. He denied having any involvement with Soviet intelligence agencies 9 | LJSpeech-1.1/wavs/LJ031-0038.wav|The first physician to see the President at Parkland Hospital was Dr. Charles J. Carrico, a resident in general surgery. 10 | LJSpeech-1.1/wavs/LJ048-0194.wav|during the morning of November twenty-two prior to the motorcade. 11 | LJSpeech-1.1/wavs/LJ049-0026.wav|On occasion the Secret Service has been permitted to have an agent riding in the passenger compartment with the President. 12 | LJSpeech-1.1/wavs/LJ004-0152.wav|although at Mr. Buxton's visit a new jail was in process of erection, the first step towards reform since Howard's visitation in seventeen seventy-four. 13 | LJSpeech-1.1/wavs/LJ008-0278.wav|or theirs might be one of many, and it might be considered necessary to "make an example." 14 | LJSpeech-1.1/wavs/LJ043-0002.wav|The Warren Commission Report. By The President's Commission on the Assassination of President Kennedy. Chapter seven. Lee Harvey Oswald: 15 | LJSpeech-1.1/wavs/LJ009-0114.wav|Mr. Wakefield winds up his graphic but somewhat sensational account by describing another religious service, which may appropriately be inserted here. 16 | LJSpeech-1.1/wavs/LJ028-0506.wav|A modern artist would have difficulty in doing such accurate work. 17 | LJSpeech-1.1/wavs/LJ050-0168.wav|with the particular purposes of the agency involved. The Commission recognizes that this is a controversial area 18 | LJSpeech-1.1/wavs/LJ039-0223.wav|Oswald's Marine training in marksmanship, his other rifle experience and his established familiarity with this particular weapon 19 | LJSpeech-1.1/wavs/LJ029-0032.wav|According to O'Donnell, quote, we had a motorcade wherever we went, end quote. 20 | LJSpeech-1.1/wavs/LJ031-0070.wav|Dr. Clark, who most closely observed the head wound, 21 | LJSpeech-1.1/wavs/LJ034-0198.wav|Euins, who was on the southwest corner of Elm and Houston Streets testified that he could not describe the man he saw in the window. 22 | LJSpeech-1.1/wavs/LJ026-0068.wav|Energy enters the plant, to a small extent, 23 | LJSpeech-1.1/wavs/LJ039-0075.wav|once you know that you must put the crosshairs on the target and that is all that is necessary. 24 | LJSpeech-1.1/wavs/LJ004-0096.wav|the fatal consequences whereof might be prevented if the justices of the peace were duly authorized 25 | LJSpeech-1.1/wavs/LJ005-0014.wav|Speaking on a debate on prison matters, he declared that 26 | LJSpeech-1.1/wavs/LJ012-0161.wav|he was reported to have fallen away to a shadow. 27 | LJSpeech-1.1/wavs/LJ018-0239.wav|His disappearance gave color and substance to evil reports already in circulation that the will and conveyance above referred to 28 | LJSpeech-1.1/wavs/LJ019-0257.wav|Here the tread-wheel was in use, there cellular cranks, or hard-labor machines. 29 | LJSpeech-1.1/wavs/LJ028-0008.wav|you tap gently with your heel upon the shoulder of the dromedary to urge her on. 30 | LJSpeech-1.1/wavs/LJ024-0083.wav|This plan of mine is no attack on the Court; 31 | LJSpeech-1.1/wavs/LJ042-0129.wav|No night clubs or bowling alleys, no places of recreation except the trade union dances. I have had enough. 32 | LJSpeech-1.1/wavs/LJ036-0103.wav|The police asked him whether he could pick out his passenger from the lineup. 33 | LJSpeech-1.1/wavs/LJ046-0058.wav|During his Presidency, Franklin D. Roosevelt made almost four hundred journeys and traveled more than three hundred fifty thousand miles. 34 | LJSpeech-1.1/wavs/LJ014-0076.wav|He was seen afterwards smoking and talking with his hosts in their back parlor, and never seen again alive. 35 | LJSpeech-1.1/wavs/LJ002-0043.wav|long narrow rooms -- one thirty-six feet, six twenty-three feet, and the eighth eighteen, 36 | LJSpeech-1.1/wavs/LJ009-0076.wav|We come to the sermon. 37 | LJSpeech-1.1/wavs/LJ017-0131.wav|even when the high sheriff had told him there was no possibility of a reprieve, and within a few hours of execution. 38 | LJSpeech-1.1/wavs/LJ046-0184.wav|but there is a system for the immediate notification of the Secret Service by the confining institution when a subject is released or escapes. 39 | LJSpeech-1.1/wavs/LJ014-0263.wav|When other pleasures palled he took a theatre, and posed as a munificent patron of the dramatic art. 40 | LJSpeech-1.1/wavs/LJ042-0096.wav|(old exchange rate) in addition to his factory salary of approximately equal amount 41 | LJSpeech-1.1/wavs/LJ049-0050.wav|Hill had both feet on the car and was climbing aboard to assist President and Mrs. Kennedy. 42 | LJSpeech-1.1/wavs/LJ019-0186.wav|seeing that since the establishment of the Central Criminal Court, Newgate received prisoners for trial from several counties, 43 | LJSpeech-1.1/wavs/LJ028-0307.wav|then let twenty days pass, and at the end of that time station near the Chaldasan gates a body of four thousand. 44 | LJSpeech-1.1/wavs/LJ012-0235.wav|While they were in a state of insensibility the murder was committed. 45 | LJSpeech-1.1/wavs/LJ034-0053.wav|reached the same conclusion as Latona that the prints found on the cartons were those of Lee Harvey Oswald. 46 | LJSpeech-1.1/wavs/LJ014-0030.wav|These were damnatory facts which well supported the prosecution. 47 | LJSpeech-1.1/wavs/LJ015-0203.wav|but were the precautions too minute, the vigilance too close to be eluded or overcome? 48 | LJSpeech-1.1/wavs/LJ028-0093.wav|but his scribe wrote it in the manner customary for the scribes of those days to write of their royal masters. 49 | LJSpeech-1.1/wavs/LJ002-0018.wav|The inadequacy of the jail was noticed and reported upon again and again by the grand juries of the city of London, 50 | LJSpeech-1.1/wavs/LJ028-0275.wav|At last, in the twentieth month, 51 | LJSpeech-1.1/wavs/LJ012-0042.wav|which he kept concealed in a hiding-place with a trap-door just under his bed. 52 | LJSpeech-1.1/wavs/LJ011-0096.wav|He married a lady also belonging to the Society of Friends, who brought him a large fortune, which, and his own money, he put into a city firm, 53 | LJSpeech-1.1/wavs/LJ036-0077.wav|Roger D. Craig, a deputy sheriff of Dallas County, 54 | LJSpeech-1.1/wavs/LJ016-0318.wav|Other officials, great lawyers, governors of prisons, and chaplains supported this view. 55 | LJSpeech-1.1/wavs/LJ013-0164.wav|who came from his room ready dressed, a suspicious circumstance, as he was always late in the morning. 56 | LJSpeech-1.1/wavs/LJ027-0141.wav|is closely reproduced in the life-history of existing deer. Or, in other words, 57 | LJSpeech-1.1/wavs/LJ028-0335.wav|accordingly they committed to him the command of their whole army, and put the keys of their city into his hands. 58 | LJSpeech-1.1/wavs/LJ031-0202.wav|Mrs. Kennedy chose the hospital in Bethesda for the autopsy because the President had served in the Navy. 59 | LJSpeech-1.1/wavs/LJ021-0145.wav|From those willing to join in establishing this hoped-for period of peace, 60 | LJSpeech-1.1/wavs/LJ016-0288.wav|"Müller, Müller, He's the man," till a diversion was created by the appearance of the gallows, which was received with continuous yells. 61 | LJSpeech-1.1/wavs/LJ028-0081.wav|Years later, when the archaeologists could readily distinguish the false from the true, 62 | LJSpeech-1.1/wavs/LJ018-0081.wav|his defense being that he had intended to commit suicide, but that, on the appearance of this officer who had wronged him, 63 | LJSpeech-1.1/wavs/LJ021-0066.wav|together with a great increase in the payrolls, there has come a substantial rise in the total of industrial profits 64 | LJSpeech-1.1/wavs/LJ009-0238.wav|After this the sheriffs sent for another rope, but the spectators interfered, and the man was carried back to jail. 65 | LJSpeech-1.1/wavs/LJ005-0079.wav|and improve the morals of the prisoners, and shall insure the proper measure of punishment to convicted offenders. 66 | LJSpeech-1.1/wavs/LJ035-0019.wav|drove to the northwest corner of Elm and Houston, and parked approximately ten feet from the traffic signal. 67 | LJSpeech-1.1/wavs/LJ036-0174.wav|This is the approximate time he entered the roominghouse, according to Earlene Roberts, the housekeeper there. 68 | LJSpeech-1.1/wavs/LJ046-0146.wav|The criteria in effect prior to November twenty-two, nineteen sixty-three, for determining whether to accept material for the PRS general files 69 | LJSpeech-1.1/wavs/LJ017-0044.wav|and the deepest anxiety was felt that the crime, if crime there had been, should be brought home to its perpetrator. 70 | LJSpeech-1.1/wavs/LJ017-0070.wav|but his sporting operations did not prosper, and he became a needy man, always driven to desperate straits for cash. 71 | LJSpeech-1.1/wavs/LJ014-0020.wav|He was soon afterwards arrested on suspicion, and a search of his lodgings brought to light several garments saturated with blood; 72 | LJSpeech-1.1/wavs/LJ016-0020.wav|He never reached the cistern, but fell back into the yard, injuring his legs severely. 73 | LJSpeech-1.1/wavs/LJ045-0230.wav|when he was finally apprehended in the Texas Theatre. Although it is not fully corroborated by others who were present, 74 | LJSpeech-1.1/wavs/LJ035-0129.wav|and she must have run down the stairs ahead of Oswald and would probably have seen or heard him. 75 | LJSpeech-1.1/wavs/LJ008-0307.wav|afterwards express a wish to murder the Recorder for having kept them so long in suspense. 76 | LJSpeech-1.1/wavs/LJ008-0294.wav|nearly indefinitely deferred. 77 | LJSpeech-1.1/wavs/LJ047-0148.wav|On October twenty-five, 78 | LJSpeech-1.1/wavs/LJ008-0111.wav|They entered a "stone cold room," and were presently joined by the prisoner. 79 | LJSpeech-1.1/wavs/LJ034-0042.wav|that he could only testify with certainty that the print was less than three days old. 80 | LJSpeech-1.1/wavs/LJ037-0234.wav|Mrs. Mary Brock, the wife of a mechanic who worked at the station, was there at the time and she saw a white male, 81 | LJSpeech-1.1/wavs/LJ040-0002.wav|Chapter seven. Lee Harvey Oswald: Background and Possible Motives, Part one. 82 | LJSpeech-1.1/wavs/LJ045-0140.wav|The arguments he used to justify his use of the alias suggest that Oswald may have come to think that the whole world was becoming involved 83 | LJSpeech-1.1/wavs/LJ012-0035.wav|the number and names on watches, were carefully removed or obliterated after the goods passed out of his hands. 84 | LJSpeech-1.1/wavs/LJ012-0250.wav|On the seventh July, eighteen thirty-seven, 85 | LJSpeech-1.1/wavs/LJ016-0179.wav|contracted with sheriffs and conveners to work by the job. 86 | LJSpeech-1.1/wavs/LJ016-0138.wav|at a distance from the prison. 87 | LJSpeech-1.1/wavs/LJ027-0052.wav|These principles of homology are essential to a correct interpretation of the facts of morphology. 88 | LJSpeech-1.1/wavs/LJ031-0134.wav|On one occasion Mrs. Johnson, accompanied by two Secret Service agents, left the room to see Mrs. Kennedy and Mrs. Connally. 89 | LJSpeech-1.1/wavs/LJ019-0273.wav|which Sir Joshua Jebb told the committee he considered the proper elements of penal discipline. 90 | LJSpeech-1.1/wavs/LJ014-0110.wav|At the first the boxes were impounded, opened, and found to contain many of O'Connor's effects. 91 | LJSpeech-1.1/wavs/LJ034-0160.wav|on Brennan's subsequent certain identification of Lee Harvey Oswald as the man he saw fire the rifle. 92 | LJSpeech-1.1/wavs/LJ038-0199.wav|eleven. If I am alive and taken prisoner, 93 | LJSpeech-1.1/wavs/LJ014-0010.wav|yet he could not overcome the strange fascination it had for him, and remained by the side of the corpse till the stretcher came. 94 | LJSpeech-1.1/wavs/LJ033-0047.wav|I noticed when I went out that the light was on, end quote, 95 | LJSpeech-1.1/wavs/LJ040-0027.wav|He was never satisfied with anything. 96 | LJSpeech-1.1/wavs/LJ048-0228.wav|and others who were present say that no agent was inebriated or acted improperly. 97 | LJSpeech-1.1/wavs/LJ003-0111.wav|He was in consequence put out of the protection of their internal law, end quote. Their code was a subject of some curiosity. 98 | LJSpeech-1.1/wavs/LJ008-0258.wav|Let me retrace my steps, and speak more in detail of the treatment of the condemned in those bloodthirsty and brutally indifferent days, 99 | LJSpeech-1.1/wavs/LJ029-0022.wav|The original plan called for the President to spend only one day in the State, making whirlwind visits to Dallas, Fort Worth, San Antonio, and Houston. 100 | LJSpeech-1.1/wavs/LJ004-0045.wav|Mr. Sturges Bourne, Sir James Mackintosh, Sir James Scarlett, and William Wilberforce. 101 | -------------------------------------------------------------------------------- /text/korean.py: -------------------------------------------------------------------------------- 1 | # Code based on 2 | 3 | import re 4 | import os 5 | import ast 6 | import json 7 | from jamo import hangul_to_jamo, h2j, j2h 8 | from jamo.jamo import _jamo_char_to_hcj 9 | 10 | from .ko_dictionary import english_dictionary, etc_dictionary 11 | #from ko_dictionary import english_dictionary, etc_dictionary 12 | 13 | PAD = '_' 14 | EOS = '~' 15 | PUNC = '!\'(),-.:;?' 16 | SPACE = ' ' 17 | 18 | JAMO_LEADS = "".join([chr(_) for _ in range(0x1100, 0x1113)]) 19 | JAMO_VOWELS = "".join([chr(_) for _ in range(0x1161, 0x1176)]) 20 | JAMO_TAILS = "".join([chr(_) for _ in range(0x11A8, 0x11C3)]) 21 | 22 | VALID_CHARS = JAMO_LEADS + JAMO_VOWELS + JAMO_TAILS + PUNC + SPACE 23 | ALL_SYMBOLS = PAD + EOS + VALID_CHARS 24 | ALL_SYMBOLS_1 = "_~ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㄱㄲㄳㄴㄵㄶㅇㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ!'(),-.:;? " 25 | ALL_SYMBOLS_2 = "_~ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄾㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ!'(),-.:;? " 26 | ALL_SYMBOLS_3 = "_~ᄀᄂᄃᄅᄆᄇᄉᄋᄌᄎᄏᄐᄑᄒㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ!'(),-.;? " 27 | ALL_SYMBOLS_4 = "_~ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ!'(),-.;? " 28 | 29 | char_to_id_1 = {s: i for i, s in enumerate(ALL_SYMBOLS_1)} 30 | char_to_id_2 = {s: i for i, s in enumerate(ALL_SYMBOLS_2)} 31 | char_to_id_3 = {s: i for i, s in enumerate(ALL_SYMBOLS_3)} 32 | char_to_id_4 = {s: i for i, s in enumerate(ALL_SYMBOLS_4)} 33 | char_to_id = {c: i for i, c in enumerate(ALL_SYMBOLS)} 34 | id_to_char = {i: c for i, c in enumerate(ALL_SYMBOLS)} 35 | 36 | quote_checker = """([`"'"“‘])(.+?)([`"'"”’])""" 37 | 38 | def is_lead(char): 39 | return char in JAMO_LEADS 40 | 41 | def is_vowel(char): 42 | return char in JAMO_VOWELS 43 | 44 | def is_tail(char): 45 | return char in JAMO_TAILS 46 | 47 | def get_mode(char): 48 | if is_lead(char): 49 | return 0 50 | elif is_vowel(char): 51 | return 1 52 | elif is_tail(char): 53 | return 2 54 | else: 55 | return -1 56 | 57 | def _get_text_from_candidates(candidates): 58 | if len(candidates) == 0: 59 | return "" 60 | elif len(candidates) == 1: 61 | return _jamo_char_to_hcj(candidates[0]) 62 | else: 63 | return j2h(**dict(zip(["lead", "vowel", "tail"], candidates))) 64 | 65 | def jamo_to_korean(text): 66 | text = h2j(text) 67 | 68 | idx = 0 69 | new_text = "" 70 | candidates = [] 71 | 72 | while True: 73 | if idx >= len(text): 74 | new_text += _get_text_from_candidates(candidates) 75 | break 76 | 77 | char = text[idx] 78 | mode = get_mode(char) 79 | 80 | if mode == 0: 81 | new_text += _get_text_from_candidates(candidates) 82 | candidates = [char] 83 | elif mode == -1: 84 | new_text += _get_text_from_candidates(candidates) 85 | new_text += char 86 | candidates = [] 87 | else: 88 | candidates.append(char) 89 | 90 | idx += 1 91 | return new_text 92 | 93 | num_to_kor = { 94 | '0': '영', 95 | '1': '일', 96 | '2': '이', 97 | '3': '삼', 98 | '4': '사', 99 | '5': '오', 100 | '6': '육', 101 | '7': '칠', 102 | '8': '팔', 103 | '9': '구', 104 | } 105 | 106 | unit_to_kor1 = { 107 | '%': '퍼센트', 108 | 'cm': '센치미터', 109 | 'mm': '밀리미터', 110 | 'km': '킬로미터', 111 | 'kg': '킬로그람', 112 | } 113 | unit_to_kor2 = { 114 | 'm': '미터', 115 | } 116 | 117 | upper_to_kor = { 118 | 'A': '에이', 119 | 'B': '비', 120 | 'C': '씨', 121 | 'D': '디', 122 | 'E': '이', 123 | 'F': '에프', 124 | 'G': '지', 125 | 'H': '에이치', 126 | 'I': '아이', 127 | 'J': '제이', 128 | 'K': '케이', 129 | 'L': '엘', 130 | 'M': '엠', 131 | 'N': '엔', 132 | 'O': '오', 133 | 'P': '피', 134 | 'Q': '큐', 135 | 'R': '알', 136 | 'S': '에스', 137 | 'T': '티', 138 | 'U': '유', 139 | 'V': '브이', 140 | 'W': '더블유', 141 | 'X': '엑스', 142 | 'Y': '와이', 143 | 'Z': '지', 144 | } 145 | 146 | def compare_sentence_with_jamo(text1, text2): 147 | return h2j(text1) != h2j(text2) 148 | 149 | def load_symbols_1(): 150 | jamo = "_~ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ!'(),-.:;? " 151 | hj = "_~ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㄱㄲㄳㄴㄵㄶㅇㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ!'(),-.:;? " 152 | assert len(jamo) == len(hj) 153 | j2hj = {j: h for j, h in zip(jamo, hj)} 154 | return j2hj 155 | 156 | def load_symbols_2(): 157 | jamo = "_~ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ!'(),-.:;? " 158 | hcj = "_~ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ!'(),-.:;? " 159 | assert len(jamo) == len(hcj) 160 | j2hcj = {j: h for j, h in zip(jamo, hcj)} 161 | return j2hcj 162 | 163 | def load_symbols_3(): 164 | jamo = "_~ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ!'(),-.:;? " 165 | sj = "_|~|ᄀ|ᄀᄀ|ᄂ|ᄃ|ᄃᄃ|ᄅ|ᄆ|ᄇ|ᄇᄇ|ᄉ|ᄉᄉ|ᄋ|ᄌ|ᄌᄌ|ᄎ|ᄏ|ᄐ|ᄑ|ᄒ|ㅏ|ㅐ|ㅑ|ㅒ|ㅓ|ㅔ|ㅕ|ㅖ|ㅗ|ㅘ|ㅙ|ㅚ|ㅛ|ㅜ|ㅝ|ㅞ|ㅟ|ㅠ|ㅡ|ㅢ|ㅣ|ㄱ|ㄱㄱ|ㄱㅅ|ㄴ|ㄴㅈ|ㄴㅎ|ㄷ|ㄹ|ㄹㄱ|ㄹㅁ|ㄹㅂ|ㄹㅅ|ㄹㅌ|ㄹㅍ|ㄹㅎ|ㅁ|ㅂ|ㅂㅅ|ㅅ|ㅅㅅ|ㅇ|ㅈ|ㅊ|ㅋ|ㅌ|ㅍ|ㅎ|!|'|(|)|,|-|.|:|;|?| " 166 | assert len(jamo) == len(sj.split("|")) 167 | j2sj = {j: s for j, s in zip(jamo, sj.split("|"))} 168 | return j2sj 169 | 170 | def load_symbols_4(): 171 | jamo = "_~ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ!'(),-.:;? " 172 | shcj = "_|~|ㄱ|ㄱㄱ|ㄴ|ㄷ|ㄷㄷ|ㄹ|ㅁ|ㅂ|ㅂㅂ|ㅅ|ㅅㅅ|ㅇ|ㅈ|ㅈㅈ|ㅊ|ㅋ|ㅌ|ㅍ|ㅎ|ㅏ|ㅐ|ㅑ|ㅒ|ㅓ|ㅔ|ㅕ|ㅖ|ㅗ|ㅘ|ㅙ|ㅚ|ㅛ|ㅜ|ㅝ|ㅞ|ㅟ|ㅠ|ㅡ|ㅢ|ㅣ|ㄱ|ㄱㄱ|ㄱㅅ|ㄴ|ㄴㅈ|ㄴㅎ|ㄷ|ㄹ|ㄹㄱ|ㄹㅁ|ㄹㅂ|ㄹㅅ|ㄹㅌ|ㄹㅍ|ㄹㅎ|ㅁ|ㅂ|ㅂㅅ|ㅅ|ㅅㅅ|ㅇ|ㅈ|ㅊ|ㅋ|ㅌ|ㅍ|ㅎ|!|'|(|)|,|-|.|:|;|?| " 173 | assert len(jamo) == len(shcj.split("|")) 174 | j2shcj = {j: s for j, s in zip(jamo, shcj.split("|"))} 175 | return j2shcj 176 | 177 | def tokenize(text, as_id=False, symbol_type=1, debug=False): 178 | 179 | j2hj, j2hcj, j2sj, j2shcj = load_symbols_1(), load_symbols_2(), load_symbols_3(), load_symbols_4() 180 | 181 | text = normalize(text) 182 | pre_tokens = list(hangul_to_jamo(text)) 183 | tokens = [] 184 | 185 | if symbol_type == 1: 186 | if debug: 187 | print(char_to_id_1) 188 | for token in pre_tokens: 189 | tokens += list(j2hj[token]) 190 | 191 | if as_id: 192 | return [char_to_id_1[token] for token in tokens] + [char_to_id_1[EOS]] 193 | else: 194 | return [token for token in tokens] + [EOS] 195 | 196 | elif symbol_type == 2: 197 | if debug: 198 | print(char_to_id_2) 199 | for token in pre_tokens: 200 | tokens += list(j2hcj[token]) 201 | 202 | if as_id: 203 | return [char_to_id_2[token] for token in tokens] + [char_to_id_2[EOS]] 204 | else: 205 | return [token for token in tokens] + [EOS] 206 | 207 | elif symbol_type == 3: 208 | if debug: 209 | print(char_to_id_3) 210 | for token in pre_tokens: 211 | tokens += list(j2sj[token]) 212 | 213 | if as_id: 214 | return [char_to_id_3[token] for token in tokens] + [char_to_id_3[EOS]] 215 | else: 216 | return [token for token in tokens] + [EOS] 217 | 218 | elif symbol_type == 4: 219 | if debug: 220 | print(char_to_id_4) 221 | for token in pre_tokens: 222 | tokens += list(j2shcj[token]) 223 | 224 | if as_id: 225 | return [char_to_id_4[token] for token in tokens] + [char_to_id_4[EOS]] 226 | else: 227 | return [token for token in tokens] + [EOS] 228 | 229 | def tokenizer_fn(iterator, symbol_type): 230 | return (token for x in iterator for token in tokenize(x, as_id=False, symbol_type=symbol_type)) 231 | 232 | def normalize(text): 233 | text = text.strip() 234 | 235 | text = text.replace("'", "") 236 | text = text.replace('"', "") 237 | 238 | text = re.sub('\(\d+일\)', '', text) 239 | text = re.sub('\([⺀-⺙⺛-⻳⼀-⿕々〇〡-〩〸-〺〻㐀-䶵一-鿃豈-鶴侮-頻並-龎]+\)', '', text) 240 | 241 | text = normalize_with_dictionary(text, etc_dictionary) 242 | text = normalize_english(text) 243 | text = re.sub('[a-zA-Z]+', normalize_upper, text) 244 | 245 | text = normalize_quote(text) 246 | text = normalize_number(text) 247 | 248 | return text 249 | 250 | def normalize_with_dictionary(text, dic): 251 | if any(key in text for key in dic.keys()): 252 | pattern = re.compile('|'.join(re.escape(key) for key in dic.keys())) 253 | return pattern.sub(lambda x: dic[x.group()], text) 254 | else: 255 | return text 256 | 257 | def normalize_english(text): 258 | def fn(m): 259 | word = m.group() 260 | if word in english_dictionary: 261 | return english_dictionary.get(word) 262 | else: 263 | return word 264 | 265 | text = re.sub("([A-Za-z]+)", fn, text) 266 | return text 267 | 268 | def normalize_upper(text): 269 | text = text.group(0) 270 | 271 | if all([char.isupper() for char in text]): 272 | return "".join(upper_to_kor[char] for char in text) 273 | else: 274 | return text 275 | 276 | def normalize_quote(text): 277 | def fn(found_text): 278 | from nltk import sent_tokenize # NLTK doesn't along with multiprocessing 279 | 280 | found_text = found_text.group() 281 | unquoted_text = found_text[1:-1] 282 | 283 | sentences = sent_tokenize(unquoted_text) 284 | return " ".join(["'{}'".format(sent) for sent in sentences]) 285 | 286 | return re.sub(quote_checker, fn, text) 287 | 288 | number_checker = "([+-]?\d[\d,]*)[\.]?\d*" 289 | count_checker = "(시|명|가지|살|마리|포기|송이|수|톨|통|점|개|벌|척|채|다발|그루|자루|줄|켤레|그릇|잔|마디|상자|사람|곡|병|판)" 290 | 291 | def normalize_number(text): 292 | text = normalize_with_dictionary(text, unit_to_kor1) 293 | text = normalize_with_dictionary(text, unit_to_kor2) 294 | text = re.sub(number_checker + count_checker, 295 | lambda x: number_to_korean(x, True), text) 296 | text = re.sub(number_checker, 297 | lambda x: number_to_korean(x, False), text) 298 | return text 299 | 300 | num_to_kor1 = [""] + list("일이삼사오육칠팔구") 301 | num_to_kor2 = [""] + list("만억조경해") 302 | num_to_kor3 = [""] + list("십백천") 303 | 304 | #count_to_kor1 = [""] + ["하나","둘","셋","넷","다섯","여섯","일곱","여덟","아홉"] 305 | count_to_kor1 = [""] + ["한","두","세","네","다섯","여섯","일곱","여덟","아홉"] 306 | 307 | count_tenth_dict = { 308 | "십": "열", 309 | "두십": "스물", 310 | "세십": "서른", 311 | "네십": "마흔", 312 | "다섯십": "쉰", 313 | "여섯십": "예순", 314 | "일곱십": "일흔", 315 | "여덟십": "여든", 316 | "아홉십": "아흔", 317 | } 318 | 319 | 320 | 321 | def number_to_korean(num_str, is_count=False): 322 | if is_count: 323 | num_str, unit_str = num_str.group(1), num_str.group(2) 324 | else: 325 | num_str, unit_str = num_str.group(), "" 326 | 327 | num_str = num_str.replace(',', '') 328 | try: 329 | num = ast.literal_eval(num_str) 330 | except: 331 | num = int(num_str) 332 | 333 | if num == 0: 334 | return "영" 335 | 336 | check_float = num_str.split('.') 337 | if len(check_float) == 2: 338 | digit_str, float_str = check_float 339 | elif len(check_float) >= 3: 340 | raise Exception(" [!] Wrong number format") 341 | else: 342 | digit_str, float_str = check_float[0], None 343 | 344 | if is_count and float_str is not None: 345 | raise Exception(" [!] `is_count` and float number does not fit each other") 346 | 347 | digit = int(digit_str) 348 | 349 | if digit_str.startswith("-"): 350 | digit, digit_str = abs(digit), str(abs(digit)) 351 | 352 | kor = "" 353 | size = len(str(digit)) 354 | tmp = [] 355 | 356 | for i, v in enumerate(digit_str, start=1): 357 | v = int(v) 358 | 359 | if v != 0: 360 | if is_count: 361 | tmp += count_to_kor1[v] 362 | else: 363 | tmp += num_to_kor1[v] 364 | 365 | tmp += num_to_kor3[(size - i) % 4] 366 | 367 | if (size - i) % 4 == 0 and len(tmp) != 0: 368 | kor += "".join(tmp) 369 | tmp = [] 370 | kor += num_to_kor2[int((size - i) / 4)] 371 | 372 | if is_count: 373 | if kor.startswith("한") and len(kor) > 1: 374 | kor = kor[1:] 375 | 376 | if any(word in kor for word in count_tenth_dict): 377 | kor = re.sub( 378 | '|'.join(count_tenth_dict.keys()), 379 | lambda x: count_tenth_dict[x.group()], kor) 380 | 381 | if not is_count and kor.startswith("일") and len(kor) > 1: 382 | kor = kor[1:] 383 | 384 | if float_str is not None: 385 | kor += "쩜 " 386 | kor += re.sub('\d', lambda x: num_to_kor[x.group()], float_str) 387 | 388 | if num_str.startswith("+"): 389 | kor = "플러스 " + kor 390 | elif num_str.startswith("-"): 391 | kor = "마이너스 " + kor 392 | 393 | return kor + unit_str 394 | 395 | if __name__ == "__main__": 396 | def test_normalize(text): 397 | print(text) 398 | print(normalize(text)) 399 | print("="*30) 400 | 401 | test_normalize("JTBC는 JTBCs를 DY는 A가 Absolute") 402 | test_normalize("오늘(13일) 101마리 강아지가") 403 | #test_normalize('"저돌"(猪突) 입니다.') 404 | #test_normalize('비대위원장이 지난 1월 이런 말을 했습니다. “난 그냥 산돼지처럼 돌파하는 스타일이다”') 405 | test_normalize("지금은 -12.35%였고 종류는 5가지와 19가지, 그리고 55가지였다") 406 | test_normalize("JTBC는 TH와 K 양이 2017년 9월 12일 오후 12시에 24살이 된다") 407 | -------------------------------------------------------------------------------- /fp16_optimizer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | from torch.autograd import Variable 4 | from torch.nn.parameter import Parameter 5 | from torch._utils import _flatten_dense_tensors, _unflatten_dense_tensors 6 | 7 | from loss_scaler import DynamicLossScaler, LossScaler 8 | 9 | FLOAT_TYPES = (torch.FloatTensor, torch.cuda.FloatTensor) 10 | HALF_TYPES = (torch.HalfTensor, torch.cuda.HalfTensor) 11 | 12 | def conversion_helper(val, conversion): 13 | """Apply conversion to val. Recursively apply conversion if `val` is a nested tuple/list structure.""" 14 | if not isinstance(val, (tuple, list)): 15 | return conversion(val) 16 | rtn = [conversion_helper(v, conversion) for v in val] 17 | if isinstance(val, tuple): 18 | rtn = tuple(rtn) 19 | return rtn 20 | 21 | def fp32_to_fp16(val): 22 | """Convert fp32 `val` to fp16""" 23 | def half_conversion(val): 24 | val_typecheck = val 25 | if isinstance(val_typecheck, (Parameter, Variable)): 26 | val_typecheck = val.data 27 | if isinstance(val_typecheck, FLOAT_TYPES): 28 | val = val.half() 29 | return val 30 | return conversion_helper(val, half_conversion) 31 | 32 | def fp16_to_fp32(val): 33 | """Convert fp16 `val` to fp32""" 34 | def float_conversion(val): 35 | val_typecheck = val 36 | if isinstance(val_typecheck, (Parameter, Variable)): 37 | val_typecheck = val.data 38 | if isinstance(val_typecheck, HALF_TYPES): 39 | val = val.float() 40 | return val 41 | return conversion_helper(val, float_conversion) 42 | 43 | class FP16_Module(nn.Module): 44 | def __init__(self, module): 45 | super(FP16_Module, self).__init__() 46 | self.add_module('module', module.half()) 47 | 48 | def forward(self, *inputs, **kwargs): 49 | return fp16_to_fp32(self.module(*(fp32_to_fp16(inputs)), **kwargs)) 50 | 51 | class FP16_Optimizer(object): 52 | """ 53 | FP16_Optimizer is designed to wrap an existing PyTorch optimizer, 54 | and enable an fp16 model to be trained using a master copy of fp32 weights. 55 | 56 | Args: 57 | optimizer (torch.optim.optimizer): Existing optimizer containing initialized fp16 parameters. Internally, FP16_Optimizer replaces the passed optimizer's fp16 parameters with new fp32 parameters copied from the original ones. FP16_Optimizer also stores references to the original fp16 parameters, and updates these fp16 parameters from the master fp32 copy after each step. 58 | static_loss_scale (float, optional, default=1.0): Loss scale used internally to scale fp16 gradients computed by the model. Scaled gradients will be copied to fp32, then downscaled before being applied to the fp32 master params, so static_loss_scale should not affect learning rate. 59 | dynamic_loss_scale (bool, optional, default=False): Use dynamic loss scaling. If True, this will override any static_loss_scale option. 60 | 61 | """ 62 | 63 | def __init__(self, optimizer, static_loss_scale=1.0, dynamic_loss_scale=False): 64 | if not torch.cuda.is_available: 65 | raise SystemError('Cannot use fp16 without CUDA') 66 | 67 | self.fp16_param_groups = [] 68 | self.fp32_param_groups = [] 69 | self.fp32_flattened_groups = [] 70 | for i, param_group in enumerate(optimizer.param_groups): 71 | print("FP16_Optimizer processing param group {}:".format(i)) 72 | fp16_params_this_group = [] 73 | fp32_params_this_group = [] 74 | for param in param_group['params']: 75 | if param.requires_grad: 76 | if param.type() == 'torch.cuda.HalfTensor': 77 | print("FP16_Optimizer received torch.cuda.HalfTensor with {}" 78 | .format(param.size())) 79 | fp16_params_this_group.append(param) 80 | elif param.type() == 'torch.cuda.FloatTensor': 81 | print("FP16_Optimizer received torch.cuda.FloatTensor with {}" 82 | .format(param.size())) 83 | fp32_params_this_group.append(param) 84 | else: 85 | raise TypeError("Wrapped parameters must be either " 86 | "torch.cuda.FloatTensor or torch.cuda.HalfTensor. " 87 | "Received {}".format(param.type())) 88 | 89 | fp32_flattened_this_group = None 90 | if len(fp16_params_this_group) > 0: 91 | fp32_flattened_this_group = _flatten_dense_tensors( 92 | [param.detach().data.clone().float() for param in fp16_params_this_group]) 93 | 94 | fp32_flattened_this_group = Variable(fp32_flattened_this_group, requires_grad = True) 95 | 96 | fp32_flattened_this_group.grad = fp32_flattened_this_group.new( 97 | *fp32_flattened_this_group.size()) 98 | 99 | # python's lovely list concatenation via + 100 | if fp32_flattened_this_group is not None: 101 | param_group['params'] = [fp32_flattened_this_group] + fp32_params_this_group 102 | else: 103 | param_group['params'] = fp32_params_this_group 104 | 105 | self.fp16_param_groups.append(fp16_params_this_group) 106 | self.fp32_param_groups.append(fp32_params_this_group) 107 | self.fp32_flattened_groups.append(fp32_flattened_this_group) 108 | 109 | # print("self.fp32_flattened_groups = ", self.fp32_flattened_groups) 110 | # print("self.fp16_param_groups = ", self.fp16_param_groups) 111 | 112 | self.optimizer = optimizer.__class__(optimizer.param_groups) 113 | 114 | # self.optimizer.load_state_dict(optimizer.state_dict()) 115 | 116 | self.param_groups = self.optimizer.param_groups 117 | 118 | if dynamic_loss_scale: 119 | self.dynamic_loss_scale = True 120 | self.loss_scaler = DynamicLossScaler() 121 | else: 122 | self.dynamic_loss_scale = False 123 | self.loss_scaler = LossScaler(static_loss_scale) 124 | 125 | self.overflow = False 126 | self.first_closure_call_this_step = True 127 | 128 | def zero_grad(self): 129 | """ 130 | Zero fp32 and fp16 parameter grads. 131 | """ 132 | self.optimizer.zero_grad() 133 | for fp16_group in self.fp16_param_groups: 134 | for param in fp16_group: 135 | if param.grad is not None: 136 | param.grad.detach_() # This does appear in torch.optim.optimizer.zero_grad(), 137 | # but I'm not sure why it's needed. 138 | param.grad.zero_() 139 | 140 | def _check_overflow(self): 141 | params = [] 142 | for group in self.fp16_param_groups: 143 | for param in group: 144 | params.append(param) 145 | for group in self.fp32_param_groups: 146 | for param in group: 147 | params.append(param) 148 | self.overflow = self.loss_scaler.has_overflow(params) 149 | 150 | def _update_scale(self, has_overflow=False): 151 | self.loss_scaler.update_scale(has_overflow) 152 | 153 | def _copy_grads_fp16_to_fp32(self): 154 | for fp32_group, fp16_group in zip(self.fp32_flattened_groups, self.fp16_param_groups): 155 | if len(fp16_group) > 0: 156 | # This might incur one more deep copy than is necessary. 157 | fp32_group.grad.data.copy_( 158 | _flatten_dense_tensors([fp16_param.grad.data for fp16_param in fp16_group])) 159 | 160 | def _downscale_fp32(self): 161 | if self.loss_scale != 1.0: 162 | for param_group in self.optimizer.param_groups: 163 | for param in param_group['params']: 164 | param.grad.data.mul_(1./self.loss_scale) 165 | 166 | def clip_fp32_grads(self, clip=-1): 167 | if not self.overflow: 168 | fp32_params = [] 169 | for param_group in self.optimizer.param_groups: 170 | for param in param_group['params']: 171 | fp32_params.append(param) 172 | if clip > 0: 173 | return torch.nn.utils.clip_grad_norm(fp32_params, clip) 174 | 175 | def _copy_params_fp32_to_fp16(self): 176 | for fp16_group, fp32_group in zip(self.fp16_param_groups, self.fp32_flattened_groups): 177 | if len(fp16_group) > 0: 178 | for fp16_param, fp32_data in zip(fp16_group, 179 | _unflatten_dense_tensors(fp32_group.data, fp16_group)): 180 | fp16_param.data.copy_(fp32_data) 181 | 182 | def state_dict(self): 183 | """ 184 | Returns a dict containing the current state of this FP16_Optimizer instance. 185 | This dict contains attributes of FP16_Optimizer, as well as the state_dict 186 | of the contained Pytorch optimizer. 187 | 188 | Untested. 189 | """ 190 | state_dict = {} 191 | state_dict['loss_scaler'] = self.loss_scaler 192 | state_dict['dynamic_loss_scale'] = self.dynamic_loss_scale 193 | state_dict['overflow'] = self.overflow 194 | state_dict['first_closure_call_this_step'] = self.first_closure_call_this_step 195 | state_dict['optimizer_state_dict'] = self.optimizer.state_dict() 196 | return state_dict 197 | 198 | def load_state_dict(self, state_dict): 199 | """ 200 | Loads a state_dict created by an earlier call to state_dict. 201 | 202 | Untested. 203 | """ 204 | self.loss_scaler = state_dict['loss_scaler'] 205 | self.dynamic_loss_scale = state_dict['dynamic_loss_scale'] 206 | self.overflow = state_dict['overflow'] 207 | self.first_closure_call_this_step = state_dict['first_closure_call_this_step'] 208 | self.optimizer.load_state_dict(state_dict['optimizer_state_dict']) 209 | 210 | def step(self, closure=None): # could add clip option. 211 | """ 212 | If no closure is supplied, step should be called after fp16_optimizer_obj.backward(loss). 213 | step updates the fp32 master copy of parameters using the optimizer supplied to 214 | FP16_Optimizer's constructor, then copies the updated fp32 params into the fp16 params 215 | originally referenced by Fp16_Optimizer's constructor, so the user may immediately run 216 | another forward pass using their model. 217 | 218 | If a closure is supplied, step may be called without a prior call to self.backward(loss). 219 | However, the user should take care that any loss.backward() call within the closure 220 | has been replaced by fp16_optimizer_obj.backward(loss). 221 | 222 | Args: 223 | closure (optional): Closure that will be supplied to the underlying optimizer originally passed to FP16_Optimizer's constructor. closure should call zero_grad on the FP16_Optimizer object, compute the loss, call .backward(loss), and return the loss. 224 | 225 | Closure example:: 226 | 227 | # optimizer is assumed to be an FP16_Optimizer object, previously constructed from an 228 | # existing pytorch optimizer. 229 | for input, target in dataset: 230 | def closure(): 231 | optimizer.zero_grad() 232 | output = model(input) 233 | loss = loss_fn(output, target) 234 | optimizer.backward(loss) 235 | return loss 236 | optimizer.step(closure) 237 | 238 | .. note:: 239 | The only changes that need to be made compared to 240 | `ordinary optimizer closures`_ are that "optimizer" itself should be an instance of 241 | FP16_Optimizer, and that the call to loss.backward should be replaced by 242 | optimizer.backward(loss). 243 | 244 | .. warning:: 245 | Currently, calling step with a closure is not compatible with dynamic loss scaling. 246 | 247 | .. _`ordinary optimizer closures`: 248 | http://pytorch.org/docs/master/optim.html#optimizer-step-closure 249 | """ 250 | if closure is not None and isinstance(self.loss_scaler, DynamicLossScaler): 251 | raise TypeError("Using step with a closure is currently not " 252 | "compatible with dynamic loss scaling.") 253 | 254 | scale = self.loss_scaler.loss_scale 255 | self._update_scale(self.overflow) 256 | 257 | if self.overflow: 258 | print("OVERFLOW! Skipping step. Attempted loss scale: {}".format(scale)) 259 | return 260 | 261 | if closure is not None: 262 | self._step_with_closure(closure) 263 | else: 264 | self.optimizer.step() 265 | 266 | self._copy_params_fp32_to_fp16() 267 | 268 | return 269 | 270 | def _step_with_closure(self, closure): 271 | def wrapped_closure(): 272 | if self.first_closure_call_this_step: 273 | """ 274 | We expect that the fp16 params are initially fresh on entering self.step(), 275 | so _copy_params_fp32_to_fp16() is unnecessary the first time wrapped_closure() 276 | is called within self.optimizer.step(). 277 | """ 278 | self.first_closure_call_this_step = False 279 | else: 280 | """ 281 | If self.optimizer.step() internally calls wrapped_closure more than once, 282 | it may update the fp32 params after each call. However, self.optimizer 283 | doesn't know about the fp16 params at all. If the fp32 params get updated, 284 | we can't rely on self.optimizer to refresh the fp16 params. We need 285 | to handle that manually: 286 | """ 287 | self._copy_params_fp32_to_fp16() 288 | 289 | """ 290 | Our API expects the user to give us ownership of the backward() call by 291 | replacing all calls to loss.backward() with optimizer.backward(loss). 292 | This requirement holds whether or not the call to backward() is made within 293 | a closure. 294 | If the user is properly calling optimizer.backward(loss) within "closure," 295 | calling closure() here will give the fp32 master params fresh gradients 296 | for the optimizer to play with, 297 | so all wrapped_closure needs to do is call closure() and return the loss. 298 | """ 299 | temp_loss = closure() 300 | return temp_loss 301 | 302 | self.optimizer.step(wrapped_closure) 303 | 304 | self.first_closure_call_this_step = True 305 | 306 | def backward(self, loss, update_fp32_grads=True): 307 | """ 308 | fp16_optimizer_obj.backward performs the following conceptual operations: 309 | 310 | fp32_loss = loss.float() (see first Note below) 311 | 312 | scaled_loss = fp32_loss*loss_scale 313 | 314 | scaled_loss.backward(), which accumulates scaled gradients into the .grad attributes of the 315 | fp16 model's leaves. 316 | 317 | fp16 grads are then copied to the stored fp32 params' .grad attributes (see second Note). 318 | 319 | Finally, fp32 grads are divided by loss_scale. 320 | 321 | In this way, after fp16_optimizer_obj.backward, the fp32 parameters have fresh gradients, 322 | and fp16_optimizer_obj.step may be called. 323 | 324 | .. note:: 325 | Converting the loss to fp32 before applying the loss scale provides some 326 | additional safety against overflow if the user has supplied an fp16 value. 327 | However, for maximum overflow safety, the user should 328 | compute the loss criterion (MSE, cross entropy, etc) in fp32 before supplying it to 329 | fp16_optimizer_obj.backward. 330 | 331 | .. note:: 332 | The gradients found in an fp16 model's leaves after a call to 333 | fp16_optimizer_obj.backward should not be regarded as valid in general, 334 | because it's possible 335 | they have been scaled (and in the case of dynamic loss scaling, 336 | the scale factor may silently change over time). 337 | If the user wants to inspect gradients after a call to fp16_optimizer_obj.backward, 338 | he/she should query the .grad attribute of FP16_Optimizer's stored fp32 parameters. 339 | 340 | Args: 341 | loss: The loss output by the user's model. loss may be either float or half (but see first Note above). 342 | update_fp32_grads (bool, optional, default=True): Option to copy fp16 grads to fp32 grads on this call. By setting this to False, the user can delay this copy, which is useful to eliminate redundant fp16->fp32 grad copies if fp16_optimizer_obj.backward is being called on multiple losses in one iteration. If set to False, the user becomes responsible for calling fp16_optimizer_obj.update_fp32_grads before calling fp16_optimizer_obj.step. 343 | 344 | Example:: 345 | 346 | # Ordinary operation: 347 | optimizer.backward(loss) 348 | 349 | # Naive operation with multiple losses (technically valid, but less efficient): 350 | # fp32 grads will be correct after the second call, but 351 | # the first call incurs an unnecessary fp16->fp32 grad copy. 352 | optimizer.backward(loss1) 353 | optimizer.backward(loss2) 354 | 355 | # More efficient way to handle multiple losses: 356 | # The fp16->fp32 grad copy is delayed until fp16 grads from all 357 | # losses have been accumulated. 358 | optimizer.backward(loss1, update_fp32_grads=False) 359 | optimizer.backward(loss2, update_fp32_grads=False) 360 | optimizer.update_fp32_grads() 361 | """ 362 | self.loss_scaler.backward(loss.float()) 363 | if update_fp32_grads: 364 | self.update_fp32_grads() 365 | 366 | def update_fp32_grads(self): 367 | """ 368 | Copy the .grad attribute from stored references to fp16 parameters to 369 | the .grad attribute of the master fp32 parameters that are directly 370 | updated by the optimizer. :attr:`update_fp32_grads` only needs to be called if 371 | fp16_optimizer_obj.backward was called with update_fp32_grads=False. 372 | """ 373 | if self.dynamic_loss_scale: 374 | self._check_overflow() 375 | if self.overflow: return 376 | self._copy_grads_fp16_to_fp32() 377 | self._downscale_fp32() 378 | 379 | @property 380 | def loss_scale(self): 381 | return self.loss_scaler.loss_scale 382 | -------------------------------------------------------------------------------- /filelists/kss_test_filelist.txt: -------------------------------------------------------------------------------- 1 | kss/wavs/4/4_3999.wav|늦어서 죄송합니다. 2 | kss/wavs/4/4_3580.wav|저울을 영에 맞춰 놓아라. 3 | kss/wavs/4/4_0431.wav|물건을 너무 많이 담아서 봉지가 터질 것 같아. 4 | kss/wavs/3/3_0252.wav|이 꽃은 향기가 좋아요. 5 | kss/wavs/4/4_2282.wav|누군가의 희생을 대가로 시합에 이기고 싶지는 않아요. 6 | kss/wavs/4/4_4666.wav|경기는 그들의 승리로 끝났다. 7 | kss/wavs/4/4_0652.wav|이번 방학에는 아이들에게 농촌 체험을 시킬 생각이에요. 8 | kss/wavs/3/3_2333.wav|우리는 동갑이었고 곧 친한 친구가 되었다. 9 | kss/wavs/4/4_4734.wav|점심은 시켜 먹을까? 10 | kss/wavs/4/4_4386.wav|오늘 저녁은 제가 살게요. 11 | kss/wavs/4/4_5317.wav|그 애의 웃긴 표정을 보고 웃음을 참을 수가 없었어요. 12 | kss/wavs/3/3_2530.wav|이것들은 단지 이론적으로만 가능하다. 13 | kss/wavs/3/3_0979.wav|일을 그만뒀더니 속이 시원해요. 14 | kss/wavs/1/1_0461.wav|음악을 듣고 있습니다. 15 | kss/wavs/3/3_4405.wav|그는 커다란 상자를 안고 내 쪽으로 걸어왔다. 16 | kss/wavs/4/4_5630.wav|이 두 소설은 줄거리가 유사해요. 17 | kss/wavs/3/3_2367.wav|첫 키스는 어땠나요? 18 | kss/wavs/3/3_3191.wav|사회 계층 간의 갈등을 해소하는 일은 매우 중요하다. 19 | kss/wavs/4/4_3702.wav|이번 비는 모레까지 계속되겠습니다. 20 | kss/wavs/3/3_2842.wav|시내에 미술관이 있나요? 21 | kss/wavs/2/2_0636.wav|알아듣기 쉽게 설명해 주시겠어요? 22 | kss/wavs/4/4_1148.wav|그 약 때문에 환자가 더 나빠졌다. 23 | kss/wavs/3/3_0423.wav|이 손 놓으세요. 24 | kss/wavs/3/3_0117.wav|제 남동생은 눈썹이 짙고 코가 오뚝해요. 25 | kss/wavs/3/3_3046.wav|밤에 밖에 나가면 위험해. 26 | kss/wavs/4/4_5371.wav|월세가 얼마예요? 27 | kss/wavs/4/4_0142.wav|현실을 있는 그대로 받아들여라. 28 | kss/wavs/3/3_4218.wav|그는 재빨리 쪽지를 주머니에 넣었다. 29 | kss/wavs/3/3_1524.wav|그녀는 음흉하고 약삭빠르다. 30 | kss/wavs/3/3_3895.wav|호주의 내륙은 하나의 거대한 사막 지역이다. 31 | kss/wavs/3/3_3311.wav|그 성당은 우리나라에서 가장 오래된 성당이다. 32 | kss/wavs/3/3_0002.wav|다섯 명 33 | kss/wavs/1/1_0475.wav|네가 뭘 잘못했는지 몰라? 34 | kss/wavs/1/1_0927.wav|엄마는 나한테 제발 동생과 그만 싸우라고 소리쳤다. 35 | kss/wavs/4/4_2757.wav|비가 오고 나서 풀이 많이 자라났어요. 36 | kss/wavs/4/4_5556.wav|재녹음 37 | kss/wavs/4/4_3952.wav|머리를 자른 지 넉 달이 넘었어요. 38 | kss/wavs/4/4_0040.wav|이번 경기는 정말 아깝게 졌어요. 39 | kss/wavs/3/3_3005.wav|서울특별 40 | kss/wavs/2/2_0833.wav|그는 웬만한 일로는 화를 내지 않는다. 41 | kss/wavs/4/4_4391.wav|날이 새기 전에 끝내야 해. 42 | kss/wavs/3/3_1441.wav|정중한 사과가 길거나 장황할 필요는 없다. 43 | kss/wavs/4/4_0025.wav|아하! 그렇구나! 44 | kss/wavs/3/3_1265.wav|우리 발상을 전환해 봅시다. 45 | kss/wavs/4/4_3803.wav|제 명함입니다. 46 | kss/wavs/2/2_1130.wav|황당해서 말이 안 나왔다. 47 | kss/wavs/3/3_3007.wav|저는 대학에서 법을 공부하고 있습니다. 48 | kss/wavs/3/3_0180.wav|몇 주간 똥을 못 누었어요. 49 | kss/wavs/3/3_1071.wav|그들 중 답을 아는 사람은 아무도 없었다. 50 | kss/wavs/3/3_4981.wav|총액 51 | kss/wavs/3/3_3903.wav|이 연못의 물을 마시지 마시오. 52 | kss/wavs/3/3_4877.wav|저는 술을 좋아합니다. 그러나 자주 마시지는 않습니다. 53 | kss/wavs/4/4_1733.wav|기침이 아주 심하고 열이 나요. 54 | kss/wavs/4/4_0944.wav|어제 엄마가 갑자기 찾아오셔서 당황했어요. 55 | kss/wavs/4/4_1552.wav|거기 그대로 있어. 56 | kss/wavs/4/4_4034.wav|그 땅은 농사짓기에 적합하지 않아요. 57 | kss/wavs/4/4_5537.wav|제 여권을 연장하고 싶은데요. 58 | kss/wavs/4/4_2604.wav|세일은 일 월 십오 일까지입니다. 59 | kss/wavs/4/4_3016.wav|배고파 죽을 지경이야. 60 | kss/wavs/3/3_4198.wav|삼 일간 묵을 겁니다. 61 | kss/wavs/1/1_0093.wav|김치가 맛이 없어서 볶았어. 62 | kss/wavs/4/4_0693.wav|몇 층 가세요? 63 | kss/wavs/1/1_1040.wav|제 아내는 요리하는 걸 좋아해요. 64 | kss/wavs/4/4_2919.wav|얼마 전에 전화번호가 바뀌었어요. 65 | kss/wavs/3/3_3397.wav|방 안의 모든 가구는 목재로 만들어졌어요. 66 | kss/wavs/4/4_0042.wav|이 그릇은 엄마가 제일 아끼시는 거예요. 67 | kss/wavs/4/4_1606.wav|우리는 돈을 걷어서 선생님의 선물을 샀다. 68 | kss/wavs/3/3_2970.wav|아버지가 외교관이어서 어릴 때 싱가포르에서 살았어요. 69 | kss/wavs/3/3_1653.wav|에이. 고마워요. 비. 뭘요. 70 | kss/wavs/4/4_4152.wav|어제부터 온몸이 아파요. 71 | kss/wavs/4/4_0334.wav|버터 좀 더 주시겠어요? 72 | kss/wavs/3/3_1202.wav|내 친구 민준이는 다른 사람 흉내를 잘 낸다. 73 | kss/wavs/3/3_0524.wav|선수들은 경기가 끝난 뒤 포옹을 주고받았다. 74 | kss/wavs/4/4_3327.wav|한국에서는 크리스마스를 어떻게 보내요? 75 | kss/wavs/1/1_0500.wav|방을 정리하는 데 여러 시간이 걸렸습니다. 76 | kss/wavs/3/3_2107.wav|무를 얇게 잘라 주세요. 77 | kss/wavs/2/2_0343.wav|그는 할아버지로부터 막대한 재산을 물려받았다. 78 | kss/wavs/4/4_3637.wav|내가 밀라고 할 때까지 밀지 마. 79 | kss/wavs/3/3_0222.wav|누군가 우리 통화 내용을 엿듣고 있는 것 같아요. 80 | kss/wavs/2/2_0380.wav|이것은 명백한 사실입니다. 81 | kss/wavs/4/4_3867.wav|가방은 거기에 내려놓으세요. 82 | kss/wavs/2/2_0687.wav|커피가 너무 써. 83 | kss/wavs/3/3_3779.wav|뒷문으로 내리세요. 84 | kss/wavs/2/2_0196.wav|정말 끈질긴 분이시군요. 85 | kss/wavs/4/4_2435.wav|이길 가능성은 거의 없어요. 86 | kss/wavs/3/3_3970.wav|어제 고양이가 쥐를 잡아먹는 것을 보았다. 87 | kss/wavs/3/3_4388.wav|도로를 이 차로에서 사 차로로 확장하는 공사가 곧 시작된다. 88 | kss/wavs/4/4_2717.wav|잔디 위에 그냥 앉지 마. 89 | kss/wavs/3/3_0571.wav|오늘 아침에 계단에서 넘어졌어. 90 | kss/wavs/3/3_4192.wav|그 꼬마가 어느덧 커서 어른이 되었구나. 91 | kss/wavs/4/4_0220.wav|밤새 잘 잤어? 92 | kss/wavs/3/3_2557.wav|때로는 정의의 개념을 정의하기가 쉽지 않습니다. 93 | kss/wavs/3/3_3041.wav|그들은 자기들이 훔치지 않았다고 맹세했다. 94 | kss/wavs/4/4_4747.wav|죄송하지만, 선생님의 계획은 실현 가능성이 없는 것 같습니다. 95 | kss/wavs/4/4_0286.wav|이응받침은 엔지 소리가 납니다. 96 | kss/wavs/4/4_4987.wav|언젠가 수첩에 그 사람 전화번호 적어 놓은 게 있을 거예요. 97 | kss/wavs/1/1_0171.wav|그녀가 내게 다가왔다. 98 | kss/wavs/4/4_5228.wav|너는 또다시 같은 잘못을 저질렀어. 99 | kss/wavs/4/4_3996.wav|월요일 아침에는 늘 사람들이 여기에 늘어섭니다. 100 | kss/wavs/4/4_2623.wav|뭐든지 할 수 있어요. 101 | kss/wavs/3/3_0848.wav|그녀의 부정적인 대답이 내 모든 희망을 날려 버렸다. 102 | kss/wavs/1/1_0583.wav|그는 호주머니에서 반지를 꺼내 내게 청혼했다. 103 | kss/wavs/4/4_2126.wav|이 문제부터 해결합시다. 104 | kss/wavs/3/3_0653.wav|남편은 주말마다 산에 오릅니다. 105 | kss/wavs/2/2_1026.wav|그는 치밀한 사람이다. 106 | kss/wavs/1/1_0659.wav|어디에 머무르실 건가요? 107 | kss/wavs/4/4_4681.wav|저는 보통 겨울 스웨터를 여름에 사 둡니다. 108 | kss/wavs/3/3_0457.wav|그 선수는 기자를 두들겨 패고 카메라를 박살 냈다. 109 | kss/wavs/4/4_3184.wav|깨진 유리 조각 밟지 않게 조심해. 110 | kss/wavs/4/4_2340.wav|화장실에 사람 있어요? 111 | kss/wavs/3/3_2195.wav|내 방에서는 거리가 내다보인다. 112 | kss/wavs/2/2_0008.wav|그녀는 지난 십 년 동안 가난한 사람들을 도아왔다. 113 | kss/wavs/3/3_4238.wav|이게 얼마 만이니? 114 | kss/wavs/3/3_0409.wav|나는 꿈을 꾸고 있는 게 아닌가 싶어 내 볼을 꼬집었다. 115 | kss/wavs/1/1_0320.wav|집에서 회사까지 지하철로 얼마나 걸려요? 116 | kss/wavs/3/3_4003.wav|오늘은 이천십사 년 십이 월 삼십 일이에요. 117 | kss/wavs/3/3_4074.wav|현 상태로는 전혀 만족스럽지 않습니다. 118 | kss/wavs/2/2_0244.wav|제 시계는 오 분 느리게 가요. 119 | kss/wavs/3/3_4260.wav|나무 아래에서 좀 쉬자. 120 | kss/wavs/3/3_4178.wav|전화가 자꾸 끊어져요. 121 | kss/wavs/4/4_4886.wav|손을 펴 보세요. 122 | kss/wavs/3/3_3204.wav|음악은 공동체 생활에서 없어서는 안 될 부분이다. 123 | kss/wavs/3/3_4831.wav|파티에 온 사람들은 모두 내가 모르는 사람들이었다. 124 | kss/wavs/2/2_0694.wav|그는 씩씩한 목소리로 대답했다. 125 | kss/wavs/3/3_1742.wav|아내는 잔소리가 심한 편이에요. 126 | kss/wavs/4/4_0478.wav|통일이 된다면 북한을 자유롭게 갈 수 있을 거야. 127 | kss/wavs/4/4_4523.wav|소비자의 생각을 이해하지 못하면 살아남을 수 없어요. 128 | kss/wavs/3/3_4836.wav|우리는 작년에 여기에서 처음 만났어요. 129 | kss/wavs/4/4_1778.wav|긴장 풀어. 이건 그냥 연습이야. 130 | kss/wavs/2/2_0753.wav|제 남동생은 저보다 나이가 한 살 어려요. 131 | kss/wavs/2/2_0470.wav|그 소식에 가슴이 벅차서 한숨도 못 잤어요. 132 | kss/wavs/4/4_0926.wav|담당자 바꿔 드리겠습니다. 133 | kss/wavs/2/2_0977.wav|여기 온 진정한 이유가 뭡니까? 134 | kss/wavs/3/3_1627.wav|그는 큰소리치지만 아무것도 안 했다. 135 | kss/wavs/3/3_1331.wav|왜 울상을 짓고 있어? 136 | kss/wavs/1/1_0780.wav|접시를 식탁 위에 놓아라. 137 | kss/wavs/4/4_4237.wav|사우나 가서 피로를 좀 풀어야겠어. 138 | kss/wavs/4/4_2517.wav|미국이나 프랑스에 가고 싶어요. 139 | kss/wavs/4/4_2962.wav|짐을 저울 위에 올려 주세요. 140 | kss/wavs/3/3_0113.wav|그녀는 눈가에 주름이 있다. 141 | kss/wavs/3/3_2124.wav|돼지고기 다 익은 거 맞아? 142 | kss/wavs/4/4_2800.wav|지금 저축을 안 하면 나중에 후회할 거야. 143 | kss/wavs/3/3_2047.wav|커피에 프림 타? 144 | kss/wavs/4/4_3406.wav|끼어들지 말아요! 145 | kss/wavs/3/3_2889.wav|단군신화는 우리나라의 건국에 관한 이야기다. 146 | kss/wavs/4/4_4031.wav|해마다 이때쯤에 농민들은 아주 바빠요. 147 | kss/wavs/4/4_1683.wav|그 사람 외모는 그래 보여도 대단한 사람이야. 148 | kss/wavs/4/4_3918.wav|저는 제 사업을 하고 싶어서 회사를 나왔어요. 149 | kss/wavs/4/4_3994.wav|네가 늘어놓은 장난감 언제 치울 거니? 150 | kss/wavs/4/4_1704.wav|네가 그러니까 병이 났지. 151 | kss/wavs/4/4_0428.wav|이 소포를 제일 빠른 방법으로 보내고 싶은데요. 152 | kss/wavs/3/3_0755.wav|몸살 기운이 좀 있어요. 153 | kss/wavs/4/4_0423.wav|볼 좀 이쪽으로 던져 줄래? 154 | kss/wavs/4/4_2310.wav|홍수가 나서 그 마을은 엄청난 피해가 발생했다. 155 | kss/wavs/4/4_5261.wav|생선을 튀기 156 | kss/wavs/4/4_0384.wav|제 머리는 갈색 빛이 나요. 157 | kss/wavs/3/3_0203.wav|저는 부모님으로부터 아무 주목을 받지 못했어요. 158 | kss/wavs/2/2_0748.wav|요즘 어떻게 지내요? 159 | kss/wavs/3/3_0042.wav|통계적으로 볼 때 여자가 남자보다 수명이 길다. 160 | kss/wavs/4/4_3046.wav|질서를 지켜서 입장해 주시기 바랍니다. 161 | kss/wavs/3/3_2900.wav|저는 그 신문에 매주 글을 쓰고 있어요. 162 | kss/wavs/4/4_1891.wav|일곱 시 공연 표 석 장 주세요. 163 | kss/wavs/3/3_3560.wav|전화번호 알려주시면 내일 제가 전화할게요. 164 | kss/wavs/3/3_0320.wav|저는 양치를 하루에 세 번 합니다. 165 | kss/wavs/2/2_0658.wav|신속한 답변 감사합니다. 166 | kss/wavs/2/2_1062.wav|눈이 파랗게 멍들었어요. 167 | kss/wavs/3/3_2637.wav|회사의 생존을 위해 대규모 구조조정이 불가피합니다. 168 | kss/wavs/3/3_1125.wav|선생님 말씀에 좀 더 주의를 기울여라. 169 | kss/wavs/3/3_2408.wav|내 여자 친구는 나보다 네 살 어린 대학생이야. 170 | kss/wavs/3/3_2622.wav|회의가 언제 끝날 것 같아요? 171 | kss/wavs/3/3_0973.wav|내가 꿈꾸던 날이 다가오자 심장이 두근거리기 시작했다. 172 | kss/wavs/3/3_4635.wav|배고플 텐데, 밥 먹으러 가자. 173 | kss/wavs/3/3_4152.wav|잠이 막 들려던 차에 전화가 왔다. 174 | kss/wavs/3/3_2335.wav|우정은 남녀 모두에게 중요하다. 175 | kss/wavs/2/2_0572.wav|그는 상당한 양의 음반을 갖고 있다. 176 | kss/wavs/4/4_1086.wav|이 작업을 하려면 도구가 몇 개 필요해요. 177 | kss/wavs/1/1_0649.wav|그녀는 그 일을 맡기를 꺼려했다. 178 | kss/wavs/1/1_0100.wav|우리는 파티 준비를 위해 풍선을 불었다. 179 | kss/wavs/4/4_0242.wav|그녀는 따뜻한 미소로 우리를 반겨 주었다. 180 | kss/wavs/2/2_0987.wav|너는 사람이 왜 그렇게 짜? 죽고 나서 그 돈 갖고 갈 거야? 181 | kss/wavs/4/4_4042.wav|나는 높은 곳이 무서워. 182 | kss/wavs/4/4_3646.wav|미리 전화를 하고 오셨어야죠. 183 | kss/wavs/4/4_2375.wav|이 꽃은 향기가 좋아요. 184 | kss/wavs/3/3_0822.wav|저는 혼자 있을 때가 제일 편해요. 185 | kss/wavs/3/3_1716.wav|귀하의 제안을 기꺼이 수락하겠습니다. 186 | kss/wavs/1/1_0218.wav|그때 그녀가 의사를 데려오지 않았으면 나는 죽었을 거야. 187 | kss/wavs/3/3_4061.wav|오늘 저녁에 시간 있어요? 188 | kss/wavs/3/3_3540.wav|내년에 인도에 공장을 세울 예정입니다. 189 | kss/wavs/4/4_2321.wav|몇 시간 후에 돌아올 거야. 190 | kss/wavs/2/2_0026.wav|아들을 보고 싶은 마음이 간절합니다. 191 | kss/wavs/4/4_2475.wav|네가 지금 하는 얘기는 내가 들은 것하고 일치하지 않아. 192 | kss/wavs/1/1_0515.wav|그는 약속을 잘 지키는 사람이다. 193 | kss/wavs/1/1_0750.wav|페이지를 한 장 넘겨라. 194 | kss/wavs/4/4_4540.wav|내 여동생이 사월에 아기를 낳을 예정이야. 195 | kss/wavs/4/4_3312.wav|재녹음 196 | kss/wavs/3/3_4139.wav|일단 밥부터 먹자. 197 | kss/wavs/4/4_0137.wav|네가 상관할 바가 아냐. 198 | kss/wavs/4/4_4406.wav|돈이 생기면 갚을게요. 199 | kss/wavs/3/3_2728.wav|그 차는 어둠 속으로 사라졌다. 200 | kss/wavs/3/3_3714.wav|그 골목은 아주 좁았다. 201 | kss/wavs/4/4_0452.wav|너도 그 일에 부분적으로 책임이 있어. 202 | kss/wavs/4/4_4559.wav|자기 발등을 자기가 찍은 셈이지. 203 | kss/wavs/3/3_1446.wav|저는 아름답고 평온한 한 마을에서 태어났어요. 204 | kss/wavs/3/3_4995.wav|건강하 205 | kss/wavs/3/3_3539.wav|정부는 중소기업 지원을 약속했다. 206 | kss/wavs/3/3_4598.wav|밤이 되자 그녀의 상태가 더욱 나빠졌다. 207 | kss/wavs/3/3_3867.wav|자동차 매연은 스모그의 주요 원인 중 하나다. 208 | kss/wavs/3/3_0434.wav|그는 할 수 있는 한 멀리 공을 던졌다. 209 | kss/wavs/2/2_0799.wav|그 여자랑 헤어진 지 오래야. 210 | kss/wavs/2/2_0011.wav|가능한 한 빨리 좀 와 줘. 211 | kss/wavs/3/3_0311.wav|저에겐 휴식이 필요해요. 212 | kss/wavs/4/4_3785.wav|길을 묻는 게 저한테는 너무 힘들어요. 213 | kss/wavs/4/4_4877.wav|솔직히 말해서 저는 제 외모에 별로 자신이 없어요. 214 | kss/wavs/2/2_0616.wav|예상 외로 나는 그를 손쉽게 이겼다. 215 | kss/wavs/3/3_1644.wav|제 소개를 하겠습니다. 216 | kss/wavs/4/4_3830.wav|화를 내고 나면 기분이 더 나빠질 거예요. 217 | kss/wavs/4/4_3907.wav|내가 나뭇가지를 모아 올 테니까 너는 구멍을 파. 218 | kss/wavs/4/4_2513.wav|이모가 졸업 선물로 노트북을 사 줬어요. 219 | kss/wavs/3/3_1390.wav|그 사람들한테 네 실력을 보여줘. 220 | kss/wavs/3/3_1451.wav|아버지는 아주 점잖은 분이셨어요. 221 | kss/wavs/4/4_1628.wav|그 사람은 결혼 이후 그전보다 더 열심히 일한다. 222 | kss/wavs/2/2_0680.wav|이 물건은 싸지만 품질은 좋아. 223 | kss/wavs/3/3_0200.wav|코치는 아이들이 축구를 하는 것을 지켜보고 있다. 224 | kss/wavs/1/1_0317.wav|벽에 많은 옷이 걸려 있다. 225 | kss/wavs/4/4_4442.wav|이 서류에 사인해 주세요. 226 | kss/wavs/3/3_3412.wav|공원 주변에 상업 시설들이 들어설 겁니다. 227 | kss/wavs/4/4_1337.wav|그 책 다 읽은 후에 빌려 줄래? 228 | kss/wavs/3/3_3174.wav|제가 뭘 잘못했죠? 229 | kss/wavs/2/2_0918.wav|지금 제 상황이 절박합니다. 230 | kss/wavs/4/4_4617.wav|여기 네 생일 선물. 231 | kss/wavs/2/2_0600.wav|아들 녀석이 고집이 너무 세서 걱정이야. 232 | kss/wavs/4/4_3108.wav|여행 일정은 다 짰어요? 233 | kss/wavs/4/4_1429.wav|갈비 먹어 봤어요? 234 | kss/wavs/2/2_0533.wav|왜 너는 불필요한 물건들을 늘 사니? 235 | kss/wavs/4/4_2621.wav|침대 옆 탁자 위에 있어요. 236 | kss/wavs/4/4_1277.wav|천천히 먹어라. 237 | kss/wavs/4/4_5194.wav|이번에는 당신 의견에 따르겠습니다. 238 | kss/wavs/3/3_2160.wav|다리 밑으로 개울이 흘러요. 239 | kss/wavs/3/3_2282.wav|어젯밤에 마누라랑 싸웠어요. 240 | kss/wavs/3/3_3038.wav|그녀는 자신이 기차에서 성추행을 당했다고 주장했다. 241 | kss/wavs/4/4_3486.wav|매년 여름이 더 더워지고 있어요. 242 | kss/wavs/4/4_0925.wav|빨래는 제 담당이에요. 243 | kss/wavs/3/3_3382.wav|김 대리가 제조 공정에 관해 설명해 드리겠습니다. 244 | kss/wavs/4/4_0122.wav|아래 그림을 참고하세요. 245 | kss/wavs/4/4_2832.wav|한국에는 절이 아주 많습니다. 246 | kss/wavs/3/3_2304.wav|사랑하는 사람과 이별하는 일은 힘든 법이다. 247 | kss/wavs/4/4_4199.wav|법원은 우리가 벌금을 내야 한다고 판결했어요. 248 | kss/wavs/4/4_5401.wav|저 남자 얄미워 죽겠어. 249 | kss/wavs/3/3_1285.wav|지난 몇 년간 상황이 나아지고 있다. 250 | kss/wavs/3/3_0405.wav|나는 스위치를 찾아 어둠 속을 더듬었다. 251 | kss/wavs/3/3_3812.wav|오늘은 날씨 때문에 배가 안 뜹니다. 252 | kss/wavs/4/4_3469.wav|공이 당신을 맞히면 게임에서 지는 겁니다. 253 | kss/wavs/3/3_0639.wav|창문을 열면 신선한 공기가 들어올 거야. 254 | kss/wavs/2/2_0268.wav|커피가 너무 달아요. 255 | kss/wavs/4/4_1688.wav|세상에. 그래서 어떻게 했니? 256 | kss/wavs/4/4_0946.wav|저는 이 집 단골이에요. 257 | kss/wavs/4/4_0523.wav|말이 안되서 제가 알아서 녹음 258 | kss/wavs/3/3_1126.wav|일에 매달려 있다 보니 하루가 금세 가 버렸다. 259 | kss/wavs/1/1_0844.wav|한국어로 제 생각을 표현하는 게 쉽지 않아요. 260 | kss/wavs/4/4_3489.wav|너는 미소가 참 매력적이구나. 261 | kss/wavs/4/4_3653.wav|침대 밑은 봤어? 262 | kss/wavs/2/2_0069.wav|그는 정신이 건전한 젊은이입니다. 263 | kss/wavs/3/3_2123.wav|고기를 바싹 익혀 주세요. 264 | kss/wavs/3/3_0537.wav|저는 손톱을 깨무는 나쁜 버릇이 있어요. 265 | kss/wavs/3/3_0422.wav|꽃잎들이 눈처럼 떨어졌다. 266 | kss/wavs/4/4_4740.wav|언제 식사 한번 같이 하시죠. 267 | kss/wavs/4/4_3651.wav|토요일에 미술관 갈래? 268 | kss/wavs/4/4_3781.wav|나는 물속에 들어가는 게 무서워. 269 | kss/wavs/4/4_1694.wav|그럴듯한 핑계를 대는구나. 270 | kss/wavs/3/3_1361.wav|그는 힘이 엄청 세다. 271 | kss/wavs/3/3_2950.wav|현재 우리나라의 인구는 오천만이 넘는다. 272 | kss/wavs/3/3_2271.wav|그는 다섯 남매를 두었다. 273 | kss/wavs/3/3_1633.wav|왜 나한테 고함치고 그래? 274 | kss/wavs/3/3_4657.wav|두 점을 자와 연필을 이용해 이으시오. 275 | kss/wavs/4/4_4465.wav|실내에서는 흡연을 삼가 주십시오. 276 | kss/wavs/4/4_2953.wav|저런, 비를 많이 맞았구나. 277 | kss/wavs/1/1_0178.wav|엄마가 돌아가신 후 모든 것이 달라졌어요. 278 | kss/wavs/3/3_3704.wav|저는 오토바이로 출퇴근을 합니다. 279 | kss/wavs/4/4_0327.wav|이 옷 정말 버리기 아까워요. 280 | kss/wavs/2/2_0114.wav|가끔은 사는 게 공허하게 느껴져요. 281 | kss/wavs/3/3_1814.wav|내가 왜 늦게 도착했는지 설명할게요. 282 | kss/wavs/4/4_2787.wav|집에 있는 먼지를 제거하려면 어떻게 해야 하나요? 283 | kss/wavs/3/3_4666.wav|부지런한 건 여전하구나. 284 | kss/wavs/3/3_3743.wav|그는 신호를 어기지 않았다고 주장했다. 285 | kss/wavs/4/4_4452.wav|저는 물만 먹어도 살이 쪄요. 286 | kss/wavs/3/3_1083.wav|네 말은 앞뒤가 안 맞아. 287 | kss/wavs/3/3_4923.wav|이곳에서 오래 사셨습니까? 288 | kss/wavs/3/3_0131.wav|손이 참 따뜻하시네요. 289 | kss/wavs/4/4_4766.wav|나는 저런 타입의 남자는 싫어. 290 | kss/wavs/3/3_0118.wav|귀가 울려요. 291 | kss/wavs/3/3_4643.wav|그녀는 의외로 날씬했다. 292 | kss/wavs/2/2_0611.wav|봐 달라고 빌어 봤자 소용없다. 293 | kss/wavs/4/4_0406.wav|케이크는 차가운 곳에 보관하세요. 294 | kss/wavs/4/4_4513.wav|엔진은 상태가 괜찮습니다. 295 | kss/wavs/3/3_0907.wav|그는 깊은 슬픔에 잠겨 있다. 296 | kss/wavs/2/2_0681.wav|싼 게 비지떡이다. 297 | kss/wavs/4/4_4539.wav|그녀는 사위가 별로 마음에 들지 않았다. 298 | kss/wavs/4/4_4080.wav|저는 이 남 일 녀 중 막내예요. 299 | kss/wavs/3/3_0219.wav|저는 귀가 어두운데 다른 사람의 얘기를 아주 잘 들어 준다는 말을 많이 들어왔어요. 300 | kss/wavs/3/3_2174.wav|어디로 이사하세요? 301 | kss/wavs/3/3_2130.wav|찐 감자 좋아해? 302 | kss/wavs/3/3_3469.wav|만 원짜리 지폐를 잔돈으로 바꿀 수 있을까요? 303 | kss/wavs/2/2_0481.wav|말하기 부끄럽지만, 저는 엄마 생일이 언제인지 몰라요. 304 | kss/wavs/1/1_0861.wav|다음 대통령이 가장 먼저 해야 할 일은 경제를 살리는 것이다. 305 | kss/wavs/3/3_2368.wav|아빠한테 뽀뽀. 306 | kss/wavs/2/2_1055.wav|저는 특정한 후보를 지지하지 않습니다. 307 | kss/wavs/3/3_4137.wav|먼저 가세요. 308 | kss/wavs/4/4_3087.wav|나한테 소리 지르지 마세요! 309 | kss/wavs/3/3_0158.wav|그는 짧은 회색 수염을 기르고 있었다. 310 | kss/wavs/3/3_4766.wav|내가 그랬어. 311 | kss/wavs/4/4_2957.wav|재활용을 하면 에너지를 크게 절약할 수 있어요. 312 | kss/wavs/3/3_3452.wav|아내는 부잣집 외동딸이에요. 313 | kss/wavs/1/1_0525.wav|여름 방학이 눈 깜짝할 사이에 지나갔어. 314 | kss/wavs/3/3_3492.wav|보험사는 보험금 지급을 거부했다. 315 | kss/wavs/4/4_2332.wav|화분에 물을 일주일에 두 번만 주세요. 316 | kss/wavs/4/4_2454.wav|한 언어를 익히려면 많은 시간이 필요하다. 317 | kss/wavs/4/4_2987.wav|이 고기는 지방이 너무 많아. 318 | kss/wavs/2/2_0757.wav|아직 그 사람하고 사이가 좀 어색해요. 319 | kss/wavs/3/3_0463.wav|쓰레기를 바깥에 내놓아라. 320 | kss/wavs/4/4_0103.wav|여기 앉아도 되나요? 321 | kss/wavs/3/3_1424.wav|그 큰돈을 그 자식한테 주다니 너 참 순진하구나. 322 | kss/wavs/1/1_0134.wav|교차로에서 저를 찾을 수 있을 거예요. 323 | kss/wavs/3/3_0899.wav|파티에 갈 수가 없어서 속상해. 324 | kss/wavs/3/3_3994.wav|우리는 금요일 오후에 떠나 일요일 저녁에 돌아올 수 있을 거라 생각했어요. 325 | kss/wavs/3/3_0116.wav|속눈썹이 자꾸 눈을 찔러요. 326 | kss/wavs/2/2_0643.wav|손이 너무 시려요. 327 | kss/wavs/3/3_1594.wav|이번 방학 기간에 영어 회화를 정복하고 싶어요. 328 | kss/wavs/4/4_4614.wav|아버지는 선장이셨어요. 329 | kss/wavs/3/3_1880.wav|옷 갈아입을 거야. 데이트가 있거든. 330 | kss/wavs/4/4_3422.wav|오늘 엄마한테 꾸중을 들어서 기분이 별로예요. 331 | kss/wavs/1/1_0235.wav|오늘은 집으로 일찍 들어와라. 332 | kss/wavs/4/4_2466.wav|저는 결혼한 지 일 년 됐어요. 333 | kss/wavs/3/3_2213.wav|에이. 내 열쇠 어디 갔지? 비. 침대 위는 봤어? 334 | kss/wavs/3/3_3790.wav|제 고향에는 아직 지하철이 없어요. 335 | kss/wavs/1/1_0011.wav|장사가 잘 안돼서 우울해. 336 | kss/wavs/3/3_3240.wav|한순간의 부주의가 치명적인 사고를 야기할 수도 있습니다. 337 | kss/wavs/3/3_3329.wav|저희 가족은 주말이면 부모님 농장에서 일합니다. 338 | kss/wavs/4/4_1005.wav|무슨 일이 있더라도 나는 네 편이야. 339 | kss/wavs/3/3_0583.wav|지하철 안은 발 디딜 틈도 없었다. 340 | kss/wavs/3/3_1104.wav|그 이론은 아직 검증이 되지 않았다. 341 | kss/wavs/2/2_0390.wav|저는 제가 못생겼다고 생각하지 않아요. 342 | kss/wavs/3/3_2412.wav|학생증을 어디서 발급받나요? 343 | kss/wavs/4/4_0183.wav|박스 옮기는 거 도와 줄까? 344 | kss/wavs/4/4_5564.wav|그들은 가난했지만 행복했다. 345 | kss/wavs/3/3_2559.wav|그것은 명백한 사실입니다. 346 | kss/wavs/1/1_0680.wav|이 문제에 관해서는 나는 아무것도 몰라. 347 | kss/wavs/4/4_2977.wav|이전에 비슷한 증상이 있었나요? 348 | kss/wavs/4/4_0345.wav|비빔밥은 해외에서도 먹을 수 있어. 349 | kss/wavs/3/3_3330.wav|많은 농경지가 침수되었다. 350 | kss/wavs/4/4_3752.wav|물론이지! 351 | kss/wavs/3/3_4551.wav|세월 참 빠르네. 352 | kss/wavs/3/3_2743.wav|삼 박 사 일 353 | kss/wavs/4/4_1796.wav|기름 안 튀게 조심해라. 354 | kss/wavs/3/3_2025.wav|배불러서 더는 못 먹겠어. 355 | kss/wavs/3/3_1360.wav|그 여자는 키가 작고 약간 통통한 편이다. 356 | kss/wavs/3/3_1722.wav|수학여행에 대한 부모님의 서면 동의가 필요합니다. 357 | kss/wavs/3/3_4979.wav|매달 358 | kss/wavs/2/2_0314.wav|옷을 따뜻하게 입고 나가라. 359 | kss/wavs/4/4_0853.wav|저는 대학교수입니다. 360 | kss/wavs/3/3_2993.wav|개표는 여섯 시 정각에 시작합니다. 361 | kss/wavs/3/3_3817.wav|지구에는 위성이 단 하나 있는데 그것이 바로 달이다. 362 | kss/wavs/4/4_2222.wav|여기 숫자들을 모두 합해 봐. 363 | kss/wavs/3/3_4224.wav|이 요구르트는 유통기한이 지났는데. 364 | kss/wavs/3/3_0407.wav|저는 치약을 중간에서부터 짭니다. 365 | kss/wavs/4/4_5254.wav|그 사람은 주식에 투자했다가 전 재산을 날렸다. 366 | kss/wavs/3/3_3816.wav|로켓이 성공적으로 과학 위성을 궤도에 진입시켰다. 367 | kss/wavs/4/4_4468.wav|사모님께서 향수를 좋아하시나요? 368 | kss/wavs/3/3_1953.wav|에이. 가격이 내렸어요? 비. 네. 올해부터 가격을 천 원 내렸어요. 369 | kss/wavs/3/3_4195.wav|갈수록 흰머리가 늘어요. 370 | kss/wavs/3/3_3516.wav|원화를 달러로 환전하고 싶은데요. 371 | kss/wavs/4/4_4970.wav|나는 내 아이가 씩씩하게 자랐으면 좋겠어요. 372 | kss/wavs/4/4_5172.wav|그 사람도 때로는 실수를 해요. 373 | kss/wavs/4/4_1357.wav|원하는 곳에 앉으십시오. 374 | kss/wavs/3/3_3445.wav|저는 늘 전기를 절약하려고 노력합니다. 375 | kss/wavs/1/1_0486.wav|그는 자신이 거의 도둑을 잡을 뻔했다고 말했다. 376 | kss/wavs/4/4_3916.wav|어제는 하루 종일 방에서 나오지 않았어요. 377 | kss/wavs/3/3_1745.wav|엄마는 저에게 공부하라는 얘기를 귀에 못이 박힐 정도로 하세요. 378 | kss/wavs/3/3_3833.wav|그 정원은 오후가 되면 그늘이 진다. 379 | kss/wavs/4/4_1534.wav|저는 가요도 즐겨 들어요. 380 | kss/wavs/3/3_4691.wav|사람은 물 없이는 살 수 없다. 381 | kss/wavs/4/4_0953.wav|밤에 혼자 다니는 것은 위험해요. 382 | kss/wavs/4/4_2214.wav|한식으로 할까, 아니면 일식으로 할까? 383 | kss/wavs/4/4_1879.wav|몇몇 사람들은 자신이 공중에 뜰 수 있다고 주장합니다. 384 | kss/wavs/4/4_1396.wav|가구 위치를 좀 바꿔 보면 어떨까? 385 | kss/wavs/4/4_5403.wav|양은 풀을 먹고 산다. 386 | kss/wavs/4/4_4660.wav|이곳에서 오래 사셨습니까? 387 | kss/wavs/3/3_2646.wav|우리 회사에서는 직급이 올라가면 연봉도 올라간다. 388 | kss/wavs/4/4_3181.wav|점심을 많이 먹었더니 졸음이 와요. 389 | kss/wavs/3/3_1987.wav|요즘에는 많은 사람들이 아침에 밥 대신 빵을 먹는다. 390 | kss/wavs/4/4_3022.wav|지식은 지혜와 별로 관계가 없어요. 391 | kss/wavs/3/3_0265.wav|방바닥이 얼음같이 차가워요. 392 | kss/wavs/4/4_3328.wav|키가 얼마예요? 393 | kss/wavs/3/3_3894.wav|신발에 모래가 들어갔어. 394 | kss/wavs/3/3_4425.wav|책의 두께가 얇군요. 395 | kss/wavs/3/3_3127.wav|그 전쟁의 희생자들 대부분 평범한 사람들이었다. 396 | kss/wavs/2/2_0315.wav|따뜻한 차 한 잔 드시겠어요? 397 | kss/wavs/4/4_2985.wav|한국은 삼십오 년 동안 일본의 지배를 받았다. 398 | kss/wavs/3/3_4422.wav|슈퍼가 우리 집에서 가까운 곳에 있어. 399 | kss/wavs/2/2_0899.wav|아들 녀석은 잘생겨서 여자들한테 인기가 많아요. 400 | kss/wavs/3/3_4485.wav|가득 넣어 주세요. 401 | kss/wavs/3/3_0429.wav|나뭇가지를 꺾으면 안 된다. 402 | kss/wavs/3/3_3084.wav|그 정치인은 뇌물을 받은 혐의로 기소되었다. 403 | kss/wavs/3/3_0554.wav|어른에게 인사할 때는 고개를 숙여야지. 404 | kss/wavs/4/4_2161.wav|제 남편은 저랑 같은 학과를 나왔어요. 405 | kss/wavs/4/4_4729.wav|요즘 누가 시집을 사? 406 | kss/wavs/3/3_2355.wav|두 사람 교제한 지 얼마나 된 거야? 407 | kss/wavs/4/4_1830.wav|그 사람은 아내를 잃고 난 뒤 술로 괴로움을 달랬다. 408 | kss/wavs/3/3_1348.wav|이 옷 입으니까 나 뚱뚱해 보이지 않아? 409 | kss/wavs/3/3_4090.wav|그때 당시 저는 고작 세 살이었어요. 410 | kss/wavs/3/3_0520.wav|생일 선물로 뭐 받고 싶어? 411 | kss/wavs/2/2_0770.wav|이 화재로 엄청난 재산 손실이 발생했다. 412 | kss/wavs/1/1_1035.wav|내일은 제일 중요한 장면을 연습할 거야. 413 | kss/wavs/2/2_0641.wav|저는 시끄러운 건 질색이에요. 414 | kss/wavs/2/2_0289.wav|아내는 얼굴이 작고 동그래요. 415 | kss/wavs/4/4_4154.wav|머릿속에 온통 그 여자 생각뿐이야. 416 | kss/wavs/1/1_0916.wav|저를 소개하겠습니다. 417 | kss/wavs/4/4_4093.wav|한때는 외아들은 군대에 가지 않았지만 지금은 아니다. 418 | kss/wavs/3/3_3954.wav|암컷이야, 수컷이야? 419 | kss/wavs/4/4_5150.wav|이 문장은 뜻이 안 통해요. 420 | kss/wavs/4/4_3319.wav|큰길에 가서 삼 번 버스를 타세요. 421 | kss/wavs/3/3_3482.wav|저는 주식 투자로 많은 돈을 벌었습니다. 422 | kss/wavs/4/4_2983.wav|누가 안 왔지? 423 | kss/wavs/3/3_0810.wav|선생님이 널 보면 기뻐하실 거야. 424 | kss/wavs/1/1_0563.wav|소리 좀 줄여 주실래요? 425 | kss/wavs/2/2_0431.wav|한마디 말도 없이 그만두다니 그 사람 참 무책임하군. 426 | kss/wavs/4/4_0223.wav|시작이 반이야. 427 | kss/wavs/3/3_4010.wav|새 학기가 내달에 시작된다. 428 | kss/wavs/3/3_0217.wav|내 말 좀 들어 봐. 429 | kss/wavs/4/4_5616.wav|의사 말로는 저한테 남은 시간이 육 개월이래요. 430 | kss/wavs/4/4_5357.wav|집은 괜찮은데 위치가 마음에 안 들어요. 431 | kss/wavs/4/4_2252.wav|상처에서 피가 계속 흘러나와요. 432 | kss/wavs/4/4_2625.wav|여기는 너무 추워서 더 못 있겠어. 433 | kss/wavs/3/3_3126.wav|저는 육군 병장으로 전역했어요. 434 | kss/wavs/4/4_2417.wav|오늘은 달이 참 밝네요! 435 | kss/wavs/3/3_1628.wav|그가 천재라는 말은 결코 과장이 아니다. 436 | kss/wavs/4/4_4807.wav|신호가 바뀌는 걸 못 봤어요. 437 | kss/wavs/4/4_0936.wav|배가 단단한 물체에 부딪혔어요. 438 | kss/wavs/4/4_5128.wav|더 좋은 방법이 틀림없이 있을 거야. 439 | kss/wavs/3/3_0166.wav|근육은 내부 장기들을 보호한다. 440 | kss/wavs/3/3_2016.wav|점심을 적게 먹어서 세 시에 간식을 먹었어요. 441 | kss/wavs/4/4_4909.wav|손톱을 너무 짧게 깎았어요. 442 | kss/wavs/3/3_2828.wav|그 이야기의 장르는 무엇인가요? 443 | kss/wavs/3/3_2042.wav|나는 음식을 잘 씹지 않는다. 444 | kss/wavs/4/4_0497.wav|그 사람의 책은 많은 논쟁을 불러일으켰다. 445 | kss/wavs/3/3_1218.wav|뚜껑을 열고 보니 결과는 예상과 달랐다. 446 | kss/wavs/4/4_2705.wav|키우던 고양이가 죽어서 딸아이는 슬픔에 잠겨 있어요. 447 | kss/wavs/4/4_0300.wav|제가 돈을 벌고 남편은 아이를 보고 있어요. 448 | kss/wavs/4/4_1701.wav|그런데 밥은 어디서 먹지? 449 | kss/wavs/3/3_1090.wav|사람들은 자주 저를 제 형하고 혼동해요. 450 | kss/wavs/1/1_0003.wav|그는 아내를 많이 아낀다. 451 | kss/wavs/4/4_3359.wav|바닥에 담요가 깔려 있어요. 452 | kss/wavs/3/3_0761.wav|목에 가래가 계속 끼어요. 453 | kss/wavs/3/3_2772.wav|그는 부상 때문에 월드컵 출전이 불투명하다. 454 | kss/wavs/3/3_2356.wav|저는 미팅을 한 번도 안 해 봤어요. 455 | kss/wavs/4/4_2603.wav|지난 십 년 동안 인터넷 산업은 엄청난 발전을 이룩했다. 456 | kss/wavs/2/2_1028.wav|우리의 첫 번째 목표는 치열한 경쟁에서 살아남는 것이다. 457 | kss/wavs/3/3_2026.wav|이제 배가 불러요. 458 | kss/wavs/3/3_1660.wav|더 이상 묻지 마. 459 | kss/wavs/4/4_5017.wav|새로 생긴 술집에 가 보자. 460 | kss/wavs/3/3_4147.wav|아직 자? 461 | kss/wavs/4/4_3362.wav|우리 가족은 피부가 까만 편이에요. 462 | kss/wavs/3/3_2962.wav|민주주의의 근본 이념은 인간 존중이다. 463 | kss/wavs/3/3_4319.wav|에이. 책상은 어떤 모양이에요? 비. 동그래요. 464 | kss/wavs/4/4_3745.wav|물질적 피 465 | kss/wavs/4/4_3215.wav|입맛이 없을 때는 죽이 아주 좋아요. 466 | kss/wavs/3/3_4937.wav|비자를 받을 필요가 없어요. 467 | kss/wavs/3/3_3945.wav|식물이 열매를 맺기 시작하면 많은 물을 필요로 한다. 468 | kss/wavs/4/4_1004.wav|자, 여러분, 책을 덮고 시험 볼 준비하세요. 469 | kss/wavs/3/3_2136.wav|채소가 아주 싱싱해 보이네요. 470 | kss/wavs/4/4_4710.wav|시금치에는 철이 풍부하다. 471 | kss/wavs/1/1_0120.wav|기름을 가득 채워 주세요. 472 | kss/wavs/1/1_1015.wav|버스를 운전할 수 있으세요? 473 | kss/wavs/1/1_0776.wav|나는 춤추는 것보다 노래하는 게 더 좋다. 474 | kss/wavs/4/4_2952.wav|저런 운전자들 때문에 정말 짜증스러워요. 475 | kss/wavs/2/2_0465.wav|남편은 잠귀가 아주 밝아요. 476 | kss/wavs/2/2_0290.wav|반죽을 동그란 모양으로 말아 주세요. 477 | kss/wavs/2/2_0617.wav|자는 것은 시간을 죽이는 가장 손쉬운 방법이다. 478 | kss/wavs/3/3_4604.wav|십팔 세 미만 출입 금 479 | kss/wavs/2/2_0819.wav|한 남자가 아기 앞에서 우스꽝스러운 몸짓을 하고 있다. 480 | kss/wavs/4/4_4050.wav|저는 가능하면 많은 책을 읽으려고 노력하고 있어요. 481 | kss/wavs/4/4_4772.wav|아기는 태어나기 전에 엄마의 심장이 뛰는 소리를 들어요. 482 | kss/wavs/4/4_4662.wav|그 여자는 스물에서 서른 사이인 것 같다. 483 | kss/wavs/3/3_0618.wav|그녀는 파티에 자기 남자 친구를 데려왔다. 484 | kss/wavs/4/4_3106.wav|저는 음식을 약간 짜게 먹어요. 485 | kss/wavs/4/4_5479.wav|배터리를 열 근처에 두지 마세요. 486 | kss/wavs/1/1_0997.wav|이 문장은 무엇을 뜻합니까? 487 | kss/wavs/3/3_1531.wav|일이 끝나지 않았는데 가다니 자네 참 무책임하군. 488 | kss/wavs/4/4_4918.wav|누군가 도와 달라고 소리쳤다. 489 | kss/wavs/3/3_1620.wav|말 돌리지 말고 핵심을 말해 봐. 490 | kss/wavs/3/3_3794.wav|지하철 입구는 어디에 있어요? 491 | kss/wavs/3/3_3022.wav|저는 얼굴과 온몸을 맞았습니다. 492 | kss/wavs/4/4_4738.wav|식빵으로 만들 수 있는 간단한 요리 알아요? 493 | kss/wavs/3/3_4060.wav|이따 오후에 오세요. 494 | kss/wavs/4/4_2643.wav|노래 자체는 좋은데, 가수가 별로야. 495 | kss/wavs/3/3_0148.wav|수업 시간에 축구를 하다가 다리를 다쳤어요. 496 | kss/wavs/2/2_0360.wav|그렇게 맛없는 음식은 처음이었어. 497 | kss/wavs/4/4_4630.wav|저는 아직 운전이 서툴러서 운전을 할 때마다 긴장돼요. 498 | kss/wavs/4/4_4245.wav|포도주는 치즈랑 같이 먹으면 딱이에요. 499 | kss/wavs/4/4_4316.wav|비 온 뒤 하늘은 푸르네요. 500 | kss/wavs/4/4_1119.wav|얼마 전에 중학교 동창회가 있었어요. 501 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | import torch 3 | from torch.autograd import Variable 4 | from torch import nn 5 | from torch.nn import functional as F 6 | from layers import ConvNorm, LinearNorm 7 | from utils import to_gpu, get_mask_from_lengths 8 | from fp16_optimizer import fp32_to_fp16, fp16_to_fp32 9 | 10 | 11 | class LocationLayer(nn.Module): 12 | def __init__(self, attention_n_filters, attention_kernel_size, 13 | attention_dim): 14 | super(LocationLayer, self).__init__() 15 | padding = int((attention_kernel_size - 1) / 2) 16 | self.location_conv = ConvNorm(2, attention_n_filters, 17 | kernel_size=attention_kernel_size, 18 | padding=padding, bias=False, stride=1, 19 | dilation=1) 20 | self.location_dense = LinearNorm(attention_n_filters, attention_dim, 21 | bias=False, w_init_gain='tanh') 22 | 23 | def forward(self, attention_weights_cat): 24 | processed_attention = self.location_conv(attention_weights_cat) 25 | processed_attention = processed_attention.transpose(1, 2) 26 | processed_attention = self.location_dense(processed_attention) 27 | return processed_attention 28 | 29 | 30 | class Attention(nn.Module): 31 | def __init__(self, attention_rnn_dim, embedding_dim, attention_dim, 32 | attention_location_n_filters, attention_location_kernel_size): 33 | super(Attention, self).__init__() 34 | self.query_layer = LinearNorm(attention_rnn_dim, attention_dim, 35 | bias=False, w_init_gain='tanh') 36 | self.memory_layer = LinearNorm(embedding_dim, attention_dim, bias=False, 37 | w_init_gain='tanh') 38 | self.v = LinearNorm(attention_dim, 1, bias=False) 39 | self.location_layer = LocationLayer(attention_location_n_filters, 40 | attention_location_kernel_size, 41 | attention_dim) 42 | self.score_mask_value = -float("inf") 43 | 44 | def get_alignment_energies(self, query, processed_memory, 45 | attention_weights_cat): 46 | """ 47 | PARAMS 48 | ------ 49 | query: decoder output (batch, n_mel_channels * n_frames_per_step) 50 | processed_memory: processed encoder outputs (B, T_in, attention_dim) 51 | attention_weights_cat: cumulative and prev. att weights (B, 2, max_time) 52 | 53 | RETURNS 54 | ------- 55 | alignment (batch, max_time) 56 | """ 57 | 58 | processed_query = self.query_layer(query.unsqueeze(1)) 59 | processed_attention_weights = self.location_layer(attention_weights_cat) 60 | energies = self.v(torch.tanh( 61 | processed_query + processed_attention_weights + processed_memory)) 62 | 63 | energies = energies.squeeze(-1) 64 | return energies 65 | 66 | def forward(self, attention_hidden_state, memory, processed_memory, 67 | attention_weights_cat, mask): 68 | """ 69 | PARAMS 70 | ------ 71 | attention_hidden_state: attention rnn last output 72 | memory: encoder outputs 73 | processed_memory: processed encoder outputs 74 | attention_weights_cat: previous and cummulative attention weights 75 | mask: binary mask for padded data 76 | """ 77 | alignment = self.get_alignment_energies( 78 | attention_hidden_state, processed_memory, attention_weights_cat) 79 | 80 | if mask is not None: 81 | alignment.data.masked_fill_(mask, self.score_mask_value) 82 | 83 | attention_weights = F.softmax(alignment, dim=1) 84 | attention_context = torch.bmm(attention_weights.unsqueeze(1), memory) 85 | attention_context = attention_context.squeeze(1) 86 | 87 | return attention_context, attention_weights 88 | 89 | 90 | class Prenet(nn.Module): 91 | def __init__(self, in_dim, sizes): 92 | super(Prenet, self).__init__() 93 | in_sizes = [in_dim] + sizes[:-1] 94 | self.layers = nn.ModuleList( 95 | [LinearNorm(in_size, out_size, bias=False) 96 | for (in_size, out_size) in zip(in_sizes, sizes)]) 97 | 98 | def forward(self, x): 99 | for linear in self.layers: 100 | x = F.dropout(F.relu(linear(x)), p=0.5, training=True) 101 | return x 102 | 103 | 104 | class Postnet(nn.Module): 105 | """Postnet 106 | - Five 1-d convolution with 512 channels and kernel size 5 107 | """ 108 | 109 | def __init__(self, hparams): 110 | super(Postnet, self).__init__() 111 | self.convolutions = nn.ModuleList() 112 | 113 | self.convolutions.append( 114 | nn.Sequential( 115 | ConvNorm(hparams.n_mel_channels, hparams.postnet_embedding_dim, 116 | kernel_size=hparams.postnet_kernel_size, stride=1, 117 | padding=int((hparams.postnet_kernel_size - 1) / 2), 118 | dilation=1, w_init_gain='tanh'), 119 | nn.BatchNorm1d(hparams.postnet_embedding_dim)) 120 | ) 121 | 122 | for i in range(1, hparams.postnet_n_convolutions - 1): 123 | self.convolutions.append( 124 | nn.Sequential( 125 | ConvNorm(hparams.postnet_embedding_dim, 126 | hparams.postnet_embedding_dim, 127 | kernel_size=hparams.postnet_kernel_size, stride=1, 128 | padding=int((hparams.postnet_kernel_size - 1) / 2), 129 | dilation=1, w_init_gain='tanh'), 130 | nn.BatchNorm1d(hparams.postnet_embedding_dim)) 131 | ) 132 | 133 | self.convolutions.append( 134 | nn.Sequential( 135 | ConvNorm(hparams.postnet_embedding_dim, hparams.n_mel_channels, 136 | kernel_size=hparams.postnet_kernel_size, stride=1, 137 | padding=int((hparams.postnet_kernel_size - 1) / 2), 138 | dilation=1, w_init_gain='linear'), 139 | nn.BatchNorm1d(hparams.n_mel_channels)) 140 | ) 141 | 142 | def forward(self, x): 143 | for i in range(len(self.convolutions) - 1): 144 | x = F.dropout(torch.tanh(self.convolutions[i](x)), 0.5, self.training) 145 | x = F.dropout(self.convolutions[-1](x), 0.5, self.training) 146 | 147 | return x 148 | 149 | 150 | class Encoder(nn.Module): 151 | """Encoder module: 152 | - Three 1-d convolution banks 153 | - Bidirectional LSTM 154 | """ 155 | def __init__(self, hparams): 156 | super(Encoder, self).__init__() 157 | 158 | convolutions = [] 159 | for _ in range(hparams.encoder_n_convolutions): 160 | conv_layer = nn.Sequential( 161 | ConvNorm(hparams.encoder_embedding_dim, 162 | hparams.encoder_embedding_dim, 163 | kernel_size=hparams.encoder_kernel_size, stride=1, 164 | padding=int((hparams.encoder_kernel_size - 1) / 2), 165 | dilation=1, w_init_gain='relu'), 166 | nn.BatchNorm1d(hparams.encoder_embedding_dim)) 167 | convolutions.append(conv_layer) 168 | self.convolutions = nn.ModuleList(convolutions) 169 | 170 | self.lstm = nn.LSTM(hparams.encoder_embedding_dim, 171 | int(hparams.encoder_embedding_dim / 2), 1, 172 | batch_first=True, bidirectional=True) 173 | 174 | def forward(self, x, input_lengths): 175 | for conv in self.convolutions: 176 | x = F.dropout(F.relu(conv(x)), 0.5, self.training) 177 | 178 | x = x.transpose(1, 2) 179 | 180 | # pytorch tensor are not reversible, hence the conversion 181 | input_lengths = input_lengths.cpu().numpy() 182 | x = nn.utils.rnn.pack_padded_sequence( 183 | x, input_lengths, batch_first=True) 184 | 185 | self.lstm.flatten_parameters() 186 | outputs, _ = self.lstm(x) 187 | 188 | outputs, _ = nn.utils.rnn.pad_packed_sequence( 189 | outputs, batch_first=True) 190 | 191 | return outputs 192 | 193 | def inference(self, x): 194 | for conv in self.convolutions: 195 | x = F.dropout(F.relu(conv(x)), 0.5, self.training) 196 | 197 | x = x.transpose(1, 2) 198 | 199 | self.lstm.flatten_parameters() 200 | outputs, _ = self.lstm(x) 201 | 202 | return outputs 203 | 204 | 205 | class Decoder(nn.Module): 206 | def __init__(self, hparams): 207 | super(Decoder, self).__init__() 208 | self.n_mel_channels = hparams.n_mel_channels 209 | self.n_frames_per_step = hparams.n_frames_per_step 210 | self.encoder_embedding_dim = hparams.encoder_embedding_dim 211 | self.attention_rnn_dim = hparams.attention_rnn_dim 212 | self.decoder_rnn_dim = hparams.decoder_rnn_dim 213 | self.prenet_dim = hparams.prenet_dim 214 | self.max_decoder_steps = hparams.max_decoder_steps 215 | self.gate_threshold = hparams.gate_threshold 216 | self.p_attention_dropout = hparams.p_attention_dropout 217 | self.p_decoder_dropout = hparams.p_decoder_dropout 218 | 219 | self.prenet = Prenet( 220 | hparams.n_mel_channels * hparams.n_frames_per_step, 221 | [hparams.prenet_dim, hparams.prenet_dim]) 222 | 223 | self.attention_rnn = nn.LSTMCell( 224 | hparams.prenet_dim + hparams.encoder_embedding_dim, 225 | hparams.attention_rnn_dim) 226 | 227 | self.attention_layer = Attention( 228 | hparams.attention_rnn_dim, hparams.encoder_embedding_dim, 229 | hparams.attention_dim, hparams.attention_location_n_filters, 230 | hparams.attention_location_kernel_size) 231 | 232 | self.decoder_rnn = nn.LSTMCell( 233 | hparams.attention_rnn_dim + hparams.encoder_embedding_dim, 234 | hparams.decoder_rnn_dim, 1) 235 | 236 | self.linear_projection = LinearNorm( 237 | hparams.decoder_rnn_dim + hparams.encoder_embedding_dim, 238 | hparams.n_mel_channels * hparams.n_frames_per_step) 239 | 240 | self.gate_layer = LinearNorm( 241 | hparams.decoder_rnn_dim + hparams.encoder_embedding_dim, 1, 242 | bias=True, w_init_gain='sigmoid') 243 | 244 | def get_go_frame(self, memory): 245 | """ Gets all zeros frames to use as first decoder input 246 | PARAMS 247 | ------ 248 | memory: decoder outputs 249 | 250 | RETURNS 251 | ------- 252 | decoder_input: all zeros frames 253 | """ 254 | B = memory.size(0) 255 | decoder_input = Variable(memory.data.new( 256 | B, self.n_mel_channels * self.n_frames_per_step).zero_()) 257 | return decoder_input 258 | 259 | def initialize_decoder_states(self, memory, mask): 260 | """ Initializes attention rnn states, decoder rnn states, attention 261 | weights, attention cumulative weights, attention context, stores memory 262 | and stores processed memory 263 | PARAMS 264 | ------ 265 | memory: Encoder outputs 266 | mask: Mask for padded data if training, expects None for inference 267 | """ 268 | B = memory.size(0) 269 | MAX_TIME = memory.size(1) 270 | 271 | self.attention_hidden = Variable(memory.data.new( 272 | B, self.attention_rnn_dim).zero_()) 273 | self.attention_cell = Variable(memory.data.new( 274 | B, self.attention_rnn_dim).zero_()) 275 | 276 | self.decoder_hidden = Variable(memory.data.new( 277 | B, self.decoder_rnn_dim).zero_()) 278 | self.decoder_cell = Variable(memory.data.new( 279 | B, self.decoder_rnn_dim).zero_()) 280 | 281 | self.attention_weights = Variable(memory.data.new( 282 | B, MAX_TIME).zero_()) 283 | self.attention_weights_cum = Variable(memory.data.new( 284 | B, MAX_TIME).zero_()) 285 | self.attention_context = Variable(memory.data.new( 286 | B, self.encoder_embedding_dim).zero_()) 287 | 288 | self.memory = memory 289 | self.processed_memory = self.attention_layer.memory_layer(memory) 290 | self.mask = mask 291 | 292 | def parse_decoder_inputs(self, decoder_inputs): 293 | """ Prepares decoder inputs, i.e. mel outputs 294 | PARAMS 295 | ------ 296 | decoder_inputs: inputs used for teacher-forced training, i.e. mel-specs 297 | 298 | RETURNS 299 | ------- 300 | inputs: processed decoder inputs 301 | 302 | """ 303 | # (B, n_mel_channels, T_out) -> (B, T_out, n_mel_channels) 304 | decoder_inputs = decoder_inputs.transpose(1, 2) 305 | decoder_inputs = decoder_inputs.view( 306 | decoder_inputs.size(0), 307 | int(decoder_inputs.size(1)/self.n_frames_per_step), -1) 308 | # (B, T_out, n_mel_channels) -> (T_out, B, n_mel_channels) 309 | decoder_inputs = decoder_inputs.transpose(0, 1) 310 | return decoder_inputs 311 | 312 | def parse_decoder_outputs(self, mel_outputs, gate_outputs, alignments): 313 | """ Prepares decoder outputs for output 314 | PARAMS 315 | ------ 316 | mel_outputs: 317 | gate_outputs: gate output energies 318 | alignments: 319 | 320 | RETURNS 321 | ------- 322 | mel_outputs: 323 | gate_outpust: gate output energies 324 | alignments: 325 | """ 326 | # (T_out, B) -> (B, T_out) 327 | alignments = torch.stack(alignments).transpose(0, 1) 328 | # (T_out, B) -> (B, T_out) 329 | gate_outputs = torch.stack(gate_outputs).transpose(0, 1) 330 | gate_outputs = gate_outputs.contiguous() 331 | # (T_out, B, n_mel_channels) -> (B, T_out, n_mel_channels) 332 | mel_outputs = torch.stack(mel_outputs).transpose(0, 1).contiguous() 333 | # decouple frames per step 334 | mel_outputs = mel_outputs.view( 335 | mel_outputs.size(0), -1, self.n_mel_channels) 336 | # (B, T_out, n_mel_channels) -> (B, n_mel_channels, T_out) 337 | mel_outputs = mel_outputs.transpose(1, 2) 338 | 339 | return mel_outputs, gate_outputs, alignments 340 | 341 | def decode(self, decoder_input): 342 | """ Decoder step using stored states, attention and memory 343 | PARAMS 344 | ------ 345 | decoder_input: previous mel output 346 | 347 | RETURNS 348 | ------- 349 | mel_output: 350 | gate_output: gate output energies 351 | attention_weights: 352 | """ 353 | cell_input = torch.cat((decoder_input, self.attention_context), -1) 354 | self.attention_hidden, self.attention_cell = self.attention_rnn( 355 | cell_input, (self.attention_hidden, self.attention_cell)) 356 | self.attention_hidden = F.dropout( 357 | self.attention_hidden, self.p_attention_dropout, self.training) 358 | self.attention_cell = F.dropout( 359 | self.attention_cell, self.p_attention_dropout, self.training) 360 | 361 | attention_weights_cat = torch.cat( 362 | (self.attention_weights.unsqueeze(1), 363 | self.attention_weights_cum.unsqueeze(1)), dim=1) 364 | self.attention_context, self.attention_weights = self.attention_layer( 365 | self.attention_hidden, self.memory, self.processed_memory, 366 | attention_weights_cat, self.mask) 367 | 368 | self.attention_weights_cum += self.attention_weights 369 | decoder_input = torch.cat( 370 | (self.attention_hidden, self.attention_context), -1) 371 | self.decoder_hidden, self.decoder_cell = self.decoder_rnn( 372 | decoder_input, (self.decoder_hidden, self.decoder_cell)) 373 | self.decoder_hidden = F.dropout( 374 | self.decoder_hidden, self.p_decoder_dropout, self.training) 375 | self.decoder_cell = F.dropout( 376 | self.decoder_cell, self.p_decoder_dropout, self.training) 377 | 378 | decoder_hidden_attention_context = torch.cat( 379 | (self.decoder_hidden, self.attention_context), dim=1) 380 | decoder_output = self.linear_projection( 381 | decoder_hidden_attention_context) 382 | 383 | gate_prediction = self.gate_layer(decoder_hidden_attention_context) 384 | return decoder_output, gate_prediction, self.attention_weights 385 | 386 | def forward(self, memory, decoder_inputs, memory_lengths): 387 | """ Decoder forward pass for training 388 | PARAMS 389 | ------ 390 | memory: Encoder outputs 391 | decoder_inputs: Decoder inputs for teacher forcing. i.e. mel-specs 392 | memory_lengths: Encoder output lengths for attention masking. 393 | 394 | RETURNS 395 | ------- 396 | mel_outputs: mel outputs from the decoder 397 | gate_outputs: gate outputs from the decoder 398 | alignments: sequence of attention weights from the decoder 399 | """ 400 | 401 | decoder_input = self.get_go_frame(memory).unsqueeze(0) 402 | decoder_inputs = self.parse_decoder_inputs(decoder_inputs) 403 | decoder_inputs = torch.cat((decoder_input, decoder_inputs), dim=0) 404 | decoder_inputs = self.prenet(decoder_inputs) 405 | 406 | self.initialize_decoder_states( 407 | memory, mask=~get_mask_from_lengths(memory_lengths)) 408 | 409 | mel_outputs, gate_outputs, alignments = [], [], [] 410 | while len(mel_outputs) < decoder_inputs.size(0) - 1: 411 | decoder_input = decoder_inputs[len(mel_outputs)] 412 | mel_output, gate_output, attention_weights = self.decode( 413 | decoder_input) 414 | mel_outputs += [mel_output.squeeze(1)] 415 | gate_outputs += [gate_output.squeeze()] 416 | alignments += [attention_weights] 417 | 418 | mel_outputs, gate_outputs, alignments = self.parse_decoder_outputs( 419 | mel_outputs, gate_outputs, alignments) 420 | 421 | return mel_outputs, gate_outputs, alignments 422 | 423 | def inference(self, memory): 424 | """ Decoder inference 425 | PARAMS 426 | ------ 427 | memory: Encoder outputs 428 | 429 | RETURNS 430 | ------- 431 | mel_outputs: mel outputs from the decoder 432 | gate_outputs: gate outputs from the decoder 433 | alignments: sequence of attention weights from the decoder 434 | """ 435 | decoder_input = self.get_go_frame(memory) 436 | 437 | self.initialize_decoder_states(memory, mask=None) 438 | 439 | mel_outputs, gate_outputs, alignments = [], [], [] 440 | while True: 441 | decoder_input = self.prenet(decoder_input) 442 | mel_output, gate_output, alignment = self.decode(decoder_input) 443 | 444 | mel_outputs += [mel_output.squeeze(1)] 445 | gate_outputs += [gate_output] 446 | alignments += [alignment] 447 | 448 | if torch.sigmoid(gate_output.data) > self.gate_threshold: 449 | break 450 | elif len(mel_outputs) == self.max_decoder_steps: 451 | print("Warning! Reached max decoder steps") 452 | break 453 | 454 | decoder_input = mel_output 455 | 456 | mel_outputs, gate_outputs, alignments = self.parse_decoder_outputs( 457 | mel_outputs, gate_outputs, alignments) 458 | 459 | return mel_outputs, gate_outputs, alignments 460 | 461 | 462 | class Tacotron2(nn.Module): 463 | def __init__(self, hparams): 464 | super(Tacotron2, self).__init__() 465 | self.mask_padding = hparams.mask_padding 466 | self.fp16_run = hparams.fp16_run 467 | self.n_mel_channels = hparams.n_mel_channels 468 | self.n_frames_per_step = hparams.n_frames_per_step 469 | self.embedding = nn.Embedding( 470 | hparams.n_symbols, hparams.symbols_embedding_dim) 471 | std = sqrt(2.0 / (hparams.n_symbols + hparams.symbols_embedding_dim)) 472 | val = sqrt(3.0) * std # uniform bounds for std 473 | self.embedding.weight.data.uniform_(-val, val) 474 | self.encoder = Encoder(hparams) 475 | self.decoder = Decoder(hparams) 476 | self.postnet = Postnet(hparams) 477 | 478 | def parse_batch(self, batch): 479 | text_padded, input_lengths, mel_padded, gate_padded, \ 480 | output_lengths = batch 481 | text_padded = to_gpu(text_padded).long() 482 | input_lengths = to_gpu(input_lengths).long() 483 | max_len = torch.max(input_lengths.data).item() 484 | mel_padded = to_gpu(mel_padded).float() 485 | gate_padded = to_gpu(gate_padded).float() 486 | output_lengths = to_gpu(output_lengths).long() 487 | 488 | return ( 489 | (text_padded, input_lengths, mel_padded, max_len, output_lengths), 490 | (mel_padded, gate_padded)) 491 | 492 | def parse_input(self, inputs): 493 | inputs = fp32_to_fp16(inputs) if self.fp16_run else inputs 494 | return inputs 495 | 496 | def parse_output(self, outputs, output_lengths=None): 497 | if self.mask_padding and output_lengths is not None: 498 | mask = ~get_mask_from_lengths(output_lengths) 499 | mask = mask.expand(self.n_mel_channels, mask.size(0), mask.size(1)) 500 | mask = mask.permute(1, 0, 2) 501 | 502 | outputs[0].data.masked_fill_(mask, 0.0) 503 | outputs[1].data.masked_fill_(mask, 0.0) 504 | outputs[2].data.masked_fill_(mask[:, 0, :], 1e3) # gate energies 505 | 506 | outputs = fp16_to_fp32(outputs) if self.fp16_run else outputs 507 | return outputs 508 | 509 | def forward(self, inputs): 510 | inputs, input_lengths, targets, max_len, \ 511 | output_lengths = self.parse_input(inputs) 512 | input_lengths, output_lengths = input_lengths.data, output_lengths.data 513 | 514 | embedded_inputs = self.embedding(inputs).transpose(1, 2) 515 | 516 | encoder_outputs = self.encoder(embedded_inputs, input_lengths) 517 | 518 | mel_outputs, gate_outputs, alignments = self.decoder( 519 | encoder_outputs, targets, memory_lengths=input_lengths) 520 | 521 | mel_outputs_postnet = self.postnet(mel_outputs) 522 | mel_outputs_postnet = mel_outputs + mel_outputs_postnet 523 | 524 | return self.parse_output( 525 | [mel_outputs, mel_outputs_postnet, gate_outputs, alignments], 526 | output_lengths) 527 | 528 | def inference(self, inputs): 529 | inputs = self.parse_input(inputs) 530 | embedded_inputs = self.embedding(inputs).transpose(1, 2) 531 | encoder_outputs = self.encoder.inference(embedded_inputs) 532 | mel_outputs, gate_outputs, alignments = self.decoder.inference( 533 | encoder_outputs) 534 | 535 | mel_outputs_postnet = self.postnet(mel_outputs) 536 | mel_outputs_postnet = mel_outputs + mel_outputs_postnet 537 | 538 | outputs = self.parse_output( 539 | [mel_outputs, mel_outputs_postnet, gate_outputs, alignments]) 540 | 541 | return outputs 542 | -------------------------------------------------------------------------------- /filelists/nam-h_test_filelist.txt: -------------------------------------------------------------------------------- 1 | nam-h/wavs/8/0000798.wav|저, 뭐 하나 부탁 드려도 될까요? 2 | nam-h/wavs/1/0000444.wav|실수로 재떨이를 엎었어요. 3 | nam-h/wavs/11/0000488.wav|우리 계속 연락하고 지내자. 4 | nam-h/wavs/5/0000698.wav|요즘은 집 구하기가 하늘의 별 따기야. 5 | nam-h/wavs/12/0000219.wav|그녀를 잊는 데에 2년이 들었어. 6 | nam-h/wavs/10/0000614.wav|저는 한국이 선진국이라고 생각하지 않아요. 7 | nam-h/wavs/6/0000096.wav|안녕히 가세요. 8 | nam-h/wavs/4/0000834.wav|산에 구름이 끼기 시작했다. 9 | nam-h/wavs/9/0000796.wav|그 사람에게는 다른 사람과 다른 면이 있어. 10 | nam-h/wavs/11/0000077.wav|한국의 몇몇 탤런트들은 중국에서 크게 인기가 있어요. 11 | nam-h/wavs/7/0000416.wav|이 가방은 가죽으로 되어 있어요. 12 | nam-h/wavs/5/0000755.wav|지난 십이개월 동안 그 회사는 두드러진 성장을 보였다. 13 | nam-h/wavs/5/0000194.wav|사람들이 조금씩 모이고 있어. 14 | nam-h/wavs/10/0000999.wav|어른에게 인사할 때는 고개를 숙여라. 15 | nam-h/wavs/10/0000184.wav|구멍을 파다 16 | nam-h/wavs/6/0000129.wav|저는 바빠서 거기 못 갈 거 같아요. 17 | nam-h/wavs/2/0000810.wav|활발한 토론을 기대합니다. 18 | nam-h/wavs/2/0000488.wav|그녀는 훌륭한 교사다. 19 | nam-h/wavs/4/0000774.wav|제주행 비행기는 5번 터미널에서 출발합니다. 20 | nam-h/wavs/10/0000199.wav|법원은 우리가 벌금을 내야 한다고 판결했어요. 21 | nam-h/wavs/2/0000346.wav|그 남자는 체격이 건장했다. 22 | nam-h/wavs/12/0000096.wav|선생님께 한 부 보내 드리겠습니다. 23 | nam-h/wavs/10/0000717.wav|시험을 다음 주 목요일로 연기할 수 있을까요? 24 | nam-h/wavs/8/0000717.wav|잔디 위에 그냥 앉지 마. 25 | nam-h/wavs/2/0000972.wav|삼계탕은 영양이 풍부합니다. 26 | nam-h/wavs/11/0000140.wav|어젯밤에 술을 너무 많이 마셨더니 토할 것 같아. 27 | nam-h/wavs/0/0000987.wav|너는 사람이 왜 그렇게 짜? 죽고 나서 그 돈 갖고 갈 거야? 28 | nam-h/wavs/12/0000854.wav|이 아기는 바비 인형처럼 생겼어요. 29 | nam-h/wavs/10/0000941.wav|싼값에 비행기 표를 구할 방법 없을까? 30 | nam-h/wavs/2/0000321.wav|너는 웃을 때가 귀여워. 31 | nam-h/wavs/4/0000188.wav|저는 사형 제도가 야만적이라고 생각하지 않아요. 32 | nam-h/wavs/4/0000405.wav|공구를 사용할 때 장갑을 꼭 껴라. 33 | nam-h/wavs/8/0000335.wav|이메일 확인해 봤어? 34 | nam-h/wavs/10/0000650.wav|스키를 타다가 팔이 부러졌어요. 35 | nam-h/wavs/0/0000074.wav|머리를 검게 염색하니 할머니는 훨씬 젊어 보였다. 36 | nam-h/wavs/9/0000121.wav|찌개는 식으면 맛이 없어요. 37 | nam-h/wavs/1/0000910.wav|아기가 울음을 그치지 않아요. 38 | nam-h/wavs/8/0000805.wav|저것 좀 봐. 39 | nam-h/wavs/5/0000307.wav|이 비누는 살균 성질이 있습니다. 40 | nam-h/wavs/9/0000294.wav|빈 칸을 채우시오. 41 | nam-h/wavs/4/0000830.wav|햇볕이 쨍쨍 내리쬐고 있다. 42 | nam-h/wavs/10/0000323.wav|지금까지 소설을 몇 편이나 쓰셨어요? 43 | nam-h/wavs/2/0000453.wav|네가 이것을 지혜롭게 극복할 거라 믿어. 44 | nam-h/wavs/4/0000357.wav|이 마을 농가들은 양봉으로 고수익을 올리고 있다. 45 | nam-h/wavs/2/0000173.wav|여기 찾느라고 애를 먹었어요. 46 | nam-h/wavs/0/0000535.wav|불행히도 우리가 할 수 있는 게 많지 않다. 47 | nam-h/wavs/10/0000803.wav|요즘 아주 신경이 날카로워요. 48 | nam-h/wavs/11/0000461.wav|우리 반은 남학생보다 여학생이 많아요. 49 | nam-h/wavs/9/0000475.wav|이 식당은 음식이 맛있기로 유명해요. 50 | nam-h/wavs/12/0000863.wav|그녀가 다른 남자와 같이 있는 걸 상상할 수가 없어요. 51 | nam-h/wavs/0/0000542.wav|그건 비겁한 변명일 뿐이야. 52 | nam-h/wavs/6/0000859.wav|대입 시험 53 | nam-h/wavs/4/0000054.wav|우리 경찰서 내 거의 모든 경찰들이 그 사건에 매달려 있어요. 54 | nam-h/wavs/4/0000300.wav|최근에 기독교에서 불교로 개종하기로 마음먹었어요. 55 | nam-h/wavs/11/0000570.wav|긴장하지 말고 여유를 가져. 56 | nam-h/wavs/3/0000549.wav|제가 초보적인 실수를 저질렀어요. 57 | nam-h/wavs/4/0000538.wav|저희는 대기업과 거래하고 있습니다. 58 | nam-h/wavs/4/0000342.wav|지금이 벼를 베기에 가장 좋은 시기야. 59 | nam-h/wavs/12/0001037.wav|김치찌개 요리하다 손가락을 베었어. 60 | nam-h/wavs/2/0000435.wav|좀 더 신중했어야 했는데. 61 | nam-h/wavs/7/0000544.wav|요즘 아이들은 말투가 거칠어요. 62 | nam-h/wavs/12/0000501.wav|부모님께 안부 전해 주세요. 63 | nam-h/wavs/2/0000434.wav|아기가 생기고 나니 어깨가 무거워요. 64 | nam-h/wavs/8/0000589.wav|우리는 헤어질 수밖에 없다는 결론에 이르렀어요. 65 | nam-h/wavs/8/0000986.wav|아버지는 집안 형편 때문에 중학교에 못 가셨어요. 66 | nam-h/wavs/1/0000677.wav|그 사람은 아파서 못 왔어. 67 | nam-h/wavs/12/0000972.wav|토론에서는 그 여자를 따라갈 사람이 없어. 68 | nam-h/wavs/8/0000200.wav|모든 한국인이 김치를 즐겨 먹는 건 아니에요. 69 | nam-h/wavs/10/0000241.wav|이십 년 전에는 피씨를 갖고 있는 사람이 많이 없었다. 70 | nam-h/wavs/11/0000512.wav|아이들은 부모의 영향을 받게 되어 있다. 71 | nam-h/wavs/12/0000458.wav|짧은 끈을 이어서 사용합시다. 72 | nam-h/wavs/10/0000950.wav|방이 썰렁한데 불 좀 넣을까? 73 | nam-h/wavs/4/0000467.wav|유럽 국가들 중 다수가 유로를 통화 단위로 사용한다. 74 | nam-h/wavs/12/0000697.wav|나무에 새싹이 났어요. 75 | nam-h/wavs/12/0000919.wav|우리는 도와 달라고 소리쳤다. 76 | nam-h/wavs/8/0000735.wav|아이는 장모님이 봐 주고 계세요. 77 | nam-h/wavs/9/0000842.wav|창밖을 내다보지 마. 78 | nam-h/wavs/3/0000867.wav|오늘밤 콘서트 어때? 79 | nam-h/wavs/8/0000982.wav|두고 봐야 알지. 80 | nam-h/wavs/0/0000465.wav|남편은 잠귀가 아주 밝아요. 81 | nam-h/wavs/9/0000298.wav|카운터는 한 층 아래에 있습니다. 82 | nam-h/wavs/5/0000639.wav|왠지 기분이 이상해. 83 | nam-h/wavs/3/0000496.wav|저희는 대학 입시에 관한 여러 정보를 제공합니다. 84 | nam-h/wavs/0/0000056.wav|고요한 밤 거룩한 밤 85 | nam-h/wavs/8/0000847.wav|저희는 저희 제품을 정기적으로 점검하고 있습니다. 86 | nam-h/wavs/2/0000760.wav|입이 거친 사람이랑 가까이하지 마. 87 | nam-h/wavs/1/0000096.wav|많은 병사들이 묘비도 없이 공동묘지에 묻혔다. 88 | nam-h/wavs/8/0000331.wav|이제 그만 화 풀어. 89 | nam-h/wavs/7/0000702.wav|벌써 다섯 시예요. 그런데 걔한테서 아직 연락이 없어요. 90 | nam-h/wavs/12/0000675.wav|비타민이 모자라면 병에 걸리기 쉽다. 91 | nam-h/wavs/3/0000213.wav|내 열쇠 어디 갔지? 침대 위는 봤어? 92 | nam-h/wavs/6/0000072.wav|저는 TV 방송국 아나운서입니다. 93 | nam-h/wavs/5/0000312.wav|그 TV프로그램은 일반 상식을 시험하기 위해 만들어졌다. 94 | nam-h/wavs/4/0000685.wav|자동차에 또 문제가 있어요? 95 | nam-h/wavs/5/0000709.wav|불편하시게 해서 죄송합니다. 96 | nam-h/wavs/3/0000454.wav|마침 쉬는 시간 종이 울렸다. 97 | nam-h/wavs/12/0000766.wav|그 녀석은 수업 시간에 늘상 늦는다. 98 | nam-h/wavs/11/0000510.wav|제일 좋아하는 영화배우가 누구예요? 99 | nam-h/wavs/1/0000914.wav|오늘 왜 그리 우울해 보여? 100 | nam-h/wavs/10/0000093.wav|한때는 외아들은 군대에 가지 않았지만 지금은 아니다. 101 | nam-h/wavs/13/0000053.wav|어제 인도네시아에서 지진이 났다. 102 | nam-h/wavs/8/0000754.wav|내가 서 있는 동안 이 의자 좀 잡아 줄래? 103 | nam-h/wavs/12/0000486.wav|그는 자신이 거의 도둑을 잡을 뻔했다고 말했다. 104 | nam-h/wavs/3/0000015.wav|저는 하루에 한 끼만 먹습니다. 105 | nam-h/wavs/12/0000144.wav|그녀는 나를 자기 집으로 초대했다. 106 | nam-h/wavs/7/0000479.wav|강의는 오전 아홉 시에 시작됩니다. 107 | nam-h/wavs/5/0000664.wav|형과 저는 공통점이 전혀 없어요. 108 | nam-h/wavs/7/0000361.wav|저는 커서 가수가 되고 싶어요. 109 | nam-h/wavs/1/0000884.wav|지각을 자주 해서 선생님 눈 밖에 났어요. 110 | nam-h/wavs/4/0000944.wav|나무에 꽃이 활짝 피었다. 111 | nam-h/wavs/4/0000766.wav|고장 난 부품 하나만 교체하시면 됩니다. 112 | nam-h/wavs/10/0000227.wav|맵고 짠 음식은 피하셔야 합니다. 113 | nam-h/wavs/1/0000929.wav|제 가장 친한 친구가 다른 애들이랑 어울리는 것을 보니 질투가 났어요. 114 | nam-h/wavs/8/0000398.wav|과학으로는 이 신기한 현상을 설명할 수 없다. 115 | nam-h/wavs/0/0000492.wav|배가 불러 더 이상은 못 먹겠어요. 116 | nam-h/wavs/5/0000887.wav|미성년자, 즉 19세 미만인 자에게 담배를 파는 것은 불법이다. 117 | nam-h/wavs/5/0000708.wav|대중교통으로 오시는 게 더 편리하실 거예요. 118 | nam-h/wavs/6/0000753.wav|여기서 회사까지 최소 한 시간은 걸릴걸. 119 | nam-h/wavs/9/0000281.wav|다음 주유소에서 잠깐 차를 세우는 게 좋겠어요. 120 | nam-h/wavs/0/0000461.wav|다시 만나 뵙게 되어 정말 반갑습니다. 121 | nam-h/wavs/11/0000487.wav|딸아이는 어찌나 게임에 열중했던지 제가 다가가는 것도 몰랐어요. 122 | nam-h/wavs/7/0000978.wav|저는 어릴 때부터 과학에 관심이 많았어요. 123 | nam-h/wavs/4/0000182.wav|공동 생활에는 질서가 요구된다. 124 | nam-h/wavs/8/0000337.wav|아내는 평소에는 화장을 안 해요. 125 | nam-h/wavs/3/0000137.wav|이런! 사과가 썩었어. 126 | nam-h/wavs/4/0000785.wav|이거 부산행 기차 맞아요? 127 | nam-h/wavs/10/0000266.wav|회의 중에 몰래 빠져나와서 전화하는 거야. 128 | nam-h/wavs/0/0001052.wav|그는 군대에서 특수한 훈련을 받았다. 129 | nam-h/wavs/2/0000463.wav|저는 미래에 대해 낙천적이에요. 130 | nam-h/wavs/12/0000918.wav|나한테 소리치지 마. 131 | nam-h/wavs/2/0000116.wav|그녀의 음악은 매우 독창적이다. 132 | nam-h/wavs/0/0000259.wav|그 일은 네 생각만큼 단순하지 않다. 133 | nam-h/wavs/1/0000241.wav|새콤한 맛을 좋아하신다면 레몬즙을 한 스푼 넣으셔도 됩니다. 134 | nam-h/wavs/4/0000802.wav|공항에 세 시까지 오셔야 합니다. 135 | nam-h/wavs/8/0000539.wav|이놈의 차가 또 말썽이야. 136 | nam-h/wavs/1/0000604.wav|저에게는 돌아갈 고향이 없어요. 137 | nam-h/wavs/0/0000365.wav|매운 냄새를 맡으니 입 안에 침이 고여요. 138 | nam-h/wavs/1/0000906.wav|이거 슬픈 영화인가요? 139 | nam-h/wavs/7/0000880.wav|실례합니다만 제일 가까운 공중전화가 어디에 있어요? 140 | nam-h/wavs/10/0000036.wav|이 문제는 논할 가치도 없어. 141 | nam-h/wavs/0/0000860.wav|간단히 말해서 상황은 이래. 142 | nam-h/wavs/4/0000600.wav|저는 라디오 진행을 할 때 마음이 편해서 라디오가 좋아요. 143 | nam-h/wavs/3/0000482.wav|다음 물음에 답하시오. 144 | nam-h/wavs/8/0000917.wav|남편한테 제가 전화했었다고 전해 주시겠어요? 145 | nam-h/wavs/9/0000897.wav|우리 반에는 남학생이 딱 한 명뿐이야. 146 | nam-h/wavs/4/0000881.wav|새 한 마리가 계곡 위를 날고 있었다. 147 | nam-h/wavs/4/0000242.wav|인터넷은 우리의 일상 생활에 거대한 변화를 가져왔다. 148 | nam-h/wavs/7/0000413.wav|날씨가 너무 더워 가지고 입맛이 없어요. 149 | nam-h/wavs/1/0000881.wav|저는 아무것도 하지 않고 앉아 있는 것을 싫어해요. 150 | nam-h/wavs/8/0000914.wav|그 해외 스타를 보기 위해 전국에서 사람들이 모였어요. 151 | nam-h/wavs/5/0000925.wav|누구한테 물어보면 제일 좋을까요? 152 | nam-h/wavs/0/0000210.wav|어젯밤 잠을 못 자서 신경이 날카로워요. 153 | nam-h/wavs/5/0000719.wav|나는 다시 돌아오지 않겠다고 굳게 결심했다. 154 | nam-h/wavs/9/0000890.wav|저는 일 남 삼 녀 중 첫째예요. 155 | nam-h/wavs/2/0000049.wav|그 사건은 과거 고통스러웠던 기억을 떠올리게 했다. 156 | nam-h/wavs/3/0000847.wav|그녀는 리듬 감각을 타고났다. 157 | nam-h/wavs/2/0000375.wav|많은 부부가 성격 차이로 이혼한다. 158 | nam-h/wavs/8/0000620.wav|짧은 끈 두 개를 이어 봐. 159 | nam-h/wavs/9/0000603.wav|하루에 먹이는 몇 번 줘야 하나요? 160 | nam-h/wavs/10/0000914.wav|이 소포를 좀 보내고 싶은데요. 161 | nam-h/wavs/9/0000546.wav|다니던 회사가 망했어요. 162 | nam-h/wavs/10/0000378.wav|이 단어는 영어로부터 왔어요. 163 | nam-h/wavs/0/0000264.wav|단조로운 일상에서 벗어나고 싶어요. 164 | nam-h/wavs/11/0000395.wav|약간의 문제가 생겼어요. 165 | nam-h/wavs/2/0000764.wav|김 과장님이 내 보고서를 보고 비웃었어요. 166 | nam-h/wavs/0/0000787.wav|이 식물은 열악한 환경에서도 잘 자란다. 167 | nam-h/wavs/4/0000235.wav|인스턴트 식품은 비만의 주요 원인 중 하나다. 168 | nam-h/wavs/2/0000822.wav|살인 동기가 불확실합니다. 169 | nam-h/wavs/2/0000391.wav|요리 솜씨가 정말 좋으시군요. 170 | nam-h/wavs/8/0000265.wav|시간이 많이 흘러서 다 잊어버렸어요. 171 | nam-h/wavs/3/0000898.wav|소설의 배경에 대한 생생한 묘사가 인상적이었다. 172 | nam-h/wavs/12/0000855.wav|이 지역에 새 아파트가 생겨나고 있다. 173 | nam-h/wavs/5/0000942.wav|주말에는 보통 영화를 보거나 책을 읽어요. 174 | nam-h/wavs/4/0000956.wav|어젯밤에 우리 집 고양이가 새끼를 낳았어요. 175 | nam-h/wavs/10/0000673.wav|최고의 스승은 부모라는 말에 동의합니다. 176 | nam-h/wavs/2/0000754.wav|그녀는 자주 다른 직원들 험담을 한다. 177 | nam-h/wavs/4/0000306.wav|저는 작년에 기독교로 개종했어요. 178 | nam-h/wavs/12/0000692.wav|뭐 하나 물어봐도 돼? 179 | nam-h/wavs/6/0000971.wav|다른 일자리를 찾아보는 건 어때요? 180 | nam-h/wavs/8/0000241.wav|헌 물건을 신고하지 않고 버리시면 안 돼요. 181 | nam-h/wavs/9/0000551.wav|차가 많이 낡았지만 팔고 싶지는 않아요. 182 | nam-h/wavs/8/0000838.wav|해외에서 일자리를 찾는 젊은이들이 늘고 있어요. 183 | nam-h/wavs/12/0000879.wav|나는 의사에게 내 증상을 자세히 설명했다. 184 | nam-h/wavs/7/0000360.wav|제가 이 반 담임입니다. 185 | nam-h/wavs/0/0000269.wav|방 안 공기가 너무 답답해요. 186 | nam-h/wavs/6/0000480.wav|많은 사람들 앞에서 넘어져서 너무 부끄러웠어요. 187 | nam-h/wavs/0/0000981.wav|사람들은 그의 이야기에 진한 감동을 느꼈다. 188 | nam-h/wavs/5/0000617.wav|확실해요? 189 | nam-h/wavs/3/0000237.wav|이 건물은 난방 시설이 열악하다. 190 | nam-h/wavs/3/0000129.wav|방금 구운 빵이야. 191 | nam-h/wavs/2/0000566.wav|저는 삶을 비관적으로 바라보는 사람들의 입장을 이해합니다. 192 | nam-h/wavs/0/0000867.wav|너 오늘 좀 이상하다. 193 | nam-h/wavs/1/0000729.wav|체온을 재겠습니다. 194 | nam-h/wavs/8/0000429.wav|공항에 도착하면 곧장 호텔로 이동하세요. 195 | nam-h/wavs/9/0000178.wav|졸업하고 나면 뭐 할 거예요? 196 | nam-h/wavs/8/0000816.wav|잘못을 저질렀으면 벌을 받아야지. 197 | nam-h/wavs/3/0000908.wav|오늘 영화 보러 갈래? 198 | nam-h/wavs/0/0000696.wav|이 옷은 버리기 아까워. 199 | nam-h/wavs/4/0000518.wav|저는 공과금을 자동 이체로 납부합니다. 200 | nam-h/wavs/7/0000145.wav|부모님은 제가 어렸을 때 돌아가셨어요. 201 | nam-h/wavs/10/0000818.wav|저는 신문사에서 일하고 있어요. 202 | nam-h/wavs/1/0000091.wav|그녀는 자신의 재산을 딸에게 모두 남긴다는 유언을 남겼다. 203 | nam-h/wavs/2/0000210.wav|제대로 좀 해! 204 | nam-h/wavs/8/0000042.wav|어떻게 그런 결론을 내리게 된 겁니까? 205 | nam-h/wavs/4/0000966.wav|사자는 동물의 왕이다. 206 | nam-h/wavs/6/0000429.wav|휴가 잘 보내세요. 207 | nam-h/wavs/7/0000365.wav|어젯밤 너랑 같이 있던 그 남자 누구야? 208 | nam-h/wavs/4/0000638.wav|인쇄가 선명하지 않아요. 209 | nam-h/wavs/4/0000047.wav|경찰은 시민의 안전을 책임진다. 210 | nam-h/wavs/1/0000014.wav|마가렛 대처의 별명은 '철의 여인'이었다. 211 | nam-h/wavs/1/0000108.wav|저는 낯을 많이 가려서 새로운 사람들에게 마음을 여는 데 많은 시간이 걸려요. 212 | nam-h/wavs/9/0000612.wav|기계가 갑자기 멈췄어요. 213 | nam-h/wavs/7/0000656.wav|박물관에서는 사진 촬영이 금지되어 있습니다. 214 | nam-h/wavs/5/0000556.wav|힘껏 밀어 봐. 215 | nam-h/wavs/2/0000839.wav|경비원이 내게 사진을 찍지 말라고 주의를 주었다. 216 | nam-h/wavs/0/0000759.wav|요즘 들어 자주 어지럽고 속이 울렁거려요. 217 | nam-h/wavs/12/0000779.wav|합격을 위해 정말 열심히 노력했어. 218 | nam-h/wavs/1/0000609.wav|열차가 아직 도착하지 않았다. 219 | nam-h/wavs/9/0000147.wav|제 영어 실력이 조금씩 나아지고 있나요? 220 | nam-h/wavs/7/0000526.wav|어렸을 때 저는 가수가 되는 게 꿈이었어요. 221 | nam-h/wavs/11/0000163.wav|오늘 토론은 주제가 뭐예요? 222 | nam-h/wavs/9/0000315.wav|왜 글자 크기가 전부 다르죠? 223 | nam-h/wavs/0/0000662.wav|이 약은 참 신통하게 잘 들어. 224 | nam-h/wavs/2/0000067.wav|접시에 조심스럽게 내려놓으세요. 225 | nam-h/wavs/9/0000490.wav|그 사건은 매스컴을 통해 대중들에게 알려졌다. 226 | nam-h/wavs/5/0000383.wav|이 가게는 넓이가 얼마나 됩니까? 227 | nam-h/wavs/1/0000650.wav|선을 넘지 마세요. 228 | nam-h/wavs/1/0000704.wav|1025실 환자 언제 퇴원해요? 229 | nam-h/wavs/5/0000351.wav|그녀는 희미한 불빛 아래서 잠이 들었다. 230 | nam-h/wavs/1/0000174.wav|지난 달에 맹장 제거 수술을 받았어요. 231 | nam-h/wavs/4/0000678.wav|이곳은 무료 와이파이 구역입니다. 232 | nam-h/wavs/9/0000204.wav|한국에서는 빨간색이 죽음을 상징해요. 233 | nam-h/wavs/9/0000327.wav|한국에서는 크리스마스를 어떻게 보내요? 234 | nam-h/wavs/1/0000560.wav|책상 밑에 숨어 봤자 소용없어. 235 | nam-h/wavs/0/0000935.wav|너한테 줄 조그만 선물이 있어. 236 | nam-h/wavs/10/0000222.wav|피아노 참 잘 치시네요. 237 | nam-h/wavs/8/0000317.wav|강남에 가려면 몇 호선을 타야 하나요? 238 | nam-h/wavs/9/0000585.wav|그 사람은 벌을 받아 마땅합니다. 239 | nam-h/wavs/6/0000351.wav|한국은 프랑스와 1대 1로 비겼어요. 240 | nam-h/wavs/3/0000383.wav|결혼식 축의금은 얼마 냈어? 241 | nam-h/wavs/3/0000249.wav|이 모금 행사는 십대 소년 소녀 가장을 돕기 위한 것입니다. 242 | nam-h/wavs/9/0000667.wav|그곳의 모든 사람들이 절 보고 웃었어요. 243 | nam-h/wavs/4/0000489.wav|보험료가 50퍼센트 인상되었어요. 244 | nam-h/wavs/9/0000109.wav|옆집에서 음악을 너무 크게 틀어서 짜증이 나요. 245 | nam-h/wavs/9/0000848.wav|여기 내과가 어디예요? 246 | nam-h/wavs/0/0001080.wav|이 이불은 참 포근해요. 247 | nam-h/wavs/8/0000143.wav|오늘은 햇볕이 좋아서 빨래가 잘 마를 것 같네. 248 | nam-h/wavs/0/0000351.wav|시험 결과가 썩 만족스럽지 않아요. 249 | nam-h/wavs/5/0000311.wav|권력을 동경하는 것은 인간의 속성 중 일부다. 250 | nam-h/wavs/12/0000255.wav|그는 자기 아내를 죽이고 해외로 도망갔다. 251 | nam-h/wavs/4/0000344.wav|추수하기 참 좋은 날씨야. 252 | nam-h/wavs/7/0000411.wav|아기는 언제 가질 생각이니? 253 | nam-h/wavs/3/0000002.wav|100퍼센트 천연 과일 주스 254 | nam-h/wavs/0/0000352.wav|당신은 만족스러운 미소를 지으며 이곳을 떠나게 될 것입니다. 255 | nam-h/wavs/5/0000113.wav|에디슨이 최초의 전구를 만든 게 언제인지 아니? 256 | nam-h/wavs/11/0000079.wav|학교까지 좀 태워 줄래? 257 | nam-h/wavs/13/0000008.wav|아들아이가 내년에 초등학교에 들어가요. 258 | nam-h/wavs/10/0000379.wav|제 집을 마련하려고 저축을 하고 있습니다. 259 | nam-h/wavs/4/0000158.wav|자본주의 사회에서는 소비자가 왕이다. 260 | nam-h/wavs/3/0000946.wav|저는 일본에서 자랐지만 국적은 한국입니다. 261 | nam-h/wavs/3/0000037.wav|직장을 구해야 하는데. 손가락 빨 수는 없잖아. 262 | nam-h/wavs/2/0000532.wav|게으른 건 여전하구나. 263 | nam-h/wavs/0/0000335.wav|공연이 끝나자 관객들은 무대 위 배우들에게 뜨거운 박수를 보냈다. 264 | nam-h/wavs/7/0000199.wav|어, 벌써 시간이 이렇게 됐구나. 265 | nam-h/wavs/11/0000569.wav|서두르지 마. 아직 여유 있어. 266 | nam-h/wavs/3/0000085.wav|이 식당이 네가 전에 추천했던 곳이야? 267 | nam-h/wavs/11/0000584.wav|돈이 없어요. 268 | nam-h/wavs/5/0000109.wav|언제 한번 들러. 269 | nam-h/wavs/10/0000140.wav|주전자를 불에 올려놓아라. 270 | nam-h/wavs/10/0000729.wav|요즘 누가 시집을 사? 271 | nam-h/wavs/7/0000094.wav|이 술 너무 독한데. 272 | nam-h/wavs/0/0000214.wav|그는 어려서부터 예술적 재능이 남달랐다. 273 | nam-h/wavs/6/0000249.wav|저는 몇 번 방송에 출연한 적이 있습니다. 274 | nam-h/wavs/12/0000336.wav|그러지 않겠다고 약속했잖아. 275 | nam-h/wavs/12/0001001.wav|한글은 15세기에 세종대왕에 의해 만들어졌어. 276 | nam-h/wavs/11/0000631.wav|올해 유월은 유난히 쌀쌀해요. 277 | nam-h/wavs/4/0000046.wav|밤에 밖에 나가면 위험해. 278 | nam-h/wavs/8/0000796.wav|내일 아침 일곱 시에 저 좀 깨워 주세요. 279 | nam-h/wavs/10/0000139.wav|그 여자는 키가 상당히 커서 나는 그녀를 올려다보아야 했다. 280 | nam-h/wavs/8/0000366.wav|202호실 환자 언제 퇴원해요? 281 | nam-h/wavs/5/0000143.wav|이미 7시가 넘었다. 282 | nam-h/wavs/2/0000261.wav|박사 학위를 받은 여성의 수가 꾸준히 증가해 왔다. 283 | nam-h/wavs/10/0000108.wav|그는 나를 외면하고 지나갔다. 284 | nam-h/wavs/10/0000288.wav|이를 아직 뽑을 필요는 없어요. 285 | nam-h/wavs/8/0000848.wav|아버지는 점잖은 분이세요. 286 | nam-h/wavs/9/0000967.wav|선을 넘지 마라. 287 | nam-h/wavs/4/0000298.wav|저는 유령을 본 적이 있어요. 288 | nam-h/wavs/9/0000035.wav|네가 직접 만들었어? 289 | nam-h/wavs/1/0000374.wav|네 물건들 정리 좀 해. 290 | nam-h/wavs/10/0000753.wav|실컷 먹어. 291 | nam-h/wavs/8/0000619.wav|이따가 다시 전화할게. 292 | nam-h/wavs/7/0000949.wav|몇 해 전에 커피숍이 몇 군데 생겼어요. 293 | nam-h/wavs/8/0000841.wav|그 여자는 오른쪽 볼에 점이 있어요. 294 | nam-h/wavs/0/0000792.wav|당신을 영원히 사랑합니다. 295 | nam-h/wavs/11/0000321.wav|이 학생은 제가 가르친 중에서 가장 우수한 학생입니다. 296 | nam-h/wavs/6/0000331.wav|빨리 이곳에서 벗어나고 싶어요. 297 | nam-h/wavs/0/0000786.wav|흑인이 백인보다 열등하다고 말하고 있는 겁니까? 298 | nam-h/wavs/11/0000586.wav|요 근처 아무 데나 내려주세요. 299 | nam-h/wavs/0/0000216.wav|영화가 원작 소설보다 나아. 300 | nam-h/wavs/9/0000841.wav|그 사람은 모든 어려움을 이겨 내고 결국 성공했다. 301 | nam-h/wavs/12/0000625.wav|어떻게 이렇게 큰 눈사람을 만들었어? 302 | nam-h/wavs/11/0000548.wav|옆집은 다음 달에 이사 간대요. 303 | nam-h/wavs/1/0000289.wav|잠자기 전에 이를 닦아라. 304 | nam-h/wavs/9/0000773.wav|다음 글을 읽고 물음에 답하시오. 305 | nam-h/wavs/2/0000789.wav|어떤 식당을 추천하고 싶으세요? 306 | nam-h/wavs/7/0000566.wav|벽에 걸려 있던 그림 어디 갔어? 307 | nam-h/wavs/0/0000201.wav|정말 끔찍한 하루였어요. 308 | nam-h/wavs/6/0000023.wav|아가씨, 이거 혹시 아가씨 지갑인가요? 309 | nam-h/wavs/1/0000483.wav|발에 유리 조각이 박혔어요. 310 | nam-h/wavs/6/0000951.wav|그 사람 이 시간에는 당연히 자고 있을 거야. 311 | nam-h/wavs/9/0000368.wav|아버님께 안부 전해 주세요. 312 | nam-h/wavs/6/0000773.wav|이 앨범을 볼 때마다 어릴 때 추억이 떠올라요. 313 | nam-h/wavs/3/0000152.wav|저는 이 지역을 아주 잘 알아요. 314 | nam-h/wavs/10/0000579.wav|설날에 우리나라 사람들은 떡국을 먹어요. 315 | nam-h/wavs/3/0000384.wav|신혼여행은 발리로 가고 싶어요. 316 | nam-h/wavs/7/0000430.wav|저녁으로 갈비탕 어때? 317 | nam-h/wavs/12/0000044.wav|저는 무력 사용을 반대합니다. 318 | nam-h/wavs/7/0000926.wav|직장 구하셨어요? 319 | nam-h/wavs/4/0000371.wav|이 나라의 경제는 대체로 제조업에 기반을 두고 있다. 320 | nam-h/wavs/10/0000276.wav|어제는 뭐 때문에 그렇게 빨리 퇴근했어요? 321 | nam-h/wavs/7/0000076.wav|어제 빌려 간 내 책 되돌려 줘. 322 | nam-h/wavs/9/0000619.wav|머리카락이 많이 상했어요. 323 | nam-h/wavs/9/0000894.wav|남동생이 하나 있었으면 좋겠어요. 324 | nam-h/wavs/5/0000697.wav|수면을 취하는 데 어려움을 겪은 적이 있나요? 325 | nam-h/wavs/3/0000910.wav|그 연극은 오 월 일 일부터 시 월 삼십일 일까지 월요일을 제외하고 매일 공연됩니다. 326 | nam-h/wavs/7/0000165.wav|이 책 얼마나 두꺼운지 봐 봐. 327 | nam-h/wavs/0/0000666.wav|저도 암이 심각한 병이라는 건 알아요. 328 | nam-h/wavs/6/0000346.wav|어둠 사이로 달빛이 비쳤다. 329 | nam-h/wavs/8/0000597.wav|그 일은 이론적으로는 가능하지만 실제로는 불가능합니다. 330 | nam-h/wavs/10/0000121.wav|오이는 다이어트에 좋아요. 331 | nam-h/wavs/11/0000361.wav|운전하면서 전화하는 것은 위험해. 332 | nam-h/wavs/1/0000676.wav|그는 과로로 젊은 나이에 죽었다. 333 | nam-h/wavs/7/0000086.wav|이 작업을 하려면 도구가 몇 개 필요해요. 334 | nam-h/wavs/8/0000513.wav|이모가 졸업 선물로 노트북을 사 줬어요. 335 | nam-h/wavs/7/0000376.wav|이웃집 개 때문에 신경이 쓰여요. 336 | nam-h/wavs/2/0000857.wav|한글과 영어는 표음 문자다. 337 | nam-h/wavs/10/0000356.wav|그는 자기 자신이 최고라고 생각한다. 338 | nam-h/wavs/11/0000273.wav|이 의자 좀 치워 주실래요? 339 | nam-h/wavs/2/0000227.wav|중국은 최근 수 년간 급격한 경제 성장을 이룩했다. 340 | nam-h/wavs/6/0000536.wav|부상을 입은 그 선수는 병원으로 옮겨졌다. 341 | nam-h/wavs/9/0000779.wav|수술은 무사히 끝났어요. 342 | nam-h/wavs/11/0000598.wav|법률 용어를 보면 머리가 아파요. 343 | nam-h/wavs/9/0000384.wav|물이 끓기 시작해요. 344 | nam-h/wavs/12/0000968.wav|이 캔 좀 따 줘. 345 | nam-h/wavs/1/0000608.wav|비명 소리를 듣고 이웃들이 달려왔다. 346 | nam-h/wavs/12/0000176.wav|블라우스에 브로치를 달았다. 347 | nam-h/wavs/4/0000883.wav|그 호텔은 절벽 끝에 위치해 있다. 348 | nam-h/wavs/8/0000414.wav|하루에 세 번 이를 닦아야 해. 349 | nam-h/wavs/5/0000066.wav|자정이 지나면 기본 요금이 오릅니다. 350 | nam-h/wavs/2/0000674.wav|어떤 색깔을 찾고 계세요? 351 | nam-h/wavs/10/0000038.wav|졸업 논문의 주제가 무엇입니까? 352 | nam-h/wavs/4/0000771.wav|택시 승강장이 어디에 있어요? 353 | nam-h/wavs/2/0000159.wav|너 정말 공부 열심히 했구나. 354 | nam-h/wavs/11/0000445.wav|할머니는 올해 여든이세요. 355 | nam-h/wavs/5/0001020.wav|남자답게 굴어라. 356 | nam-h/wavs/7/0000643.wav|침묵은 금이다. 357 | nam-h/wavs/1/0000254.wav|그 사람이 떠날 것 같은 느낌이 들어. 358 | nam-h/wavs/9/0000388.wav|비가 끊임없이 내리네. 359 | nam-h/wavs/6/0000322.wav|저는 이 문제에 대해 법적 책임이 없어요. 360 | nam-h/wavs/7/0000524.wav|그 소식에 가슴이 너무 아팠어요. 361 | nam-h/wavs/0/0000856.wav|의심스러우면 지수한테 물어봐. 362 | nam-h/wavs/5/0000893.wav|요즘 TV에는 광고가 너무 많아. 363 | nam-h/wavs/9/0000922.wav|파리가 방 안을 날아다니고 있어요. 364 | nam-h/wavs/1/0000462.wav|그대로 놓아두세요. 365 | nam-h/wavs/8/0000937.wav|우리나라는 전통적으로 큰아들이 부모님을 모시고 살아요. 366 | nam-h/wavs/4/0000893.wav|바위가 너무 무거워서 움직일 수가 없어. 367 | nam-h/wavs/4/0000356.wav|간밤에 돼지 축사에서 화재가 있었다. 368 | nam-h/wavs/3/0000608.wav|연말에 보너스가 나옵니다. 369 | nam-h/wavs/5/0000335.wav|왜 모자를 삐뚤게 쓰니? 370 | nam-h/wavs/9/0000270.wav|목에 생기는 주름은 감출 수가 없어요. 371 | nam-h/wavs/3/0000435.wav|나는 고등학교 때 제2외국어로 일본어를 배웠다. 372 | nam-h/wavs/10/0000153.wav|온라인으로 책을 몇 권 주문했어요. 373 | nam-h/wavs/5/0000637.wav|아무래도 우리가 질 것 같아. 374 | nam-h/wavs/9/0000454.wav|이제 떠날 시간이야. 375 | nam-h/wavs/7/0000602.wav|화장실은 거실 옆에 있어요. 376 | nam-h/wavs/11/0000212.wav|젓가락을 떨어뜨렸는데 다른 걸로 바꿔 주실래요? 377 | nam-h/wavs/12/0000748.wav|참을 수 있는 한계를 넘어섰어요. 378 | nam-h/wavs/5/0000237.wav|수원에 가 본 적 있으세요? 379 | nam-h/wavs/2/0000068.wav|주의 사항을 읽어 봤어? 380 | nam-h/wavs/5/0000405.wav|그는 커다란 상자를 안고 내 쪽으로 걸어왔다. 381 | nam-h/wavs/9/0000090.wav|의사 지시대로 했어? 382 | nam-h/wavs/5/0000779.wav|저는 영업 사원으로서 10년의 경험을 갖고 있습니다. 383 | nam-h/wavs/3/0000731.wav|일행이 있으세요? 384 | nam-h/wavs/5/0000435.wav|토지를 측량하려면 전문 장비와 훈련이 필요하다. 385 | nam-h/wavs/0/0000625.wav|그녀는 크고 순박한 눈으로 나를 바라보았다. 386 | nam-h/wavs/8/0000279.wav|더 힘껏 밀어. 387 | nam-h/wavs/2/0000526.wav|나는 그를 못 본 척했다. 388 | nam-h/wavs/2/0000308.wav|사람을 외모로 판단하지 마라. 389 | nam-h/wavs/8/0000560.wav|입장을 바꿔서 생각해 봐. 390 | nam-h/wavs/2/0000117.wav|그의 사진에는 독창성이 전혀 없다. 391 | nam-h/wavs/2/0000794.wav|그는 내게 병원에 가 보라고 조언했다. 392 | nam-h/wavs/10/0000912.wav|그 사람은 십대 소년 소녀 가장들을 돕고 있어요. 393 | nam-h/wavs/0/0000040.wav|그는 스카우터들에게 강렬한 인상을 남겼다. 394 | nam-h/wavs/6/0000774.wav|추가 비용은 없습니다. 395 | nam-h/wavs/6/0000318.wav|이 단어는 영어로 번역하기가 쉽지 않아요. 396 | nam-h/wavs/10/0000130.wav|도대체 고양이가 저 나무 위로 어떻게 올라갔지? 397 | nam-h/wavs/1/0000734.wav|독감 예방 주사는 맞았어요? 398 | nam-h/wavs/5/0000321.wav|지구는 둥글다. 399 | nam-h/wavs/1/0000519.wav|소금 좀 건네줄래? 400 | nam-h/wavs/11/0000117.wav|기억나는 다른 특징은 없나요? 401 | nam-h/wavs/2/0000459.wav|그는 그 문제를 융통성 있게 처리했다. 402 | nam-h/wavs/0/0000162.wav|방 안에서 그윽한 커피 향이 났다. 403 | nam-h/wavs/5/0000978.wav|매년 404 | nam-h/wavs/12/0000875.wav|서두르지 않아도 돼. 405 | nam-h/wavs/0/0000945.wav|그것 좋은 생각이다. 406 | nam-h/wavs/4/0000798.wav|비행기는 5분 후에 이륙할 예정입니다. 407 | nam-h/wavs/6/0000486.wav|풍선 불어 본 지도 정말 오래됐다. 408 | nam-h/wavs/3/0000183.wav|문 닫고 들어오세요. 409 | nam-h/wavs/11/0000336.wav|이 와이셔츠 내일까지 드라이 좀 해 주세요. 410 | nam-h/wavs/12/0000793.wav|누군가 도와 달라고 외치는 것을 들었다. 411 | nam-h/wavs/6/0000884.wav|다음에는 내가 살게. 412 | nam-h/wavs/0/0000691.wav|네가 없으니 너무 쓸쓸해. 413 | nam-h/wavs/10/0000871.wav|옆 사람하고 속삭이지 마세요. 414 | nam-h/wavs/9/0000050.wav|졸다가 내릴 곳을 지나칠 뻔했어요. 415 | nam-h/wavs/3/0000276.wav|어제는 언니 집에서 잤어요. 416 | nam-h/wavs/6/0000734.wav|이 책은 초보자에게 적합해요. 417 | nam-h/wavs/8/0000073.wav|물건들을 계산대에 올려 놓아 주세요. 418 | nam-h/wavs/5/0000444.wav|종이 넉 장 419 | nam-h/wavs/10/0000599.wav|실패는 성공의 어머니다. 420 | nam-h/wavs/4/0000955.wav|꿀벌은 무리를 지어 산다. 421 | nam-h/wavs/7/0000418.wav|계산은 각자 합시다. 422 | nam-h/wavs/11/0000611.wav|한국에서의 유학 생활은 어때요? 423 | nam-h/wavs/4/0000118.wav|나 3일 후에 훈련소 들어가. 424 | nam-h/wavs/12/0000166.wav|그녀는 나를 딸처럼 대한다. 425 | nam-h/wavs/12/0000597.wav|수리공이 실수로 선을 끊어 버린 것 같아. 426 | nam-h/wavs/10/0000795.wav|국이 좀 싱거워요. 427 | nam-h/wavs/12/0000462.wav|왜 아직 안 자고 깨어 있니? 428 | nam-h/wavs/6/0000026.wav|할아버지는 올해 연세가 아흔이세요. 429 | nam-h/wavs/10/0000890.wav|손대지 마세요. 430 | nam-h/wavs/11/0000479.wav|배터리를 열 근처에 두지 마세요. 431 | nam-h/wavs/7/0000472.wav|가능성이 어느 정도라고 생각합니까? 432 | nam-h/wavs/12/0000132.wav|엄마랑 아빠는 항상 같이 상을 차리세요. 433 | nam-h/wavs/1/0000305.wav|이불 깔아라. 434 | nam-h/wavs/0/0000950.wav|저는 그 사람이 좋아요. 435 | nam-h/wavs/5/0000465.wav|매일 수많은 사람들이 교통사고로 사망한다. 436 | nam-h/wavs/12/0000431.wav|부모님이 이혼하신 이후로 엄마랑 살고 있어요. 437 | nam-h/wavs/5/0000287.wav|다친 데 없어요? 438 | nam-h/wavs/4/0000299.wav|나는 귀신을 안 믿어. 439 | nam-h/wavs/9/0000870.wav|내용도 중요하지만 형식도 중요하다. 440 | nam-h/wavs/9/0000183.wav|제사는 조상을 기념하는 의식입니다. 441 | nam-h/wavs/0/0000141.wav|어떤 것도 생명보다 귀중하지는 않습니다. 442 | nam-h/wavs/12/0000128.wav|많은 배우들이 그 시상식에 참석하지 않았다. 443 | nam-h/wavs/9/0000083.wav|이제부터는 어려운 부분만 집중적으로 공부할 필요가 있어요. 444 | nam-h/wavs/12/0000881.wav|사업에 성공하려면 우선 자신을 돌봐야 한다. 445 | nam-h/wavs/1/0000157.wav|저는 팔에 털이 굉장히 많아요. 446 | nam-h/wavs/6/0000454.wav|서울로 편지를 부치고 싶은데요. 447 | nam-h/wavs/7/0000586.wav|그 사람은 몰래 정치인에게 돈을 건넨 사실이 드러났다. 448 | nam-h/wavs/10/0000540.wav|내 여동생이 사월에 아기를 낳을 예정이야. 449 | nam-h/wavs/2/0000646.wav|덕분에 잘 지냅니다. 450 | nam-h/wavs/9/0000048.wav|바지는 잘 맞지만 셔츠는 너무 껴요. 451 | nam-h/wavs/3/0000911.wav|제가 그 오페라의 주연을 따냈다는 얘기를 들었을 때 저는 정말 믿기지가 않았어요. 452 | nam-h/wavs/12/0000290.wav|이 자리에 와 주신 여러분께 감사드립니다. 453 | nam-h/wavs/0/0000282.wav|회의실이 너무 덥지 않아? 454 | nam-h/wavs/9/0000970.wav|당신이 너무 보고 싶어요. 455 | nam-h/wavs/9/0000912.wav|낯익은 풍경이 눈에 들어왔다. 456 | nam-h/wavs/1/0000470.wav|반대하시는 분은 손을 들어 주세요. 457 | nam-h/wavs/10/0000623.wav|이렇게 가시니 섭섭하네요. 458 | nam-h/wavs/2/0000466.wav|그녀가 합리적 선택을 하리라 믿습니다. 459 | nam-h/wavs/1/0000745.wav|비타민 제품을 고를 때 약사에게 조언을 구하세요. 460 | nam-h/wavs/9/0000288.wav|남편과 저는 캠퍼스 커플이었어요. 461 | nam-h/wavs/4/0000447.wav|어느 쪽이 더 경제적이야? 462 | nam-h/wavs/11/0000579.wav|백남준은 한국이 낳은 위대한 예술가였어요. 463 | nam-h/wavs/6/0000430.wav|우리 연말에 보너스가 나올까? 464 | nam-h/wavs/3/0000666.wav|매표소가 어디예요? 465 | nam-h/wavs/5/0000151.wav|그들은 나와 동시에 떠났다. 466 | nam-h/wavs/8/0000145.wav|이 문장은 해석하기가 쉽지 않네요. 467 | nam-h/wavs/4/0000229.wav|두 나라 간의 무역 마찰이 최고점에 다다랐다. 468 | nam-h/wavs/1/0000925.wav|남의 물건에 침을 흘리지 마라. 469 | nam-h/wavs/6/0000633.wav|너 때문에 창피해 죽겠다. 470 | nam-h/wavs/11/0000573.wav|제 예상보다 훨씬 어려웠어요. 471 | nam-h/wavs/9/0000139.wav|잠을 쫓으려고 커피를 두 잔이나 마셨어요. 472 | nam-h/wavs/10/0000883.wav|부인께서 요리 솜씨가 정말 좋으시군요. 473 | nam-h/wavs/4/0000471.wav|잔돈 없으세요? 474 | nam-h/wavs/0/0000223.wav|그 사람 얼굴은 낯익은데 이름은 기억이 안 나. 475 | nam-h/wavs/8/0000018.wav|귀신 믿으세요? 476 | nam-h/wavs/10/0000324.wav|아내는 항상 아들 편만 들어요. 477 | nam-h/wavs/11/0000063.wav|근처에 이십사 시간 여는 슈퍼마켓 있나요? 478 | nam-h/wavs/7/0000963.wav|그 사람 글은 다 구성이 좋아요. 479 | nam-h/wavs/0/0000276.wav|그 노래는 작년에 대단한 인기를 끌었다. 480 | nam-h/wavs/8/0000920.wav|요즘에는 집 전화기가 없는 집도 많아요. 481 | nam-h/wavs/4/0000510.wav|현재 은행 예금 이율은 5퍼센트도 채 안 된다. 482 | nam-h/wavs/8/0000837.wav|나는 자네 젊음이 부러워. 483 | nam-h/wavs/9/0000347.wav|밥 먹기 전에 먼저 손 깨끗이 씻어라. 484 | nam-h/wavs/6/0000598.wav|당신 몸은 당신이 좀 챙겨요. 485 | nam-h/wavs/5/0000999.wav|사랑받다 486 | nam-h/wavs/10/0000016.wav|텔레비전 프로그램 녹화 좀 해 줄래? 487 | nam-h/wavs/2/0000089.wav|죄송해요, 제 친구로 착각했어요. 488 | nam-h/wavs/7/0000278.wav|얼음이 녹을 때까지는 운전하지 않는 게 어때? 489 | nam-h/wavs/0/0000874.wav|저는 외계인이 있다고 믿습니다. 490 | nam-h/wavs/12/0000210.wav|투수는 타자가 아닌 포수에게 공을 던져야 한다. 491 | nam-h/wavs/3/0000915.wav|그 소설은 영화로 제작될 예정이다. 492 | nam-h/wavs/12/0000768.wav|책상 위에 놓여 있던 연필 어디 갔어? 493 | nam-h/wavs/0/0000552.wav|그녀는 어릴 때 빨간 머리 때문에 놀림을 받았다. 494 | nam-h/wavs/9/0000579.wav|우리 서로 답 맞춰 보자. 495 | nam-h/wavs/5/0000134.wav|저는 항상 시험 직전에 공부해요. 496 | nam-h/wavs/9/0000299.wav|케첩은 빼 주세요. 497 | nam-h/wavs/1/0000160.wav|손으로 여드름을 짜다가 세균에 감염될 수도 있다. 498 | nam-h/wavs/0/0000643.wav|손이 너무 시려요. 499 | nam-h/wavs/6/0000035.wav|냄새가 아주 좋은데요. 500 | nam-h/wavs/12/0000031.wav|오타를 발견하시는 분께 사례하겠습니다. --------------------------------------------------------------------------------