diff --git a/.gitignore b/.gitignore index 00f6bb9..96e754a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,8 @@ runtime output logs reference +GPT_weights SoVITS_weights -GPT_weights \ No newline at end of file +TEMP + + diff --git a/GPT_SoVITS/AR/data/data_module.py b/GPT_SoVITS/AR/data/data_module.py index 037484a..54d4634 100644 --- a/GPT_SoVITS/AR/data/data_module.py +++ b/GPT_SoVITS/AR/data/data_module.py @@ -41,7 +41,8 @@ class Text2SemanticDataModule(LightningDataModule): # pad_val=self.config['data']['pad_val']) def train_dataloader(self): - batch_size = max(min(self.config["train"]["batch_size"],len(self._train_dataset)//4),1)#防止不保存 + batch_size=self.config["train"]["batch_size"]//2 if self.config["train"].get("if_dpo",False)==True else self.config["train"]["batch_size"] + batch_size = max(min(batch_size,len(self._train_dataset)//4),1)#防止不保存 sampler = DistributedBucketSampler(self._train_dataset, batch_size=batch_size) return DataLoader( self._train_dataset, diff --git a/GPT_SoVITS/AR/models/t2s_lightning_module.py b/GPT_SoVITS/AR/models/t2s_lightning_module.py index f9dfc64..594b73b 100644 --- a/GPT_SoVITS/AR/models/t2s_lightning_module.py +++ b/GPT_SoVITS/AR/models/t2s_lightning_module.py @@ -11,7 +11,6 @@ from AR.models.t2s_model import Text2SemanticDecoder from AR.modules.lr_schedulers import WarmupCosineLRSchedule from AR.modules.optim import ScaledAdam - class Text2SemanticLightningModule(LightningModule): def __init__(self, config, output_dir, is_train=True): super().__init__() @@ -35,7 +34,8 @@ class Text2SemanticLightningModule(LightningModule): def training_step(self, batch: Dict, batch_idx: int): opt = self.optimizers() scheduler = self.lr_schedulers() - loss, acc = self.model.forward( + forward=self.model.forward if self.config["train"].get("if_dpo",False)==True else self.model.forward_old + loss, acc = forward( batch["phoneme_ids"], batch["phoneme_ids_len"], batch["semantic_ids"], diff --git a/GPT_SoVITS/AR/models/t2s_model.py b/GPT_SoVITS/AR/models/t2s_model.py index aaeace9..815ecec 100644 --- a/GPT_SoVITS/AR/models/t2s_model.py +++ b/GPT_SoVITS/AR/models/t2s_model.py @@ -337,7 +337,7 @@ class Text2SemanticDecoder(nn.Module): # AR Decoder y = prompts - prefix_len = y.shape[1] + x_len = x.shape[1] x_attn_mask = torch.zeros((x_len, x_len), dtype=torch.bool) stop = False @@ -353,47 +353,41 @@ class Text2SemanticDecoder(nn.Module): "first_infer": 1, "stage": 0, } - for idx in tqdm(range(1500)): - if cache["first_infer"] == 1: - y_emb = self.ar_audio_embedding(y) - else: - y_emb = torch.cat( - [cache["y_emb"], self.ar_audio_embedding(y[:, -1:])], 1 - ) - cache["y_emb"] = y_emb + ################### first step ########################## + if y is not None: + y_emb = self.ar_audio_embedding(y) + y_len = y_emb.shape[1] + prefix_len = y.shape[1] y_pos = self.ar_audio_position(y_emb) - # x 和逐渐增长的 y 一起输入给模型 - if cache["first_infer"] == 1: - xy_pos = torch.concat([x, y_pos], dim=1) - else: - xy_pos = y_pos[:, -1:] - y_len = y_pos.shape[1] - ###以下3个不做缓存 - if cache["first_infer"] == 1: - x_attn_mask_pad = F.pad( + xy_pos = torch.concat([x, y_pos], dim=1) + cache["y_emb"] = y_emb + ref_free = False + else: + y_emb = None + y_len = 0 + prefix_len = 0 + y_pos = None + xy_pos = x + y = torch.zeros(x.shape[0], 0, dtype=torch.int, device=x.device) + ref_free = True + + x_attn_mask_pad = F.pad( x_attn_mask, (0, y_len), ###xx的纯0扩展到xx纯0+xy纯1,(x,x+y) value=True, ) - y_attn_mask = F.pad( ###yy的右上1扩展到左边xy的0,(y,x+y) - torch.triu(torch.ones(y_len, y_len, dtype=torch.bool), diagonal=1), - (x_len, 0), - value=False, - ) - xy_attn_mask = torch.concat([x_attn_mask_pad, y_attn_mask], dim=0).to( - y.device - ) - else: - ###最右边一列(是错的) - # xy_attn_mask=torch.ones((1, x_len+y_len), dtype=torch.bool,device=xy_pos.device) - # xy_attn_mask[:,-1]=False - ###最下面一行(是对的) - xy_attn_mask = torch.zeros( - (1, x_len + y_len), dtype=torch.bool, device=xy_pos.device - ) - # pdb.set_trace() - ###缓存重头戏 - # print(1111,xy_pos.shape,xy_attn_mask.shape,x_len,y_len) + y_attn_mask = F.pad( ###yy的右上1扩展到左边xy的0,(y,x+y) + torch.triu(torch.ones(y_len, y_len, dtype=torch.bool), diagonal=1), + (x_len, 0), + value=False, + ) + xy_attn_mask = torch.concat([x_attn_mask_pad, y_attn_mask], dim=0).to( + x.device + ) + + + for idx in tqdm(range(1500)): + xy_dec, _ = self.h((xy_pos, None), mask=xy_attn_mask, cache=cache) logits = self.ar_predict_layer( xy_dec[:, -1] @@ -404,6 +398,10 @@ class Text2SemanticDecoder(nn.Module): samples = sample( logits[0], y, top_k=top_k, top_p=top_p, repetition_penalty=1.35, temperature=temperature )[0].unsqueeze(0) + # 本次生成的 semantic_ids 和之前的 y 构成新的 y + # print(samples.shape)#[1,1]#第一个1是bs + y = torch.concat([y, samples], dim=1) + if early_stop_num != -1 and (y.shape[1] - prefix_len) > early_stop_num: print("use early stop num:", early_stop_num) stop = True @@ -412,13 +410,38 @@ class Text2SemanticDecoder(nn.Module): # print(torch.argmax(logits, dim=-1)[0] == self.EOS, samples[0, 0] == self.EOS) stop = True if stop: - if prompts.shape[1] == y.shape[1]: + # if prompts.shape[1] == y.shape[1]: + # y = torch.concat([y, torch.zeros_like(samples)], dim=1) + # print("bad zero prediction") + if y.shape[1]==0: y = torch.concat([y, torch.zeros_like(samples)], dim=1) print("bad zero prediction") print(f"T2S Decoding EOS [{prefix_len} -> {y.shape[1]}]") break - # 本次生成的 semantic_ids 和之前的 y 构成新的 y - # print(samples.shape)#[1,1]#第一个1是bs - y = torch.concat([y, samples], dim=1) + + ####################### update next step ################################### cache["first_infer"] = 0 - return y, idx + if cache["y_emb"] is not None: + y_emb = torch.cat( + [cache["y_emb"], self.ar_audio_embedding(y[:, -1:])], dim = 1 + ) + cache["y_emb"] = y_emb + y_pos = self.ar_audio_position(y_emb) + xy_pos = y_pos[:, -1:] + else: + y_emb = self.ar_audio_embedding(y[:, -1:]) + cache["y_emb"] = y_emb + y_pos = self.ar_audio_position(y_emb) + xy_pos = y_pos + y_len = y_pos.shape[1] + + ###最右边一列(是错的) + # xy_attn_mask=torch.ones((1, x_len+y_len), dtype=torch.bool,device=xy_pos.device) + # xy_attn_mask[:,-1]=False + ###最下面一行(是对的) + xy_attn_mask = torch.zeros( + (1, x_len + y_len), dtype=torch.bool, device=xy_pos.device + ) + if ref_free: + return y[:, :-1], 0 + return y[:, :-1], idx-1 diff --git a/GPT_SoVITS/AR/models/utils.py b/GPT_SoVITS/AR/models/utils.py index bc5f2d0..84063f8 100644 --- a/GPT_SoVITS/AR/models/utils.py +++ b/GPT_SoVITS/AR/models/utils.py @@ -114,7 +114,8 @@ def logits_to_probs( top_p: Optional[int] = None, repetition_penalty: float = 1.0, ): - previous_tokens = previous_tokens.squeeze() + if previous_tokens is not None: + previous_tokens = previous_tokens.squeeze() # print(logits.shape,previous_tokens.shape) # pdb.set_trace() if previous_tokens is not None and repetition_penalty != 1.0: diff --git a/GPT_SoVITS/AR/modules/patched_mha_with_cache.py b/GPT_SoVITS/AR/modules/patched_mha_with_cache.py index 5720670..7be241d 100644 --- a/GPT_SoVITS/AR/modules/patched_mha_with_cache.py +++ b/GPT_SoVITS/AR/modules/patched_mha_with_cache.py @@ -5,8 +5,8 @@ from torch.nn.functional import ( _none_or_dtype, _in_projection_packed, ) - -# import torch +from torch.nn import functional as F +import torch # Tensor = torch.Tensor # from typing import Callable, List, Optional, Tuple, Union @@ -448,9 +448,11 @@ def multi_head_attention_forward_patched( k = k.view(bsz, num_heads, src_len, head_dim) v = v.view(bsz, num_heads, src_len, head_dim) + # with torch.backends.cuda.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=True): attn_output = scaled_dot_product_attention( q, k, v, attn_mask, dropout_p, is_causal ) + attn_output = ( attn_output.permute(2, 0, 1, 3).contiguous().view(bsz * tgt_len, embed_dim) ) diff --git a/GPT_SoVITS/inference_webui.py b/GPT_SoVITS/inference_webui.py index 9c5197a..39ae7e4 100644 --- a/GPT_SoVITS/inference_webui.py +++ b/GPT_SoVITS/inference_webui.py @@ -248,6 +248,10 @@ def clean_text_inf(text, language): formattext = "" language = language.replace("all_","") for tmp in LangSegment.getTexts(text): + if language == "ja": + if tmp["lang"] == language or tmp["lang"] == "zh": + formattext += tmp["text"] + " " + continue if tmp["lang"] == language: formattext += tmp["text"] + " " while " " in formattext: @@ -279,8 +283,6 @@ def nonen_clean_text_inf(text, language): for tmp in LangSegment.getTexts(text): langlist.append(tmp["lang"]) textlist.append(tmp["text"]) - print(textlist) - print(langlist) phones_list = [] word2ph_list = [] norm_text_list = [] @@ -365,15 +367,19 @@ def merge_short_text_in_array(texts, threshold): result[len(result) - 1] += text return result -def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, how_to_cut=i18n("不切"), top_k=20, top_p=0.6, temperature=0.6): +def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, how_to_cut=i18n("不切"), top_k=20, top_p=0.6, temperature=0.6, ref_free = False): + if prompt_text is None or len(prompt_text) == 0: + ref_free = True t0 = ttime() prompt_language = dict_language[prompt_language] text_language = dict_language[text_language] - prompt_text = prompt_text.strip("\n") - if (prompt_text[-1] not in splits): prompt_text += "。" if prompt_language != "en" else "." + if not ref_free: + prompt_text = prompt_text.strip("\n") + if (prompt_text[-1] not in splits): prompt_text += "。" if prompt_language != "en" else "." + print(i18n("实际输入的参考文本:"), prompt_text) text = text.strip("\n") if (text[0] not in splits and len(get_first(text)) < 4): text = "。" + text if text_language != "en" else "." + text - print(i18n("实际输入的参考文本:"), prompt_text) + print(i18n("实际输入的目标文本:"), text) zero_wav = np.zeros( int(hps.data.sampling_rate * 0.3), @@ -398,11 +404,10 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, 1, 2 ) # .float() codes = vq_model.extract_latent(ssl_content) + prompt_semantic = codes[0, 0] t1 = ttime() - phones1, word2ph1, norm_text1=get_cleaned_text_final(prompt_text, prompt_language) - if (how_to_cut == i18n("凑四句一切")): text = cut1(text) elif (how_to_cut == i18n("凑50字一切")): @@ -419,7 +424,9 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, texts = text.split("\n") texts = merge_short_text_in_array(texts, 5) audio_opt = [] - bert1=get_bert_final(phones1, word2ph1, norm_text1,prompt_language,device).to(dtype) + if not ref_free: + phones1, word2ph1, norm_text1=get_cleaned_text_final(prompt_text, prompt_language) + bert1=get_bert_final(phones1, word2ph1, norm_text1,prompt_language,device).to(dtype) for text in texts: # 解决输入目标文本的空行导致报错的问题 @@ -429,9 +436,13 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, print(i18n("实际输入的目标文本(每句):"), text) phones2, word2ph2, norm_text2 = get_cleaned_text_final(text, text_language) bert2 = get_bert_final(phones2, word2ph2, norm_text2, text_language, device).to(dtype) - bert = torch.cat([bert1, bert2], 1) + if not ref_free: + bert = torch.cat([bert1, bert2], 1) + all_phoneme_ids = torch.LongTensor(phones1+phones2).to(device).unsqueeze(0) + else: + bert = bert2 + all_phoneme_ids = torch.LongTensor(phones2).to(device).unsqueeze(0) - all_phoneme_ids = torch.LongTensor(phones1 + phones2).to(device).unsqueeze(0) bert = bert.to(device).unsqueeze(0) all_phoneme_len = torch.tensor([all_phoneme_ids.shape[-1]]).to(device) prompt = prompt_semantic.unsqueeze(0).to(device) @@ -441,7 +452,7 @@ def get_tts_wav(ref_wav_path, prompt_text, prompt_language, text, text_language, pred_semantic, idx = t2s_model.model.infer_panel( all_phoneme_ids, all_phoneme_len, - prompt, + None if ref_free else prompt, bert, # prompt_phone_len=ph_offset, top_k=top_k, @@ -607,7 +618,10 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app: gr.Markdown(value=i18n("*请上传并填写参考信息")) with gr.Row(): inp_ref = gr.Audio(label=i18n("请上传3~10秒内参考音频,超过会报错!"), type="filepath") - prompt_text = gr.Textbox(label=i18n("参考音频的文本"), value="") + with gr.Column(): + ref_text_free = gr.Checkbox(label=i18n("开启无参考文本模式。不填参考文本亦相当于开启。"), value=False, interactive=True, show_label=True) + gr.Markdown(i18n("使用无参考文本模式时建议使用微调的GPT")) + prompt_text = gr.Textbox(label=i18n("参考音频的文本"), value="") prompt_language = gr.Dropdown( label=i18n("参考音频的语种"), choices=[i18n("中文"), i18n("英文"), i18n("日文"), i18n("中英混合"), i18n("日英混合"), i18n("多语种混合")], value=i18n("中文") ) @@ -624,6 +638,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app: interactive=True, ) with gr.Row(): + gr.Markdown("gpt采样参数(无参考文本时不要太低):") top_k = gr.Slider(minimum=1,maximum=100,step=1,label=i18n("top_k"),value=5,interactive=True) top_p = gr.Slider(minimum=0,maximum=1,step=0.05,label=i18n("top_p"),value=1,interactive=True) temperature = gr.Slider(minimum=0,maximum=1,step=0.05,label=i18n("temperature"),value=1,interactive=True) @@ -632,7 +647,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app: inference_button.click( get_tts_wav, - [inp_ref, prompt_text, prompt_language, text, text_language, how_to_cut,top_k,top_p,temperature], + [inp_ref, prompt_text, prompt_language, text, text_language, how_to_cut, top_k, top_p, temperature, ref_text_free], [output], ) @@ -650,7 +665,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app: button3.click(cut3, [text_inp], [text_opt]) button4.click(cut4, [text_inp], [text_opt]) button5.click(cut5, [text_inp], [text_opt]) - gr.Markdown(value=i18n("后续将支持混合语种编码文本输入。")) + gr.Markdown(value=i18n("后续将支持转音素、手工修改音素、语音合成分步执行。")) app.queue(concurrency_count=511, max_size=1022).launch( server_name="0.0.0.0", diff --git a/GPT_SoVITS/module/models.py b/GPT_SoVITS/module/models.py index c99485c..a4d2235 100644 --- a/GPT_SoVITS/module/models.py +++ b/GPT_SoVITS/module/models.py @@ -228,6 +228,7 @@ class TextEncoder(nn.Module): ) y = self.ssl_proj(y * y_mask) * y_mask + y = self.encoder_ssl(y * y_mask, y_mask) text_mask = torch.unsqueeze( @@ -958,11 +959,13 @@ class SynthesizerTrn(nn.Module): @torch.no_grad() def decode(self, codes, text, refer, noise_scale=0.5): - refer_lengths = torch.LongTensor([refer.size(2)]).to(refer.device) - refer_mask = torch.unsqueeze( - commons.sequence_mask(refer_lengths, refer.size(2)), 1 - ).to(refer.dtype) - ge = self.ref_enc(refer * refer_mask, refer_mask) + ge = None + if refer is not None: + refer_lengths = torch.LongTensor([refer.size(2)]).to(refer.device) + refer_mask = torch.unsqueeze( + commons.sequence_mask(refer_lengths, refer.size(2)), 1 + ).to(refer.dtype) + ge = self.ref_enc(refer * refer_mask, refer_mask) y_lengths = torch.LongTensor([codes.size(2) * 2]).to(codes.device) text_lengths = torch.LongTensor([text.size(-1)]).to(text.device) diff --git a/GPT_SoVITS/prepare_datasets/1-get-text.py b/GPT_SoVITS/prepare_datasets/1-get-text.py index 88c9d85..5873164 100644 --- a/GPT_SoVITS/prepare_datasets/1-get-text.py +++ b/GPT_SoVITS/prepare_datasets/1-get-text.py @@ -33,13 +33,13 @@ from time import time as ttime import shutil -def my_save(fea, path): #####fix issue: torch.save doesn't support chinese path - dir = os.path.dirname(path) - name = os.path.basename(path) - tmp_path = "%s/%s%s.pth" % (dir, ttime(), i_part) - torch.save(fea, tmp_path) - shutil.move(tmp_path, "%s/%s" % (dir, name)) - +def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path + dir=os.path.dirname(path) + name=os.path.basename(path) + # tmp_path="%s/%s%s.pth"%(dir,ttime(),i_part) + tmp_path="%s%s.pth"%(ttime(),i_part) + torch.save(fea,tmp_path) + shutil.move(tmp_path,"%s/%s"%(dir,name)) txt_path = "%s/2-name2text-%s.txt" % (opt_dir, i_part) diff --git a/GPT_SoVITS/prepare_datasets/2-get-hubert-wav32k.py b/GPT_SoVITS/prepare_datasets/2-get-hubert-wav32k.py index 9e137a9..76a7ec9 100644 --- a/GPT_SoVITS/prepare_datasets/2-get-hubert-wav32k.py +++ b/GPT_SoVITS/prepare_datasets/2-get-hubert-wav32k.py @@ -35,7 +35,8 @@ import shutil def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path dir=os.path.dirname(path) name=os.path.basename(path) - tmp_path="%s/%s%s.pth"%(dir,ttime(),i_part) + # tmp_path="%s/%s%s.pth"%(dir,ttime(),i_part) + tmp_path="%s%s.pth"%(ttime(),i_part) torch.save(fea,tmp_path) shutil.move(tmp_path,"%s/%s"%(dir,name)) diff --git a/GPT_SoVITS/process_ckpt.py b/GPT_SoVITS/process_ckpt.py index 7483337..3a436f1 100644 --- a/GPT_SoVITS/process_ckpt.py +++ b/GPT_SoVITS/process_ckpt.py @@ -1,11 +1,18 @@ import traceback from collections import OrderedDict - +from time import time as ttime +import shutil,os import torch from tools.i18n.i18n import I18nAuto i18n = I18nAuto() +def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path + dir=os.path.dirname(path) + name=os.path.basename(path) + tmp_path="%s.pth"%(ttime()) + torch.save(fea,tmp_path) + shutil.move(tmp_path,"%s/%s"%(dir,name)) def savee(ckpt, name, epoch, steps, hps): try: @@ -17,7 +24,8 @@ def savee(ckpt, name, epoch, steps, hps): opt["weight"][key] = ckpt[key].half() opt["config"] = hps opt["info"] = "%sepoch_%siteration" % (epoch, steps) - torch.save(opt, "%s/%s.pth" % (hps.save_weight_dir, name)) + # torch.save(opt, "%s/%s.pth" % (hps.save_weight_dir, name)) + my_save(opt, "%s/%s.pth" % (hps.save_weight_dir, name)) return "Success." except: return traceback.format_exc() diff --git a/GPT_SoVITS/s1_train.py b/GPT_SoVITS/s1_train.py index c26302a..fb27354 100644 --- a/GPT_SoVITS/s1_train.py +++ b/GPT_SoVITS/s1_train.py @@ -24,6 +24,14 @@ torch.set_float32_matmul_precision("high") from AR.utils import get_newest_ckpt from collections import OrderedDict +from time import time as ttime +import shutil +def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path + dir=os.path.dirname(path) + name=os.path.basename(path) + tmp_path="%s.pth"%(ttime()) + torch.save(fea,tmp_path) + shutil.move(tmp_path,"%s/%s"%(dir,name)) class my_model_ckpt(ModelCheckpoint): @@ -70,7 +78,8 @@ class my_model_ckpt(ModelCheckpoint): to_save_od["weight"][key] = dictt[key].half() to_save_od["config"] = self.config to_save_od["info"] = "GPT-e%s" % (trainer.current_epoch + 1) - torch.save( + # torch.save( + my_save( to_save_od, "%s/%s-e%s.ckpt" % ( diff --git a/GPT_SoVITS/text/english.py b/GPT_SoVITS/text/english.py index 0a5d6c2..90f48a5 100644 --- a/GPT_SoVITS/text/english.py +++ b/GPT_SoVITS/text/english.py @@ -169,9 +169,9 @@ def read_dict_new(): line = line.strip() word_split = line.split(" ") word = word_split[0] - if word not in g2p_dict: - g2p_dict[word] = [] - g2p_dict[word].append(word_split[1:]) + #if word not in g2p_dict: + g2p_dict[word] = [] + g2p_dict[word].append(word_split[1:]) line_index = line_index + 1 line = f.readline() diff --git a/GPT_SoVITS/text/tone_sandhi.py b/GPT_SoVITS/text/tone_sandhi.py index 9f62abe..c557dad 100644 --- a/GPT_SoVITS/text/tone_sandhi.py +++ b/GPT_SoVITS/text/tone_sandhi.py @@ -672,6 +672,7 @@ class ToneSandhi: and i + 1 < len(seg) and seg[i - 1][0] == seg[i + 1][0] and seg[i - 1][1] == "v" + and seg[i + 1][1] == "v" ): new_seg[i - 1][0] = new_seg[i - 1][0] + "一" + new_seg[i - 1][0] else: diff --git a/GPT_SoVITS/utils.py b/GPT_SoVITS/utils.py index 0ce03b3..7984b5a 100644 --- a/GPT_SoVITS/utils.py +++ b/GPT_SoVITS/utils.py @@ -64,6 +64,14 @@ def load_checkpoint(checkpoint_path, model, optimizer=None, skip_optimizer=False ) return model, optimizer, learning_rate, iteration +from time import time as ttime +import shutil +def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path + dir=os.path.dirname(path) + name=os.path.basename(path) + tmp_path="%s.pth"%(ttime()) + torch.save(fea,tmp_path) + shutil.move(tmp_path,"%s/%s"%(dir,name)) def save_checkpoint(model, optimizer, learning_rate, iteration, checkpoint_path): logger.info( @@ -75,7 +83,8 @@ def save_checkpoint(model, optimizer, learning_rate, iteration, checkpoint_path) state_dict = model.module.state_dict() else: state_dict = model.state_dict() - torch.save( + # torch.save( + my_save( { "model": state_dict, "iteration": iteration, diff --git a/colab_webui.ipynb b/colab_webui.ipynb index 21722da..70fa794 100644 --- a/colab_webui.ipynb +++ b/colab_webui.ipynb @@ -82,7 +82,7 @@ "source": [ "# @title launch WebUI 启动WebUI\n", "!/usr/local/bin/pip install ipykernel\n", - "!sed -i '9s/False/True/' /content/GPT-SoVITS/config.py\n", + "!sed -i '10s/False/True/' /content/GPT-SoVITS/config.py\n", "%cd /content/GPT-SoVITS/\n", "!/usr/local/bin/python webui.py" ], @@ -93,4 +93,4 @@ "outputs": [] } ] -} \ No newline at end of file +} diff --git a/docs/cn/Changelog_CN.md b/docs/cn/Changelog_CN.md index dee3fcc..6622146 100644 --- a/docs/cn/Changelog_CN.md +++ b/docs/cn/Changelog_CN.md @@ -113,12 +113,21 @@ 2-DPO Loss实验性训练选项开启,通过构造负样本训练缓解GPT重复漏字问题。推理界面公开几个推理参数。 https://github.com/RVC-Boss/GPT-SoVITS/pull/457 +### 20240214更新 + +1-训练支持中文实验名(原来会报错) + +2-DPO训练改为可勾选选项而非必须。如勾选batch size自动减半。修复推理界面新参数不传参的问题。 + +### 20240216更新 + +1-支持无参考文本输入 + +2-修复中文文本前端bug https://github.com/RVC-Boss/GPT-SoVITS/issues/475 todolist: 1-中文多音字推理优化 -2-训练支持中文实验名(原来会报错) - diff --git a/webui.py b/webui.py index fa40c3a..cff7cdb 100644 --- a/webui.py +++ b/webui.py @@ -266,7 +266,7 @@ def close1Ba(): return "已终止SoVITS训练",{"__type__":"update","visible":True},{"__type__":"update","visible":False} p_train_GPT=None -def open1Bb(batch_size,total_epoch,exp_name,if_save_latest,if_save_every_weights,save_every_epoch,gpu_numbers,pretrained_s1): +def open1Bb(batch_size,total_epoch,exp_name,if_dpo,if_save_latest,if_save_every_weights,save_every_epoch,gpu_numbers,pretrained_s1): global p_train_GPT if(p_train_GPT==None): with open("GPT_SoVITS/configs/s1longer.yaml")as f: @@ -283,6 +283,7 @@ def open1Bb(batch_size,total_epoch,exp_name,if_save_latest,if_save_every_weights data["train"]["save_every_n_epoch"]=save_every_epoch data["train"]["if_save_every_weights"]=if_save_every_weights data["train"]["if_save_latest"]=if_save_latest + data["train"]["if_dpo"]=if_dpo data["train"]["half_weights_save_dir"]=GPT_weight_root data["train"]["exp_name"]=exp_name data["train_semantic_path"]="%s/6-name2semantic.tsv"%s1_dir @@ -807,6 +808,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app: with gr.Row(): batch_size1Bb = gr.Slider(minimum=1,maximum=40,step=1,label=i18n("每张显卡的batch_size"),value=default_batch_size,interactive=True) total_epoch1Bb = gr.Slider(minimum=2,maximum=50,step=1,label=i18n("总训练轮数total_epoch"),value=15,interactive=True) + if_dpo = gr.Checkbox(label=i18n("是否开启dpo训练选项(实验性)"), value=False, interactive=True, show_label=True) if_save_latest1Bb = gr.Checkbox(label=i18n("是否仅保存最新的ckpt文件以节省硬盘空间"), value=True, interactive=True, show_label=True) if_save_every_weights1Bb = gr.Checkbox(label=i18n("是否在每次保存时间点将最终小模型保存至weights文件夹"), value=True, interactive=True, show_label=True) save_every_epoch1Bb = gr.Slider(minimum=1,maximum=50,step=1,label=i18n("保存频率save_every_epoch"),value=5,interactive=True) @@ -817,7 +819,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI") as app: info1Bb=gr.Textbox(label=i18n("GPT训练进程输出信息")) button1Ba_open.click(open1Ba, [batch_size,total_epoch,exp_name,text_low_lr_rate,if_save_latest,if_save_every_weights,save_every_epoch,gpu_numbers1Ba,pretrained_s2G,pretrained_s2D], [info1Ba,button1Ba_open,button1Ba_close]) button1Ba_close.click(close1Ba, [], [info1Ba,button1Ba_open,button1Ba_close]) - button1Bb_open.click(open1Bb, [batch_size1Bb,total_epoch1Bb,exp_name,if_save_latest1Bb,if_save_every_weights1Bb,save_every_epoch1Bb,gpu_numbers1Bb,pretrained_s1], [info1Bb,button1Bb_open,button1Bb_close]) + button1Bb_open.click(open1Bb, [batch_size1Bb,total_epoch1Bb,exp_name,if_dpo,if_save_latest1Bb,if_save_every_weights1Bb,save_every_epoch1Bb,gpu_numbers1Bb,pretrained_s1], [info1Bb,button1Bb_open,button1Bb_close]) button1Bb_close.click(close1Bb, [], [info1Bb,button1Bb_open,button1Bb_close]) with gr.TabItem(i18n("1C-推理")): gr.Markdown(value=i18n("选择训练完存放在SoVITS_weights和GPT_weights下的模型。默认的一个是底模,体验5秒Zero Shot TTS用。"))