parent
77802f92db
commit
ee70c2eadc
@ -0,0 +1,34 @@
|
|||||||
|
from paddlespeech.t2s.models.CosyVoice.cosyvoice import CosyVoice2
|
||||||
|
import sys
|
||||||
|
from paddlenlp.transformers import AutoTokenizer, AutoModelForCausalLM
|
||||||
|
from pathlib import Path
|
||||||
|
import paddle
|
||||||
|
import torch
|
||||||
|
from paddlespeech.t2s.models.CosyVoice.llm import Qwen2LM,ras_sampling,Qwen2Encoder
|
||||||
|
# cosyvoice_model = CosyVoice2("../CosyVoice/pretrained_models/CosyVoice2-0.5B_paddle")
|
||||||
|
model = AutoModelForCausalLM.from_pretrained('Qwen/Qwen2-0.5B')
|
||||||
|
llm = Qwen2Encoder(model)
|
||||||
|
qwen_lm = Qwen2LM(896,896,6561,llm,ras_sampling)
|
||||||
|
state_dict = paddle.load("/root/paddlejob/workspace/zhangjinghong/CosyVoice/pretrained_models/CosyVoice2-0.5B_paddle/llm.pdparams")
|
||||||
|
qwen_lm.set_state_dict(state_dict)
|
||||||
|
new_dict = torch.load("data.pt")
|
||||||
|
text = new_dict['text']
|
||||||
|
text_len = new_dict['text_len']
|
||||||
|
prompt_text = new_dict['prompt_text']
|
||||||
|
prompt_text_len = new_dict['prompt_text_len']
|
||||||
|
prompt_speech_token = new_dict['prompt_speech_token']
|
||||||
|
prompt_speech_token_len = new_dict['prompt_speech_token_len']
|
||||||
|
embedding = new_dict['embedding']
|
||||||
|
uuid = new_dict['uuid']
|
||||||
|
print("text:",text)
|
||||||
|
# for i in qwen_lm.inference(text=paddle.to_tensor(text),
|
||||||
|
# text_len=text_len,
|
||||||
|
# prompt_text=paddle.to_tensor(prompt_text),
|
||||||
|
# prompt_text_len=prompt_text_len,
|
||||||
|
# prompt_speech_token=paddle.to_tensor(prompt_speech_token),
|
||||||
|
# prompt_speech_token_len=prompt_speech_token_len,
|
||||||
|
# embedding=paddle.to_tensor(embedding,dtype = 'float32'),
|
||||||
|
# uuid=uuid):
|
||||||
|
# print(text)
|
||||||
|
# print(i)
|
||||||
|
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from .cosyvoice import *
|
||||||
@ -0,0 +1,360 @@
|
|||||||
|
import os
|
||||||
|
import time
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
import paddle
|
||||||
|
from hyperpyyaml import load_hyperpyyaml
|
||||||
|
from modelscope import snapshot_download
|
||||||
|
import logging
|
||||||
|
logging.getLogger('matplotlib').setLevel(logging.WARNING)
|
||||||
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
|
format='%(asctime)s %(levelname)s %(message)s')
|
||||||
|
from paddlespeech.t2s.models.CosyVoice.frontend import CosyVoiceFrontEnd
|
||||||
|
from paddlespeech.t2s.models.CosyVoice.model import CosyVoice2Model
|
||||||
|
|
||||||
|
def get_model_type(configs):
|
||||||
|
# NOTE CosyVoice2Model inherits CosyVoiceModel
|
||||||
|
if isinstance(configs['llm'], TransformerLM) and isinstance(configs['flow'], MaskedDiffWithXvec) and isinstance(configs['hift'], HiFTGenerator):
|
||||||
|
return CosyVoiceModel
|
||||||
|
if isinstance(configs['llm'], Qwen2LM) and isinstance(configs['flow'], CausalMaskedDiffWithXvec) and isinstance(configs['hift'], HiFTGenerator):
|
||||||
|
return CosyVoice2Model
|
||||||
|
raise TypeError('No valid model type found!')
|
||||||
|
class CosyVoice:
|
||||||
|
def __init__(
|
||||||
|
self, model_dir, load_jit=False, load_trt=False, fp16=False, trt_concurrent=1
|
||||||
|
):
|
||||||
|
self.instruct = True if "-Instruct" in model_dir else False
|
||||||
|
self.model_dir = model_dir
|
||||||
|
self.fp16 = fp16
|
||||||
|
if not os.path.exists(model_dir):
|
||||||
|
model_dir = snapshot_download(model_dir)
|
||||||
|
hyper_yaml_path = "{}/cosyvoice.yaml".format(model_dir)
|
||||||
|
if not os.path.exists(hyper_yaml_path):
|
||||||
|
raise ValueError("{} not found!".format(hyper_yaml_path))
|
||||||
|
with open(hyper_yaml_path, "r") as f:
|
||||||
|
configs = load_hyperpyyaml(f)
|
||||||
|
# assert (
|
||||||
|
# get_model_type(configs) != CosyVoice2Model
|
||||||
|
# ), "do not use {} for CosyVoice initialization!".format(model_dir)
|
||||||
|
self.frontend = CosyVoiceFrontEnd(
|
||||||
|
configs["get_tokenizer"],
|
||||||
|
configs["feat_extractor"],
|
||||||
|
"{}/campplus.onnx".format(model_dir),
|
||||||
|
"{}/speech_tokenizer_v1.onnx".format(model_dir),
|
||||||
|
"{}/spk2info.pt".format(model_dir),
|
||||||
|
configs["allowed_special"],
|
||||||
|
)
|
||||||
|
self.sample_rate = configs["sample_rate"]
|
||||||
|
if (paddle.device.cuda.device_count() >= 1) is False and (
|
||||||
|
load_jit is True or load_trt is True or fp16 is True
|
||||||
|
):
|
||||||
|
load_jit, load_trt, fp16 = False, False, False
|
||||||
|
logging.warning("no cuda device, set load_jit/load_trt/fp16 to False")
|
||||||
|
self.model = CosyVoiceModel(
|
||||||
|
configs["llm"], configs["flow"], configs["hift"], fp16
|
||||||
|
)
|
||||||
|
self.model.load(
|
||||||
|
"{}/llm.pt".format(model_dir),
|
||||||
|
"{}/flow.pt".format(model_dir),
|
||||||
|
"{}/hift.pt".format(model_dir),
|
||||||
|
)
|
||||||
|
if load_jit:
|
||||||
|
self.model.load_jit(
|
||||||
|
"{}/llm.text_encoder.{}.zip".format(
|
||||||
|
model_dir, "fp16" if self.fp16 is True else "fp32"
|
||||||
|
),
|
||||||
|
"{}/llm.llm.{}.zip".format(
|
||||||
|
model_dir, "fp16" if self.fp16 is True else "fp32"
|
||||||
|
),
|
||||||
|
"{}/flow.encoder.{}.zip".format(
|
||||||
|
model_dir, "fp16" if self.fp16 is True else "fp32"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if load_trt:
|
||||||
|
self.model.load_trt(
|
||||||
|
"{}/flow.decoder.estimator.{}.mygpu.plan".format(
|
||||||
|
model_dir, "fp16" if self.fp16 is True else "fp32"
|
||||||
|
),
|
||||||
|
"{}/flow.decoder.estimator.fp32.onnx".format(model_dir),
|
||||||
|
trt_concurrent,
|
||||||
|
self.fp16,
|
||||||
|
)
|
||||||
|
del configs
|
||||||
|
|
||||||
|
def list_available_spks(self):
|
||||||
|
spks = list(self.frontend.spk2info.keys())
|
||||||
|
return spks
|
||||||
|
|
||||||
|
def add_zero_shot_spk(self, prompt_text, prompt_speech_16k, zero_shot_spk_id):
|
||||||
|
assert zero_shot_spk_id != "", "do not use empty zero_shot_spk_id"
|
||||||
|
model_input = self.frontend.frontend_zero_shot(
|
||||||
|
"", prompt_text, prompt_speech_16k, self.sample_rate, ""
|
||||||
|
)
|
||||||
|
del model_input["text"]
|
||||||
|
del model_input["text_len"]
|
||||||
|
self.frontend.spk2info[zero_shot_spk_id] = model_input
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_spkinfo(self):
|
||||||
|
paddle.save(
|
||||||
|
obj=self.frontend.spk2info, path="{}/spk2info.pt".format(self.model_dir)
|
||||||
|
)
|
||||||
|
|
||||||
|
def inference_sft(
|
||||||
|
self, tts_text, spk_id, stream=False, speed=1.0, text_frontend=True
|
||||||
|
):
|
||||||
|
for i in tqdm(
|
||||||
|
self.frontend.text_normalize(
|
||||||
|
tts_text, split=True, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
):
|
||||||
|
model_input = self.frontend.frontend_sft(i, spk_id)
|
||||||
|
start_time = time.time()
|
||||||
|
logging.info("synthesis text {}".format(i))
|
||||||
|
for model_output in self.model.tts(
|
||||||
|
**model_input, stream=stream, speed=speed
|
||||||
|
):
|
||||||
|
speech_len = model_output["tts_speech"].shape[1] / self.sample_rate
|
||||||
|
logging.info(
|
||||||
|
"yield speech len {}, rtf {}".format(
|
||||||
|
speech_len, (time.time() - start_time) / speech_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield model_output
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
def inference_zero_shot(
|
||||||
|
self,
|
||||||
|
tts_text,
|
||||||
|
prompt_text,
|
||||||
|
prompt_speech_16k,
|
||||||
|
zero_shot_spk_id="",
|
||||||
|
stream=False,
|
||||||
|
speed=1.0,
|
||||||
|
text_frontend=True,
|
||||||
|
):
|
||||||
|
prompt_text = self.frontend.text_normalize(
|
||||||
|
prompt_text, split=False, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
for i in tqdm(
|
||||||
|
self.frontend.text_normalize(
|
||||||
|
tts_text, split=True, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
):
|
||||||
|
if not isinstance(i, Generator) and len(i) < 0.5 * len(prompt_text):
|
||||||
|
logging.warning(
|
||||||
|
"synthesis text {} too short than prompt text {}, this may lead to bad performance".format(
|
||||||
|
i, prompt_text
|
||||||
|
)
|
||||||
|
)
|
||||||
|
model_input = self.frontend.frontend_zero_shot(
|
||||||
|
i, prompt_text, prompt_speech_16k, self.sample_rate, zero_shot_spk_id
|
||||||
|
)
|
||||||
|
start_time = time.time()
|
||||||
|
logging.info("synthesis text {}".format(i))
|
||||||
|
for model_output in self.model.tts(
|
||||||
|
**model_input, stream=stream, speed=speed
|
||||||
|
):
|
||||||
|
speech_len = model_output["tts_speech"].shape[1] / self.sample_rate
|
||||||
|
logging.info(
|
||||||
|
"yield speech len {}, rtf {}".format(
|
||||||
|
speech_len, (time.time() - start_time) / speech_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield model_output
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
def inference_cross_lingual(
|
||||||
|
self,
|
||||||
|
tts_text,
|
||||||
|
prompt_speech_16k,
|
||||||
|
zero_shot_spk_id="",
|
||||||
|
stream=False,
|
||||||
|
speed=1.0,
|
||||||
|
text_frontend=True,
|
||||||
|
):
|
||||||
|
for i in tqdm(
|
||||||
|
self.frontend.text_normalize(
|
||||||
|
tts_text, split=True, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
):
|
||||||
|
model_input = self.frontend.frontend_cross_lingual(
|
||||||
|
i, prompt_speech_16k, self.sample_rate, zero_shot_spk_id
|
||||||
|
)
|
||||||
|
start_time = time.time()
|
||||||
|
logging.info("synthesis text {}".format(i))
|
||||||
|
for model_output in self.model.tts(
|
||||||
|
**model_input, stream=stream, speed=speed
|
||||||
|
):
|
||||||
|
speech_len = model_output["tts_speech"].shape[1] / self.sample_rate
|
||||||
|
logging.info(
|
||||||
|
"yield speech len {}, rtf {}".format(
|
||||||
|
speech_len, (time.time() - start_time) / speech_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield model_output
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
def inference_instruct(
|
||||||
|
self,
|
||||||
|
tts_text,
|
||||||
|
spk_id,
|
||||||
|
instruct_text,
|
||||||
|
stream=False,
|
||||||
|
speed=1.0,
|
||||||
|
text_frontend=True,
|
||||||
|
):
|
||||||
|
assert isinstance(
|
||||||
|
self.model, CosyVoiceModel
|
||||||
|
), "inference_instruct is only implemented for CosyVoice!"
|
||||||
|
if self.instruct is False:
|
||||||
|
raise ValueError(
|
||||||
|
"{} do not support instruct inference".format(self.model_dir)
|
||||||
|
)
|
||||||
|
instruct_text = self.frontend.text_normalize(
|
||||||
|
instruct_text, split=False, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
for i in tqdm(
|
||||||
|
self.frontend.text_normalize(
|
||||||
|
tts_text, split=True, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
):
|
||||||
|
model_input = self.frontend.frontend_instruct(i, spk_id, instruct_text)
|
||||||
|
start_time = time.time()
|
||||||
|
logging.info("synthesis text {}".format(i))
|
||||||
|
for model_output in self.model.tts(
|
||||||
|
**model_input, stream=stream, speed=speed
|
||||||
|
):
|
||||||
|
speech_len = model_output["tts_speech"].shape[1] / self.sample_rate
|
||||||
|
logging.info(
|
||||||
|
"yield speech len {}, rtf {}".format(
|
||||||
|
speech_len, (time.time() - start_time) / speech_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield model_output
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
def inference_vc(
|
||||||
|
self, source_speech_16k, prompt_speech_16k, stream=False, speed=1.0
|
||||||
|
):
|
||||||
|
model_input = self.frontend.frontend_vc(
|
||||||
|
source_speech_16k, prompt_speech_16k, self.sample_rate
|
||||||
|
)
|
||||||
|
start_time = time.time()
|
||||||
|
for model_output in self.model.tts(**model_input, stream=stream, speed=speed):
|
||||||
|
speech_len = model_output["tts_speech"].shape[1] / self.sample_rate
|
||||||
|
logging.info(
|
||||||
|
"yield speech len {}, rtf {}".format(
|
||||||
|
speech_len, (time.time() - start_time) / speech_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield model_output
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
|
||||||
|
class CosyVoice2(CosyVoice):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
model_dir,
|
||||||
|
load_jit=False,
|
||||||
|
load_trt=False,
|
||||||
|
load_vllm=False,
|
||||||
|
fp16=False,
|
||||||
|
trt_concurrent=1,
|
||||||
|
):
|
||||||
|
self.instruct = True if "-Instruct" in model_dir else False
|
||||||
|
self.model_dir = model_dir
|
||||||
|
self.fp16 = fp16
|
||||||
|
hyper_yaml_path = "{}/cosyvoice2.yaml".format(model_dir)
|
||||||
|
if not os.path.exists(hyper_yaml_path):
|
||||||
|
raise ValueError("{} not found!".format(hyper_yaml_path))
|
||||||
|
with open(hyper_yaml_path, "r") as f:
|
||||||
|
configs = load_hyperpyyaml(
|
||||||
|
f,
|
||||||
|
overrides={
|
||||||
|
"qwen_pretrain_path": os.path.join(model_dir, "CosyVoice-BlankEN")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
# assert (
|
||||||
|
# get_model_type(configs) == CosyVoice2Model
|
||||||
|
# ), "do not use {} for CosyVoice2 initialization!".format(model_dir)
|
||||||
|
self.frontend = CosyVoiceFrontEnd(
|
||||||
|
configs["get_tokenizer"],
|
||||||
|
configs["feat_extractor"],
|
||||||
|
"{}/campplus.onnx".format(model_dir),
|
||||||
|
"{}/speech_tokenizer_v2.onnx".format(model_dir),
|
||||||
|
"{}/spk2info.pt".format(model_dir),
|
||||||
|
configs["allowed_special"],
|
||||||
|
)
|
||||||
|
self.sample_rate = configs["sample_rate"]
|
||||||
|
if (paddle.device.cuda.device_count() >= 1) is False and (
|
||||||
|
load_jit is True or load_trt is True or fp16 is True
|
||||||
|
):
|
||||||
|
load_jit, load_trt, fp16 = False, False, False
|
||||||
|
logging.warning("no cuda device, set load_jit/load_trt/fp16 to False")
|
||||||
|
self.model = CosyVoice2Model(
|
||||||
|
configs["llm"], configs["flow"], configs["hift"], fp16
|
||||||
|
)
|
||||||
|
self.model.load(
|
||||||
|
"{}/llm.pt".format(model_dir),
|
||||||
|
"{}/flow.pt".format(model_dir),
|
||||||
|
"{}/hift.pt".format(model_dir),
|
||||||
|
)
|
||||||
|
if load_vllm:
|
||||||
|
self.model.load_vllm("{}/vllm".format(model_dir))
|
||||||
|
if load_jit:
|
||||||
|
self.model.load_jit(
|
||||||
|
"{}/flow.encoder.{}.zip".format(
|
||||||
|
model_dir, "fp16" if self.fp16 is True else "fp32"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if load_trt:
|
||||||
|
self.model.load_trt(
|
||||||
|
"{}/flow.decoder.estimator.{}.mygpu.plan".format(
|
||||||
|
model_dir, "fp16" if self.fp16 is True else "fp32"
|
||||||
|
),
|
||||||
|
"{}/flow.decoder.estimator.fp32.onnx".format(model_dir),
|
||||||
|
trt_concurrent,
|
||||||
|
self.fp16,
|
||||||
|
)
|
||||||
|
del configs
|
||||||
|
|
||||||
|
def inference_instruct(self, *args, **kwargs):
|
||||||
|
raise NotImplementedError(
|
||||||
|
"inference_instruct is not implemented for CosyVoice2!"
|
||||||
|
)
|
||||||
|
|
||||||
|
def inference_instruct2(
|
||||||
|
self,
|
||||||
|
tts_text,
|
||||||
|
instruct_text,
|
||||||
|
prompt_speech_16k,
|
||||||
|
zero_shot_spk_id="",
|
||||||
|
stream=False,
|
||||||
|
speed=1.0,
|
||||||
|
text_frontend=True,
|
||||||
|
):
|
||||||
|
assert isinstance(
|
||||||
|
self.model, CosyVoice2Model
|
||||||
|
), "inference_instruct2 is only implemented for CosyVoice2!"
|
||||||
|
for i in tqdm(
|
||||||
|
self.frontend.text_normalize(
|
||||||
|
tts_text, split=True, text_frontend=text_frontend
|
||||||
|
)
|
||||||
|
):
|
||||||
|
model_input = self.frontend.frontend_instruct2(
|
||||||
|
i, instruct_text, prompt_speech_16k, self.sample_rate, zero_shot_spk_id
|
||||||
|
)
|
||||||
|
start_time = time.time()
|
||||||
|
logging.info("synthesis text {}".format(i))
|
||||||
|
for model_output in self.model.tts(
|
||||||
|
**model_input, stream=stream, speed=speed
|
||||||
|
):
|
||||||
|
speech_len = model_output["tts_speech"].shape[1] / self.sample_rate
|
||||||
|
logging.info(
|
||||||
|
"yield speech len {}, rtf {}".format(
|
||||||
|
speech_len, (time.time() - start_time) / speech_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield model_output
|
||||||
|
start_time = time.time()
|
||||||
@ -0,0 +1,253 @@
|
|||||||
|
import math
|
||||||
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
import paddle
|
||||||
|
from paddle import nn
|
||||||
|
from paddle.nn import functional as F
|
||||||
|
|
||||||
|
class Decoder(nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels,
|
||||||
|
out_channels,
|
||||||
|
channels=(256, 256),
|
||||||
|
dropout=0.05,
|
||||||
|
attention_head_dim=64,
|
||||||
|
n_blocks=1,
|
||||||
|
num_mid_blocks=2,
|
||||||
|
num_heads=4,
|
||||||
|
act_fn="snake",
|
||||||
|
down_block_type="transformer",
|
||||||
|
mid_block_type="transformer",
|
||||||
|
up_block_type="transformer",
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
channels = tuple(channels)
|
||||||
|
self.in_channels = in_channels
|
||||||
|
self.out_channels = out_channels
|
||||||
|
|
||||||
|
self.time_embeddings = SinusoidalPosEmb(in_channels)
|
||||||
|
time_embed_dim = channels[0] * 4
|
||||||
|
self.time_mlp = TimestepEmbedding(
|
||||||
|
in_channels=in_channels,
|
||||||
|
time_embed_dim=time_embed_dim,
|
||||||
|
act_fn="silu",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.down_blocks = nn.ModuleList([])
|
||||||
|
self.mid_blocks = nn.ModuleList([])
|
||||||
|
self.up_blocks = nn.ModuleList([])
|
||||||
|
|
||||||
|
output_channel = in_channels
|
||||||
|
for i in range(len(channels)): # pylint: disable=consider-using-enumerate
|
||||||
|
input_channel = output_channel
|
||||||
|
output_channel = channels[i]
|
||||||
|
is_last = i == len(channels) - 1
|
||||||
|
resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim)
|
||||||
|
transformer_blocks = nn.ModuleList(
|
||||||
|
[
|
||||||
|
self.get_block(
|
||||||
|
down_block_type,
|
||||||
|
output_channel,
|
||||||
|
attention_head_dim,
|
||||||
|
num_heads,
|
||||||
|
dropout,
|
||||||
|
act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
downsample = (
|
||||||
|
Downsample1D(output_channel) if not is_last else nn.Conv1d(output_channel, output_channel, 3, padding=1)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.down_blocks.append(nn.ModuleList([resnet, transformer_blocks, downsample]))
|
||||||
|
|
||||||
|
for i in range(num_mid_blocks):
|
||||||
|
input_channel = channels[-1]
|
||||||
|
out_channels = channels[-1]
|
||||||
|
|
||||||
|
resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim)
|
||||||
|
|
||||||
|
transformer_blocks = nn.ModuleList(
|
||||||
|
[
|
||||||
|
self.get_block(
|
||||||
|
mid_block_type,
|
||||||
|
output_channel,
|
||||||
|
attention_head_dim,
|
||||||
|
num_heads,
|
||||||
|
dropout,
|
||||||
|
act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mid_blocks.append(nn.ModuleList([resnet, transformer_blocks]))
|
||||||
|
|
||||||
|
channels = channels[::-1] + (channels[0],)
|
||||||
|
for i in range(len(channels) - 1):
|
||||||
|
input_channel = channels[i]
|
||||||
|
output_channel = channels[i + 1]
|
||||||
|
is_last = i == len(channels) - 2
|
||||||
|
|
||||||
|
resnet = ResnetBlock1D(
|
||||||
|
dim=2 * input_channel,
|
||||||
|
dim_out=output_channel,
|
||||||
|
time_emb_dim=time_embed_dim,
|
||||||
|
)
|
||||||
|
transformer_blocks = nn.ModuleList(
|
||||||
|
[
|
||||||
|
self.get_block(
|
||||||
|
up_block_type,
|
||||||
|
output_channel,
|
||||||
|
attention_head_dim,
|
||||||
|
num_heads,
|
||||||
|
dropout,
|
||||||
|
act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
upsample = (
|
||||||
|
Upsample1D(output_channel, use_conv_transpose=True)
|
||||||
|
if not is_last
|
||||||
|
else nn.Conv1d(output_channel, output_channel, 3, padding=1)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.up_blocks.append(nn.ModuleList([resnet, transformer_blocks, upsample]))
|
||||||
|
|
||||||
|
self.final_block = Block1D(channels[-1], channels[-1])
|
||||||
|
self.final_proj = nn.Conv1d(channels[-1], self.out_channels, 1)
|
||||||
|
|
||||||
|
self.initialize_weights()
|
||||||
|
# nn.init.normal_(self.final_proj.weight)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_block(block_type, dim, attention_head_dim, num_heads, dropout, act_fn):
|
||||||
|
if block_type == "conformer":
|
||||||
|
block = ConformerWrapper(
|
||||||
|
dim=dim,
|
||||||
|
dim_head=attention_head_dim,
|
||||||
|
heads=num_heads,
|
||||||
|
ff_mult=1,
|
||||||
|
conv_expansion_factor=2,
|
||||||
|
ff_dropout=dropout,
|
||||||
|
attn_dropout=dropout,
|
||||||
|
conv_dropout=dropout,
|
||||||
|
conv_kernel_size=31,
|
||||||
|
)
|
||||||
|
elif block_type == "transformer":
|
||||||
|
block = BasicTransformerBlock(
|
||||||
|
dim=dim,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown block type {block_type}")
|
||||||
|
|
||||||
|
return block
|
||||||
|
|
||||||
|
def initialize_weights(self):
|
||||||
|
for m in self.modules():
|
||||||
|
if isinstance(m, nn.Conv1d):
|
||||||
|
nn.init.kaiming_normal_(m.weight, nonlinearity="relu")
|
||||||
|
|
||||||
|
if m.bias is not None:
|
||||||
|
nn.init.constant_(m.bias, 0)
|
||||||
|
|
||||||
|
elif isinstance(m, nn.GroupNorm):
|
||||||
|
nn.init.constant_(m.weight, 1)
|
||||||
|
nn.init.constant_(m.bias, 0)
|
||||||
|
|
||||||
|
elif isinstance(m, nn.Linear):
|
||||||
|
nn.init.kaiming_normal_(m.weight, nonlinearity="relu")
|
||||||
|
|
||||||
|
if m.bias is not None:
|
||||||
|
nn.init.constant_(m.bias, 0)
|
||||||
|
|
||||||
|
def forward(self, x, mask, mu, t, spks=None, cond=None):
|
||||||
|
"""Forward pass of the UNet1DConditional model.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x (torch.Tensor): shape (batch_size, in_channels, time)
|
||||||
|
mask (_type_): shape (batch_size, 1, time)
|
||||||
|
t (_type_): shape (batch_size)
|
||||||
|
spks (_type_, optional): shape: (batch_size, condition_channels). Defaults to None.
|
||||||
|
cond (_type_, optional): placeholder for future use. Defaults to None.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: _description_
|
||||||
|
ValueError: _description_
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
_type_: _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
t = self.time_embeddings(t)
|
||||||
|
t = self.time_mlp(t)
|
||||||
|
|
||||||
|
x = pack([x, mu], "b * t")[0]
|
||||||
|
|
||||||
|
if spks is not None:
|
||||||
|
spks = repeat(spks, "b c -> b c t", t=x.shape[-1])
|
||||||
|
x = pack([x, spks], "b * t")[0]
|
||||||
|
|
||||||
|
hiddens = []
|
||||||
|
masks = [mask]
|
||||||
|
for resnet, transformer_blocks, downsample in self.down_blocks:
|
||||||
|
mask_down = masks[-1]
|
||||||
|
x = resnet(x, mask_down, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c")
|
||||||
|
mask_down = rearrange(mask_down, "b 1 t -> b t")
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=mask_down,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t")
|
||||||
|
mask_down = rearrange(mask_down, "b t -> b 1 t")
|
||||||
|
hiddens.append(x) # Save hidden states for skip connections
|
||||||
|
x = downsample(x * mask_down)
|
||||||
|
masks.append(mask_down[:, :, ::2])
|
||||||
|
|
||||||
|
masks = masks[:-1]
|
||||||
|
mask_mid = masks[-1]
|
||||||
|
|
||||||
|
for resnet, transformer_blocks in self.mid_blocks:
|
||||||
|
x = resnet(x, mask_mid, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c")
|
||||||
|
mask_mid = rearrange(mask_mid, "b 1 t -> b t")
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=mask_mid,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t")
|
||||||
|
mask_mid = rearrange(mask_mid, "b t -> b 1 t")
|
||||||
|
|
||||||
|
for resnet, transformer_blocks, upsample in self.up_blocks:
|
||||||
|
mask_up = masks.pop()
|
||||||
|
x = resnet(pack([x, hiddens.pop()], "b * t")[0], mask_up, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c")
|
||||||
|
mask_up = rearrange(mask_up, "b 1 t -> b t")
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=mask_up,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t")
|
||||||
|
mask_up = rearrange(mask_up, "b t -> b 1 t")
|
||||||
|
x = upsample(x * mask_up)
|
||||||
|
|
||||||
|
x = self.final_block(x, mask_up)
|
||||||
|
output = self.final_proj(x * mask_up)
|
||||||
|
|
||||||
|
return output * mask
|
||||||
@ -0,0 +1,737 @@
|
|||||||
|
import queue
|
||||||
|
import random
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from typing import Callable, Dict, Generator, List, Optional
|
||||||
|
import logging
|
||||||
|
import paddle.nn.functional as F
|
||||||
|
import paddle
|
||||||
|
IGNORE_ID = -1
|
||||||
|
# from cosyvoice.transformer.label_smoothing_loss import LabelSmoothingLoss
|
||||||
|
# from cosyvoice.utils.common import IGNORE_ID, th_accuracy
|
||||||
|
# from cosyvoice.utils.file_utils import logging
|
||||||
|
# from cosyvoice.utils.mask import make_pad_mask
|
||||||
|
import torch
|
||||||
|
LabelSmoothingLoss = None
|
||||||
|
def ras_sampling(weighted_scores, decoded_tokens, sampling, top_p=0.8, top_k=25, win_size=10, tau_r=0.1):
|
||||||
|
top_ids = nucleus_sampling(weighted_scores, top_p=top_p, top_k=top_k)
|
||||||
|
recent_tokens = paddle.to_tensor(decoded_tokens[-win_size:], dtype='int64')
|
||||||
|
rep_num = paddle.sum(recent_tokens.cpu() == top_ids.cpu()).cpu().item()
|
||||||
|
if rep_num >= win_size * tau_r:
|
||||||
|
top_ids = random_sampling(weighted_scores, decoded_tokens, sampling)
|
||||||
|
return top_ids
|
||||||
|
|
||||||
|
|
||||||
|
def nucleus_sampling(weighted_scores, top_p=0.8, top_k=25):
|
||||||
|
softmax_scores = paddle.nn.functional.softmax(weighted_scores, axis=0)
|
||||||
|
sorted_indices = paddle.argsort(softmax_scores, axis=0, descending=True)
|
||||||
|
sorted_probs = paddle.gather(softmax_scores, sorted_indices, axis=0)
|
||||||
|
|
||||||
|
prob_list = []
|
||||||
|
indices_list = []
|
||||||
|
cum_prob = 0.0
|
||||||
|
|
||||||
|
for i in range(len(sorted_indices)):
|
||||||
|
if cum_prob < top_p and len(prob_list) < top_k:
|
||||||
|
cum_prob += sorted_probs[i].item()
|
||||||
|
prob_list.append(sorted_probs[i])
|
||||||
|
indices_list.append(sorted_indices[i])
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
prob_tensor = paddle.to_tensor(prob_list, dtype=weighted_scores.dtype)
|
||||||
|
indices_tensor = paddle.to_tensor(indices_list, dtype='int64')
|
||||||
|
top_ids = indices_tensor[paddle.multinomial(prob_tensor, num_samples=1, replacement=True)]
|
||||||
|
|
||||||
|
return top_ids
|
||||||
|
|
||||||
|
|
||||||
|
def random_sampling(weighted_scores, decoded_tokens, sampling):
|
||||||
|
probs = paddle.nn.functional.softmax(weighted_scores, axis=0)
|
||||||
|
top_ids = paddle.multinomial(probs, num_samples=1, replacement=True)
|
||||||
|
return top_ids
|
||||||
|
def make_pad_mask(lengths: paddle.Tensor, max_len: int = 0) -> paddle.Tensor:
|
||||||
|
batch_size = lengths.shape[0]
|
||||||
|
max_len = max_len if max_len > 0 else lengths.max().item()
|
||||||
|
seq_range = paddle.arange(0, max_len, dtype='int64')
|
||||||
|
seq_range_expand = seq_range.unsqueeze(0).expand([batch_size, max_len])
|
||||||
|
seq_length_expand = lengths.unsqueeze(-1)
|
||||||
|
mask = seq_range_expand >= seq_length_expand
|
||||||
|
return mask
|
||||||
|
|
||||||
|
def th_accuracy(pad_outputs: paddle.Tensor, pad_targets: paddle.Tensor,
|
||||||
|
ignore_label: int) -> paddle.Tensor:
|
||||||
|
pad_pred = pad_outputs.reshape((pad_targets.shape[0], pad_targets.shape[1], -1)).argmax(axis=2)
|
||||||
|
mask = pad_targets != ignore_label
|
||||||
|
numerator = paddle.sum((pad_pred[mask] == pad_targets[mask]).astype('float32'))
|
||||||
|
denominator = paddle.sum(mask.astype('float32'))
|
||||||
|
accuracy = numerator / denominator
|
||||||
|
|
||||||
|
return accuracy.detach()
|
||||||
|
class TransformerLM(paddle.nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
text_encoder_input_size: int,
|
||||||
|
llm_input_size: int,
|
||||||
|
llm_output_size: int,
|
||||||
|
text_token_size: int,
|
||||||
|
speech_token_size: int,
|
||||||
|
text_encoder: paddle.nn.Layer,
|
||||||
|
llm: paddle.nn.Layer,
|
||||||
|
sampling: Callable,
|
||||||
|
length_normalized_loss: bool = True,
|
||||||
|
lsm_weight: float = 0.0,
|
||||||
|
spk_embed_dim: int = 192,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.llm_input_size = llm_input_size
|
||||||
|
self.speech_token_size = speech_token_size
|
||||||
|
self.text_embedding = paddle.nn.Embedding(
|
||||||
|
text_token_size, text_encoder_input_size
|
||||||
|
)
|
||||||
|
self.text_encoder = text_encoder
|
||||||
|
self.text_encoder_affine_layer = paddle.nn.Linear(
|
||||||
|
in_features=self.text_encoder.output_size(), out_features=llm_input_size
|
||||||
|
)
|
||||||
|
self.sos_eos = 0
|
||||||
|
self.task_id = 1
|
||||||
|
self.llm_embedding = paddle.nn.Embedding(2, llm_input_size)
|
||||||
|
self.llm = llm
|
||||||
|
self.llm_decoder = paddle.nn.Linear(
|
||||||
|
in_features=llm_output_size, out_features=speech_token_size + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
self.criterion_ce = LabelSmoothingLoss(
|
||||||
|
size=speech_token_size + 1,
|
||||||
|
padding_idx=IGNORE_ID,
|
||||||
|
smoothing=lsm_weight,
|
||||||
|
normalize_length=length_normalized_loss,
|
||||||
|
)
|
||||||
|
self.speech_embedding = paddle.nn.Embedding(speech_token_size, llm_input_size)
|
||||||
|
self.spk_embed_affine_layer = paddle.nn.Linear(
|
||||||
|
in_features=spk_embed_dim, out_features=llm_input_size
|
||||||
|
)
|
||||||
|
self.sampling = sampling
|
||||||
|
|
||||||
|
def encode(self, text: paddle.Tensor, text_lengths: paddle.Tensor):
|
||||||
|
encoder_out, encoder_mask = self.text_encoder(
|
||||||
|
text, text_lengths, decoding_chunk_size=1, num_decoding_left_chunks=-1
|
||||||
|
)
|
||||||
|
encoder_out_lens = encoder_mask.squeeze(1).sum(1)
|
||||||
|
encoder_out = self.text_encoder_affine_layer(encoder_out)
|
||||||
|
return encoder_out, encoder_out_lens
|
||||||
|
|
||||||
|
def pad_unpad_sequence(
|
||||||
|
self,
|
||||||
|
sos_eos_emb,
|
||||||
|
embedding,
|
||||||
|
text_token,
|
||||||
|
text_token_len,
|
||||||
|
task_id_emb,
|
||||||
|
speech_token,
|
||||||
|
speech_token_len,
|
||||||
|
):
|
||||||
|
|
||||||
|
text_token = paddle.static.nn.sequence_unpad(
|
||||||
|
text_token, text_token_len.cpu()
|
||||||
|
)
|
||||||
|
speech_token = paddle.static.nn.sequence_unpad(
|
||||||
|
speech_token, speech_token_len.cpu()
|
||||||
|
)
|
||||||
|
lm_input = [
|
||||||
|
paddle.cat(
|
||||||
|
[
|
||||||
|
sos_eos_emb.squeeze(dim=0),
|
||||||
|
embedding[i],
|
||||||
|
text_token[i],
|
||||||
|
task_id_emb.squeeze(dim=0),
|
||||||
|
speech_token[i],
|
||||||
|
],
|
||||||
|
dim=0,
|
||||||
|
)
|
||||||
|
for i in range(len(text_token))
|
||||||
|
]
|
||||||
|
lm_input_len = paddle.tensor([i.size(0) for i in lm_input], dtype=paddle.int32)
|
||||||
|
lm_input = paddle.static.nn.sequence_unpad(
|
||||||
|
lm_input, batch_first=True, padding_value=IGNORE_ID
|
||||||
|
)
|
||||||
|
return lm_input, lm_input_len
|
||||||
|
|
||||||
|
def forward(
|
||||||
|
self, batch: dict, device: torch.device
|
||||||
|
) -> Dict[str, Optional[paddle.Tensor]]:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
text: (B, L, D)
|
||||||
|
text_lengths: (B,)
|
||||||
|
audio: (B, T, N) or (B, T)
|
||||||
|
audio_lengths: (B,)
|
||||||
|
"""
|
||||||
|
text_token = batch["text_token"].to(device)
|
||||||
|
text_token_len = batch["text_token_len"].to(device)
|
||||||
|
speech_token = batch["speech_token"].to(device)
|
||||||
|
speech_token_len = batch["speech_token_len"].to(device)
|
||||||
|
embedding = batch["embedding"].to(device)
|
||||||
|
lm_target = [
|
||||||
|
paddle.tensor(
|
||||||
|
[IGNORE_ID] * (2 + text_token_len[i])
|
||||||
|
+ speech_token[i, : speech_token_len[i]].tolist()
|
||||||
|
+ [self.speech_token_size]
|
||||||
|
)
|
||||||
|
for i in range(text_token.size(0))
|
||||||
|
]
|
||||||
|
lm_target = torch.nn.utils.rnn.pad_sequence(
|
||||||
|
lm_target, batch_first=True, padding_value=IGNORE_ID
|
||||||
|
).to(device)
|
||||||
|
text_token = self.text_embedding(text_token)
|
||||||
|
text_token, text_token_len = self.encode(text_token, text_token_len)
|
||||||
|
embedding = paddle.nn.functional.normalize(x=embedding, axis=1)
|
||||||
|
embedding = self.spk_embed_affine_layer(embedding)
|
||||||
|
embedding = embedding.unsqueeze(1)
|
||||||
|
sos_eos_emb = self.llm_embedding.weight[self.sos_eos].reshape(1, 1, -1)
|
||||||
|
task_id_emb = self.llm_embedding.weight[self.task_id].reshape(1, 1, -1)
|
||||||
|
speech_token = self.speech_embedding(speech_token)
|
||||||
|
lm_input, lm_input_len = self.pad_unpad_sequence(
|
||||||
|
sos_eos_emb,
|
||||||
|
embedding,
|
||||||
|
text_token,
|
||||||
|
text_token_len,
|
||||||
|
task_id_emb,
|
||||||
|
speech_token,
|
||||||
|
speech_token_len,
|
||||||
|
)
|
||||||
|
lm_output, lm_output_mask = self.llm(lm_input, lm_input_len.to(device))
|
||||||
|
logits = self.llm_decoder(lm_output)
|
||||||
|
loss = self.criterion_ce(logits, lm_target)
|
||||||
|
acc = th_accuracy(
|
||||||
|
logits.view(-1, self.speech_token_size + 1),
|
||||||
|
lm_target,
|
||||||
|
ignore_label=IGNORE_ID,
|
||||||
|
)
|
||||||
|
return {"loss": loss, "acc": acc}
|
||||||
|
|
||||||
|
def sampling_ids(
|
||||||
|
self,
|
||||||
|
weighted_scores: paddle.Tensor,
|
||||||
|
decoded_tokens: List,
|
||||||
|
sampling: int,
|
||||||
|
ignore_eos: bool = True,
|
||||||
|
):
|
||||||
|
num_trials, max_trials = 0, 100
|
||||||
|
while True:
|
||||||
|
top_ids = self.sampling(weighted_scores, decoded_tokens, sampling)
|
||||||
|
if not ignore_eos or self.speech_token_size not in top_ids:
|
||||||
|
break
|
||||||
|
num_trials += 1
|
||||||
|
if num_trials > max_trials:
|
||||||
|
raise RuntimeError(
|
||||||
|
"sampling reaches max_trials {} and still get eos when ignore_eos is True, check your input!".format(
|
||||||
|
max_trials
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return top_ids
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def inference(
|
||||||
|
self,
|
||||||
|
text: paddle.Tensor,
|
||||||
|
text_len: paddle.Tensor,
|
||||||
|
prompt_text: paddle.Tensor,
|
||||||
|
prompt_text_len: paddle.Tensor,
|
||||||
|
prompt_speech_token: paddle.Tensor,
|
||||||
|
prompt_speech_token_len: paddle.Tensor,
|
||||||
|
embedding: paddle.Tensor,
|
||||||
|
sampling: int = 25,
|
||||||
|
max_token_text_ratio: float = 20,
|
||||||
|
min_token_text_ratio: float = 2,
|
||||||
|
uuid: str = "",
|
||||||
|
) -> Generator[paddle.Tensor, None, None]:
|
||||||
|
device = text.place
|
||||||
|
text = paddle.cat([prompt_text, text], dim=1)
|
||||||
|
text_len += prompt_text_len
|
||||||
|
text = self.text_embedding(text)
|
||||||
|
text, text_len = self.encode(text, text_len)
|
||||||
|
if embedding.shape[0] != 0:
|
||||||
|
embedding = paddle.nn.functional.normalize(x=embedding, axis=1)
|
||||||
|
embedding = self.spk_embed_affine_layer(embedding)
|
||||||
|
embedding = embedding.unsqueeze(dim=1)
|
||||||
|
else:
|
||||||
|
embedding = (
|
||||||
|
paddle.zeros(1, 0, self.llm_input_size, dtype=text.dtype)
|
||||||
|
.to(device)
|
||||||
|
.to(text.dtype)
|
||||||
|
)
|
||||||
|
sos_eos_emb = self.llm_embedding.weight[self.sos_eos].reshape(1, 1, -1)
|
||||||
|
task_id_emb = self.llm_embedding.weight[self.task_id].reshape(1, 1, -1)
|
||||||
|
if prompt_speech_token_len != 0:
|
||||||
|
prompt_speech_token_emb = self.speech_embedding(prompt_speech_token)
|
||||||
|
else:
|
||||||
|
prompt_speech_token_emb = paddle.zeros(
|
||||||
|
1, 0, self.llm_input_size, dtype=text.dtype
|
||||||
|
).to(device)
|
||||||
|
lm_input = paddle.cat(
|
||||||
|
[sos_eos_emb, embedding, text, task_id_emb, prompt_speech_token_emb], dim=1
|
||||||
|
)
|
||||||
|
min_len = int((text_len - prompt_text_len) * min_token_text_ratio)
|
||||||
|
max_len = int((text_len - prompt_text_len) * max_token_text_ratio)
|
||||||
|
out_tokens = []
|
||||||
|
offset = 0
|
||||||
|
att_cache, cnn_cache = paddle.zeros(
|
||||||
|
(0, 0, 0, 0), device=lm_input.place
|
||||||
|
), paddle.zeros((0, 0, 0, 0), device=lm_input.place)
|
||||||
|
for i in range(max_len):
|
||||||
|
y_pred, att_cache, cnn_cache = self.llm.forward_chunk(
|
||||||
|
lm_input,
|
||||||
|
offset=offset,
|
||||||
|
required_cache_size=-1,
|
||||||
|
att_cache=att_cache,
|
||||||
|
cnn_cache=cnn_cache,
|
||||||
|
att_mask=paddle.tril(
|
||||||
|
paddle.ones(
|
||||||
|
(1, lm_input.shape[1], lm_input.shape[1]), device=lm_input.place
|
||||||
|
)
|
||||||
|
).to(paddle.bool),
|
||||||
|
)
|
||||||
|
logp = self.llm_decoder(y_pred[:, -1]).log_softmax(dim=-1)
|
||||||
|
if i == 0:
|
||||||
|
logp[:, self.speech_token_size] = -float("inf")
|
||||||
|
top_ids = self.sampling_ids(
|
||||||
|
logp.squeeze(dim=0),
|
||||||
|
out_tokens,
|
||||||
|
sampling,
|
||||||
|
ignore_eos=True if i < min_len else False,
|
||||||
|
).item()
|
||||||
|
if top_ids == self.speech_token_size:
|
||||||
|
break
|
||||||
|
yield top_ids
|
||||||
|
out_tokens.append(top_ids)
|
||||||
|
offset += lm_input.size(1)
|
||||||
|
lm_input = self.speech_embedding.weight[top_ids].reshape(1, 1, -1)
|
||||||
|
|
||||||
|
|
||||||
|
class Qwen2Encoder(paddle.nn.Layer):
|
||||||
|
def __init__(self, model):
|
||||||
|
super().__init__()
|
||||||
|
self.model = model
|
||||||
|
|
||||||
|
def forward(self, xs: paddle.Tensor, xs_lens: paddle.Tensor):
|
||||||
|
T = xs.size(1)
|
||||||
|
masks = ~make_pad_mask(xs_lens, T)
|
||||||
|
outs = self.model(
|
||||||
|
inputs_embeds=xs,
|
||||||
|
attention_mask=masks,
|
||||||
|
output_hidden_states=True,
|
||||||
|
return_dict=True,
|
||||||
|
)
|
||||||
|
return outs.hidden_states[-1], masks.unsqueeze(1)
|
||||||
|
|
||||||
|
def forward_one_step(self, xs, masks, cache=None):
|
||||||
|
input_masks = masks[:, -1, :]
|
||||||
|
outs = self.model(
|
||||||
|
inputs_embeds=xs,
|
||||||
|
attention_mask=input_masks,
|
||||||
|
output_hidden_states=True,
|
||||||
|
return_dict=True,
|
||||||
|
use_cache=True,
|
||||||
|
past_key_values=cache,
|
||||||
|
)
|
||||||
|
xs = outs.hidden_states[-1]
|
||||||
|
new_cache = outs.past_key_values
|
||||||
|
xs = paddle.cast(xs, dtype = 'float32')
|
||||||
|
return xs, new_cache
|
||||||
|
|
||||||
|
|
||||||
|
class Qwen2LM(TransformerLM):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
llm_input_size: int,
|
||||||
|
llm_output_size: int,
|
||||||
|
speech_token_size: int,
|
||||||
|
llm: paddle.nn.Layer,
|
||||||
|
sampling: Callable,
|
||||||
|
length_normalized_loss: bool = True,
|
||||||
|
lsm_weight: float = 0.0,
|
||||||
|
mix_ratio: List[int] = [5, 15],
|
||||||
|
):
|
||||||
|
paddle.nn.Layer.__init__(self)
|
||||||
|
self.llm_input_size = llm_input_size
|
||||||
|
self.llm_output_size = llm_output_size
|
||||||
|
self.speech_token_size = speech_token_size
|
||||||
|
self.sos_eos = 0
|
||||||
|
self.task_id = 1
|
||||||
|
self.fill_token = 2
|
||||||
|
self.llm_embedding = paddle.nn.Embedding(2, llm_input_size)
|
||||||
|
self.llm = llm
|
||||||
|
self.llm_decoder = paddle.nn.Linear(
|
||||||
|
in_features=llm_output_size, out_features=speech_token_size + 3
|
||||||
|
)
|
||||||
|
# self.llm_decoder.weight = paddle.create_parameter(
|
||||||
|
# shape=self.llm_decoder.weight.shape,
|
||||||
|
# dtype='bfloat16',
|
||||||
|
# default_initializer=paddle.nn.initializer.Assign(self.llm_decoder.weight.astype('bfloat16'))
|
||||||
|
# )
|
||||||
|
# if self.llm_decoder.bias is not None:
|
||||||
|
# self.llm_decoder.bias = paddle.create_parameter(
|
||||||
|
# shape=self.llm_decoder.bias.shape,
|
||||||
|
# dtype='bfloat16',
|
||||||
|
# default_initializer=paddle.nn.initializer.Assign(self.llm_decoder.bias.astype('bfloat16'))
|
||||||
|
# )
|
||||||
|
# self.criterion_ce = LabelSmoothingLoss(
|
||||||
|
# size=speech_token_size + 3,
|
||||||
|
# padding_idx=IGNORE_ID,
|
||||||
|
# smoothing=lsm_weight,
|
||||||
|
# normalize_length=length_normalized_loss,
|
||||||
|
# )
|
||||||
|
self.speech_embedding = paddle.nn.Embedding(
|
||||||
|
speech_token_size + 3, llm_input_size
|
||||||
|
)
|
||||||
|
self.sampling = sampling
|
||||||
|
self.mix_ratio = mix_ratio
|
||||||
|
self.stop_token_ids = [(speech_token_size + i) for i in range(3)]
|
||||||
|
self.vllm_output_queue = {}
|
||||||
|
|
||||||
|
# def prepare_lm_input_target(
|
||||||
|
# self,
|
||||||
|
# text_token,
|
||||||
|
# text_token_emb,
|
||||||
|
# text_token_len,
|
||||||
|
# speech_token,
|
||||||
|
# speech_token_emb,
|
||||||
|
# speech_token_len,
|
||||||
|
# ):
|
||||||
|
# lm_target, lm_input = [], []
|
||||||
|
# text_token = torch.nn.utils.rnn.unpad_sequence(
|
||||||
|
# text_token, text_token_len.cpu(), batch_first=True
|
||||||
|
# )
|
||||||
|
# speech_token = torch.nn.utils.rnn.unpad_sequence(
|
||||||
|
# speech_token, speech_token_len.cpu(), batch_first=True
|
||||||
|
# )
|
||||||
|
# text_token_emb = torch.nn.utils.rnn.unpad_sequence(
|
||||||
|
# text_token_emb, text_token_len.cpu(), batch_first=True
|
||||||
|
# )
|
||||||
|
# speech_token_emb = torch.nn.utils.rnn.unpad_sequence(
|
||||||
|
# speech_token_emb, speech_token_len.cpu(), batch_first=True
|
||||||
|
# )
|
||||||
|
# for i in range(len(text_token)):
|
||||||
|
# if (
|
||||||
|
# random.random() < 0.5
|
||||||
|
# and speech_token_len[i] / text_token_len[i]
|
||||||
|
# > self.mix_ratio[1] / self.mix_ratio[0]
|
||||||
|
# ):
|
||||||
|
# this_lm_target, this_lm_input = [], []
|
||||||
|
# this_lm_target.append(IGNORE_ID)
|
||||||
|
# this_lm_input.append(
|
||||||
|
# self.llm_embedding.weight[self.sos_eos].reshape(1, -1)
|
||||||
|
# )
|
||||||
|
# for j in range(
|
||||||
|
# ((text_token_len[i] + 1) / self.mix_ratio[0]).ceil().int().item()
|
||||||
|
# ):
|
||||||
|
# this_text_token = text_token[i][
|
||||||
|
# j * self.mix_ratio[0] : (j + 1) * self.mix_ratio[0]
|
||||||
|
# ].tolist()
|
||||||
|
# this_speech_token = speech_token[i][
|
||||||
|
# j * self.mix_ratio[1] : (j + 1) * self.mix_ratio[1]
|
||||||
|
# ].tolist()
|
||||||
|
# if len(this_text_token) == self.mix_ratio[0]:
|
||||||
|
# assert len(this_speech_token) == self.mix_ratio[1]
|
||||||
|
# this_lm_target += [IGNORE_ID] * (self.mix_ratio[0] - 1)
|
||||||
|
# this_lm_target += this_speech_token
|
||||||
|
# this_lm_target.append(self.speech_token_size + 2)
|
||||||
|
# this_lm_input.append(
|
||||||
|
# text_token_emb[i][
|
||||||
|
# j * self.mix_ratio[0] : (j + 1) * self.mix_ratio[0]
|
||||||
|
# ]
|
||||||
|
# )
|
||||||
|
# this_lm_input.append(
|
||||||
|
# speech_token_emb[i][
|
||||||
|
# j * self.mix_ratio[1] : (j + 1) * self.mix_ratio[1]
|
||||||
|
# ]
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# this_lm_target += [-1] * len(this_text_token)
|
||||||
|
# this_lm_target += speech_token[i][
|
||||||
|
# j * self.mix_ratio[1] :
|
||||||
|
# ].tolist()
|
||||||
|
# this_lm_target.append(self.speech_token_size)
|
||||||
|
# this_lm_input.append(text_token_emb[i][j * self.mix_ratio[0] :])
|
||||||
|
# this_lm_input.append(
|
||||||
|
# self.llm_embedding.weight[self.task_id].reshape(1, -1)
|
||||||
|
# )
|
||||||
|
# this_lm_input.append(
|
||||||
|
# speech_token_emb[i][j * self.mix_ratio[1] :]
|
||||||
|
# )
|
||||||
|
# this_lm_target, this_lm_input = paddle.tensor(
|
||||||
|
# this_lm_target
|
||||||
|
# ), paddle.cat(this_lm_input, dim=0)
|
||||||
|
# else:
|
||||||
|
# this_lm_target = paddle.tensor(
|
||||||
|
# [IGNORE_ID] * (1 + text_token_len[i])
|
||||||
|
# + speech_token[i].tolist()
|
||||||
|
# + [self.speech_token_size]
|
||||||
|
# )
|
||||||
|
# this_lm_input = paddle.cat(
|
||||||
|
# [
|
||||||
|
# self.llm_embedding.weight[self.sos_eos].reshape(1, -1),
|
||||||
|
# text_token_emb[i],
|
||||||
|
# self.llm_embedding.weight[self.task_id].reshape(1, -1),
|
||||||
|
# speech_token_emb[i],
|
||||||
|
# ],
|
||||||
|
# dim=0,
|
||||||
|
# )
|
||||||
|
# lm_target.append(this_lm_target)
|
||||||
|
# lm_input.append(this_lm_input)
|
||||||
|
# lm_input_len = paddle.tensor([i.size(0) for i in lm_input], dtype=paddle.int32)
|
||||||
|
# lm_input = torch.nn.utils.rnn.pad_sequence(
|
||||||
|
# lm_input, batch_first=True, padding_value=IGNORE_ID
|
||||||
|
# )
|
||||||
|
# lm_target = torch.nn.utils.rnn.pad_sequence(
|
||||||
|
# lm_target, batch_first=True, padding_value=IGNORE_ID
|
||||||
|
# )
|
||||||
|
# return lm_target, lm_input, lm_input_len
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def inference(
|
||||||
|
self,
|
||||||
|
text: paddle.Tensor,
|
||||||
|
text_len: paddle.Tensor,
|
||||||
|
prompt_text: paddle.Tensor,
|
||||||
|
prompt_text_len: paddle.Tensor,
|
||||||
|
prompt_speech_token: paddle.Tensor,
|
||||||
|
prompt_speech_token_len: paddle.Tensor,
|
||||||
|
embedding: paddle.Tensor,
|
||||||
|
sampling: int = 25,
|
||||||
|
max_token_text_ratio: float = 20,
|
||||||
|
min_token_text_ratio: float = 2,
|
||||||
|
uuid: str = "",
|
||||||
|
) -> Generator[paddle.Tensor, None, None]:
|
||||||
|
device = text.place
|
||||||
|
text = paddle.cat([prompt_text, text], dim=1)
|
||||||
|
text_len += prompt_text_len
|
||||||
|
text = self.llm.model.qwen2.embed_tokens(text)
|
||||||
|
sos_eos_emb = self.llm_embedding.weight[self.sos_eos].reshape([1, 1, -1])
|
||||||
|
task_id_emb = self.llm_embedding.weight[self.task_id].reshape([1, 1, -1])
|
||||||
|
if prompt_speech_token_len != 0:
|
||||||
|
prompt_speech_token_emb = self.speech_embedding(prompt_speech_token)
|
||||||
|
else:
|
||||||
|
prompt_speech_token_emb = paddle.zeros(
|
||||||
|
1, 0, self.llm_input_size, dtype=text.dtype
|
||||||
|
).to(device)
|
||||||
|
text = paddle.cast(text,dtype = 'float32')
|
||||||
|
lm_input = paddle.cat(
|
||||||
|
[sos_eos_emb, text, task_id_emb, prompt_speech_token_emb], dim=1
|
||||||
|
)
|
||||||
|
min_len = int((text_len - prompt_text_len) * min_token_text_ratio)
|
||||||
|
max_len = int((text_len - prompt_text_len) * max_token_text_ratio)
|
||||||
|
for token in self.inference_wrapper(lm_input, sampling, min_len, max_len, uuid):
|
||||||
|
yield token
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def inference_wrapper(self, lm_input, sampling, min_len, max_len, uuid):
|
||||||
|
if hasattr(self, "vllm"):
|
||||||
|
from vllm import RequestOutput, SamplingParams
|
||||||
|
|
||||||
|
sampling_params = SamplingParams(
|
||||||
|
top_k=sampling,
|
||||||
|
stop_token_ids=self.stop_token_ids,
|
||||||
|
min_tokens=min_len,
|
||||||
|
max_tokens=max_len,
|
||||||
|
)
|
||||||
|
with self.lock:
|
||||||
|
self.vllm.add_request(
|
||||||
|
uuid,
|
||||||
|
{
|
||||||
|
"prompt_embeds": lm_input.squeeze(0)
|
||||||
|
.to(paddle.bfloat16)
|
||||||
|
.to(lm_input.place)
|
||||||
|
},
|
||||||
|
sampling_params,
|
||||||
|
)
|
||||||
|
self.vllm_output_queue[uuid] = queue.Queue()
|
||||||
|
out_tokens = []
|
||||||
|
while True:
|
||||||
|
with self.lock:
|
||||||
|
if self.vllm_output_queue[uuid].empty() is True:
|
||||||
|
request_outputs: List[RequestOutput] = self.vllm.step()
|
||||||
|
for request_output in request_outputs:
|
||||||
|
top_ids = list(request_output.outputs[0].token_ids)[-1]
|
||||||
|
self.vllm_output_queue[request_output.request_id].put(
|
||||||
|
top_ids
|
||||||
|
)
|
||||||
|
if self.vllm_output_queue[uuid].empty() is False:
|
||||||
|
top_ids = self.vllm_output_queue[uuid].get()
|
||||||
|
if top_ids in self.stop_token_ids:
|
||||||
|
break
|
||||||
|
yield top_ids
|
||||||
|
out_tokens.append(top_ids)
|
||||||
|
if len(out_tokens) == max_len:
|
||||||
|
break
|
||||||
|
time.sleep(0.001)
|
||||||
|
with self.lock:
|
||||||
|
self.vllm_output_queue.pop(uuid)
|
||||||
|
else:
|
||||||
|
out_tokens = []
|
||||||
|
cache = None
|
||||||
|
for i in range(max_len):
|
||||||
|
y_pred, cache = self.llm.forward_one_step(
|
||||||
|
lm_input,
|
||||||
|
masks=paddle.tril(
|
||||||
|
paddle.ones(
|
||||||
|
(1, lm_input.shape[1], lm_input.shape[1]),
|
||||||
|
)
|
||||||
|
).to(paddle.bool),
|
||||||
|
cache=cache,
|
||||||
|
)
|
||||||
|
logp = F.log_softmax(self.llm_decoder(y_pred[:, -1]), axis = -1)
|
||||||
|
top_ids = self.sampling_ids(
|
||||||
|
logp.squeeze(axis=0),
|
||||||
|
out_tokens,
|
||||||
|
sampling,
|
||||||
|
ignore_eos=True if i < min_len else False,
|
||||||
|
).item()
|
||||||
|
if top_ids == self.speech_token_size:
|
||||||
|
break
|
||||||
|
if top_ids > self.speech_token_size:
|
||||||
|
continue
|
||||||
|
yield top_ids
|
||||||
|
out_tokens.append(top_ids)
|
||||||
|
lm_input = self.speech_embedding.weight[top_ids].reshape([1, 1, -1])
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def inference_bistream(
|
||||||
|
self,
|
||||||
|
text: Generator,
|
||||||
|
prompt_text: paddle.Tensor,
|
||||||
|
prompt_text_len: paddle.Tensor,
|
||||||
|
prompt_speech_token: paddle.Tensor,
|
||||||
|
prompt_speech_token_len: paddle.Tensor,
|
||||||
|
embedding: paddle.Tensor,
|
||||||
|
sampling: int = 25,
|
||||||
|
max_token_text_ratio: float = 20,
|
||||||
|
min_token_text_ratio: float = 2,
|
||||||
|
) -> Generator[paddle.Tensor, None, None]:
|
||||||
|
device = prompt_text.place
|
||||||
|
sos_eos_emb = self.llm_embedding.weight[self.sos_eos].reshape(1, 1, -1)
|
||||||
|
task_id_emb = self.llm_embedding.weight[self.task_id].reshape(1, 1, -1)
|
||||||
|
if prompt_speech_token_len != 0:
|
||||||
|
prompt_speech_token_emb = self.speech_embedding(prompt_speech_token)
|
||||||
|
else:
|
||||||
|
prompt_speech_token_emb = paddle.zeros(
|
||||||
|
1, 0, self.llm_input_size, dtype=prompt_text.dtype
|
||||||
|
).to(device)
|
||||||
|
lm_input = paddle.cat([sos_eos_emb], dim=1)
|
||||||
|
out_tokens = []
|
||||||
|
cache = None
|
||||||
|
text_cache = self.llm.model.model.embed_tokens(prompt_text)
|
||||||
|
next_fill_index = -1
|
||||||
|
for this_text in text:
|
||||||
|
text_cache = paddle.cat(
|
||||||
|
[text_cache, self.llm.model.model.embed_tokens(this_text)], dim=1
|
||||||
|
)
|
||||||
|
while prompt_speech_token_emb.size(1) != 0:
|
||||||
|
if text_cache.size(1) >= self.mix_ratio[0]:
|
||||||
|
lm_input_text, lm_input_speech = (
|
||||||
|
text_cache[:, : self.mix_ratio[0]],
|
||||||
|
prompt_speech_token_emb[:, : self.mix_ratio[1]],
|
||||||
|
)
|
||||||
|
logging.info(
|
||||||
|
"append {} text token {} speech token".format(
|
||||||
|
lm_input_text.size(1), lm_input_speech.size(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lm_input = paddle.cat(
|
||||||
|
[lm_input, lm_input_text, lm_input_speech], dim=1
|
||||||
|
)
|
||||||
|
text_cache, prompt_speech_token_emb = (
|
||||||
|
text_cache[:, self.mix_ratio[0] :],
|
||||||
|
prompt_speech_token_emb[:, self.mix_ratio[1] :],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.info("not enough text token to decode, wait for more")
|
||||||
|
break
|
||||||
|
if prompt_speech_token_emb.size(1) == 0:
|
||||||
|
if (
|
||||||
|
len(out_tokens) != 0
|
||||||
|
and out_tokens[-1] == self.speech_token_size + 2
|
||||||
|
or len(out_tokens) == 0
|
||||||
|
and lm_input.size(1) == 1
|
||||||
|
):
|
||||||
|
logging.info("get fill token, need to append more text token")
|
||||||
|
if text_cache.size(1) >= self.mix_ratio[0]:
|
||||||
|
lm_input_text = text_cache[:, : self.mix_ratio[0]]
|
||||||
|
logging.info(
|
||||||
|
"append {} text token".format(lm_input_text.size(1))
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
len(out_tokens) != 0
|
||||||
|
and out_tokens[-1] == self.speech_token_size + 2
|
||||||
|
):
|
||||||
|
lm_input = lm_input_text
|
||||||
|
else:
|
||||||
|
lm_input = paddle.cat([lm_input, lm_input_text], dim=1)
|
||||||
|
text_cache = text_cache[:, self.mix_ratio[0] :]
|
||||||
|
else:
|
||||||
|
logging.info("not enough text token to decode, wait for more")
|
||||||
|
continue
|
||||||
|
while True:
|
||||||
|
seq_len = (
|
||||||
|
lm_input.shape[1]
|
||||||
|
if cache is None
|
||||||
|
else lm_input.shape[1] + cache[0][0].size(2)
|
||||||
|
)
|
||||||
|
y_pred, cache = self.llm.forward_one_step(
|
||||||
|
lm_input,
|
||||||
|
masks=paddle.tril(
|
||||||
|
paddle.ones((1, seq_len, seq_len), device=lm_input.place)
|
||||||
|
).to(paddle.bool),
|
||||||
|
cache=cache,
|
||||||
|
)
|
||||||
|
logp = self.llm_decoder(y_pred[:, -1]).log_softmax(dim=-1)
|
||||||
|
if next_fill_index != -1 and len(out_tokens) == next_fill_index:
|
||||||
|
top_ids = self.speech_token_size + 2
|
||||||
|
next_fill_index += self.mix_ratio[1] + 1
|
||||||
|
else:
|
||||||
|
top_ids = self.sampling_ids(
|
||||||
|
logp.squeeze(dim=0), out_tokens, sampling, ignore_eos=True
|
||||||
|
).item()
|
||||||
|
if top_ids == self.speech_token_size + 2:
|
||||||
|
next_fill_index = len(out_tokens) + self.mix_ratio[1] + 1
|
||||||
|
logging.info(
|
||||||
|
"fill_token index {} next fill_token index {}".format(
|
||||||
|
len(out_tokens), next_fill_index
|
||||||
|
)
|
||||||
|
)
|
||||||
|
out_tokens.append(top_ids)
|
||||||
|
if top_ids >= self.speech_token_size:
|
||||||
|
if top_ids == self.speech_token_size + 2:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("should not get token {}".format(top_ids))
|
||||||
|
yield top_ids
|
||||||
|
lm_input = self.speech_embedding.weight[top_ids].reshape(1, 1, -1)
|
||||||
|
lm_input = paddle.cat([lm_input, text_cache, task_id_emb], dim=1)
|
||||||
|
logging.info("no more text token, decode until met eos")
|
||||||
|
while True:
|
||||||
|
seq_len = (
|
||||||
|
lm_input.shape[1]
|
||||||
|
if cache is None
|
||||||
|
else lm_input.shape[1] + cache[0][0].size(2)
|
||||||
|
)
|
||||||
|
y_pred, cache = self.llm.forward_one_step(
|
||||||
|
lm_input,
|
||||||
|
masks=paddle.tril(
|
||||||
|
paddle.ones((1, seq_len, seq_len), device=lm_input.place)
|
||||||
|
).to(paddle.bool),
|
||||||
|
cache=cache,
|
||||||
|
)
|
||||||
|
logp = self.llm_decoder(y_pred[:, -1]).log_softmax(dim=-1)
|
||||||
|
top_ids = self.sampling_ids(
|
||||||
|
logp.squeeze(dim=0), out_tokens, sampling, ignore_eos=False
|
||||||
|
).item()
|
||||||
|
out_tokens.append(top_ids)
|
||||||
|
if top_ids >= self.speech_token_size:
|
||||||
|
if top_ids == self.speech_token_size:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("should not get token {}".format(top_ids))
|
||||||
|
yield top_ids
|
||||||
|
lm_input = self.speech_embedding.weight[top_ids].reshape(1, 1, -1)
|
||||||
@ -0,0 +1,597 @@
|
|||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
from contextlib import nullcontext
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import paddle
|
||||||
|
|
||||||
|
# from cosyvoice.utils.common import TrtContextWrapper, fade_in_out
|
||||||
|
# from cosyvoice.utils.file_utils import *
|
||||||
|
# from cosyvoice.utils.file_utils import convert_onnx_to_trt, export_cosyvoice2_vllm
|
||||||
|
|
||||||
|
|
||||||
|
class CosyVoiceModel:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
llm: paddle.nn.Layer,
|
||||||
|
flow: paddle.nn.Layer,
|
||||||
|
hift: paddle.nn.Layer,
|
||||||
|
fp16: bool = False,
|
||||||
|
):
|
||||||
|
self.device = device2str(
|
||||||
|
"cuda" if paddle.device.cuda.device_count() >= 1 else "cpu"
|
||||||
|
)
|
||||||
|
self.llm = llm
|
||||||
|
self.flow = flow
|
||||||
|
self.hift = hift
|
||||||
|
self.fp16 = fp16
|
||||||
|
if self.fp16 is True:
|
||||||
|
self.llm.half()
|
||||||
|
self.flow.half()
|
||||||
|
self.token_min_hop_len = 2 * self.flow.input_frame_rate
|
||||||
|
self.token_max_hop_len = 4 * self.flow.input_frame_rate
|
||||||
|
self.token_overlap_len = 20
|
||||||
|
self.mel_overlap_len = int(
|
||||||
|
self.token_overlap_len / self.flow.input_frame_rate * 22050 / 256
|
||||||
|
)
|
||||||
|
self.mel_window = np.hamming(2 * self.mel_overlap_len)
|
||||||
|
self.mel_cache_len = 20
|
||||||
|
self.source_cache_len = int(self.mel_cache_len * 256)
|
||||||
|
self.speech_window = np.hamming(2 * self.source_cache_len)
|
||||||
|
self.stream_scale_factor = 1
|
||||||
|
assert (
|
||||||
|
self.stream_scale_factor >= 1
|
||||||
|
), "stream_scale_factor should be greater than 1, change it according to your actual rtf"
|
||||||
|
self.llm_context = (
|
||||||
|
paddle.device.stream_guard(
|
||||||
|
paddle.device.Stream(device=device2str(self.device))
|
||||||
|
)
|
||||||
|
if paddle.device.cuda.device_count() >= 1
|
||||||
|
else nullcontext()
|
||||||
|
)
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.tts_speech_token_dict = {}
|
||||||
|
self.llm_end_dict = {}
|
||||||
|
self.mel_overlap_dict = {}
|
||||||
|
self.flow_cache_dict = {}
|
||||||
|
self.hift_cache_dict = {}
|
||||||
|
|
||||||
|
def load(self, llm_model, flow_model, hift_model):
|
||||||
|
self.llm.set_state_dict(state_dict=paddle.load(path=str(llm_model)))
|
||||||
|
self.llm.to(self.device).eval()
|
||||||
|
self.flow.set_state_dict(state_dict=paddle.load(path=str(flow_model)))
|
||||||
|
self.flow.to(self.device).eval()
|
||||||
|
hift_state_dict = {
|
||||||
|
k.replace("generator.", ""): v
|
||||||
|
for k, v in paddle.load(path=str(hift_model)).items()
|
||||||
|
}
|
||||||
|
self.hift.set_state_dict(state_dict=hift_state_dict)
|
||||||
|
self.hift.to(self.device).eval()
|
||||||
|
|
||||||
|
def load_jit(self, llm_text_encoder_model, llm_llm_model, flow_encoder_model):
|
||||||
|
llm_text_encoder = torch.jit.load(
|
||||||
|
llm_text_encoder_model, map_location=self.device
|
||||||
|
)
|
||||||
|
self.llm.text_encoder = llm_text_encoder
|
||||||
|
llm_llm = torch.jit.load(llm_llm_model, map_location=self.device)
|
||||||
|
self.llm.llm = llm_llm
|
||||||
|
flow_encoder = torch.jit.load(flow_encoder_model, map_location=self.device)
|
||||||
|
self.flow.encoder = flow_encoder
|
||||||
|
|
||||||
|
def load_trt(
|
||||||
|
self,
|
||||||
|
flow_decoder_estimator_model,
|
||||||
|
flow_decoder_onnx_model,
|
||||||
|
trt_concurrent,
|
||||||
|
fp16,
|
||||||
|
):
|
||||||
|
assert paddle.device.cuda.device_count() >= 1, "tensorrt only supports gpu!"
|
||||||
|
if (
|
||||||
|
not os.path.exists(flow_decoder_estimator_model)
|
||||||
|
or os.path.getsize(flow_decoder_estimator_model) == 0
|
||||||
|
):
|
||||||
|
convert_onnx_to_trt(
|
||||||
|
flow_decoder_estimator_model,
|
||||||
|
self.get_trt_kwargs(),
|
||||||
|
flow_decoder_onnx_model,
|
||||||
|
fp16,
|
||||||
|
)
|
||||||
|
del self.flow.decoder.estimator
|
||||||
|
import tensorrt as trt
|
||||||
|
|
||||||
|
with open(flow_decoder_estimator_model, "rb") as f:
|
||||||
|
estimator_engine = trt.Runtime(
|
||||||
|
trt.Logger(trt.Logger.INFO)
|
||||||
|
).deserialize_cuda_engine(f.read())
|
||||||
|
assert estimator_engine is not None, "failed to load trt {}".format(
|
||||||
|
flow_decoder_estimator_model
|
||||||
|
)
|
||||||
|
self.flow.decoder.estimator = TrtContextWrapper(
|
||||||
|
estimator_engine, trt_concurrent=trt_concurrent, device=self.device
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_trt_kwargs(self):
|
||||||
|
min_shape = [(2, 80, 4), (2, 1, 4), (2, 80, 4), (2, 80, 4)]
|
||||||
|
opt_shape = [(2, 80, 500), (2, 1, 500), (2, 80, 500), (2, 80, 500)]
|
||||||
|
max_shape = [(2, 80, 3000), (2, 1, 3000), (2, 80, 3000), (2, 80, 3000)]
|
||||||
|
input_names = ["x", "mask", "mu", "cond"]
|
||||||
|
return {
|
||||||
|
"min_shape": min_shape,
|
||||||
|
"opt_shape": opt_shape,
|
||||||
|
"max_shape": max_shape,
|
||||||
|
"input_names": input_names,
|
||||||
|
}
|
||||||
|
|
||||||
|
def llm_job(self, text, prompt_text, llm_prompt_speech_token, llm_embedding, uuid):
|
||||||
|
with self.llm_context, paddle.amp.auto_cast(
|
||||||
|
enable=self.fp16 is True and hasattr(self.llm, "vllm") is False
|
||||||
|
):
|
||||||
|
if isinstance(text, Generator):
|
||||||
|
assert isinstance(self, CosyVoice2Model) and not hasattr(
|
||||||
|
self.llm, "vllm"
|
||||||
|
), "streaming input text is only implemented for CosyVoice2 and do not support vllm!"
|
||||||
|
for i in self.llm.inference_bistream(
|
||||||
|
text=text,
|
||||||
|
prompt_text=prompt_text.to(self.device),
|
||||||
|
prompt_text_len=paddle.tensor(
|
||||||
|
[prompt_text.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
prompt_speech_token=llm_prompt_speech_token.to(self.device),
|
||||||
|
prompt_speech_token_len=paddle.tensor(
|
||||||
|
[llm_prompt_speech_token.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
embedding=llm_embedding.to(self.device),
|
||||||
|
):
|
||||||
|
self.tts_speech_token_dict[uuid].append(i)
|
||||||
|
else:
|
||||||
|
for i in self.llm.inference(
|
||||||
|
text=text.to(self.device),
|
||||||
|
text_len=paddle.tensor([text.shape[1]], dtype=paddle.int32).to(
|
||||||
|
self.device
|
||||||
|
),
|
||||||
|
prompt_text=prompt_text.to(self.device),
|
||||||
|
prompt_text_len=paddle.tensor(
|
||||||
|
[prompt_text.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
prompt_speech_token=llm_prompt_speech_token.to(self.device),
|
||||||
|
prompt_speech_token_len=paddle.tensor(
|
||||||
|
[llm_prompt_speech_token.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
embedding=llm_embedding.to(self.device),
|
||||||
|
uuid=uuid,
|
||||||
|
):
|
||||||
|
self.tts_speech_token_dict[uuid].append(i)
|
||||||
|
self.llm_end_dict[uuid] = True
|
||||||
|
|
||||||
|
def vc_job(self, source_speech_token, uuid):
|
||||||
|
self.tts_speech_token_dict[uuid] = source_speech_token.flatten().tolist()
|
||||||
|
self.llm_end_dict[uuid] = True
|
||||||
|
|
||||||
|
def token2wav(
|
||||||
|
self,
|
||||||
|
token,
|
||||||
|
prompt_token,
|
||||||
|
prompt_feat,
|
||||||
|
embedding,
|
||||||
|
uuid,
|
||||||
|
finalize=False,
|
||||||
|
speed=1.0,
|
||||||
|
):
|
||||||
|
with paddle.amp.auto_cast(enable=self.fp16):
|
||||||
|
tts_mel, self.flow_cache_dict[uuid] = self.flow.inference(
|
||||||
|
token=token.to(self.device),
|
||||||
|
token_len=paddle.tensor([token.shape[1]], dtype=paddle.int32).to(
|
||||||
|
self.device
|
||||||
|
),
|
||||||
|
prompt_token=prompt_token.to(self.device),
|
||||||
|
prompt_token_len=paddle.tensor(
|
||||||
|
[prompt_token.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
prompt_feat=prompt_feat.to(self.device),
|
||||||
|
prompt_feat_len=paddle.tensor(
|
||||||
|
[prompt_feat.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
embedding=embedding.to(self.device),
|
||||||
|
flow_cache=self.flow_cache_dict[uuid],
|
||||||
|
)
|
||||||
|
if self.mel_overlap_dict[uuid].shape[2] != 0:
|
||||||
|
tts_mel = fade_in_out(tts_mel, self.mel_overlap_dict[uuid], self.mel_window)
|
||||||
|
if self.hift_cache_dict[uuid] is not None:
|
||||||
|
hift_cache_mel, hift_cache_source = (
|
||||||
|
self.hift_cache_dict[uuid]["mel"],
|
||||||
|
self.hift_cache_dict[uuid]["source"],
|
||||||
|
)
|
||||||
|
tts_mel = paddle.cat([hift_cache_mel, tts_mel], dim=2)
|
||||||
|
else:
|
||||||
|
hift_cache_source = paddle.zeros([1, 1, 0])
|
||||||
|
if finalize is False:
|
||||||
|
self.mel_overlap_dict[uuid] = tts_mel[:, :, -self.mel_overlap_len :]
|
||||||
|
tts_mel = tts_mel[:, :, : -self.mel_overlap_len]
|
||||||
|
tts_speech, tts_source = self.hift.inference(
|
||||||
|
speech_feat=tts_mel, cache_source=hift_cache_source
|
||||||
|
)
|
||||||
|
if self.hift_cache_dict[uuid] is not None:
|
||||||
|
tts_speech = fade_in_out(
|
||||||
|
tts_speech, self.hift_cache_dict[uuid]["speech"], self.speech_window
|
||||||
|
)
|
||||||
|
self.hift_cache_dict[uuid] = {
|
||||||
|
"mel": tts_mel[:, :, -self.mel_cache_len :],
|
||||||
|
"source": tts_source[:, :, -self.source_cache_len :],
|
||||||
|
"speech": tts_speech[:, -self.source_cache_len :],
|
||||||
|
}
|
||||||
|
tts_speech = tts_speech[:, : -self.source_cache_len]
|
||||||
|
else:
|
||||||
|
if speed != 1.0:
|
||||||
|
assert (
|
||||||
|
self.hift_cache_dict[uuid] is None
|
||||||
|
), "speed change only support non-stream inference mode"
|
||||||
|
tts_mel = paddle.nn.functional.interpolate(
|
||||||
|
x=tts_mel, size=int(tts_mel.shape[2] / speed), mode="linear"
|
||||||
|
)
|
||||||
|
tts_speech, tts_source = self.hift.inference(
|
||||||
|
speech_feat=tts_mel, cache_source=hift_cache_source
|
||||||
|
)
|
||||||
|
if self.hift_cache_dict[uuid] is not None:
|
||||||
|
tts_speech = fade_in_out(
|
||||||
|
tts_speech, self.hift_cache_dict[uuid]["speech"], self.speech_window
|
||||||
|
)
|
||||||
|
return tts_speech
|
||||||
|
|
||||||
|
def tts(
|
||||||
|
self,
|
||||||
|
text=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
flow_embedding=paddle.zeros([0, 192]),
|
||||||
|
llm_embedding=paddle.zeros([0, 192]),
|
||||||
|
prompt_text=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
llm_prompt_speech_token=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
flow_prompt_speech_token=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
prompt_speech_feat=paddle.zeros([1, 0, 80]),
|
||||||
|
source_speech_token=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
stream=False,
|
||||||
|
speed=1.0,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
this_uuid = str(uuid.uuid1())
|
||||||
|
with self.lock:
|
||||||
|
self.tts_speech_token_dict[this_uuid], self.llm_end_dict[this_uuid] = (
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
self.hift_cache_dict[this_uuid] = None
|
||||||
|
self.mel_overlap_dict[this_uuid] = paddle.zeros([1, 80, 0])
|
||||||
|
self.flow_cache_dict[this_uuid] = paddle.zeros([1, 80, 0, 2])
|
||||||
|
if source_speech_token.shape[1] == 0:
|
||||||
|
p = threading.Thread(
|
||||||
|
target=self.llm_job,
|
||||||
|
args=(
|
||||||
|
text,
|
||||||
|
prompt_text,
|
||||||
|
llm_prompt_speech_token,
|
||||||
|
llm_embedding,
|
||||||
|
this_uuid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
p = threading.Thread(
|
||||||
|
target=self.vc_job, args=(source_speech_token, this_uuid)
|
||||||
|
)
|
||||||
|
"""Not Support auto convert *.start, please judge whether it is Pytorch API and convert by yourself"""
|
||||||
|
p.start()
|
||||||
|
if stream is True:
|
||||||
|
token_hop_len = self.token_min_hop_len
|
||||||
|
while True:
|
||||||
|
time.sleep(0.1)
|
||||||
|
if (
|
||||||
|
len(self.tts_speech_token_dict[this_uuid])
|
||||||
|
>= token_hop_len + self.token_overlap_len
|
||||||
|
):
|
||||||
|
this_tts_speech_token = paddle.tensor(
|
||||||
|
self.tts_speech_token_dict[this_uuid][
|
||||||
|
: token_hop_len + self.token_overlap_len
|
||||||
|
]
|
||||||
|
).unsqueeze(dim=0)
|
||||||
|
this_tts_speech = self.token2wav(
|
||||||
|
token=this_tts_speech_token,
|
||||||
|
prompt_token=flow_prompt_speech_token,
|
||||||
|
prompt_feat=prompt_speech_feat,
|
||||||
|
embedding=flow_embedding,
|
||||||
|
uuid=this_uuid,
|
||||||
|
finalize=False,
|
||||||
|
)
|
||||||
|
yield {"tts_speech": this_tts_speech.cpu()}
|
||||||
|
with self.lock:
|
||||||
|
self.tts_speech_token_dict[
|
||||||
|
this_uuid
|
||||||
|
] = self.tts_speech_token_dict[this_uuid][token_hop_len:]
|
||||||
|
token_hop_len = min(
|
||||||
|
self.token_max_hop_len,
|
||||||
|
int(token_hop_len * self.stream_scale_factor),
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
self.llm_end_dict[this_uuid] is True
|
||||||
|
and len(self.tts_speech_token_dict[this_uuid])
|
||||||
|
< token_hop_len + self.token_overlap_len
|
||||||
|
):
|
||||||
|
break
|
||||||
|
p.join()
|
||||||
|
this_tts_speech_token = paddle.tensor(
|
||||||
|
self.tts_speech_token_dict[this_uuid]
|
||||||
|
).unsqueeze(dim=0)
|
||||||
|
this_tts_speech = self.token2wav(
|
||||||
|
token=this_tts_speech_token,
|
||||||
|
prompt_token=flow_prompt_speech_token,
|
||||||
|
prompt_feat=prompt_speech_feat,
|
||||||
|
embedding=flow_embedding,
|
||||||
|
uuid=this_uuid,
|
||||||
|
finalize=True,
|
||||||
|
)
|
||||||
|
yield {"tts_speech": this_tts_speech.cpu()}
|
||||||
|
else:
|
||||||
|
p.join()
|
||||||
|
this_tts_speech_token = paddle.tensor(
|
||||||
|
self.tts_speech_token_dict[this_uuid]
|
||||||
|
).unsqueeze(dim=0)
|
||||||
|
this_tts_speech = self.token2wav(
|
||||||
|
token=this_tts_speech_token,
|
||||||
|
prompt_token=flow_prompt_speech_token,
|
||||||
|
prompt_feat=prompt_speech_feat,
|
||||||
|
embedding=flow_embedding,
|
||||||
|
uuid=this_uuid,
|
||||||
|
finalize=True,
|
||||||
|
speed=speed,
|
||||||
|
)
|
||||||
|
yield {"tts_speech": this_tts_speech.cpu()}
|
||||||
|
with self.lock:
|
||||||
|
self.tts_speech_token_dict.pop(this_uuid)
|
||||||
|
self.llm_end_dict.pop(this_uuid)
|
||||||
|
self.mel_overlap_dict.pop(this_uuid)
|
||||||
|
self.hift_cache_dict.pop(this_uuid)
|
||||||
|
self.flow_cache_dict.pop(this_uuid)
|
||||||
|
if paddle.device.cuda.device_count() >= 1:
|
||||||
|
paddle.device.cuda.empty_cache()
|
||||||
|
paddle.device.current_stream().synchronize()
|
||||||
|
|
||||||
|
|
||||||
|
class CosyVoice2Model(CosyVoiceModel):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
llm: paddle.nn.Layer,
|
||||||
|
flow: paddle.nn.Layer,
|
||||||
|
hift: paddle.nn.Layer,
|
||||||
|
fp16: bool = False,
|
||||||
|
):
|
||||||
|
self.device = device2str(
|
||||||
|
"cuda" if paddle.device.cuda.device_count() >= 1 else "cpu"
|
||||||
|
)
|
||||||
|
self.llm = llm
|
||||||
|
self.flow = flow
|
||||||
|
self.hift = hift
|
||||||
|
self.fp16 = fp16
|
||||||
|
if self.fp16 is True:
|
||||||
|
self.llm.half()
|
||||||
|
self.flow.half()
|
||||||
|
self.token_hop_len = 25
|
||||||
|
self.mel_cache_len = 8
|
||||||
|
self.source_cache_len = int(self.mel_cache_len * 480)
|
||||||
|
self.speech_window = np.hamming(2 * self.source_cache_len)
|
||||||
|
self.llm_context = (
|
||||||
|
paddle.device.stream_guard(
|
||||||
|
paddle.device.Stream(device=device2str(self.device))
|
||||||
|
)
|
||||||
|
if paddle.device.cuda.device_count() >= 1
|
||||||
|
else nullcontext()
|
||||||
|
)
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.tts_speech_token_dict = {}
|
||||||
|
self.llm_end_dict = {}
|
||||||
|
self.hift_cache_dict = {}
|
||||||
|
|
||||||
|
def load_jit(self, flow_encoder_model):
|
||||||
|
flow_encoder = torch.jit.load(flow_encoder_model, map_location=self.device)
|
||||||
|
self.flow.encoder = flow_encoder
|
||||||
|
|
||||||
|
def load_vllm(self, model_dir):
|
||||||
|
export_cosyvoice2_vllm(self.llm, model_dir, self.device)
|
||||||
|
from vllm import EngineArgs, LLMEngine
|
||||||
|
|
||||||
|
engine_args = EngineArgs(
|
||||||
|
model=model_dir,
|
||||||
|
skip_tokenizer_init=True,
|
||||||
|
enable_prompt_embeds=True,
|
||||||
|
gpu_memory_utilization=0.2,
|
||||||
|
)
|
||||||
|
self.llm.vllm = LLMEngine.from_engine_args(engine_args)
|
||||||
|
self.llm.lock = threading.Lock()
|
||||||
|
del self.llm.llm.model.model.layers
|
||||||
|
|
||||||
|
def token2wav(
|
||||||
|
self,
|
||||||
|
token,
|
||||||
|
prompt_token,
|
||||||
|
prompt_feat,
|
||||||
|
embedding,
|
||||||
|
token_offset,
|
||||||
|
uuid,
|
||||||
|
stream=False,
|
||||||
|
finalize=False,
|
||||||
|
speed=1.0,
|
||||||
|
):
|
||||||
|
with paddle.amp.auto_cast(enable=self.fp16):
|
||||||
|
tts_mel, _ = self.flow.inference(
|
||||||
|
token=token.to(self.device),
|
||||||
|
token_len=paddle.tensor([token.shape[1]], dtype=paddle.int32).to(
|
||||||
|
self.device
|
||||||
|
),
|
||||||
|
prompt_token=prompt_token.to(self.device),
|
||||||
|
prompt_token_len=paddle.tensor(
|
||||||
|
[prompt_token.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
prompt_feat=prompt_feat.to(self.device),
|
||||||
|
prompt_feat_len=paddle.tensor(
|
||||||
|
[prompt_feat.shape[1]], dtype=paddle.int32
|
||||||
|
).to(self.device),
|
||||||
|
embedding=embedding.to(self.device),
|
||||||
|
streaming=stream,
|
||||||
|
finalize=finalize,
|
||||||
|
)
|
||||||
|
tts_mel = tts_mel[:, :, token_offset * self.flow.token_mel_ratio :]
|
||||||
|
if self.hift_cache_dict[uuid] is not None:
|
||||||
|
hift_cache_mel, hift_cache_source = (
|
||||||
|
self.hift_cache_dict[uuid]["mel"],
|
||||||
|
self.hift_cache_dict[uuid]["source"],
|
||||||
|
)
|
||||||
|
tts_mel = paddle.cat([hift_cache_mel, tts_mel], dim=2)
|
||||||
|
else:
|
||||||
|
hift_cache_source = paddle.zeros([1, 1, 0])
|
||||||
|
if finalize is False:
|
||||||
|
tts_speech, tts_source = self.hift.inference(
|
||||||
|
speech_feat=tts_mel, cache_source=hift_cache_source
|
||||||
|
)
|
||||||
|
if self.hift_cache_dict[uuid] is not None:
|
||||||
|
tts_speech = fade_in_out(
|
||||||
|
tts_speech, self.hift_cache_dict[uuid]["speech"], self.speech_window
|
||||||
|
)
|
||||||
|
self.hift_cache_dict[uuid] = {
|
||||||
|
"mel": tts_mel[:, :, -self.mel_cache_len :],
|
||||||
|
"source": tts_source[:, :, -self.source_cache_len :],
|
||||||
|
"speech": tts_speech[:, -self.source_cache_len :],
|
||||||
|
}
|
||||||
|
tts_speech = tts_speech[:, : -self.source_cache_len]
|
||||||
|
else:
|
||||||
|
if speed != 1.0:
|
||||||
|
assert (
|
||||||
|
self.hift_cache_dict[uuid] is None
|
||||||
|
), "speed change only support non-stream inference mode"
|
||||||
|
tts_mel = paddle.nn.functional.interpolate(
|
||||||
|
x=tts_mel, size=int(tts_mel.shape[2] / speed), mode="linear"
|
||||||
|
)
|
||||||
|
tts_speech, tts_source = self.hift.inference(
|
||||||
|
speech_feat=tts_mel, cache_source=hift_cache_source
|
||||||
|
)
|
||||||
|
if self.hift_cache_dict[uuid] is not None:
|
||||||
|
tts_speech = fade_in_out(
|
||||||
|
tts_speech, self.hift_cache_dict[uuid]["speech"], self.speech_window
|
||||||
|
)
|
||||||
|
return tts_speech
|
||||||
|
|
||||||
|
def tts(
|
||||||
|
self,
|
||||||
|
text=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
flow_embedding=paddle.zeros([0, 192]),
|
||||||
|
llm_embedding=paddle.zeros([0, 192]),
|
||||||
|
prompt_text=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
llm_prompt_speech_token=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
flow_prompt_speech_token=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
prompt_speech_feat=paddle.zeros([1, 0, 80]),
|
||||||
|
source_speech_token=paddle.zeros([1, 0], dtype=paddle.int32),
|
||||||
|
stream=False,
|
||||||
|
speed=1.0,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
this_uuid = str(uuid.uuid1())
|
||||||
|
with self.lock:
|
||||||
|
self.tts_speech_token_dict[this_uuid], self.llm_end_dict[this_uuid] = (
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
self.hift_cache_dict[this_uuid] = None
|
||||||
|
if source_speech_token.shape[1] == 0:
|
||||||
|
p = threading.Thread(
|
||||||
|
target=self.llm_job,
|
||||||
|
args=(
|
||||||
|
text,
|
||||||
|
prompt_text,
|
||||||
|
llm_prompt_speech_token,
|
||||||
|
llm_embedding,
|
||||||
|
this_uuid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
p = threading.Thread(
|
||||||
|
target=self.vc_job, args=(source_speech_token, this_uuid)
|
||||||
|
)
|
||||||
|
"""Not Support auto convert *.start, please judge whether it is Pytorch API and convert by yourself"""
|
||||||
|
p.start()
|
||||||
|
if stream is True:
|
||||||
|
token_offset = 0
|
||||||
|
prompt_token_pad = int(
|
||||||
|
np.ceil(flow_prompt_speech_token.shape[1] / self.token_hop_len)
|
||||||
|
* self.token_hop_len
|
||||||
|
- flow_prompt_speech_token.shape[1]
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
time.sleep(0.1)
|
||||||
|
this_token_hop_len = (
|
||||||
|
self.token_hop_len + prompt_token_pad
|
||||||
|
if token_offset == 0
|
||||||
|
else self.token_hop_len
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
len(self.tts_speech_token_dict[this_uuid]) - token_offset
|
||||||
|
>= this_token_hop_len + self.flow.pre_lookahead_len
|
||||||
|
):
|
||||||
|
this_tts_speech_token = paddle.tensor(
|
||||||
|
self.tts_speech_token_dict[this_uuid][
|
||||||
|
: token_offset
|
||||||
|
+ this_token_hop_len
|
||||||
|
+ self.flow.pre_lookahead_len
|
||||||
|
]
|
||||||
|
).unsqueeze(dim=0)
|
||||||
|
this_tts_speech = self.token2wav(
|
||||||
|
token=this_tts_speech_token,
|
||||||
|
prompt_token=flow_prompt_speech_token,
|
||||||
|
prompt_feat=prompt_speech_feat,
|
||||||
|
embedding=flow_embedding,
|
||||||
|
token_offset=token_offset,
|
||||||
|
uuid=this_uuid,
|
||||||
|
stream=stream,
|
||||||
|
finalize=False,
|
||||||
|
)
|
||||||
|
token_offset += this_token_hop_len
|
||||||
|
yield {"tts_speech": this_tts_speech.cpu()}
|
||||||
|
if (
|
||||||
|
self.llm_end_dict[this_uuid] is True
|
||||||
|
and len(self.tts_speech_token_dict[this_uuid]) - token_offset
|
||||||
|
< this_token_hop_len + self.flow.pre_lookahead_len
|
||||||
|
):
|
||||||
|
break
|
||||||
|
p.join()
|
||||||
|
this_tts_speech_token = paddle.tensor(
|
||||||
|
self.tts_speech_token_dict[this_uuid]
|
||||||
|
).unsqueeze(dim=0)
|
||||||
|
this_tts_speech = self.token2wav(
|
||||||
|
token=this_tts_speech_token,
|
||||||
|
prompt_token=flow_prompt_speech_token,
|
||||||
|
prompt_feat=prompt_speech_feat,
|
||||||
|
embedding=flow_embedding,
|
||||||
|
token_offset=token_offset,
|
||||||
|
uuid=this_uuid,
|
||||||
|
finalize=True,
|
||||||
|
)
|
||||||
|
yield {"tts_speech": this_tts_speech.cpu()}
|
||||||
|
else:
|
||||||
|
p.join()
|
||||||
|
this_tts_speech_token = paddle.tensor(
|
||||||
|
self.tts_speech_token_dict[this_uuid]
|
||||||
|
).unsqueeze(dim=0)
|
||||||
|
this_tts_speech = self.token2wav(
|
||||||
|
token=this_tts_speech_token,
|
||||||
|
prompt_token=flow_prompt_speech_token,
|
||||||
|
prompt_feat=prompt_speech_feat,
|
||||||
|
embedding=flow_embedding,
|
||||||
|
token_offset=0,
|
||||||
|
uuid=this_uuid,
|
||||||
|
finalize=True,
|
||||||
|
speed=speed,
|
||||||
|
)
|
||||||
|
yield {"tts_speech": this_tts_speech.cpu()}
|
||||||
|
with self.lock:
|
||||||
|
self.tts_speech_token_dict.pop(this_uuid)
|
||||||
|
self.llm_end_dict.pop(this_uuid)
|
||||||
|
self.hift_cache_dict.pop(this_uuid)
|
||||||
|
if paddle.device.cuda.device_count() >= 1:
|
||||||
|
paddle.device.cuda.empty_cache()
|
||||||
|
paddle.device.current_stream().synchronize()
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
import torchaudio
|
||||||
|
import
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
class Transpose(torch.nn.Module):
|
||||||
|
def __init__(self, dim0: int, dim1: int):
|
||||||
|
super().__init__()
|
||||||
|
self.dim0 = dim0
|
||||||
|
self.dim1 = dim1
|
||||||
|
|
||||||
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
||||||
|
x = torch.transpose(x, self.dim0, self.dim1)
|
||||||
|
return x
|
||||||
@ -0,0 +1,227 @@
|
|||||||
|
|
||||||
|
class BasicTransformerBlock(nn.Module):
|
||||||
|
r"""
|
||||||
|
A basic Transformer block.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
dim (`int`): The number of channels in the input and output.
|
||||||
|
num_attention_heads (`int`): The number of heads to use for multi-head attention.
|
||||||
|
attention_head_dim (`int`): The number of channels in each head.
|
||||||
|
dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use.
|
||||||
|
cross_attention_dim (`int`, *optional*): The size of the encoder_hidden_states vector for cross attention.
|
||||||
|
only_cross_attention (`bool`, *optional*):
|
||||||
|
Whether to use only cross-attention layers. In this case two cross attention layers are used.
|
||||||
|
double_self_attention (`bool`, *optional*):
|
||||||
|
Whether to use two self-attention layers. In this case no cross attention layers are used.
|
||||||
|
activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward.
|
||||||
|
num_embeds_ada_norm (:
|
||||||
|
obj: `int`, *optional*): The number of diffusion steps used during training. See `Transformer2DModel`.
|
||||||
|
attention_bias (:
|
||||||
|
obj: `bool`, *optional*, defaults to `False`): Configure if the attentions should contain a bias parameter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
dim: int,
|
||||||
|
num_attention_heads: int,
|
||||||
|
attention_head_dim: int,
|
||||||
|
dropout=0.0,
|
||||||
|
activation_fn: str = "geglu",
|
||||||
|
cross_attention_dim: Optional[int] = None,
|
||||||
|
num_embeds_ada_norm: Optional[int] = None,
|
||||||
|
attention_bias: bool = False,
|
||||||
|
double_self_attention: bool = False,
|
||||||
|
upcast_attention: bool = False,
|
||||||
|
norm_elementwise_affine: bool = True,
|
||||||
|
norm_type: str = "layer_norm",
|
||||||
|
final_dropout: bool = False,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.use_ada_layer_norm_zero = (num_embeds_ada_norm is not None) and norm_type == "ada_norm_zero"
|
||||||
|
self.use_ada_layer_norm = (num_embeds_ada_norm is not None) and norm_type == "ada_norm"
|
||||||
|
|
||||||
|
if norm_type in ("ada_norm", "ada_norm_zero") and num_embeds_ada_norm is None:
|
||||||
|
raise ValueError(
|
||||||
|
f"`norm_type` is set to {norm_type}, but `num_embeds_ada_norm` is not defined. Please make sure to"
|
||||||
|
f" define `num_embeds_ada_norm` if setting `norm_type` to {norm_type}."
|
||||||
|
)
|
||||||
|
# Define 3 blocks. Each block has its own normalization layer.
|
||||||
|
# 1. Self-Attn
|
||||||
|
self.norm1 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
|
||||||
|
self.attn1 = Attention(
|
||||||
|
query_dim=dim,
|
||||||
|
heads=num_attention_heads,
|
||||||
|
dim_head=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
bias=attention_bias,
|
||||||
|
cross_attention_dim=None
|
||||||
|
upcast_attention=False
|
||||||
|
)
|
||||||
|
# 2. Cross-Attn
|
||||||
|
self.norm2 = None
|
||||||
|
self.attn2 = None
|
||||||
|
self.norm3 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine)
|
||||||
|
self.ff = FeedForward(dim, dropout=dropout, activation_fn=activation_fn, final_dropout=final_dropout)
|
||||||
|
|
||||||
|
# let chunk size default to None
|
||||||
|
self._chunk_size = None
|
||||||
|
self._chunk_dim = 0
|
||||||
|
def forward(self,hidden_states):
|
||||||
|
norm_hidden_states = self.norm1(hidden_states)
|
||||||
|
cross_attention_kwargs = {}
|
||||||
|
attn_output = self.attn1(
|
||||||
|
norm_hidden_states,
|
||||||
|
encoder_hidden_states=encoder_hidden_states if self.only_cross_attention else None,
|
||||||
|
attention_mask=encoder_attention_mask if self.only_cross_attention else attention_mask,
|
||||||
|
**cross_attention_kwargs,
|
||||||
|
)
|
||||||
|
hidden_states = attn_output + hidden_states
|
||||||
|
norm_hidden_states = self.norm3(hidden_states)
|
||||||
|
ff_output = self.ff(norm_hidden_states)
|
||||||
|
hidden_states = ff_output + hidden_states
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
|
class FeedForward(nn.Layer):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
dim: int,
|
||||||
|
dim_out: Optional[int] = None,
|
||||||
|
mult: int = 4,
|
||||||
|
dropout: float = 0.0,
|
||||||
|
activation_fn: str = "geglu",
|
||||||
|
final_dropout: bool = False,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
inner_dim = int(dim * mult)
|
||||||
|
dim_out = dim_out if dim_out is not None else dim
|
||||||
|
|
||||||
|
if activation_fn == "gelu":
|
||||||
|
act_fn = GELU(dim, inner_dim, approximate=False)
|
||||||
|
elif activation_fn == "gelu-approximate":
|
||||||
|
act_fn = GELU(dim, inner_dim, approximate=True)
|
||||||
|
elif activation_fn == "geglu":
|
||||||
|
act_fn = GEGLU(dim, inner_dim)
|
||||||
|
elif activation_fn == "geglu-approximate":
|
||||||
|
act_fn = ApproximateGELU(dim, inner_dim)
|
||||||
|
elif activation_fn == "snakebeta":
|
||||||
|
act_fn = SnakeBeta(dim, inner_dim)
|
||||||
|
else:
|
||||||
|
act_fn = GEGLU(dim, inner_dim)
|
||||||
|
|
||||||
|
self.net = nn.LayerList()
|
||||||
|
self.net.append(act_fn)
|
||||||
|
self.net.append(nn.Dropout(dropout))
|
||||||
|
self.net.append(LoRACompatibleLinear(inner_dim, dim_out))
|
||||||
|
|
||||||
|
if final_dropout:
|
||||||
|
self.net.append(nn.Dropout(dropout))
|
||||||
|
|
||||||
|
def forward(self, hidden_states):
|
||||||
|
for module in self.net:
|
||||||
|
hidden_states = module(hidden_states)
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
|
query_dim=dim,
|
||||||
|
heads=num_attention_heads,
|
||||||
|
dim_head=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
bias=attention_bias,
|
||||||
|
cross_attention_dim=None,
|
||||||
|
upcast_attention=upcast_attention,
|
||||||
|
class Attention(nn.Module):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
query_dim: int,
|
||||||
|
cross_attention_dim: Optional[int] = None,
|
||||||
|
heads: int = 8,
|
||||||
|
dim_head: int = 64,
|
||||||
|
dropout: float = 0.0,
|
||||||
|
bias: bool = False,
|
||||||
|
upcast_attention: bool = False,
|
||||||
|
upcast_softmax: bool = False,
|
||||||
|
cross_attention_norm: Optional[str] = None,
|
||||||
|
cross_attention_norm_num_groups: int = 32,
|
||||||
|
qk_norm: Optional[str] = None,
|
||||||
|
norm_num_groups: Optional[int] = None,
|
||||||
|
spatial_norm_dim: Optional[int] = None,
|
||||||
|
out_bias: bool = True,
|
||||||
|
scale_qk: bool = True,
|
||||||
|
only_cross_attention: bool = False,
|
||||||
|
eps: float = 1e-5,
|
||||||
|
rescale_output_factor: float = 1.0,
|
||||||
|
processor: Optional["AttnProcessor"] = None,
|
||||||
|
out_dim: int = None,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.inner_dim = out_dim if out_dim is not None else dim_head * heads
|
||||||
|
self.query_dim = query_dim
|
||||||
|
self.use_bias = bias
|
||||||
|
self.is_cross_attention = cross_attention_dim is not None
|
||||||
|
self.cross_attention_dim = cross_attention_dim if cross_attention_dim is not None else query_dim
|
||||||
|
self.upcast_attention = upcast_attention
|
||||||
|
self.upcast_softmax = upcast_softmax
|
||||||
|
self.rescale_output_factor = rescale_output_factor
|
||||||
|
self.dropout = dropout
|
||||||
|
self.fused_projections = False
|
||||||
|
self.out_dim = out_dim if out_dim is not None else query_dim
|
||||||
|
# we make use of this private variable to know whether this class is loaded
|
||||||
|
# with an deprecated state dict so that we can convert it on the fly
|
||||||
|
|
||||||
|
self.scale_qk = scale_qk
|
||||||
|
self.scale = dim_head**-0.5 if self.scale_qk else 1.0
|
||||||
|
|
||||||
|
self.heads = out_dim // dim_head if out_dim is not None else heads
|
||||||
|
# for slice_size > 0 the attention score computation
|
||||||
|
# is split across the batch axis to save memory
|
||||||
|
# You can set slice_size with `set_attention_slice`
|
||||||
|
self.sliceable_head_dim = heads
|
||||||
|
self.to_q = nn.Linear(query_dim, self.inner_dim, bias=bias)
|
||||||
|
self.to_k = nn.Linear(self.cross_attention_dim, self.inner_dim, bias=bias)
|
||||||
|
self.to_v = nn.Linear(self.cross_attention_dim, self.inner_dim, bias=bias)
|
||||||
|
self.to_out = nn.ModuleList([])
|
||||||
|
self.to_out.append(nn.Linear(self.inner_dim, self.out_dim, bias=out_bias))
|
||||||
|
self.to_out.append(nn.Dropout(dropout))
|
||||||
|
def forward(
|
||||||
|
self,
|
||||||
|
hidden_states: torch.Tensor,
|
||||||
|
encoder_hidden_states: Optional[torch.Tensor] = None,
|
||||||
|
attention_mask: Optional[torch.Tensor] = None,
|
||||||
|
temb: Optional[torch.Tensor] = None,
|
||||||
|
):
|
||||||
|
residual = hidden_states
|
||||||
|
input_ndim = hidden_states.ndim
|
||||||
|
if input_ndim == 4:
|
||||||
|
batch_size, channel, height, width = hidden_states.shape
|
||||||
|
hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2)
|
||||||
|
|
||||||
|
batch_size, sequence_length, _ = (
|
||||||
|
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
|
||||||
|
)
|
||||||
|
query = attn.to_q(hidden_states)
|
||||||
|
key = attn.to_k(encoder_hidden_states)
|
||||||
|
value = attn.to_v(encoder_hidden_states)
|
||||||
|
|
||||||
|
inner_dim = key.shape[-1]
|
||||||
|
head_dim = inner_dim // attn.heads
|
||||||
|
|
||||||
|
query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
||||||
|
|
||||||
|
key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
||||||
|
value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
||||||
|
hidden_states = F.scaled_dot_product_attention(
|
||||||
|
query, key, value, attn_mask=attention_mask, dropout_p=0.0, is_causal=False
|
||||||
|
)
|
||||||
|
hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
|
||||||
|
hidden_states = hidden_states.to(query.dtype)
|
||||||
|
|
||||||
|
# linear proj
|
||||||
|
hidden_states = attn.to_out[0](hidden_states)
|
||||||
|
# dropout
|
||||||
|
hidden_states = attn.to_out[1](hidden_states)
|
||||||
|
|
||||||
|
if input_ndim == 4:
|
||||||
|
hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width)
|
||||||
|
hidden_states = hidden_states / attn.rescale_output_factor
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
@ -0,0 +1,766 @@
|
|||||||
|
# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du)
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from typing import Tuple
|
||||||
|
import paddle
|
||||||
|
from paddle import nn
|
||||||
|
import paddle.nn.functional as F
|
||||||
|
from einops import pack, rearrange, repeat
|
||||||
|
from cosyvoice.utils.common import mask_to_bias
|
||||||
|
from cosyvoice.utils.mask import add_optional_chunk_mask
|
||||||
|
from matcha.models.components.decoder import SinusoidalPosEmb, Block1D, ResnetBlock1D, Downsample1D, TimestepEmbedding, Upsample1D
|
||||||
|
from .attention import BasicTransformerBlock
|
||||||
|
|
||||||
|
def get_activation(act_fn):
|
||||||
|
if act_fn == "silu":
|
||||||
|
return nn.Silu()
|
||||||
|
elif act_fn == "mish":
|
||||||
|
return nn.Mish()
|
||||||
|
elif act_fn == "relu":
|
||||||
|
return nn.ReLU()
|
||||||
|
elif act_fn == "gelu":
|
||||||
|
return nn.GELU()
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported activation function: {act_fn}")
|
||||||
|
|
||||||
|
class Block1D(nn.Layer):
|
||||||
|
def __init__(self, dim, dim_out, groups=8):
|
||||||
|
super().__init__()
|
||||||
|
self.block = nn.Sequential(
|
||||||
|
nn.Conv1D(dim, dim_out, 3, padding=1),
|
||||||
|
nn.GroupNorm(groups, dim_out),
|
||||||
|
nn.Mish(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def forward(self, x, mask):
|
||||||
|
output = self.block(x * mask)
|
||||||
|
return output * mask
|
||||||
|
|
||||||
|
class ResnetBlock1D(nn.Layer):
|
||||||
|
def __init__(self, dim, dim_out, time_emb_dim, groups=8):
|
||||||
|
super().__init__()
|
||||||
|
self.mlp = nn.Sequential(
|
||||||
|
nn.Mish(),
|
||||||
|
nn.Linear(time_emb_dim, dim_out)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.block1 = Block1D(dim, dim_out, groups=groups)
|
||||||
|
self.block2 = Block1D(dim_out, dim_out, groups=groups)
|
||||||
|
self.res_conv = nn.Conv1D(dim, dim_out, 1)
|
||||||
|
|
||||||
|
def forward(self, x, mask, time_emb):
|
||||||
|
h = self.block1(x, mask)
|
||||||
|
# 添加时间嵌入并调整维度
|
||||||
|
h += self.mlp(time_emb).unsqueeze(-1)
|
||||||
|
h = self.block2(h, mask)
|
||||||
|
output = h + self.res_conv(x * mask)
|
||||||
|
return output
|
||||||
|
|
||||||
|
class Downsample1D(nn.Layer):
|
||||||
|
def __init__(self, dim):
|
||||||
|
super().__init__()
|
||||||
|
self.conv = nn.Conv1D(dim, dim, 3, stride=2, padding=1)
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
return self.conv(x)
|
||||||
|
|
||||||
|
class TimestepEmbedding(nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels: int,
|
||||||
|
time_embed_dim: int,
|
||||||
|
act_fn: str = "silu",
|
||||||
|
out_dim: int = None,
|
||||||
|
post_act_fn: Optional[str] = None,
|
||||||
|
cond_proj_dim=None,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.linear_1 = nn.Linear(in_channels, time_embed_dim)
|
||||||
|
|
||||||
|
if cond_proj_dim is not None:
|
||||||
|
self.cond_proj = nn.Linear(cond_proj_dim, in_channels, bias=False)
|
||||||
|
else:
|
||||||
|
self.cond_proj = None
|
||||||
|
|
||||||
|
self.act = get_activation(act_fn)
|
||||||
|
|
||||||
|
if out_dim is not None:
|
||||||
|
time_embed_dim_out = out_dim
|
||||||
|
else:
|
||||||
|
time_embed_dim_out = time_embed_dim
|
||||||
|
self.linear_2 = nn.Linear(time_embed_dim, time_embed_dim_out)
|
||||||
|
|
||||||
|
if post_act_fn is None:
|
||||||
|
self.post_act = None
|
||||||
|
else:
|
||||||
|
self.post_act = get_activation(post_act_fn)
|
||||||
|
|
||||||
|
def forward(self, sample, condition=None):
|
||||||
|
if condition is not None and self.cond_proj is not None:
|
||||||
|
sample = sample + self.cond_proj(condition)
|
||||||
|
sample = self.linear_1(sample)
|
||||||
|
|
||||||
|
if self.act is not None:
|
||||||
|
sample = self.act(sample)
|
||||||
|
|
||||||
|
sample = self.linear_2(sample)
|
||||||
|
|
||||||
|
if self.post_act is not None:
|
||||||
|
sample = self.post_act(sample)
|
||||||
|
return sample
|
||||||
|
|
||||||
|
class Upsample1D(nn.Layer):
|
||||||
|
"""A 1D upsampling layer with an optional convolution.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
channels (`int`):
|
||||||
|
number of channels in the inputs and outputs.
|
||||||
|
use_conv (`bool`, default `False`):
|
||||||
|
option to use a convolution.
|
||||||
|
use_conv_transpose (`bool`, default `False`):
|
||||||
|
option to use a convolution transpose.
|
||||||
|
out_channels (`int`, optional):
|
||||||
|
number of output channels. Defaults to `channels`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, channels, use_conv=False, use_conv_transpose=True, out_channels=None, name="conv"):
|
||||||
|
super().__init__()
|
||||||
|
self.channels = channels
|
||||||
|
self.out_channels = out_channels or channels
|
||||||
|
self.use_conv = use_conv
|
||||||
|
self.use_conv_transpose = use_conv_transpose
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
self.conv = None
|
||||||
|
if use_conv_transpose:
|
||||||
|
self.conv = nn.Conv1DTranspose(channels, self.out_channels, 4, stride=2, padding=1)
|
||||||
|
elif use_conv:
|
||||||
|
self.conv = nn.Conv1D(self.channels, self.out_channels, 3, padding=1)
|
||||||
|
|
||||||
|
def forward(self, inputs):
|
||||||
|
assert inputs.shape[1] == self.channels
|
||||||
|
if self.use_conv_transpose:
|
||||||
|
return self.conv(inputs)
|
||||||
|
|
||||||
|
outputs = F.interpolate(inputs, scale_factor=2.0, mode="nearest")
|
||||||
|
|
||||||
|
if self.use_conv:
|
||||||
|
outputs = self.conv(outputs)
|
||||||
|
|
||||||
|
return outputs
|
||||||
|
|
||||||
|
class Transpose(nn.Module):
|
||||||
|
def __init__(self, dim0: int, dim1: int):
|
||||||
|
super().__init__()
|
||||||
|
self.dim0 = dim0
|
||||||
|
self.dim1 = dim1
|
||||||
|
|
||||||
|
def forward(self, x: paddle.Tensor) -> paddle.Tensor:
|
||||||
|
x = paddle.transpose(x, (self.dim0, self.dim1))
|
||||||
|
return x
|
||||||
|
|
||||||
|
class CausalConv1d(nn.Conv1d):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels: int,
|
||||||
|
out_channels: int,
|
||||||
|
kernel_size: int,
|
||||||
|
stride: int = 1,
|
||||||
|
dilation: int = 1,
|
||||||
|
groups: int = 1,
|
||||||
|
padding_mode: str = 'zeros'
|
||||||
|
) -> None:
|
||||||
|
super(CausalConv1d, self).__init__(in_channels, out_channels,
|
||||||
|
kernel_size, stride,
|
||||||
|
padding=0, dilation=dilation,
|
||||||
|
groups=groups,
|
||||||
|
padding_mode=padding_mode)
|
||||||
|
assert stride == 1
|
||||||
|
self.causal_padding = kernel_size - 1
|
||||||
|
|
||||||
|
def forward(self, x: paddle.Tensor) -> paddle.Tensor:
|
||||||
|
x = F.pad(x, (self.causal_padding, 0), value=0.0)
|
||||||
|
x = super(CausalConv1d, self).forward(x)
|
||||||
|
return x
|
||||||
|
|
||||||
|
class SinusoidalPosEmb(paddle.nn.Layer):
|
||||||
|
def __init__(self, dim):
|
||||||
|
super().__init__()
|
||||||
|
self.dim = dim
|
||||||
|
assert self.dim % 2 == 0, "SinusoidalPosEmb requires dim to be even"
|
||||||
|
def forward(self, x, scale=1000):
|
||||||
|
if x.ndim < 1:
|
||||||
|
x = x.unsqueeze(0)
|
||||||
|
half_dim = self.dim // 2
|
||||||
|
emb = math.log(10000) / (half_dim - 1)
|
||||||
|
emb = paddle.exp(paddle.arange(half_dim).astype('float32') * -emb)
|
||||||
|
emb = scale * x.unsqueeze(1) * emb.unsqueeze(0)
|
||||||
|
emb = paddle.concat([paddle.sin(emb), paddle.cos(emb)], axis=-1)
|
||||||
|
return emb
|
||||||
|
|
||||||
|
class CausalBlock1D(Block1D):
|
||||||
|
def __init__(self, dim: int, dim_out: int):
|
||||||
|
super(CausalBlock1D, self).__init__(dim, dim_out)
|
||||||
|
self.block = nn.Sequential(
|
||||||
|
CausalConv1d(dim, dim_out, 3),
|
||||||
|
Transpose(1, 2),
|
||||||
|
nn.LayerNorm(dim_out),
|
||||||
|
Transpose(1, 2),
|
||||||
|
nn.Mish()
|
||||||
|
)
|
||||||
|
|
||||||
|
def forward(self, x: paddle.Tensor, mask: paddle.Tensor) -> Tuple[paddle.Tensor, paddle.Tensor]:
|
||||||
|
output = self.block(x * mask)
|
||||||
|
return output * mask
|
||||||
|
|
||||||
|
|
||||||
|
class CausalResnetBlock1D(ResnetBlock1D):
|
||||||
|
def __init__(self, dim: int, dim_out: int, time_emb_dim: int, groups: int = 8):
|
||||||
|
super(CausalResnetBlock1D, self).__init__(dim, dim_out, time_emb_dim, groups)
|
||||||
|
self.block1 = CausalBlock1D(dim, dim_out)
|
||||||
|
self.block2 = CausalBlock1D(dim_out, dim_out)
|
||||||
|
|
||||||
|
def subsequent_chunk_mask(
|
||||||
|
size: int,
|
||||||
|
chunk_size: int,
|
||||||
|
num_left_chunks: int = -1,
|
||||||
|
) -> paddle.Tensor:
|
||||||
|
"""Create mask for subsequent steps (size, size) with chunk size,
|
||||||
|
this is for streaming encoder
|
||||||
|
|
||||||
|
Args:
|
||||||
|
size (int): size of mask
|
||||||
|
chunk_size (int): size of chunk
|
||||||
|
num_left_chunks (int): number of left chunks
|
||||||
|
<0: use full chunk
|
||||||
|
>=0: use num_left_chunks
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
paddle.Tensor: mask
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> subsequent_chunk_mask(4, 2)
|
||||||
|
[[1, 1, 0, 0],
|
||||||
|
[1, 1, 0, 0],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[1, 1, 1, 1]]
|
||||||
|
"""
|
||||||
|
pos_idx = paddle.arange(size, dtype='int64')
|
||||||
|
block_value = (paddle.floor_divide(pos_idx, chunk_size) + 1) * chunk_size
|
||||||
|
ret = pos_idx.unsqueeze(0) < block_value.unsqueeze(1)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def add_optional_chunk_mask(xs: paddle.Tensor,
|
||||||
|
masks: paddle.Tensor,
|
||||||
|
use_dynamic_chunk: bool,
|
||||||
|
use_dynamic_left_chunk: bool,
|
||||||
|
decoding_chunk_size: int,
|
||||||
|
static_chunk_size: int,
|
||||||
|
num_decoding_left_chunks: int,
|
||||||
|
enable_full_context: bool = True):
|
||||||
|
""" Apply optional mask for encoder.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
xs (paddle.Tensor): padded input, (B, L, D), L for max length
|
||||||
|
mask (paddle.Tensor): mask for xs, (B, 1, L)
|
||||||
|
use_dynamic_chunk (bool): whether to use dynamic chunk or not
|
||||||
|
use_dynamic_left_chunk (bool): whether to use dynamic left chunk for
|
||||||
|
training.
|
||||||
|
decoding_chunk_size (int): decoding chunk size for dynamic chunk, it's
|
||||||
|
0: default for training, use random dynamic chunk.
|
||||||
|
<0: for decoding, use full chunk.
|
||||||
|
>0: for decoding, use fixed chunk size as set.
|
||||||
|
static_chunk_size (int): chunk size for static chunk training/decoding
|
||||||
|
if it's greater than 0, if use_dynamic_chunk is true,
|
||||||
|
this parameter will be ignored
|
||||||
|
num_decoding_left_chunks: number of left chunks, this is for decoding,
|
||||||
|
the chunk size is decoding_chunk_size.
|
||||||
|
>=0: use num_decoding_left_chunks
|
||||||
|
<0: use all left chunks
|
||||||
|
enable_full_context (bool):
|
||||||
|
True: chunk size is either [1, 25] or full context(max_len)
|
||||||
|
False: chunk size ~ U[1, 25]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
paddle.Tensor: chunk mask of the input xs.
|
||||||
|
"""
|
||||||
|
# Whether to use chunk mask or not
|
||||||
|
if use_dynamic_chunk:
|
||||||
|
max_len = xs.shape[1]
|
||||||
|
if decoding_chunk_size < 0:
|
||||||
|
chunk_size = max_len
|
||||||
|
num_left_chunks = -1
|
||||||
|
elif decoding_chunk_size > 0:
|
||||||
|
chunk_size = decoding_chunk_size
|
||||||
|
num_left_chunks = num_decoding_left_chunks
|
||||||
|
else:
|
||||||
|
# chunk size is either [1, 25] or full context(max_len).
|
||||||
|
# Since we use 4 times subsampling and allow up to 1s(100 frames)
|
||||||
|
# delay, the maximum frame is 100 / 4 = 25.
|
||||||
|
chunk_size = paddle.randint(1, max_len, shape=(1,)).item()
|
||||||
|
num_left_chunks = -1
|
||||||
|
if chunk_size > max_len // 2 and enable_full_context:
|
||||||
|
chunk_size = max_len
|
||||||
|
else:
|
||||||
|
chunk_size = chunk_size % 25 + 1
|
||||||
|
if use_dynamic_left_chunk:
|
||||||
|
max_left_chunks = (max_len - 1) // chunk_size
|
||||||
|
num_left_chunks = paddle.randint(0, max_left_chunks, shape=(1,)).item()
|
||||||
|
|
||||||
|
chunk_masks = subsequent_chunk_mask(xs.shape[1], chunk_size,
|
||||||
|
num_left_chunks) # (L, L)
|
||||||
|
chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
|
||||||
|
chunk_masks = masks & chunk_masks # (B, L, L)
|
||||||
|
elif static_chunk_size > 0:
|
||||||
|
num_left_chunks = num_decoding_left_chunks
|
||||||
|
chunk_masks = subsequent_chunk_mask(xs.shape[1], static_chunk_size,
|
||||||
|
num_left_chunks) # (L, L)
|
||||||
|
chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L)
|
||||||
|
chunk_masks = masks & chunk_masks # (B, L, L)
|
||||||
|
else:
|
||||||
|
chunk_masks = masks
|
||||||
|
|
||||||
|
assert chunk_masks.dtype == 'bool'
|
||||||
|
if (chunk_masks.sum(axis=-1) == 0).sum().item() != 0:
|
||||||
|
print('get chunk_masks all false at some timestep, force set to true, make sure they are masked in future computation!')
|
||||||
|
all_false_mask = chunk_masks.sum(axis=-1) == 0
|
||||||
|
chunk_masks = paddle.where(all_false_mask.unsqueeze(-1), paddle.ones_like(chunk_masks, dtype='bool'), chunk_masks)
|
||||||
|
|
||||||
|
return chunk_masks
|
||||||
|
|
||||||
|
def mask_to_bias(mask: paddle.Tensor, dtype: str) -> paddle.Tensor:
|
||||||
|
assert mask.dtype == 'bool', "Input mask must be of boolean type"
|
||||||
|
assert dtype in ['float32', 'bfloat16', 'float16'], f"Unsupported dtype: {dtype}"
|
||||||
|
mask = mask.astype(dtype)
|
||||||
|
mask = (1.0 - mask) * -1.0e+10
|
||||||
|
|
||||||
|
return mask
|
||||||
|
|
||||||
|
class ConditionalDecoder(nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels,
|
||||||
|
out_channels,
|
||||||
|
channels=(256, 256),
|
||||||
|
dropout=0.05,
|
||||||
|
attention_head_dim=64,
|
||||||
|
n_blocks=1,
|
||||||
|
num_mid_blocks=2,
|
||||||
|
num_heads=4,
|
||||||
|
act_fn="snake",
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
This decoder requires an input with the same shape of the target. So, if your text content
|
||||||
|
is shorter or longer than the outputs, please re-sampling it before feeding to the decoder.
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
channels = tuple(channels)
|
||||||
|
self.in_channels = in_channels
|
||||||
|
self.out_channels = out_channels
|
||||||
|
|
||||||
|
self.time_embeddings = SinusoidalPosEmb(in_channels)
|
||||||
|
time_embed_dim = channels[0] * 4
|
||||||
|
self.time_mlp = TimestepEmbedding(
|
||||||
|
in_channels=in_channels,
|
||||||
|
time_embed_dim=time_embed_dim,
|
||||||
|
act_fn="silu",
|
||||||
|
)
|
||||||
|
self.down_blocks = nn.LayerList([])
|
||||||
|
self.mid_blocks = nn.LayerList([])
|
||||||
|
self.up_blocks = nn.LayerList([])
|
||||||
|
|
||||||
|
output_channel = in_channels
|
||||||
|
for i in range(len(channels)):
|
||||||
|
input_channel = output_channel
|
||||||
|
output_channel = channels[i]
|
||||||
|
is_last = i == len(channels) - 1
|
||||||
|
resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim)
|
||||||
|
transformer_blocks = nn.LayerList(
|
||||||
|
[
|
||||||
|
BasicTransformerBlock(
|
||||||
|
dim=output_channel,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
downsample = (
|
||||||
|
Downsample1D(output_channel) if not is_last else nn.Conv1D(output_channel, output_channel, 3, padding=1)
|
||||||
|
)
|
||||||
|
self.down_blocks.append(nn.LayerList([resnet, transformer_blocks, downsample]))
|
||||||
|
|
||||||
|
for _ in range(num_mid_blocks):
|
||||||
|
input_channel = channels[-1]
|
||||||
|
out_channels = channels[-1]
|
||||||
|
resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim)
|
||||||
|
|
||||||
|
transformer_blocks = nn.LayerList(
|
||||||
|
[
|
||||||
|
BasicTransformerBlock(
|
||||||
|
dim=output_channel,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mid_blocks.append(nn.LayerList([resnet, transformer_blocks]))
|
||||||
|
|
||||||
|
channels = channels[::-1] + (channels[0],)
|
||||||
|
for i in range(len(channels) - 1):
|
||||||
|
input_channel = channels[i] * 2
|
||||||
|
output_channel = channels[i + 1]
|
||||||
|
is_last = i == len(channels) - 2
|
||||||
|
resnet = ResnetBlock1D(
|
||||||
|
dim=input_channel,
|
||||||
|
dim_out=output_channel,
|
||||||
|
time_emb_dim=time_embed_dim,
|
||||||
|
)
|
||||||
|
transformer_blocks = nn.LayerList(
|
||||||
|
[
|
||||||
|
BasicTransformerBlock(
|
||||||
|
dim=output_channel,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
upsample = (
|
||||||
|
Upsample1D(output_channel, use_conv_transpose=True)
|
||||||
|
if not is_last
|
||||||
|
else nn.Conv1D(output_channel, output_channel, 3, padding=1)
|
||||||
|
)
|
||||||
|
self.up_blocks.append(nn.LayerList([resnet, transformer_blocks, upsample]))
|
||||||
|
self.final_block = Block1D(channels[-1], channels[-1])
|
||||||
|
self.final_proj = nn.Conv1D(channels[-1], self.out_channels, 1)
|
||||||
|
self.initialize_weights()
|
||||||
|
|
||||||
|
def initialize_weights(self):
|
||||||
|
for m in self.sublayers():
|
||||||
|
if isinstance(m, nn.Conv1D):
|
||||||
|
nn.initializer.KaimingNormal(m.weight, nonlinearity='relu')
|
||||||
|
if m.bias is not None:
|
||||||
|
nn.initializer.Constant(m.bias, value=0)
|
||||||
|
elif isinstance(m, nn.GroupNorm):
|
||||||
|
nn.initializer.Constant(m.weight, value=1)
|
||||||
|
nn.initializer.Constant(m.bias, value=0)
|
||||||
|
elif isinstance(m, nn.Linear):
|
||||||
|
nn.initializer.KaimingNormal(m.weight, nonlinearity='relu')
|
||||||
|
if m.bias is not None:
|
||||||
|
nn.initializer.Constant(m.bias, value=0)
|
||||||
|
|
||||||
|
def forward(self, x, mask, mu, t, spks=None, cond=None, streaming=False):
|
||||||
|
"""Forward pass of the UNet1DConditional model.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x (paddle.Tensor): shape (batch_size, in_channels, time)
|
||||||
|
mask (paddle.Tensor): shape (batch_size, 1, time)
|
||||||
|
t (paddle.Tensor): shape (batch_size)
|
||||||
|
spks (paddle.Tensor, optional): shape: (batch_size, condition_channels). Defaults to None.
|
||||||
|
cond (paddle.Tensor, optional): placeholder for future use. Defaults to None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
paddle.Tensor: output tensor
|
||||||
|
"""
|
||||||
|
|
||||||
|
t = self.time_embeddings(t).astype(t.dtype)
|
||||||
|
t = self.time_mlp(t)
|
||||||
|
|
||||||
|
x = pack([x, mu], "b * t")[0]
|
||||||
|
|
||||||
|
if spks is not None:
|
||||||
|
spks = repeat(spks, "b c -> b c t", t=x.shape[-1])
|
||||||
|
x = pack([x, spks], "b * t")[0]
|
||||||
|
if cond is not None:
|
||||||
|
x = pack([x, cond], "b * t")[0]
|
||||||
|
|
||||||
|
hiddens = []
|
||||||
|
masks = [mask]
|
||||||
|
for resnet, transformer_blocks, downsample in self.down_blocks:
|
||||||
|
mask_down = masks[-1]
|
||||||
|
x = resnet(x, mask_down, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c").contiguous()
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_down.astype('bool'), False, False, 0, 0, -1).repeat(1, x.shape[1], 1)
|
||||||
|
attn_mask = mask_to_bias(attn_mask, x.dtype)
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=attn_mask,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t").contiguous()
|
||||||
|
hiddens.append(x) # Save hidden states for skip connections
|
||||||
|
x = downsample(x * mask_down)
|
||||||
|
masks.append(mask_down[:, :, ::2])
|
||||||
|
masks = masks[:-1]
|
||||||
|
mask_mid = masks[-1]
|
||||||
|
|
||||||
|
for resnet, transformer_blocks in self.mid_blocks:
|
||||||
|
x = resnet(x, mask_mid, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c").contiguous()
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_mid.astype('bool'), False, False, 0, 0, -1).repeat(1, x.shape[1], 1)
|
||||||
|
attn_mask = mask_to_bias(attn_mask, x.dtype)
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=attn_mask,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t").contiguous()
|
||||||
|
|
||||||
|
for resnet, transformer_blocks, upsample in self.up_blocks:
|
||||||
|
mask_up = masks.pop()
|
||||||
|
skip = hiddens.pop()
|
||||||
|
x = pack([x[:, :, :skip.shape[-1]], skip], "b * t")[0]
|
||||||
|
x = resnet(x, mask_up, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c").contiguous()
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_up.astype('bool'), False, False, 0, 0, -1).repeat(1, x.shape[1], 1)
|
||||||
|
attn_mask = mask_to_bias(attn_mask, x.dtype)
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=attn_mask,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t").contiguous()
|
||||||
|
x = upsample(x * mask_up)
|
||||||
|
x = self.final_block(x, mask_up)
|
||||||
|
output = self.final_proj(x * mask_up)
|
||||||
|
return output * mask
|
||||||
|
|
||||||
|
|
||||||
|
class CausalConditionalDecoder(nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels,
|
||||||
|
out_channels,
|
||||||
|
channels=(256, 256),
|
||||||
|
dropout=0.05,
|
||||||
|
attention_head_dim=64,
|
||||||
|
n_blocks=1,
|
||||||
|
num_mid_blocks=2,
|
||||||
|
num_heads=4,
|
||||||
|
act_fn="snake",
|
||||||
|
static_chunk_size=50,
|
||||||
|
num_decoding_left_chunks=2,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
This decoder requires an input with the same shape of the target. So, if your text content
|
||||||
|
is shorter or longer than the outputs, please re-sampling it before feeding to the decoder.
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
channels = tuple(channels)
|
||||||
|
self.in_channels = in_channels
|
||||||
|
self.out_channels = out_channels
|
||||||
|
self.time_embeddings = SinusoidalPosEmb(in_channels)
|
||||||
|
time_embed_dim = channels[0] * 4
|
||||||
|
self.time_mlp = TimestepEmbedding(
|
||||||
|
in_channels=in_channels,
|
||||||
|
time_embed_dim=time_embed_dim,
|
||||||
|
act_fn="silu",
|
||||||
|
)
|
||||||
|
self.static_chunk_size = static_chunk_size
|
||||||
|
self.num_decoding_left_chunks = num_decoding_left_chunks
|
||||||
|
self.down_blocks = nn.LayerList([])
|
||||||
|
self.mid_blocks = nn.LayerList([])
|
||||||
|
self.up_blocks = nn.LayerList([])
|
||||||
|
|
||||||
|
output_channel = in_channels
|
||||||
|
for i in range(len(channels)):
|
||||||
|
input_channel = output_channel
|
||||||
|
output_channel = channels[i]
|
||||||
|
is_last = i == len(channels) - 1
|
||||||
|
resnet = CausalResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim)
|
||||||
|
transformer_blocks = nn.LayerList(
|
||||||
|
[
|
||||||
|
BasicTransformerBlock(
|
||||||
|
dim=output_channel,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
downsample = (
|
||||||
|
Downsample1D(output_channel) if not is_last else CausalConv1d(output_channel, output_channel, 3) # 假设已实现
|
||||||
|
)
|
||||||
|
self.down_blocks.append(nn.LayerList([resnet, transformer_blocks, downsample]))
|
||||||
|
|
||||||
|
for _ in range(num_mid_blocks):
|
||||||
|
input_channel = channels[-1]
|
||||||
|
out_channels = channels[-1]
|
||||||
|
resnet = CausalResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim)
|
||||||
|
|
||||||
|
transformer_blocks = nn.LayerList(
|
||||||
|
[
|
||||||
|
BasicTransformerBlock(
|
||||||
|
dim=output_channel,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mid_blocks.append(nn.LayerList([resnet, transformer_blocks]))
|
||||||
|
|
||||||
|
channels = channels[::-1] + (channels[0],)
|
||||||
|
for i in range(len(channels) - 1):
|
||||||
|
input_channel = channels[i] * 2
|
||||||
|
output_channel = channels[i + 1]
|
||||||
|
is_last = i == len(channels) - 2
|
||||||
|
resnet = CausalResnetBlock1D(
|
||||||
|
dim=input_channel,
|
||||||
|
dim_out=output_channel,
|
||||||
|
time_emb_dim=time_embed_dim,
|
||||||
|
)
|
||||||
|
transformer_blocks = nn.LayerList(
|
||||||
|
[
|
||||||
|
BasicTransformerBlock(
|
||||||
|
dim=output_channel,
|
||||||
|
num_attention_heads=num_heads,
|
||||||
|
attention_head_dim=attention_head_dim,
|
||||||
|
dropout=dropout,
|
||||||
|
activation_fn=act_fn,
|
||||||
|
)
|
||||||
|
for _ in range(n_blocks)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
upsample = (
|
||||||
|
Upsample1D(output_channel, use_conv_transpose=True) # 假设已实现
|
||||||
|
if not is_last
|
||||||
|
else CausalConv1d(output_channel, output_channel, 3)
|
||||||
|
)
|
||||||
|
self.up_blocks.append(nn.LayerList([resnet, transformer_blocks, upsample]))
|
||||||
|
self.final_block = CausalBlock1D(channels[-1], channels[-1]) # 假设已实现
|
||||||
|
self.final_proj = nn.Conv1D(channels[-1], self.out_channels, 1) # 使用 Conv1D
|
||||||
|
self.initialize_weights()
|
||||||
|
|
||||||
|
def initialize_weights(self):
|
||||||
|
for m in self.sublayers(): # 使用 sublayers() 而不是 modules()
|
||||||
|
if isinstance(m, nn.Conv1D):
|
||||||
|
nn.initializer.KaimingNormal(m.weight, nonlinearity='relu')
|
||||||
|
if m.bias is not None:
|
||||||
|
nn.initializer.Constant(m.bias, value=0)
|
||||||
|
elif isinstance(m, nn.GroupNorm):
|
||||||
|
nn.initializer.Constant(m.weight, value=1)
|
||||||
|
nn.initializer.Constant(m.bias, value=0)
|
||||||
|
elif isinstance(m, nn.Linear):
|
||||||
|
nn.initializer.KaimingNormal(m.weight, nonlinearity='relu')
|
||||||
|
if m.bias is not None:
|
||||||
|
nn.initializer.Constant(m.bias, value=0)
|
||||||
|
|
||||||
|
def forward(self, x, mask, mu, t, spks=None, cond=None, streaming=False):
|
||||||
|
"""Forward pass of the UNet1DConditional model.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x (paddle.Tensor): shape (batch_size, in_channels, time)
|
||||||
|
mask (paddle.Tensor): shape (batch_size, 1, time)
|
||||||
|
mu (paddle.Tensor): mean tensor for conditioning
|
||||||
|
t (paddle.Tensor): shape (batch_size)
|
||||||
|
spks (paddle.Tensor, optional): shape: (batch_size, condition_channels). Defaults to None.
|
||||||
|
cond (paddle.Tensor, optional): placeholder for future use. Defaults to None.
|
||||||
|
streaming (bool, optional): whether to use streaming mode. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
paddle.Tensor: output tensor
|
||||||
|
"""
|
||||||
|
t = self.time_embeddings(t).astype(t.dtype) # 使用 astype 代替 .to(t.dtype)
|
||||||
|
t = self.time_mlp(t)
|
||||||
|
|
||||||
|
x = pack([x, mu], "b * t")[0] # 假设 pack 函数已实现
|
||||||
|
|
||||||
|
if spks is not None:
|
||||||
|
spks = repeat(spks, "b c -> b c t", t=x.shape[-1]) # 假设 repeat 函数已实现
|
||||||
|
x = pack([x, spks], "b * t")[0]
|
||||||
|
if cond is not None:
|
||||||
|
x = pack([x, cond], "b * t")[0]
|
||||||
|
|
||||||
|
hiddens = []
|
||||||
|
masks = [mask]
|
||||||
|
for resnet, transformer_blocks, downsample in self.down_blocks:
|
||||||
|
mask_down = masks[-1]
|
||||||
|
x = resnet(x, mask_down, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c").contiguous() # 假设 rearrange 函数已实现
|
||||||
|
if streaming is True:
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_down.astype('bool'), False, False, 0, self.static_chunk_size, -1) # 使用 astype('bool')
|
||||||
|
else:
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_down.astype('bool'), False, False, 0, 0, -1).repeat(1, x.shape[1], 1) # 使用 .shape 而不是 .size()
|
||||||
|
attn_mask = mask_to_bias(attn_mask, x.dtype) # 假设 mask_to_bias 函数已实现
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=attn_mask,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t").contiguous()
|
||||||
|
hiddens.append(x) # Save hidden states for skip connections
|
||||||
|
x = downsample(x * mask_down)
|
||||||
|
masks.append(mask_down[:, :, ::2])
|
||||||
|
masks = masks[:-1]
|
||||||
|
mask_mid = masks[-1]
|
||||||
|
|
||||||
|
for resnet, transformer_blocks in self.mid_blocks:
|
||||||
|
x = resnet(x, mask_mid, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c").contiguous()
|
||||||
|
if streaming is True:
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_mid.astype('bool'), False, False, 0, self.static_chunk_size, -1)
|
||||||
|
else:
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_mid.astype('bool'), False, False, 0, 0, -1).repeat(1, x.shape[1], 1)
|
||||||
|
attn_mask = mask_to_bias(attn_mask, x.dtype)
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=attn_mask,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t").contiguous()
|
||||||
|
|
||||||
|
for resnet, transformer_blocks, upsample in self.up_blocks:
|
||||||
|
mask_up = masks.pop()
|
||||||
|
skip = hiddens.pop()
|
||||||
|
x = pack([x[:, :, :skip.shape[-1]], skip], "b * t")[0]
|
||||||
|
x = resnet(x, mask_up, t)
|
||||||
|
x = rearrange(x, "b c t -> b t c").contiguous()
|
||||||
|
if streaming is True:
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_up.astype('bool'), False, False, 0, self.static_chunk_size, -1)
|
||||||
|
else:
|
||||||
|
attn_mask = add_optional_chunk_mask(x, mask_up.astype('bool'), False, False, 0, 0, -1).repeat(1, x.shape[1], 1)
|
||||||
|
attn_mask = mask_to_bias(attn_mask, x.dtype)
|
||||||
|
for transformer_block in transformer_blocks:
|
||||||
|
x = transformer_block(
|
||||||
|
hidden_states=x,
|
||||||
|
attention_mask=attn_mask,
|
||||||
|
timestep=t,
|
||||||
|
)
|
||||||
|
x = rearrange(x, "b t c -> b c t").contiguous()
|
||||||
|
x = upsample(x * mask_up)
|
||||||
|
x = self.final_block(x, mask_up)
|
||||||
|
output = self.final_proj(x * mask_up)
|
||||||
|
return output * mask
|
||||||
@ -0,0 +1,320 @@
|
|||||||
|
import logging
|
||||||
|
import random
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
import paddle
|
||||||
|
from omegaconf import DictConfig
|
||||||
|
|
||||||
|
from cosyvoice.utils.mask import make_pad_mask
|
||||||
|
|
||||||
|
|
||||||
|
class MaskedDiffWithXvec(paddle.nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
input_size: int = 512,
|
||||||
|
output_size: int = 80,
|
||||||
|
spk_embed_dim: int = 192,
|
||||||
|
output_type: str = "mel",
|
||||||
|
vocab_size: int = 4096,
|
||||||
|
input_frame_rate: int = 50,
|
||||||
|
only_mask_loss: bool = True,
|
||||||
|
encoder: paddle.nn.Layer = None,
|
||||||
|
length_regulator: paddle.nn.Layer = None,
|
||||||
|
decoder: paddle.nn.Layer = None,
|
||||||
|
decoder_conf: Dict = {
|
||||||
|
"in_channels": 240,
|
||||||
|
"out_channel": 80,
|
||||||
|
"spk_emb_dim": 80,
|
||||||
|
"n_spks": 1,
|
||||||
|
"cfm_params": DictConfig(
|
||||||
|
{
|
||||||
|
"sigma_min": 1e-06,
|
||||||
|
"solver": "euler",
|
||||||
|
"t_scheduler": "cosine",
|
||||||
|
"training_cfg_rate": 0.2,
|
||||||
|
"inference_cfg_rate": 0.7,
|
||||||
|
"reg_loss_type": "l1",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"decoder_params": {
|
||||||
|
"channels": [256, 256],
|
||||||
|
"dropout": 0.0,
|
||||||
|
"attention_head_dim": 64,
|
||||||
|
"n_blocks": 4,
|
||||||
|
"num_mid_blocks": 12,
|
||||||
|
"num_heads": 8,
|
||||||
|
"act_fn": "gelu",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mel_feat_conf: Dict = {
|
||||||
|
"n_fft": 1024,
|
||||||
|
"num_mels": 80,
|
||||||
|
"sampling_rate": 22050,
|
||||||
|
"hop_size": 256,
|
||||||
|
"win_size": 1024,
|
||||||
|
"fmin": 0,
|
||||||
|
"fmax": 8000,
|
||||||
|
},
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.input_size = input_size
|
||||||
|
self.output_size = output_size
|
||||||
|
self.decoder_conf = decoder_conf
|
||||||
|
self.mel_feat_conf = mel_feat_conf
|
||||||
|
self.vocab_size = vocab_size
|
||||||
|
self.output_type = output_type
|
||||||
|
self.input_frame_rate = input_frame_rate
|
||||||
|
logging.info(f"input frame rate={self.input_frame_rate}")
|
||||||
|
self.input_embedding = paddle.nn.Embedding(vocab_size, input_size)
|
||||||
|
self.spk_embed_affine_layer = paddle.nn.Linear(
|
||||||
|
in_features=spk_embed_dim, out_features=output_size
|
||||||
|
)
|
||||||
|
self.encoder = encoder
|
||||||
|
self.encoder_proj = paddle.nn.Linear(
|
||||||
|
in_features=self.encoder.output_size(), out_features=output_size
|
||||||
|
)
|
||||||
|
self.decoder = decoder
|
||||||
|
self.length_regulator = length_regulator
|
||||||
|
self.only_mask_loss = only_mask_loss
|
||||||
|
|
||||||
|
def forward(
|
||||||
|
>>>>>> self, batch: dict, device: torch.device
|
||||||
|
) -> Dict[str, Optional[paddle.Tensor]]:
|
||||||
|
token = batch["speech_token"].to(device)
|
||||||
|
token_len = batch["speech_token_len"].to(device)
|
||||||
|
feat = batch["speech_feat"].to(device)
|
||||||
|
feat_len = batch["speech_feat_len"].to(device)
|
||||||
|
embedding = batch["embedding"].to(device)
|
||||||
|
embedding = paddle.nn.functional.normalize(x=embedding, axis=1)
|
||||||
|
embedding = self.spk_embed_affine_layer(embedding)
|
||||||
|
mask = (~make_pad_mask(token_len)).float().unsqueeze(-1).to(device)
|
||||||
|
token = self.input_embedding(paddle.clamp(token, min=0)) * mask
|
||||||
|
h, h_lengths = self.encoder(token, token_len)
|
||||||
|
h = self.encoder_proj(h)
|
||||||
|
h, h_lengths = self.length_regulator(h, feat_len)
|
||||||
|
conds = paddle.zeros(feat.shape, device=token.place)
|
||||||
|
for i, j in enumerate(feat_len):
|
||||||
|
if random.random() < 0.5:
|
||||||
|
continue
|
||||||
|
index = random.randint(0, int(0.3 * j))
|
||||||
|
conds[i, :index] = feat[i, :index]
|
||||||
|
conds = conds.transpose(1, 2)
|
||||||
|
mask = (~make_pad_mask(feat_len)).to(h)
|
||||||
|
loss, _ = self.decoder.compute_loss(
|
||||||
|
feat.transpose(1, 2).contiguous(),
|
||||||
|
mask.unsqueeze(1),
|
||||||
|
h.transpose(1, 2).contiguous(),
|
||||||
|
embedding,
|
||||||
|
cond=conds,
|
||||||
|
)
|
||||||
|
return {"loss": loss}
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def inference(
|
||||||
|
self,
|
||||||
|
token,
|
||||||
|
token_len,
|
||||||
|
prompt_token,
|
||||||
|
prompt_token_len,
|
||||||
|
prompt_feat,
|
||||||
|
prompt_feat_len,
|
||||||
|
embedding,
|
||||||
|
flow_cache,
|
||||||
|
):
|
||||||
|
assert token.shape[0] == 1
|
||||||
|
embedding = paddle.nn.functional.normalize(x=embedding, axis=1)
|
||||||
|
embedding = self.spk_embed_affine_layer(embedding)
|
||||||
|
token_len1, token_len2 = prompt_token.shape[1], token.shape[1]
|
||||||
|
token, token_len = (
|
||||||
|
paddle.cat([prompt_token, token], dim=1),
|
||||||
|
prompt_token_len + token_len,
|
||||||
|
)
|
||||||
|
mask = (~make_pad_mask(token_len)).unsqueeze(-1).to(embedding)
|
||||||
|
token = self.input_embedding(paddle.clamp(token, min=0)) * mask
|
||||||
|
h, h_lengths = self.encoder(token, token_len)
|
||||||
|
h = self.encoder_proj(h)
|
||||||
|
mel_len1, mel_len2 = prompt_feat.shape[1], int(
|
||||||
|
token_len2 / self.input_frame_rate * 22050 / 256
|
||||||
|
)
|
||||||
|
h, h_lengths = self.length_regulator.inference(
|
||||||
|
h[:, :token_len1],
|
||||||
|
h[:, token_len1:],
|
||||||
|
mel_len1,
|
||||||
|
mel_len2,
|
||||||
|
self.input_frame_rate,
|
||||||
|
)
|
||||||
|
conds = paddle.zeros(
|
||||||
|
[1, mel_len1 + mel_len2, self.output_size], device=token.place
|
||||||
|
).to(h.dtype)
|
||||||
|
conds[:, :mel_len1] = prompt_feat
|
||||||
|
conds = conds.transpose(1, 2)
|
||||||
|
mask = (~make_pad_mask(paddle.tensor([mel_len1 + mel_len2]))).to(h)
|
||||||
|
feat, flow_cache = self.decoder(
|
||||||
|
mu=h.transpose(1, 2).contiguous(),
|
||||||
|
mask=mask.unsqueeze(1),
|
||||||
|
spks=embedding,
|
||||||
|
cond=conds,
|
||||||
|
n_timesteps=10,
|
||||||
|
prompt_len=mel_len1,
|
||||||
|
cache=flow_cache,
|
||||||
|
)
|
||||||
|
feat = feat[:, :, mel_len1:]
|
||||||
|
assert feat.shape[2] == mel_len2
|
||||||
|
return feat.float(), flow_cache
|
||||||
|
|
||||||
|
|
||||||
|
class CausalMaskedDiffWithXvec(paddle.nn.Layer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
input_size: int = 512,
|
||||||
|
output_size: int = 80,
|
||||||
|
spk_embed_dim: int = 192,
|
||||||
|
output_type: str = "mel",
|
||||||
|
vocab_size: int = 6561,
|
||||||
|
input_frame_rate: int = 25,
|
||||||
|
only_mask_loss: bool = True,
|
||||||
|
token_mel_ratio: int = 2,
|
||||||
|
pre_lookahead_len: int = 3,
|
||||||
|
encoder: paddle.nn.Layer = None,
|
||||||
|
decoder: paddle.nn.Layer = None,
|
||||||
|
decoder_conf: Dict = {
|
||||||
|
"in_channels": 240,
|
||||||
|
"out_channel": 80,
|
||||||
|
"spk_emb_dim": 80,
|
||||||
|
"n_spks": 1,
|
||||||
|
"cfm_params": DictConfig(
|
||||||
|
{
|
||||||
|
"sigma_min": 1e-06,
|
||||||
|
"solver": "euler",
|
||||||
|
"t_scheduler": "cosine",
|
||||||
|
"training_cfg_rate": 0.2,
|
||||||
|
"inference_cfg_rate": 0.7,
|
||||||
|
"reg_loss_type": "l1",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"decoder_params": {
|
||||||
|
"channels": [256, 256],
|
||||||
|
"dropout": 0.0,
|
||||||
|
"attention_head_dim": 64,
|
||||||
|
"n_blocks": 4,
|
||||||
|
"num_mid_blocks": 12,
|
||||||
|
"num_heads": 8,
|
||||||
|
"act_fn": "gelu",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mel_feat_conf: Dict = {
|
||||||
|
"n_fft": 1024,
|
||||||
|
"num_mels": 80,
|
||||||
|
"sampling_rate": 22050,
|
||||||
|
"hop_size": 256,
|
||||||
|
"win_size": 1024,
|
||||||
|
"fmin": 0,
|
||||||
|
"fmax": 8000,
|
||||||
|
},
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.input_size = input_size
|
||||||
|
self.output_size = output_size
|
||||||
|
self.decoder_conf = decoder_conf
|
||||||
|
self.mel_feat_conf = mel_feat_conf
|
||||||
|
self.vocab_size = vocab_size
|
||||||
|
self.output_type = output_type
|
||||||
|
self.input_frame_rate = input_frame_rate
|
||||||
|
logging.info(f"input frame rate={self.input_frame_rate}")
|
||||||
|
self.input_embedding = paddle.nn.Embedding(vocab_size, input_size)
|
||||||
|
self.spk_embed_affine_layer = paddle.nn.Linear(
|
||||||
|
in_features=spk_embed_dim, out_features=output_size
|
||||||
|
)
|
||||||
|
self.encoder = encoder
|
||||||
|
self.encoder_proj = paddle.nn.Linear(
|
||||||
|
in_features=self.encoder.output_size(), out_features=output_size
|
||||||
|
)
|
||||||
|
self.decoder = decoder
|
||||||
|
self.only_mask_loss = only_mask_loss
|
||||||
|
self.token_mel_ratio = token_mel_ratio
|
||||||
|
self.pre_lookahead_len = pre_lookahead_len
|
||||||
|
|
||||||
|
def forward(
|
||||||
|
>>>>>> self, batch: dict, device: torch.device
|
||||||
|
) -> Dict[str, Optional[paddle.Tensor]]:
|
||||||
|
token = batch["speech_token"].to(device)
|
||||||
|
token_len = batch["speech_token_len"].to(device)
|
||||||
|
feat = batch["speech_feat"].to(device)
|
||||||
|
feat_len = batch["speech_feat_len"].to(device)
|
||||||
|
embedding = batch["embedding"].to(device)
|
||||||
|
streaming = True if random.random() < 0.5 else False
|
||||||
|
embedding = paddle.nn.functional.normalize(x=embedding, axis=1)
|
||||||
|
embedding = self.spk_embed_affine_layer(embedding)
|
||||||
|
mask = (~make_pad_mask(token_len)).float().unsqueeze(-1).to(device)
|
||||||
|
token = self.input_embedding(paddle.clamp(token, min=0)) * mask
|
||||||
|
h, h_lengths = self.encoder(token, token_len, streaming=streaming)
|
||||||
|
h = self.encoder_proj(h)
|
||||||
|
conds = paddle.zeros(feat.shape, device=token.place)
|
||||||
|
for i, j in enumerate(feat_len):
|
||||||
|
if random.random() < 0.5:
|
||||||
|
continue
|
||||||
|
index = random.randint(0, int(0.3 * j))
|
||||||
|
conds[i, :index] = feat[i, :index]
|
||||||
|
conds = conds.transpose(1, 2)
|
||||||
|
mask = (~make_pad_mask(h_lengths.sum(dim=-1).squeeze(dim=1))).to(h)
|
||||||
|
loss, _ = self.decoder.compute_loss(
|
||||||
|
feat.transpose(1, 2).contiguous(),
|
||||||
|
mask.unsqueeze(1),
|
||||||
|
h.transpose(1, 2).contiguous(),
|
||||||
|
embedding,
|
||||||
|
cond=conds,
|
||||||
|
streaming=streaming,
|
||||||
|
)
|
||||||
|
return {"loss": loss}
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def inference(
|
||||||
|
self,
|
||||||
|
token,
|
||||||
|
token_len,
|
||||||
|
prompt_token,
|
||||||
|
prompt_token_len,
|
||||||
|
prompt_feat,
|
||||||
|
prompt_feat_len,
|
||||||
|
embedding,
|
||||||
|
streaming,
|
||||||
|
finalize,
|
||||||
|
):
|
||||||
|
assert token.shape[0] == 1
|
||||||
|
embedding = paddle.nn.functional.normalize(x=embedding, axis=1)
|
||||||
|
embedding = self.spk_embed_affine_layer(embedding)
|
||||||
|
token, token_len = (
|
||||||
|
paddle.cat([prompt_token, token], dim=1),
|
||||||
|
prompt_token_len + token_len,
|
||||||
|
)
|
||||||
|
mask = (~make_pad_mask(token_len)).unsqueeze(-1).to(embedding)
|
||||||
|
token = self.input_embedding(paddle.clamp(token, min=0)) * mask
|
||||||
|
if finalize is True:
|
||||||
|
h, h_lengths = self.encoder(token, token_len, streaming=streaming)
|
||||||
|
else:
|
||||||
|
token, context = (
|
||||||
|
token[:, : -self.pre_lookahead_len],
|
||||||
|
token[:, -self.pre_lookahead_len :],
|
||||||
|
)
|
||||||
|
h, h_lengths = self.encoder(
|
||||||
|
token, token_len, context=context, streaming=streaming
|
||||||
|
)
|
||||||
|
mel_len1, mel_len2 = prompt_feat.shape[1], h.shape[1] - prompt_feat.shape[1]
|
||||||
|
h = self.encoder_proj(h)
|
||||||
|
conds = paddle.zeros(
|
||||||
|
[1, mel_len1 + mel_len2, self.output_size], device=token.place
|
||||||
|
).to(h.dtype)
|
||||||
|
conds[:, :mel_len1] = prompt_feat
|
||||||
|
conds = conds.transpose(1, 2)
|
||||||
|
mask = (~make_pad_mask(paddle.tensor([mel_len1 + mel_len2]))).to(h)
|
||||||
|
feat, _ = self.decoder(
|
||||||
|
mu=h.transpose(1, 2).contiguous(),
|
||||||
|
mask=mask.unsqueeze(1),
|
||||||
|
spks=embedding,
|
||||||
|
cond=conds,
|
||||||
|
n_timesteps=10,
|
||||||
|
streaming=streaming,
|
||||||
|
)
|
||||||
|
feat = feat[:, :, mel_len1:]
|
||||||
|
assert feat.shape[2] == mel_len2
|
||||||
|
return feat.float(), None
|
||||||
@ -0,0 +1,250 @@
|
|||||||
|
import paddle
|
||||||
|
from matcha.models.components.flow_matching import BASECFM
|
||||||
|
|
||||||
|
from cosyvoice.utils.common import set_all_random_seed
|
||||||
|
|
||||||
|
|
||||||
|
class ConditionalCFM(BASECFM):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels,
|
||||||
|
cfm_params,
|
||||||
|
n_spks=1,
|
||||||
|
spk_emb_dim=64,
|
||||||
|
estimator: paddle.nn.Layer = None,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
n_feats=in_channels,
|
||||||
|
cfm_params=cfm_params,
|
||||||
|
n_spks=n_spks,
|
||||||
|
spk_emb_dim=spk_emb_dim,
|
||||||
|
)
|
||||||
|
self.t_scheduler = cfm_params.t_scheduler
|
||||||
|
self.training_cfg_rate = cfm_params.training_cfg_rate
|
||||||
|
self.inference_cfg_rate = cfm_params.inference_cfg_rate
|
||||||
|
in_channels = in_channels + (spk_emb_dim if n_spks > 0 else 0)
|
||||||
|
self.estimator = estimator
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def forward(
|
||||||
|
self,
|
||||||
|
mu,
|
||||||
|
mask,
|
||||||
|
n_timesteps,
|
||||||
|
temperature=1.0,
|
||||||
|
spks=None,
|
||||||
|
cond=None,
|
||||||
|
prompt_len=0,
|
||||||
|
cache=paddle.zeros(1, 80, 0, 2),
|
||||||
|
):
|
||||||
|
"""Forward diffusion
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mu (torch.Tensor): output of encoder
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
mask (torch.Tensor): output_mask
|
||||||
|
shape: (batch_size, 1, mel_timesteps)
|
||||||
|
n_timesteps (int): number of diffusion steps
|
||||||
|
temperature (float, optional): temperature for scaling noise. Defaults to 1.0.
|
||||||
|
spks (torch.Tensor, optional): speaker ids. Defaults to None.
|
||||||
|
shape: (batch_size, spk_emb_dim)
|
||||||
|
cond: Not used but kept for future purposes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
sample: generated mel-spectrogram
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
"""
|
||||||
|
z = (
|
||||||
|
paddle.randn(shape=mu.shape, dtype=mu.dtype).to(mu.place).to(mu.dtype)
|
||||||
|
* temperature
|
||||||
|
)
|
||||||
|
cache_size = cache.shape[2]
|
||||||
|
if cache_size != 0:
|
||||||
|
z[:, :, :cache_size] = cache[:, :, :, 0]
|
||||||
|
mu[:, :, :cache_size] = cache[:, :, :, 1]
|
||||||
|
z_cache = paddle.cat([z[:, :, :prompt_len], z[:, :, -34:]], dim=2)
|
||||||
|
mu_cache = paddle.cat([mu[:, :, :prompt_len], mu[:, :, -34:]], dim=2)
|
||||||
|
cache = paddle.stack([z_cache, mu_cache], dim=-1)
|
||||||
|
t_span = paddle.linspace(start=0, stop=1, num=n_timesteps + 1, dtype=mu.dtype)
|
||||||
|
if self.t_scheduler == "cosine":
|
||||||
|
t_span = 1 - paddle.cos(t_span * 0.5 * paddle.pi)
|
||||||
|
return (
|
||||||
|
self.solve_euler(z, t_span=t_span, mu=mu, mask=mask, spks=spks, cond=cond),
|
||||||
|
cache,
|
||||||
|
)
|
||||||
|
|
||||||
|
def solve_euler(self, x, t_span, mu, mask, spks, cond, streaming=False):
|
||||||
|
"""
|
||||||
|
Fixed euler solver for ODEs.
|
||||||
|
Args:
|
||||||
|
x (torch.Tensor): random noise
|
||||||
|
t_span (torch.Tensor): n_timesteps interpolated
|
||||||
|
shape: (n_timesteps + 1,)
|
||||||
|
mu (torch.Tensor): output of encoder
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
mask (torch.Tensor): output_mask
|
||||||
|
shape: (batch_size, 1, mel_timesteps)
|
||||||
|
spks (torch.Tensor, optional): speaker ids. Defaults to None.
|
||||||
|
shape: (batch_size, spk_emb_dim)
|
||||||
|
cond: Not used but kept for future purposes
|
||||||
|
"""
|
||||||
|
t, _, dt = t_span[0], t_span[-1], t_span[1] - t_span[0]
|
||||||
|
t = t.unsqueeze(dim=0)
|
||||||
|
sol = []
|
||||||
|
x_in = paddle.zeros([2, 80, x.size(2)], device=x.place, dtype=x.dtype)
|
||||||
|
mask_in = paddle.zeros([2, 1, x.size(2)], device=x.place, dtype=x.dtype)
|
||||||
|
mu_in = paddle.zeros([2, 80, x.size(2)], device=x.place, dtype=x.dtype)
|
||||||
|
t_in = paddle.zeros([2], device=x.place, dtype=x.dtype)
|
||||||
|
spks_in = paddle.zeros([2, 80], device=x.place, dtype=x.dtype)
|
||||||
|
cond_in = paddle.zeros([2, 80, x.size(2)], device=x.place, dtype=x.dtype)
|
||||||
|
for step in range(1, len(t_span)):
|
||||||
|
x_in[:] = x
|
||||||
|
mask_in[:] = mask
|
||||||
|
mu_in[0] = mu
|
||||||
|
t_in[:] = t.unsqueeze(0)
|
||||||
|
spks_in[0] = spks
|
||||||
|
cond_in[0] = cond
|
||||||
|
dphi_dt = self.forward_estimator(
|
||||||
|
x_in, mask_in, mu_in, t_in, spks_in, cond_in, streaming
|
||||||
|
)
|
||||||
|
dphi_dt, cfg_dphi_dt = paddle.compat.split(
|
||||||
|
dphi_dt, [x.size(0), x.size(0)], dim=0
|
||||||
|
)
|
||||||
|
dphi_dt = (
|
||||||
|
1.0 + self.inference_cfg_rate
|
||||||
|
) * dphi_dt - self.inference_cfg_rate * cfg_dphi_dt
|
||||||
|
x = x + dt * dphi_dt
|
||||||
|
t = t + dt
|
||||||
|
sol.append(x)
|
||||||
|
if step < len(t_span) - 1:
|
||||||
|
dt = t_span[step + 1] - t
|
||||||
|
return sol[-1].float()
|
||||||
|
|
||||||
|
def forward_estimator(self, x, mask, mu, t, spks, cond, streaming=False):
|
||||||
|
if isinstance(self.estimator, paddle.nn.Layer):
|
||||||
|
return self.estimator(x, mask, mu, t, spks, cond, streaming=streaming)
|
||||||
|
else:
|
||||||
|
[estimator, stream], trt_engine = self.estimator.acquire_estimator()
|
||||||
|
paddle.device.current_stream().synchronize()
|
||||||
|
with stream:
|
||||||
|
estimator.set_input_shape("x", (2, 80, x.size(2)))
|
||||||
|
estimator.set_input_shape("mask", (2, 1, x.size(2)))
|
||||||
|
estimator.set_input_shape("mu", (2, 80, x.size(2)))
|
||||||
|
estimator.set_input_shape("t", (2,))
|
||||||
|
estimator.set_input_shape("spks", (2, 80))
|
||||||
|
estimator.set_input_shape("cond", (2, 80, x.size(2)))
|
||||||
|
data_ptrs = [
|
||||||
|
x.contiguous().data_ptr(),
|
||||||
|
mask.contiguous().data_ptr(),
|
||||||
|
mu.contiguous().data_ptr(),
|
||||||
|
t.contiguous().data_ptr(),
|
||||||
|
spks.contiguous().data_ptr(),
|
||||||
|
cond.contiguous().data_ptr(),
|
||||||
|
x.data_ptr(),
|
||||||
|
]
|
||||||
|
for i, j in enumerate(data_ptrs):
|
||||||
|
estimator.set_tensor_address(trt_engine.get_tensor_name(i), j)
|
||||||
|
assert (
|
||||||
|
estimator.execute_async_v3(
|
||||||
|
paddle.device.current_stream().cuda_stream
|
||||||
|
)
|
||||||
|
is True
|
||||||
|
)
|
||||||
|
paddle.device.current_stream().synchronize()
|
||||||
|
self.estimator.release_estimator(estimator, stream)
|
||||||
|
return x
|
||||||
|
|
||||||
|
def compute_loss(self, x1, mask, mu, spks=None, cond=None, streaming=False):
|
||||||
|
"""Computes diffusion loss
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x1 (torch.Tensor): Target
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
mask (torch.Tensor): target mask
|
||||||
|
shape: (batch_size, 1, mel_timesteps)
|
||||||
|
mu (torch.Tensor): output of encoder
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
spks (torch.Tensor, optional): speaker embedding. Defaults to None.
|
||||||
|
shape: (batch_size, spk_emb_dim)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
loss: conditional flow matching loss
|
||||||
|
y: conditional flow
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
"""
|
||||||
|
b, _, t = mu.shape
|
||||||
|
t = paddle.rand(shape=[b, 1, 1], dtype=mu.dtype)
|
||||||
|
if self.t_scheduler == "cosine":
|
||||||
|
t = 1 - paddle.cos(t * 0.5 * paddle.pi)
|
||||||
|
z = paddle.randn(shape=x1.shape, dtype=x1.dtype)
|
||||||
|
y = (1 - (1 - self.sigma_min) * t) * z + t * x1
|
||||||
|
u = x1 - (1 - self.sigma_min) * z
|
||||||
|
if self.training_cfg_rate > 0:
|
||||||
|
cfg_mask = paddle.rand(shape=b) > self.training_cfg_rate
|
||||||
|
mu = mu * cfg_mask.view(-1, 1, 1)
|
||||||
|
spks = spks * cfg_mask.view(-1, 1)
|
||||||
|
cond = cond * cfg_mask.view(-1, 1, 1)
|
||||||
|
pred = self.estimator(y, mask, mu, t.squeeze(), spks, cond, streaming=streaming)
|
||||||
|
loss = paddle.nn.functional.mse_loss(
|
||||||
|
input=pred * mask, label=u * mask, reduction="sum"
|
||||||
|
) / (paddle.sum(mask) * u.shape[1])
|
||||||
|
return loss, y
|
||||||
|
|
||||||
|
|
||||||
|
class CausalConditionalCFM(ConditionalCFM):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels,
|
||||||
|
cfm_params,
|
||||||
|
n_spks=1,
|
||||||
|
spk_emb_dim=64,
|
||||||
|
estimator: paddle.nn.Layer = None,
|
||||||
|
):
|
||||||
|
super().__init__(in_channels, cfm_params, n_spks, spk_emb_dim, estimator)
|
||||||
|
set_all_random_seed(0)
|
||||||
|
self.rand_noise = paddle.randn([1, 80, 50 * 300])
|
||||||
|
|
||||||
|
@paddle.no_grad()
|
||||||
|
def forward(
|
||||||
|
self,
|
||||||
|
mu,
|
||||||
|
mask,
|
||||||
|
n_timesteps,
|
||||||
|
temperature=1.0,
|
||||||
|
spks=None,
|
||||||
|
cond=None,
|
||||||
|
streaming=False,
|
||||||
|
):
|
||||||
|
"""Forward diffusion
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mu (torch.Tensor): output of encoder
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
mask (torch.Tensor): output_mask
|
||||||
|
shape: (batch_size, 1, mel_timesteps)
|
||||||
|
n_timesteps (int): number of diffusion steps
|
||||||
|
temperature (float, optional): temperature for scaling noise. Defaults to 1.0.
|
||||||
|
spks (torch.Tensor, optional): speaker ids. Defaults to None.
|
||||||
|
shape: (batch_size, spk_emb_dim)
|
||||||
|
cond: Not used but kept for future purposes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
sample: generated mel-spectrogram
|
||||||
|
shape: (batch_size, n_feats, mel_timesteps)
|
||||||
|
"""
|
||||||
|
z = self.rand_noise[:, :, : mu.size(2)].to(mu.place).to(mu.dtype) * temperature
|
||||||
|
t_span = paddle.linspace(start=0, stop=1, num=n_timesteps + 1, dtype=mu.dtype)
|
||||||
|
if self.t_scheduler == "cosine":
|
||||||
|
t_span = 1 - paddle.cos(t_span * 0.5 * paddle.pi)
|
||||||
|
return (
|
||||||
|
self.solve_euler(
|
||||||
|
z,
|
||||||
|
t_span=t_span,
|
||||||
|
mu=mu,
|
||||||
|
mask=mask,
|
||||||
|
spks=spks,
|
||||||
|
cond=cond,
|
||||||
|
streaming=streaming,
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
import base64
|
||||||
|
import os
|
||||||
|
from functools import lru_cache
|
||||||
|
from paddlenlp.transformers import AutoTokenizer
|
||||||
|
import paddle
|
||||||
|
import tiktoken
|
||||||
|
|
||||||
|
LANGUAGES = {
|
||||||
|
"en": "english",
|
||||||
|
"zh": "chinese",
|
||||||
|
"de": "german",
|
||||||
|
"es": "spanish",
|
||||||
|
"ru": "russian",
|
||||||
|
"ko": "korean",
|
||||||
|
"fr": "french",
|
||||||
|
"ja": "japanese",
|
||||||
|
"pt": "portuguese",
|
||||||
|
"tr": "turkish",
|
||||||
|
"pl": "polish",
|
||||||
|
"ca": "catalan",
|
||||||
|
"nl": "dutch",
|
||||||
|
"ar": "arabic",
|
||||||
|
"sv": "swedish",
|
||||||
|
"it": "italian",
|
||||||
|
"id": "indonesian",
|
||||||
|
"hi": "hindi",
|
||||||
|
"fi": "finnish",
|
||||||
|
"vi": "vietnamese",
|
||||||
|
"he": "hebrew",
|
||||||
|
"uk": "ukrainian",
|
||||||
|
"el": "greek",
|
||||||
|
"ms": "malay",
|
||||||
|
"cs": "czech",
|
||||||
|
"ro": "romanian",
|
||||||
|
"da": "danish",
|
||||||
|
"hu": "hungarian",
|
||||||
|
"ta": "tamil",
|
||||||
|
"no": "norwegian",
|
||||||
|
"th": "thai",
|
||||||
|
"ur": "urdu",
|
||||||
|
"hr": "croatian",
|
||||||
|
"bg": "bulgarian",
|
||||||
|
"lt": "lithuanian",
|
||||||
|
"la": "latin",
|
||||||
|
"mi": "maori",
|
||||||
|
"ml": "malayalam",
|
||||||
|
"cy": "welsh",
|
||||||
|
"sk": "slovak",
|
||||||
|
"te": "telugu",
|
||||||
|
"fa": "persian",
|
||||||
|
"lv": "latvian",
|
||||||
|
"bn": "bengali",
|
||||||
|
"sr": "serbian",
|
||||||
|
"az": "azerbaijani",
|
||||||
|
"sl": "slovenian",
|
||||||
|
"kn": "kannada",
|
||||||
|
"et": "estonian",
|
||||||
|
"mk": "macedonian",
|
||||||
|
"br": "breton",
|
||||||
|
"eu": "basque",
|
||||||
|
"is": "icelandic",
|
||||||
|
"hy": "armenian",
|
||||||
|
"ne": "nepali",
|
||||||
|
"mn": "mongolian",
|
||||||
|
"bs": "bosnian",
|
||||||
|
"kk": "kazakh",
|
||||||
|
"sq": "albanian",
|
||||||
|
"sw": "swahili",
|
||||||
|
"gl": "galician",
|
||||||
|
"mr": "marathi",
|
||||||
|
"pa": "punjabi",
|
||||||
|
"si": "sinhala",
|
||||||
|
"km": "khmer",
|
||||||
|
"sn": "shona",
|
||||||
|
"yo": "yoruba",
|
||||||
|
"so": "somali",
|
||||||
|
"af": "afrikaans",
|
||||||
|
"oc": "occitan",
|
||||||
|
"ka": "georgian",
|
||||||
|
"be": "belarusian",
|
||||||
|
"tg": "tajik",
|
||||||
|
"sd": "sindhi",
|
||||||
|
"gu": "gujarati",
|
||||||
|
"am": "amharic",
|
||||||
|
"yi": "yiddish",
|
||||||
|
"lo": "lao",
|
||||||
|
"uz": "uzbek",
|
||||||
|
"fo": "faroese",
|
||||||
|
"ht": "haitian creole",
|
||||||
|
"ps": "pashto",
|
||||||
|
"tk": "turkmen",
|
||||||
|
"nn": "nynorsk",
|
||||||
|
"mt": "maltese",
|
||||||
|
"sa": "sanskrit",
|
||||||
|
"lb": "luxembourgish",
|
||||||
|
"my": "myanmar",
|
||||||
|
"bo": "tibetan",
|
||||||
|
"tl": "tagalog",
|
||||||
|
"mg": "malagasy",
|
||||||
|
"as": "assamese",
|
||||||
|
"tt": "tatar",
|
||||||
|
"haw": "hawaiian",
|
||||||
|
"ln": "lingala",
|
||||||
|
"ha": "hausa",
|
||||||
|
"ba": "bashkir",
|
||||||
|
"jw": "javanese",
|
||||||
|
"su": "sundanese",
|
||||||
|
"yue": "cantonese",
|
||||||
|
"minnan": "minnan",
|
||||||
|
"wuyu": "wuyu",
|
||||||
|
"dialect": "dialect",
|
||||||
|
"zh/en": "zh/en",
|
||||||
|
"en/zh": "en/zh",
|
||||||
|
}
|
||||||
|
TO_LANGUAGE_CODE = {
|
||||||
|
**{language: code for code, language in LANGUAGES.items()},
|
||||||
|
"burmese": "my",
|
||||||
|
"valencian": "ca",
|
||||||
|
"flemish": "nl",
|
||||||
|
"haitian": "ht",
|
||||||
|
"letzeburgesch": "lb",
|
||||||
|
"pushto": "ps",
|
||||||
|
"panjabi": "pa",
|
||||||
|
"moldavian": "ro",
|
||||||
|
"moldovan": "ro",
|
||||||
|
"sinhalese": "si",
|
||||||
|
"castilian": "es",
|
||||||
|
"mandarin": "zh",
|
||||||
|
}
|
||||||
|
AUDIO_EVENT = {
|
||||||
|
"ASR": "ASR",
|
||||||
|
"AED": "AED",
|
||||||
|
"SER": "SER",
|
||||||
|
"Speech": "Speech",
|
||||||
|
"/Speech": "/Speech",
|
||||||
|
"BGM": "BGM",
|
||||||
|
"/BGM": "/BGM",
|
||||||
|
"Laughter": "Laughter",
|
||||||
|
"/Laughter": "/Laughter",
|
||||||
|
"Applause": "Applause",
|
||||||
|
"/Applause": "/Applause",
|
||||||
|
}
|
||||||
|
EMOTION = {"HAPPY": "HAPPY", "SAD": "SAD", "ANGRY": "ANGRY", "NEUTRAL": "NEUTRAL"}
|
||||||
|
TTS_Vocal_Token = {
|
||||||
|
"TTS/B": "TTS/B",
|
||||||
|
"TTS/O": "TTS/O",
|
||||||
|
"TTS/Q": "TTS/Q",
|
||||||
|
"TTS/A": "TTS/A",
|
||||||
|
"TTS/CO": "TTS/CO",
|
||||||
|
"TTS/CL": "TTS/CL",
|
||||||
|
"TTS/H": "TTS/H",
|
||||||
|
**{f"TTS/SP{i:02d}": f"TTS/SP{i:02d}" for i in range(1, 14)},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=None)
|
||||||
|
def get_encoding(name: str = "gpt2", num_languages: int = 99):
|
||||||
|
vocab_path = os.path.join(os.path.dirname(__file__), "assets", f"{name}.tiktoken")
|
||||||
|
ranks = {
|
||||||
|
base64.b64decode(token): int(rank)
|
||||||
|
for token, rank in (line.split() for line in open(vocab_path) if line)
|
||||||
|
}
|
||||||
|
n_vocab = len(ranks)
|
||||||
|
special_tokens = {}
|
||||||
|
specials = [
|
||||||
|
"<|endoftext|>",
|
||||||
|
"<|startoftranscript|>",
|
||||||
|
*[f"<|{lang}|>" for lang in list(LANGUAGES.keys())[:num_languages]],
|
||||||
|
*[f"<|{audio_event}|>" for audio_event in list(AUDIO_EVENT.keys())],
|
||||||
|
*[f"<|{emotion}|>" for emotion in list(EMOTION.keys())],
|
||||||
|
"<|translate|>",
|
||||||
|
"<|transcribe|>",
|
||||||
|
"<|startoflm|>",
|
||||||
|
"<|startofprev|>",
|
||||||
|
"<|nospeech|>",
|
||||||
|
"<|notimestamps|>",
|
||||||
|
*[f"<|SPECIAL_TOKEN_{i}|>" for i in range(1, 31)],
|
||||||
|
*[f"<|{tts}|>" for tts in list(TTS_Vocal_Token.keys())],
|
||||||
|
*[f"<|{i * 0.02:.2f}|>" for i in range(1501)],
|
||||||
|
]
|
||||||
|
for token in specials:
|
||||||
|
special_tokens[token] = n_vocab
|
||||||
|
n_vocab += 1
|
||||||
|
return tiktoken.Encoding(
|
||||||
|
name=os.path.basename(vocab_path),
|
||||||
|
explicit_n_vocab=n_vocab,
|
||||||
|
pat_str="'s|'t|'re|'ve|'m|'ll|'d| ?\\p{L}+| ?\\p{N}+| ?[^\\s\\p{L}\\p{N}]+|\\s+(?!\\S)|\\s+",
|
||||||
|
mergeable_ranks=ranks,
|
||||||
|
special_tokens=special_tokens,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class QwenTokenizer:
|
||||||
|
def __init__(self, skip_special_tokens=True):
|
||||||
|
super().__init__()
|
||||||
|
special_tokens = {
|
||||||
|
"eos_token": "<|endoftext|>",
|
||||||
|
"pad_token": "<|endoftext|>",
|
||||||
|
"additional_special_tokens": [
|
||||||
|
"<|im_start|>",
|
||||||
|
"<|im_end|>",
|
||||||
|
"<|endofprompt|>",
|
||||||
|
"[breath]",
|
||||||
|
"<strong>",
|
||||||
|
"</strong>",
|
||||||
|
"[noise]",
|
||||||
|
"[laughter]",
|
||||||
|
"[cough]",
|
||||||
|
"[clucking]",
|
||||||
|
"[accent]",
|
||||||
|
"[quick_breath]",
|
||||||
|
"<laughter>",
|
||||||
|
"</laughter>",
|
||||||
|
"[hissing]",
|
||||||
|
"[sigh]",
|
||||||
|
"[vocalized-noise]",
|
||||||
|
"[lipsmack]",
|
||||||
|
"[mn]",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
self.special_tokens = special_tokens
|
||||||
|
self.tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B")
|
||||||
|
self.tokenizer.add_special_tokens(special_tokens)
|
||||||
|
self.skip_special_tokens = skip_special_tokens
|
||||||
|
|
||||||
|
def encode(self, text, **kwargs):
|
||||||
|
tokens = self.tokenizer([text], return_tensors="pd")
|
||||||
|
tokens = tokens["input_ids"][0].cpu().tolist()
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def decode(self, tokens):
|
||||||
|
tokens = paddle.tensor(tokens, dtype=paddle.int64)
|
||||||
|
text = self.tokenizer.batch_decode(
|
||||||
|
[tokens], skip_special_tokens=self.skip_special_tokens
|
||||||
|
)[0]
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=None)
|
||||||
|
def get_qwen_tokenizer(skip_special_tokens: bool) -> QwenTokenizer:
|
||||||
|
return QwenTokenizer(skip_special_tokens=skip_special_tokens)
|
||||||
Loading…
Reference in new issue