From 3508e4882f49de281a1cd7ab78dfbc69bf09cc13 Mon Sep 17 00:00:00 2001 From: Wannaphong Phatthiyaphaibun Date: Wed, 24 Jan 2024 13:31:31 +0700 Subject: [PATCH] PyThaiTTS v0.3.0 - Add Lunarlist TTS model (ONNX) - Change default model to Lunarlist TTS model --- notebook/cat.wav | Bin 0 -> 49708 bytes notebook/use_lunarlist_model_onnx.ipynb | 307 ++++++++++++++++++++++++ pythaitts/__init__.py | 25 +- pythaitts/pretrained/__init__.py | 8 - pythaitts/pretrained/lunarlist_model.py | 5 +- pythaitts/pretrained/lunarlist_onnx.py | 189 +++++++++++++++ requirements.txt | 5 +- setup.py | 2 +- 8 files changed, 520 insertions(+), 21 deletions(-) create mode 100644 notebook/cat.wav create mode 100644 notebook/use_lunarlist_model_onnx.ipynb create mode 100755 pythaitts/pretrained/lunarlist_onnx.py diff --git a/notebook/cat.wav b/notebook/cat.wav new file mode 100644 index 0000000000000000000000000000000000000000..c04cd2499cb17b78df665855d5ae4ca37ffee979 GIT binary patch literal 49708 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" + ], + "text/html": [ + "\n", + " \n", + " " + ] + }, + "metadata": {}, + "execution_count": 9 + } + ] + }, + { + "cell_type": "code", + "source": [ + "wave = tts.tts(\"ภาษาไทย ง่าย มาก มาก\",return_type=\"waveform\")\n", + "IPython.display.Audio(wave, rate=22010) # load a NumPy array" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 60 + }, + "id": "pkoPFBU4rUQX", + "outputId": "f616231a-6ec1-4d22-ecc6-81f561c59c09" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "\n", + " \n", + " " + ] + }, + "metadata": {}, + "execution_count": 10 + } + ] + }, + { + "cell_type": "code", + "source": [ + "file = tts.tts(\"ภาษาไทยตัดคำได้นานแล้ว\")" + ], + "metadata": { + "id": "xa21tvyvVtFU" + }, + "execution_count": 23, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "IPython.display.Audio(file)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 60 + }, + "id": "BNmVNV7WVvLh", + "outputId": "465b508d-42db-4bc5-c39e-64b3eeca963d" + }, + "execution_count": 24, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "\n", + " \n", + " " + ] + }, + "metadata": {}, + "execution_count": 24 + } + ] + }, + { + "cell_type": "code", + "source": [ + "file = tts.tts(\"ภาษา ไทย ตัด คำ ได้ นาน แล้ว\")" + ], + "metadata": { + "id": "I6gdBKvyVwSq" + }, + "execution_count": 25, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "IPython.display.Audio(file)" + ], + "metadata": { + "id": "HlEm7UngqAeL", + "outputId": "ce2c1e2e-8658-4d4f-d270-f234fa77d0de", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 60 + } + }, + "execution_count": 26, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "\n", + " \n", + " " + ] + }, + "metadata": {}, + "execution_count": 26 + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "KHcX3zC_qBRm" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/pythaitts/__init__.py b/pythaitts/__init__.py index 23099d6..f32b396 100644 --- a/pythaitts/__init__.py +++ b/pythaitts/__init__.py @@ -2,15 +2,16 @@ """ PyThaiTTS """ -__version__ = "0.2.1" +__version__ = "0.3.0" class TTS: - def __init__(self, pretrained="khanomtan", mode="last_checkpoint", version="1.0", device:str="cpu") -> None: + def __init__(self, pretrained="lunarlist_onnx", mode="last_checkpoint", version="1.0", device:str="cpu") -> None: """ - :param str pretrained: TTS pretrained (khanomtan, lunarlist) - :param str mode: pretrained mode + :param str pretrained: TTS pretrained (lunarlist_onnx, khanomtan, lunarlist) + :param str mode: pretrained mode (lunarlist_onnx don't support) :param str version: model version (default is 1.0 or 1.1) + :param str device: device for running model. (lunarlist_onnx support CPU only.) **Options for mode** * *last_checkpoint* (default) - last checkpoint of model @@ -21,6 +22,11 @@ def __init__(self, pretrained="khanomtan", mode="last_checkpoint", version="1.0" For lunarlist tts model, you must to install nemo before use the model by pip install nemo_toolkit['tts']. You can see more about lunarlist tts at `https://link.medium.com/OpPjQis6wBb `_ + + For lunarlist_onnx tts model, \ + You can see more about lunarlist tts at `https://github.com/PyThaiNLP/thaitts-onnx `_ + + """ self.pretrained = pretrained @@ -32,11 +38,14 @@ def load_pretrained(self,version): """ Load pretrained """ - if self.pretrained == "khanomtan": - from pythaitts.pretrained import KhanomTan + if self.pretrained == "lunarlist_onnx": + from pythaitts.pretrained.lunarlist_onnx import LunarlistONNX + self.model = LunarlistONNX() + elif self.pretrained == "khanomtan": + from pythaitts.pretrained.khanomtan_tts import KhanomTan self.model = KhanomTan(mode=self.mode, version=version) elif self.pretrained == "lunarlist": - from pythaitts.pretrained import LunarlistModel + from pythaitts.pretrained.lunarlist_model import LunarlistModel self.model = LunarlistModel(mode=self.mode, device=self.device) else: raise NotImplemented( @@ -53,7 +62,7 @@ def tts(self, text: str, speaker_idx: str = "Linda", language_idx: str = "th-th" :param str return_type: return type (default is file) :param str filename: path filename for save wav file if return_type is file. """ - if self.pretrained == "lunarlist": + if self.pretrained == "lunarlist" or self.pretrained == "lunarlist_onnx": return self.model(text=text,return_type=return_type,filename=filename) return self.model( text=text, diff --git a/pythaitts/pretrained/__init__.py b/pythaitts/pretrained/__init__.py index 140f8d7..e69de29 100644 --- a/pythaitts/pretrained/__init__.py +++ b/pythaitts/pretrained/__init__.py @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- -from pythaitts.pretrained.khanomtan_tts import KhanomTan -from pythaitts.pretrained.lunarlist_model import LunarlistModel - -__all__ = [ - "KhanomTan", - "LunarlistModel" -] \ No newline at end of file diff --git a/pythaitts/pretrained/lunarlist_model.py b/pythaitts/pretrained/lunarlist_model.py index 678aa62..0c2dadf 100644 --- a/pythaitts/pretrained/lunarlist_model.py +++ b/pythaitts/pretrained/lunarlist_model.py @@ -5,7 +5,10 @@ You can see more about lunarlist tts at `https://link.medium.com/OpPjQis6wBb `_ """ import tempfile -import torch +try: + import torch +except ImportError: + raise ImportError("You must to install torch before use this model.") class LunarlistModel: diff --git a/pythaitts/pretrained/lunarlist_onnx.py b/pythaitts/pretrained/lunarlist_onnx.py new file mode 100755 index 0000000..0e0b245 --- /dev/null +++ b/pythaitts/pretrained/lunarlist_onnx.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +""" +Lunarlist TTS model (ONNX) + +You can see more about lunarlist tts at `https://link.medium.com/OpPjQis6wBb `_ + +ONNX port: `https://github.com/PyThaiNLP/thaitts-onnx `_ +""" +import tempfile +import numpy as np +import onnxruntime as ort +from huggingface_hub import hf_hub_download + + +# from https://huggingface.co/lunarlist/tts-thai-last-step +index_list=['ก', 'ข', 'ค', 'ฆ', 'ง', 'จ', 'ฉ', 'ช', 'ซ', 'ฌ', 'ญ', 'ฎ', 'ฏ', 'ฐ', 'ฑ', 'ฒ', 'ณ', 'ด', 'ต', 'ถ', 'ท', 'ธ', 'น', 'บ', 'ป', 'ผ', 'ฝ', 'พ', 'ฟ', 'ภ', 'ม', 'ย', 'ร', 'ฤ', 'ล', 'ว', 'ศ', 'ษ', 'ส', 'ห', 'ฬ', 'อ', 'ฮ', 'ะ', 'ั', 'า', 'ำ', 'ิ', 'ี', 'ึ', 'ื', 'ุ', 'ู', 'เ', 'แ', 'โ', 'ใ', 'ไ', 'ๅ', '็', '่', '้', '๊', '๋', '์', ' '] +dict_idx={k:i for i,k in enumerate(index_list)} + +def clean(text): + seq = np.array([[66]+[dict_idx[i] for i in text if i]+[67]]) + _s=np.array([len(seq[0])]) + return seq,_s + +n_mel_channels = 80 +n_frames_per_step = 1 +attention_rnn_dim = 1024 +decoder_rnn_dim=1024 +encoder_embedding_dim=512 + +def initialize_decoder_states(memory): + B = memory.shape[0] + MAX_TIME = memory.shape[1] + + attention_hidden = np.zeros((B, attention_rnn_dim), dtype=np.float32) + attention_cell = np.zeros((B, attention_rnn_dim), dtype=np.float32) + + decoder_hidden = np.zeros((B, decoder_rnn_dim), dtype=np.float32) + decoder_cell = np.zeros((B, decoder_rnn_dim), dtype=np.float32) + + attention_weights = np.zeros((B, MAX_TIME), dtype=np.float32) + attention_weights_cum = np.zeros((B, MAX_TIME), dtype=np.float32) + attention_context = np.zeros((B, encoder_embedding_dim), dtype=np.float32) + + return ( + attention_hidden, + attention_cell, + decoder_hidden, + decoder_cell, + attention_weights, + attention_weights_cum, + attention_context, + ) + + +def get_go_frame(memory): + B = memory.shape[0] + decoder_input = np.zeros((B, n_mel_channels*n_frames_per_step), dtype=np.float32) + return decoder_input + + +def sigmoid(x): + return np.exp(-np.logaddexp(0, -x)) + + +def parse_decoder_outputs(mel_outputs, gate_outputs, alignments): + # (T_out, B) -> (B, T_out) + alignments = np.stack(alignments).transpose((1, 0, 2, 3)) + # (T_out, B) -> (B, T_out) + # Add a -1 to prevent squeezing the batch dimension in case + # batch is 1 + gate_outputs = np.stack(gate_outputs).squeeze(-1).transpose((1, 0, 2)) + # (T_out, B, n_mel_channels) -> (B, T_out, n_mel_channels) + mel_outputs = np.stack(mel_outputs).transpose((1, 0, 2, 3)) + # decouple frames per step + mel_outputs = mel_outputs.reshape(mel_outputs.shape[0], -1, n_mel_channels) + # (B, T_out, n_mel_channels) -> (B, n_mel_channels, T_out) + mel_outputs = mel_outputs.transpose((0, 2, 1)) + + return mel_outputs, gate_outputs, alignments + + +# only numpy operations +def inference(text, encoder, decoder_iter, postnet): + sequences, sequence_lengths = clean(text) + + # print("Running Tacotron2 Encoder") + inputs = {"seq": sequences, "seq_len": sequence_lengths} + memory, processed_memory, _ = encoder.run(None, inputs) + + # print("Running Tacotron2 Decoder") + mel_lengths = np.zeros([memory.shape[0]], dtype=np.int32) + not_finished = np.ones([memory.shape[0]], dtype=np.int32) + mel_outputs, gate_outputs, alignments = [], [], [] + gate_threshold = 0.5 + max_decoder_steps = 5000 + first_iter = True + + ( + attention_hidden, + attention_cell, + decoder_hidden, + decoder_cell, + attention_weights, + attention_weights_cum, + attention_context, + ) = initialize_decoder_states(memory) + + decoder_input = get_go_frame(memory) + + while True: + inputs = { + "decoder_input": decoder_input, + "attention_hidden": attention_hidden, + "attention_cell": attention_cell, + "decoder_hidden": decoder_hidden, + "decoder_cell": decoder_cell, + "attention_weights": attention_weights, + "attention_weights_cum": attention_weights_cum, + "attention_context": attention_context, + "memory": memory, + "processed_memory": processed_memory, + } + ( + mel_output, + gate_output, + attention_hidden, + attention_cell, + decoder_hidden, + decoder_cell, + attention_weights, + attention_weights_cum, + attention_context, + ) = decoder_iter.run(None, inputs) + + if first_iter: + mel_outputs = [np.expand_dims(mel_output, 2)] + gate_outputs = [np.expand_dims(gate_output, 2)] + alignments = [np.expand_dims(attention_weights, 2)] + first_iter = False + else: + mel_outputs += [np.expand_dims(mel_output, 2)] + gate_outputs += [np.expand_dims(gate_output, 2)] + alignments += [np.expand_dims(attention_weights, 2)] + + dec = np.less(sigmoid(gate_output), gate_threshold) + dec = np.squeeze(dec, axis=1) + not_finished = not_finished * dec + mel_lengths += not_finished + + if not_finished.sum() == 0: + # print("Stopping after ", len(mel_outputs), " decoder steps") + break + if len(mel_outputs) == max_decoder_steps: + # print("Warning! Reached max decoder steps") + break + + decoder_input = mel_output + + mel_outputs, gate_outputs, alignments = parse_decoder_outputs( + mel_outputs, gate_outputs, alignments + ) + + # print("Running Tacotron2 PostNet") + inputs = {"mel_spec": mel_outputs} + mel_outputs_postnet = postnet.run(None, inputs) + + return mel_outputs_postnet + +class LunarlistONNX: + def __init__(self) -> None: + self.encoder = ort.InferenceSession(hf_hub_download(repo_id="pythainlp/thaitts-onnx",filename="tacotron2encoder-th.onnx")) + self.decoder = ort.InferenceSession(hf_hub_download(repo_id="pythainlp/thaitts-onnx",filename="tacotron2decoder-th.onnx")) + self.postnet = ort.InferenceSession(hf_hub_download(repo_id="pythainlp/thaitts-onnx",filename="tacotron2postnet-th.onnx")) + self.hifi = ort.InferenceSession(hf_hub_download(repo_id="pythainlp/thaitts-onnx",filename="vocoder.onnx")) + def tts(self, text: str): + mel = inference(text, self.encoder, self.decoder, self.postnet) + return self.hifi.run(None, {"spec": mel[0]}) + def __call__(self, text: str,return_type: str = "file", filename: str = None): + wavs = self.tts(text) + if return_type == "waveform": + return wavs[0][0, 0, :] + import soundfile as sf + if filename != None: + sf.write(filename, wavs[0][0, 0, :], 22050) + return filename + else: + with tempfile.NamedTemporaryFile(suffix = ".wav", delete = False) as fp: + sf.write(fp.name, wavs[0][0, 0, :], 22050) + return fp.name \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a4bada8..77ef34a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -TTS>=0.8.0 -pythainlp>=3.0.0 huggingface_hub -torch \ No newline at end of file +numpy>=1.22 +onnxruntime \ No newline at end of file diff --git a/setup.py b/setup.py index 7a0b309..878d721 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="PyThaiTTS", - version="0.2.1", + version="0.3.0", description="Open Source Thai Text-to-speech library in Python", long_description=readme, long_description_content_type="text/markdown",