Support inference on CPU

This commit is contained in:
Yrom 2025-04-11 20:52:31 +08:00
parent 471a45435c
commit ec65755fc8
No known key found for this signature in database
2 changed files with 55 additions and 75 deletions

View File

@ -37,7 +37,7 @@ def main():
try:
import torch
if not torch.cuda.is_available():
print("WARNING: CUDA is not available. Running in CPU mode.")
print("WARNING: CUDA is not available. Running on CPU may be slow.")
except ImportError:
print("ERROR: PyTorch is not installed. Please install it first.")
sys.exit(1)

View File

@ -1,7 +1,6 @@
import os
import re
import sys
import time
import sentencepiece as spm
import torch
import torchaudio
@ -16,17 +15,22 @@ from indextts.utils.common import tokenize_by_CJK_char
from indextts.vqvae.xtts_dvae import DiscreteVAE
from indextts.utils.front import TextNormalizer
class IndexTTS:
def __init__(self, cfg_path='checkpoints/config.yaml', model_dir='checkpoints', is_fp16=True):
self.cfg = OmegaConf.load(cfg_path)
self.device = 'cuda:0'
self.model_dir = model_dir
self.is_fp16 = is_fp16
self.stop_mel_token = self.cfg.gpt.stop_mel_token
if self.is_fp16:
self.dtype = torch.float16
if torch.cuda.is_available():
self.device = 'cuda:0'
self.is_fp16 = is_fp16
else:
self.dtype = None
self.device = 'cpu'
self.is_fp16 = False
print(">> Be patient, it may take a while to run in CPU mode.")
self.model_dir = model_dir
self.dtype = torch.float16 if self.is_fp16 else None
self.stop_mel_token = self.cfg.gpt.stop_mel_token
self.dvae = DiscreteVAE(**self.cfg.vqvae)
self.dvae_path = os.path.join(self.model_dir, self.cfg.dvae_checkpoint)
load_checkpoint(self.dvae, self.dvae_path)
@ -36,7 +40,6 @@ class IndexTTS:
else:
self.dvae.eval()
print(">> vqvae weights restored from:", self.dvae_path)
self.gpt = UnifiedVoice(**self.cfg.gpt)
self.gpt_path = os.path.join(self.model_dir, self.cfg.gpt_checkpoint)
load_checkpoint(self.gpt, self.gpt_path)
@ -74,9 +77,11 @@ class IndexTTS:
# return text.translate(punctuation_map)
return self.normalizer.infer(text)
def remove_long_silence(self, codes, silent_token=52, max_consecutive=30):
def remove_long_silence(self, codes: torch.Tensor, silent_token=52, max_consecutive=30):
code_lens = []
codes_list = []
device = codes.device
dtype = codes.dtype
isfix = False
for i in range(0, codes.shape[0]):
code = codes[i]
@ -104,7 +109,7 @@ class IndexTTS:
# n += 1
len_ = len(ncode)
ncode = torch.LongTensor(ncode)
codes_list.append(ncode.cuda())
codes_list.append(ncode.to(device, dtype=dtype))
isfix = True
#codes[i] = self.stop_mel_token
#codes[i, 0:len_] = ncode
@ -113,7 +118,7 @@ class IndexTTS:
code_lens.append(len_)
codes = pad_sequence(codes_list, batch_first=True) if isfix else codes[:, :-2]
code_lens = torch.LongTensor(code_lens).cuda()
code_lens = torch.LongTensor(code_lens).to(device, dtype=dtype)
return codes, code_lens
def infer(self, audio_prompt, text, output_path):
@ -128,7 +133,7 @@ class IndexTTS:
audio = audio[0].unsqueeze(0)
audio = torchaudio.transforms.Resample(sr, 24000)(audio)
cond_mel = MelSpectrogramFeatures()(audio).to(self.device)
print(f"cond_mel shape: {cond_mel.shape}")
print(f"cond_mel shape: {cond_mel.shape}", "dtype:", cond_mel.dtype)
auto_conditioning = cond_mel
@ -138,7 +143,7 @@ class IndexTTS:
punctuation = ["!", "?", ".", ";", "", "", "", ""]
pattern = r"(?<=[{0}])\s*".format("".join(punctuation))
sentences = [i for i in re.split(pattern, text) if i.strip() != ""]
print(sentences)
print("sentences:", sentences)
top_p = .8
top_k = 30
@ -152,20 +157,23 @@ class IndexTTS:
lang = "EN"
lang = "ZH"
wavs = []
wavs1 = []
print(">> start inference...")
start_time = time.time()
for sent in sentences:
print(sent)
# sent = " ".join([char for char in sent.upper()]) if lang == "ZH" else sent.upper()
cleand_text = tokenize_by_CJK_char(sent)
# cleand_text = "他 那 像 HONG3 小 孩 似 的 话 , 引 得 人 们 HONG1 堂 大 笑 , 大 家 听 了 一 HONG3 而 散 ."
print(cleand_text)
print("cleand_text:", cleand_text)
text_tokens = torch.IntTensor(tokenizer.encode(cleand_text)).unsqueeze(0).to(self.device)
# text_tokens = F.pad(text_tokens, (0, 1)) # This may not be necessary.
# text_tokens = F.pad(text_tokens, (1, 0), value=0)
# text_tokens = F.pad(text_tokens, (0, 1), value=1)
text_tokens = text_tokens.to(self.device)
# text_tokens = text_tokens.to(self.device)
print(text_tokens)
print(f"text_tokens shape: {text_tokens.shape}, text_tokens type: {text_tokens.dtype}")
text_token_syms = [tokenizer.IdToPiece(idx) for idx in text_tokens[0].tolist()]
@ -173,38 +181,24 @@ class IndexTTS:
text_len = [text_tokens.size(1)]
text_len = torch.IntTensor(text_len).to(self.device)
print(text_len)
with torch.no_grad():
if self.is_fp16:
with torch.cuda.amp.autocast(enabled=self.dtype is not None, dtype=self.dtype):
codes = self.gpt.inference_speech(auto_conditioning, text_tokens,
cond_mel_lengths=torch.tensor([auto_conditioning.shape[-1]],
device=text_tokens.device),
# text_lengths=text_len,
do_sample=True,
top_p=top_p,
top_k=top_k,
temperature=temperature,
num_return_sequences=autoregressive_batch_size,
length_penalty=length_penalty,
num_beams=num_beams,
repetition_penalty=repetition_penalty,
max_generate_length=max_mel_tokens)
else:
with torch.amp.autocast(self.device, enabled=self.dtype is not None, dtype=self.dtype):
codes = self.gpt.inference_speech(auto_conditioning, text_tokens,
cond_mel_lengths=torch.tensor([auto_conditioning.shape[-1]],
device=text_tokens.device),
# text_lengths=text_len,
do_sample=True,
top_p=top_p,
top_k=top_k,
temperature=temperature,
num_return_sequences=autoregressive_batch_size,
length_penalty=length_penalty,
num_beams=num_beams,
repetition_penalty=repetition_penalty,
max_generate_length=max_mel_tokens)
cond_mel_lengths=torch.tensor([auto_conditioning.shape[-1]],
device=text_tokens.device),
# text_lengths=text_len,
do_sample=True,
top_p=top_p,
top_k=top_k,
temperature=temperature,
num_return_sequences=autoregressive_batch_size,
length_penalty=length_penalty,
num_beams=num_beams,
repetition_penalty=repetition_penalty,
max_generate_length=max_mel_tokens)
#codes = codes[:, :-2]
code_lens = torch.tensor([codes.shape[-1]])
code_lens = torch.tensor([codes.shape[-1]], device=codes.device, dtype=codes.dtype)
print(codes, type(codes))
print(f"codes shape: {codes.shape}, codes type: {codes.dtype}")
print(f"code len: {code_lens}")
@ -216,35 +210,14 @@ class IndexTTS:
print(f"code len: {code_lens}")
# latent, text_lens_out, code_lens_out = \
if self.is_fp16:
with torch.cuda.amp.autocast(enabled=self.dtype is not None, dtype=self.dtype):
latent = \
self.gpt(auto_conditioning, text_tokens,
torch.tensor([text_tokens.shape[-1]], device=text_tokens.device), codes,
code_lens*self.gpt.mel_length_compression,
cond_mel_lengths=torch.tensor([auto_conditioning.shape[-1]], device=text_tokens.device),
return_latent=True, clip_inputs=False)
latent = latent.transpose(1, 2)
wav, _ = self.bigvgan(latent.transpose(1, 2), auto_conditioning.transpose(1, 2))
wav = wav.squeeze(1).cpu()
else:
with torch.amp.autocast(self.device, enabled=self.dtype is not None, dtype=self.dtype):
latent = \
self.gpt(auto_conditioning, text_tokens,
torch.tensor([text_tokens.shape[-1]], device=text_tokens.device), codes,
code_lens*self.gpt.mel_length_compression,
cond_mel_lengths=torch.tensor([auto_conditioning.shape[-1]], device=text_tokens.device),
return_latent=True, clip_inputs=False)
torch.tensor([text_tokens.shape[-1]], device=text_tokens.device), codes,
code_lens*self.gpt.mel_length_compression,
cond_mel_lengths=torch.tensor([auto_conditioning.shape[-1]], device=text_tokens.device),
return_latent=True, clip_inputs=False)
latent = latent.transpose(1, 2)
'''
latent_list = []
for lat, t_len in zip(latent, text_lens_out):
lat = lat[:, t_len:]
latent_list.append(lat)
latent = torch.stack(latent_list)
print(f"latent shape: {latent.shape}")
'''
wav, _ = self.bigvgan(latent.transpose(1, 2), auto_conditioning.transpose(1, 2))
wav = wav.squeeze(1).cpu()
@ -254,8 +227,15 @@ class IndexTTS:
# wavs.append(wav[:, :-512])
wavs.append(wav)
end_time = time.time()
elapsed_time = end_time - start_time
minutes, seconds = divmod(int(elapsed_time), 60)
milliseconds = int((elapsed_time - int(elapsed_time)) * 1000)
print(f">> inference done. time: {minutes}:{seconds}.{milliseconds}")
print(">> saving wav file")
wav = torch.cat(wavs, dim=1)
torchaudio.save(output_path, wav.type(torch.int16), 24000)
torchaudio.save(output_path, wav.type(torch.int16), sampling_rate)
print(">> wav file saved to:", output_path)
if __name__ == "__main__":