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