diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,1441 +1,1441 @@ -import os, sys -import datetime, subprocess -from mega import Mega -now_dir = os.getcwd() -sys.path.append(now_dir) -import logging -import shutil -import threading -import traceback -import warnings -from random import shuffle -from subprocess import Popen -from time import sleep -import json -import pathlib - -import fairseq -import faiss -import gradio as gr -import numpy as np -import torch -from dotenv import load_dotenv -from sklearn.cluster import MiniBatchKMeans - -from configs.config import Config -from i18n.i18n import I18nAuto -from infer.lib.train.process_ckpt import ( - change_info, - extract_small_model, - merge, - show_info, -) -from infer.modules.uvr5.modules import uvr -from infer.modules.vc.modules import VC -logging.getLogger("numba").setLevel(logging.WARNING) - -logger = logging.getLogger(__name__) - -tmp = os.path.join(now_dir, "TEMP") -shutil.rmtree(tmp, ignore_errors=True) -shutil.rmtree("%s/runtime/Lib/site-packages/infer_pack" % (now_dir), ignore_errors=True) -shutil.rmtree("%s/runtime/Lib/site-packages/uvr5_pack" % (now_dir), ignore_errors=True) -os.makedirs(tmp, exist_ok=True) -os.makedirs(os.path.join(now_dir, "logs"), exist_ok=True) -os.makedirs(os.path.join(now_dir, "assets/weights"), exist_ok=True) -os.environ["TEMP"] = tmp -warnings.filterwarnings("ignore") -torch.manual_seed(114514) - - -load_dotenv() -config = Config() -vc = VC(config) - -if config.dml == True: - - def forward_dml(ctx, x, scale): - ctx.scale = scale - res = x.clone().detach() - return res - - fairseq.modules.grad_multiply.GradMultiply.forward = forward_dml -i18n = I18nAuto() -logger.info(i18n) -# 判断是否有能用来训练和加速推理的N卡 -ngpu = torch.cuda.device_count() -gpu_infos = [] -mem = [] -if_gpu_ok = False - -if torch.cuda.is_available() or ngpu != 0: - for i in range(ngpu): - gpu_name = torch.cuda.get_device_name(i) - if any( - value in gpu_name.upper() - for value in [ - "10", - "16", - "20", - "30", - "40", - "A2", - "A3", - "A4", - "P4", - "A50", - "500", - "A60", - "70", - "80", - "90", - "M4", - "T4", - "TITAN", - ] - ): - # A10#A100#V100#A40#P40#M40#K80#A4500 - if_gpu_ok = True # 至少有一张能用的N卡 - gpu_infos.append("%s\t%s" % (i, gpu_name)) - mem.append( - int( - torch.cuda.get_device_properties(i).total_memory - / 1024 - / 1024 - / 1024 - + 0.4 - ) - ) -if if_gpu_ok and len(gpu_infos) > 0: - gpu_info = "\n".join(gpu_infos) - default_batch_size = min(mem) // 2 -else: - gpu_info = i18n("很遗憾您这没有能用的显卡来支持您训练") - default_batch_size = 1 -gpus = "-".join([i[0] for i in gpu_infos]) - - -class ToolButton(gr.Button, gr.components.FormComponent): - """Small button with single emoji as text, fits inside gradio forms""" - - def __init__(self, **kwargs): - super().__init__(variant="tool", **kwargs) - - def get_block_name(self): - return "button" - - -weight_root = os.getenv("weight_root") -weight_uvr5_root = os.getenv("weight_uvr5_root") -index_root = os.getenv("index_root") - -names = [] -for name in os.listdir(weight_root): - if name.endswith(".pth"): - names.append(name) -index_paths = [] -for root, dirs, files in os.walk(index_root, topdown=False): - for name in files: - if name.endswith(".index") and "trained" not in name: - index_paths.append("%s/%s" % (root, name)) -uvr5_names = [] -for name in os.listdir(weight_uvr5_root): - if name.endswith(".pth") or "onnx" in name: - uvr5_names.append(name.replace(".pth", "")) - - -def change_choices(): - names = [] - for name in os.listdir(weight_root): - if name.endswith(".pth"): - names.append(name) - index_paths = [] - for root, dirs, files in os.walk(index_root, topdown=False): - for name in files: - if name.endswith(".index") and "trained" not in name: - index_paths.append("%s/%s" % (root, name)) - audio_files=[] - for filename in os.listdir("./audios"): - if filename.endswith(('.wav','.mp3','.ogg')): - audio_files.append('./audios/'+filename) - return {"choices": sorted(names), "__type__": "update"}, { - "choices": sorted(index_paths), - "__type__": "update", - }, {"choices": sorted(audio_files), "__type__": "update"} - -def clean(): - return {"value": "", "__type__": "update"} - - -def export_onnx(): - from infer.modules.onnx.export import export_onnx as eo - - eo() - - -sr_dict = { - "32k": 32000, - "40k": 40000, - "48k": 48000, -} - - -def if_done(done, p): - while 1: - if p.poll() is None: - sleep(0.5) - else: - break - done[0] = True - - -def if_done_multi(done, ps): - while 1: - # poll==None代表进程未结束 - # 只要有一个进程未结束都不停 - flag = 1 - for p in ps: - if p.poll() is None: - flag = 0 - sleep(0.5) - break - if flag == 1: - break - done[0] = True - - -def preprocess_dataset(trainset_dir, exp_dir, sr, n_p): - sr = sr_dict[sr] - os.makedirs("%s/logs/%s" % (now_dir, exp_dir), exist_ok=True) - f = open("%s/logs/%s/preprocess.log" % (now_dir, exp_dir), "w") - f.close() - per = 3.0 if config.is_half else 3.7 - cmd = '"%s" infer/modules/train/preprocess.py "%s" %s %s "%s/logs/%s" %s %.1f' % ( - config.python_cmd, - trainset_dir, - sr, - n_p, - now_dir, - exp_dir, - config.noparallel, - per, - ) - logger.info(cmd) - p = Popen(cmd, shell=True) # , stdin=PIPE, stdout=PIPE,stderr=PIPE,cwd=now_dir - ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 - done = [False] - threading.Thread( - target=if_done, - args=( - done, - p, - ), - ).start() - while 1: - with open("%s/logs/%s/preprocess.log" % (now_dir, exp_dir), "r") as f: - yield (f.read()) - sleep(1) - if done[0]: - break - with open("%s/logs/%s/preprocess.log" % (now_dir, exp_dir), "r") as f: - log = f.read() - logger.info(log) - yield log - - -# but2.click(extract_f0,[gpus6,np7,f0method8,if_f0_3,trainset_dir4],[info2]) -def extract_f0_feature(gpus, n_p, f0method, if_f0, exp_dir, version19, gpus_rmvpe): - gpus = gpus.split("-") - os.makedirs("%s/logs/%s" % (now_dir, exp_dir), exist_ok=True) - f = open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "w") - f.close() - if if_f0: - if f0method != "rmvpe_gpu": - cmd = ( - '"%s" infer/modules/train/extract/extract_f0_print.py "%s/logs/%s" %s %s' - % ( - config.python_cmd, - now_dir, - exp_dir, - n_p, - f0method, - ) - ) - logger.info(cmd) - p = Popen( - cmd, shell=True, cwd=now_dir - ) # , stdin=PIPE, stdout=PIPE,stderr=PIPE - ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 - done = [False] - threading.Thread( - target=if_done, - args=( - done, - p, - ), - ).start() - else: - if gpus_rmvpe != "-": - gpus_rmvpe = gpus_rmvpe.split("-") - leng = len(gpus_rmvpe) - ps = [] - for idx, n_g in enumerate(gpus_rmvpe): - cmd = ( - '"%s" infer/modules/train/extract/extract_f0_rmvpe.py %s %s %s "%s/logs/%s" %s ' - % ( - config.python_cmd, - leng, - idx, - n_g, - now_dir, - exp_dir, - config.is_half, - ) - ) - logger.info(cmd) - p = Popen( - cmd, shell=True, cwd=now_dir - ) # , shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=now_dir - ps.append(p) - ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 - done = [False] - threading.Thread( - target=if_done_multi, # - args=( - done, - ps, - ), - ).start() - else: - cmd = ( - config.python_cmd - + ' infer/modules/train/extract/extract_f0_rmvpe_dml.py "%s/logs/%s" ' - % ( - now_dir, - exp_dir, - ) - ) - logger.info(cmd) - p = Popen( - cmd, shell=True, cwd=now_dir - ) # , shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=now_dir - p.wait() - done = [True] - while 1: - with open( - "%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r" - ) as f: - yield (f.read()) - sleep(1) - if done[0]: - break - with open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r") as f: - log = f.read() - logger.info(log) - yield log - ####对不同part分别开多进程 - """ - n_part=int(sys.argv[1]) - i_part=int(sys.argv[2]) - i_gpu=sys.argv[3] - exp_dir=sys.argv[4] - os.environ["CUDA_VISIBLE_DEVICES"]=str(i_gpu) - """ - leng = len(gpus) - ps = [] - for idx, n_g in enumerate(gpus): - cmd = ( - '"%s" infer/modules/train/extract_feature_print.py %s %s %s %s "%s/logs/%s" %s' - % ( - config.python_cmd, - config.device, - leng, - idx, - n_g, - now_dir, - exp_dir, - version19, - ) - ) - logger.info(cmd) - p = Popen( - cmd, shell=True, cwd=now_dir - ) # , shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=now_dir - ps.append(p) - ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 - done = [False] - threading.Thread( - target=if_done_multi, - args=( - done, - ps, - ), - ).start() - while 1: - with open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r") as f: - yield (f.read()) - sleep(1) - if done[0]: - break - with open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r") as f: - log = f.read() - logger.info(log) - yield log - - -def get_pretrained_models(path_str, f0_str, sr2): - if_pretrained_generator_exist = os.access( - "assets/pretrained%s/%sG%s.pth" % (path_str, f0_str, sr2), os.F_OK - ) - if_pretrained_discriminator_exist = os.access( - "assets/pretrained%s/%sD%s.pth" % (path_str, f0_str, sr2), os.F_OK - ) - if not if_pretrained_generator_exist: - logger.warn( - "assets/pretrained%s/%sG%s.pth not exist, will not use pretrained model", - path_str, - f0_str, - sr2, - ) - if not if_pretrained_discriminator_exist: - logger.warn( - "assets/pretrained%s/%sD%s.pth not exist, will not use pretrained model", - path_str, - f0_str, - sr2, - ) - return ( - "assets/pretrained%s/%sG%s.pth" % (path_str, f0_str, sr2) - if if_pretrained_generator_exist - else "", - "assets/pretrained%s/%sD%s.pth" % (path_str, f0_str, sr2) - if if_pretrained_discriminator_exist - else "", - ) - - -def change_sr2(sr2, if_f0_3, version19): - path_str = "" if version19 == "v1" else "_v2" - f0_str = "f0" if if_f0_3 else "" - return get_pretrained_models(path_str, f0_str, sr2) - - -def change_version19(sr2, if_f0_3, version19): - path_str = "" if version19 == "v1" else "_v2" - if sr2 == "32k" and version19 == "v1": - sr2 = "40k" - to_return_sr2 = ( - {"choices": ["40k", "48k"], "__type__": "update", "value": sr2} - if version19 == "v1" - else {"choices": ["40k", "48k", "32k"], "__type__": "update", "value": sr2} - ) - f0_str = "f0" if if_f0_3 else "" - return ( - *get_pretrained_models(path_str, f0_str, sr2), - to_return_sr2, - ) - - -def change_f0(if_f0_3, sr2, version19): # f0method8,pretrained_G14,pretrained_D15 - path_str = "" if version19 == "v1" else "_v2" - return ( - {"visible": if_f0_3, "__type__": "update"}, - *get_pretrained_models(path_str, "f0", sr2), - ) - - -# but3.click(click_train,[exp_dir1,sr2,if_f0_3,save_epoch10,total_epoch11,batch_size12,if_save_latest13,pretrained_G14,pretrained_D15,gpus16]) -def click_train( - exp_dir1, - sr2, - if_f0_3, - spk_id5, - save_epoch10, - total_epoch11, - batch_size12, - if_save_latest13, - pretrained_G14, - pretrained_D15, - gpus16, - if_cache_gpu17, - if_save_every_weights18, - version19, -): - # 生成filelist - exp_dir = "%s/logs/%s" % (now_dir, exp_dir1) - os.makedirs(exp_dir, exist_ok=True) - gt_wavs_dir = "%s/0_gt_wavs" % (exp_dir) - feature_dir = ( - "%s/3_feature256" % (exp_dir) - if version19 == "v1" - else "%s/3_feature768" % (exp_dir) - ) - if if_f0_3: - f0_dir = "%s/2a_f0" % (exp_dir) - f0nsf_dir = "%s/2b-f0nsf" % (exp_dir) - names = ( - set([name.split(".")[0] for name in os.listdir(gt_wavs_dir)]) - & set([name.split(".")[0] for name in os.listdir(feature_dir)]) - & set([name.split(".")[0] for name in os.listdir(f0_dir)]) - & set([name.split(".")[0] for name in os.listdir(f0nsf_dir)]) - ) - else: - names = set([name.split(".")[0] for name in os.listdir(gt_wavs_dir)]) & set( - [name.split(".")[0] for name in os.listdir(feature_dir)] - ) - opt = [] - for name in names: - if if_f0_3: - opt.append( - "%s/%s.wav|%s/%s.npy|%s/%s.wav.npy|%s/%s.wav.npy|%s" - % ( - gt_wavs_dir.replace("\\", "\\\\"), - name, - feature_dir.replace("\\", "\\\\"), - name, - f0_dir.replace("\\", "\\\\"), - name, - f0nsf_dir.replace("\\", "\\\\"), - name, - spk_id5, - ) - ) - else: - opt.append( - "%s/%s.wav|%s/%s.npy|%s" - % ( - gt_wavs_dir.replace("\\", "\\\\"), - name, - feature_dir.replace("\\", "\\\\"), - name, - spk_id5, - ) - ) - fea_dim = 256 if version19 == "v1" else 768 - if if_f0_3: - for _ in range(2): - opt.append( - "%s/logs/mute/0_gt_wavs/mute%s.wav|%s/logs/mute/3_feature%s/mute.npy|%s/logs/mute/2a_f0/mute.wav.npy|%s/logs/mute/2b-f0nsf/mute.wav.npy|%s" - % (now_dir, sr2, now_dir, fea_dim, now_dir, now_dir, spk_id5) - ) - else: - for _ in range(2): - opt.append( - "%s/logs/mute/0_gt_wavs/mute%s.wav|%s/logs/mute/3_feature%s/mute.npy|%s" - % (now_dir, sr2, now_dir, fea_dim, spk_id5) - ) - shuffle(opt) - with open("%s/filelist.txt" % exp_dir, "w") as f: - f.write("\n".join(opt)) - logger.debug("Write filelist done") - # 生成config#无需生成config - # cmd = python_cmd + " train_nsf_sim_cache_sid_load_pretrain.py -e mi-test -sr 40k -f0 1 -bs 4 -g 0 -te 10 -se 5 -pg pretrained/f0G40k.pth -pd pretrained/f0D40k.pth -l 1 -c 0" - logger.info("Use gpus: %s", str(gpus16)) - if pretrained_G14 == "": - logger.info("No pretrained Generator") - if pretrained_D15 == "": - logger.info("No pretrained Discriminator") - if version19 == "v1" or sr2 == "40k": - config_path = "v1/%s.json" % sr2 - else: - config_path = "v2/%s.json" % sr2 - config_save_path = os.path.join(exp_dir, "config.json") - if not pathlib.Path(config_save_path).exists(): - with open(config_save_path, "w", encoding="utf-8") as f: - json.dump( - config.json_config[config_path], - f, - ensure_ascii=False, - indent=4, - sort_keys=True, - ) - f.write("\n") - if gpus16: - cmd = ( - '"%s" infer/modules/train/train.py -e "%s" -sr %s -f0 %s -bs %s -g %s -te %s -se %s %s %s -l %s -c %s -sw %s -v %s' - % ( - config.python_cmd, - exp_dir1, - sr2, - 1 if if_f0_3 else 0, - batch_size12, - gpus16, - total_epoch11, - save_epoch10, - "-pg %s" % pretrained_G14 if pretrained_G14 != "" else "", - "-pd %s" % pretrained_D15 if pretrained_D15 != "" else "", - 1 if if_save_latest13 == i18n("是") else 0, - 1 if if_cache_gpu17 == i18n("是") else 0, - 1 if if_save_every_weights18 == i18n("是") else 0, - version19, - ) - ) - else: - cmd = ( - '"%s" infer/modules/train/train.py -e "%s" -sr %s -f0 %s -bs %s -te %s -se %s %s %s -l %s -c %s -sw %s -v %s' - % ( - config.python_cmd, - exp_dir1, - sr2, - 1 if if_f0_3 else 0, - batch_size12, - total_epoch11, - save_epoch10, - "-pg %s" % pretrained_G14 if pretrained_G14 != "" else "", - "-pd %s" % pretrained_D15 if pretrained_D15 != "" else "", - 1 if if_save_latest13 == i18n("是") else 0, - 1 if if_cache_gpu17 == i18n("是") else 0, - 1 if if_save_every_weights18 == i18n("是") else 0, - version19, - ) - ) - logger.info(cmd) - p = Popen(cmd, shell=True, cwd=now_dir) - p.wait() - return "训练结束, 您可查看控制台训练日志或实验文件夹下的train.log" - - -# but4.click(train_index, [exp_dir1], info3) -def train_index(exp_dir1, version19): - # exp_dir = "%s/logs/%s" % (now_dir, exp_dir1) - exp_dir = "logs/%s" % (exp_dir1) - os.makedirs(exp_dir, exist_ok=True) - feature_dir = ( - "%s/3_feature256" % (exp_dir) - if version19 == "v1" - else "%s/3_feature768" % (exp_dir) - ) - if not os.path.exists(feature_dir): - return "请先进行特征提取!" - listdir_res = list(os.listdir(feature_dir)) - if len(listdir_res) == 0: - return "请先进行特征提取!" - infos = [] - npys = [] - for name in sorted(listdir_res): - phone = np.load("%s/%s" % (feature_dir, name)) - npys.append(phone) - big_npy = np.concatenate(npys, 0) - big_npy_idx = np.arange(big_npy.shape[0]) - np.random.shuffle(big_npy_idx) - big_npy = big_npy[big_npy_idx] - if big_npy.shape[0] > 2e5: - infos.append("Trying doing kmeans %s shape to 10k centers." % big_npy.shape[0]) - yield "\n".join(infos) - try: - big_npy = ( - MiniBatchKMeans( - n_clusters=10000, - verbose=True, - batch_size=256 * config.n_cpu, - compute_labels=False, - init="random", - ) - .fit(big_npy) - .cluster_centers_ - ) - except: - info = traceback.format_exc() - logger.info(info) - infos.append(info) - yield "\n".join(infos) - - np.save("%s/total_fea.npy" % exp_dir, big_npy) - n_ivf = min(int(16 * np.sqrt(big_npy.shape[0])), big_npy.shape[0] // 39) - infos.append("%s,%s" % (big_npy.shape, n_ivf)) - yield "\n".join(infos) - index = faiss.index_factory(256 if version19 == "v1" else 768, "IVF%s,Flat" % n_ivf) - # index = faiss.index_factory(256if version19=="v1"else 768, "IVF%s,PQ128x4fs,RFlat"%n_ivf) - infos.append("training") - yield "\n".join(infos) - index_ivf = faiss.extract_index_ivf(index) # - index_ivf.nprobe = 1 - index.train(big_npy) - faiss.write_index( - index, - "%s/trained_IVF%s_Flat_nprobe_%s_%s_%s.index" - % (exp_dir, n_ivf, index_ivf.nprobe, exp_dir1, version19), - ) - - infos.append("adding") - yield "\n".join(infos) - batch_size_add = 8192 - for i in range(0, big_npy.shape[0], batch_size_add): - index.add(big_npy[i : i + batch_size_add]) - faiss.write_index( - index, - "%s/added_IVF%s_Flat_nprobe_%s_%s_%s.index" - % (exp_dir, n_ivf, index_ivf.nprobe, exp_dir1, version19), - ) - infos.append( - "成功构建索引,added_IVF%s_Flat_nprobe_%s_%s_%s.index" - % (n_ivf, index_ivf.nprobe, exp_dir1, version19) - ) - # faiss.write_index(index, '%s/added_IVF%s_Flat_FastScan_%s.index'%(exp_dir,n_ivf,version19)) - # infos.append("成功构建索引,added_IVF%s_Flat_FastScan_%s.index"%(n_ivf,version19)) - yield "\n".join(infos) - - -# but5.click(train1key, [exp_dir1, sr2, if_f0_3, trainset_dir4, spk_id5, gpus6, np7, f0method8, save_epoch10, total_epoch11, batch_size12, if_save_latest13, pretrained_G14, pretrained_D15, gpus16, if_cache_gpu17], info3) -def train1key( - exp_dir1, - sr2, - if_f0_3, - trainset_dir4, - spk_id5, - np7, - f0method8, - save_epoch10, - total_epoch11, - batch_size12, - if_save_latest13, - pretrained_G14, - pretrained_D15, - gpus16, - if_cache_gpu17, - if_save_every_weights18, - version19, - gpus_rmvpe, -): - infos = [] - - def get_info_str(strr): - infos.append(strr) - return "\n".join(infos) - - ####### step1:处理数据 - yield get_info_str(i18n("step1:正在处理数据")) - [get_info_str(_) for _ in preprocess_dataset(trainset_dir4, exp_dir1, sr2, np7)] - - ####### step2a:提取音高 - yield get_info_str(i18n("step2:正在提取音高&正在提取特征")) - [ - get_info_str(_) - for _ in extract_f0_feature( - gpus16, np7, f0method8, if_f0_3, exp_dir1, version19, gpus_rmvpe - ) - ] - - ####### step3a:训练模型 - yield get_info_str(i18n("step3a:正在训练模型")) - click_train( - exp_dir1, - sr2, - if_f0_3, - spk_id5, - save_epoch10, - total_epoch11, - batch_size12, - if_save_latest13, - pretrained_G14, - pretrained_D15, - gpus16, - if_cache_gpu17, - if_save_every_weights18, - version19, - ) - yield get_info_str(i18n("训练结束, 您可查看控制台训练日志或实验文件夹下的train.log")) - - ####### step3b:训练索引 - [get_info_str(_) for _ in train_index(exp_dir1, version19)] - yield get_info_str(i18n("全流程结束!")) - - -# ckpt_path2.change(change_info_,[ckpt_path2],[sr__,if_f0__]) -def change_info_(ckpt_path): - if not os.path.exists(ckpt_path.replace(os.path.basename(ckpt_path), "train.log")): - return {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"} - try: - with open( - ckpt_path.replace(os.path.basename(ckpt_path), "train.log"), "r" - ) as f: - info = eval(f.read().strip("\n").split("\n")[0].split("\t")[-1]) - sr, f0 = info["sample_rate"], info["if_f0"] - version = "v2" if ("version" in info and info["version"] == "v2") else "v1" - return sr, str(f0), version - except: - traceback.print_exc() - return {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"} - - -F0GPUVisible = config.dml == False - - -def change_f0_method(f0method8): - if f0method8 == "rmvpe_gpu": - visible = F0GPUVisible - else: - visible = False - return {"visible": visible, "__type__": "update"} - -def find_model(): - if len(names) > 0: - vc.get_vc(sorted(names)[0],None,None) - return sorted(names)[0] - else: - try: - gr.Info("Do not forget to choose a model.") - except: - pass - return '' - -def find_audios(index=False): - audio_files=[] - if not os.path.exists('./audios'): os.mkdir("./audios") - for filename in os.listdir("./audios"): - if filename.endswith(('.wav','.mp3','.ogg')): - audio_files.append("./audios/"+filename) - if index: - if len(audio_files) > 0: return sorted(audio_files)[0] - else: return "" - elif len(audio_files) > 0: return sorted(audio_files) - else: return [] - -def get_index(): - if find_model() != '': - chosen_model=sorted(names)[0].split(".")[0] - logs_path="./logs/"+chosen_model - if os.path.exists(logs_path): - for file in os.listdir(logs_path): - if file.endswith(".index"): - return os.path.join(logs_path, file) - return '' - else: - return '' - -def get_indexes(): - indexes_list=[] - for dirpath, dirnames, filenames in os.walk("./logs/"): - for filename in filenames: - if filename.endswith(".index"): - indexes_list.append(os.path.join(dirpath,filename)) - if len(indexes_list) > 0: - return indexes_list - else: - return '' - -def save_wav(file): - try: - file_path=file.name - shutil.move(file_path,'./audios') - return './audios/'+os.path.basename(file_path) - except AttributeError: - try: - new_name = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")+'.wav' - new_path='./audios/'+new_name - shutil.move(file,new_path) - return new_path - except TypeError: - return None - -def download_from_url(url, model): - if url == '': - return "URL cannot be left empty." - if model =='': - return "You need to name your model. For example: My-Model" - url = url.strip() - zip_dirs = ["zips", "unzips"] - for directory in zip_dirs: - if os.path.exists(directory): - shutil.rmtree(directory) - os.makedirs("zips", exist_ok=True) - os.makedirs("unzips", exist_ok=True) - zipfile = model + '.zip' - zipfile_path = './zips/' + zipfile - try: - if "drive.google.com" in url: - subprocess.run(["gdown", url, "--fuzzy", "-O", zipfile_path]) - elif "mega.nz" in url: - m = Mega() - m.download_url(url, './zips') - else: - subprocess.run(["wget", url, "-O", zipfile_path]) - for filename in os.listdir("./zips"): - if filename.endswith(".zip"): - zipfile_path = os.path.join("./zips/",filename) - shutil.unpack_archive(zipfile_path, "./unzips", 'zip') - else: - return "No zipfile found." - for root, dirs, files in os.walk('./unzips'): - for file in files: - file_path = os.path.join(root, file) - if file.endswith(".index"): - os.mkdir(f'./logs/{model}') - shutil.copy2(file_path,f'./logs/{model}') - elif "G_" not in file and "D_" not in file and file.endswith(".pth"): - shutil.copy(file_path,f'./assets/weights/{model}.pth') - shutil.rmtree("zips") - shutil.rmtree("unzips") - return "Success." - except: - return "There's been an error." - -def upload_to_dataset(files, dir): - if dir == '': - dir = './dataset/'+datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") - if not os.path.exists(dir): - os.makedirs(dir) - for file in files: - path=file.name - shutil.copy2(path,dir) - try: - gr.Info(i18n("处理数据")) - except: - pass - return i18n("处理数据"), {"value":dir,"__type__":"update"} - -def download_model_files(model): - model_found = False - index_found = False - if os.path.exists(f'./assets/weights/{model}.pth'): model_found = True - if os.path.exists(f'./logs/{model}'): - for file in os.listdir(f'./logs/{model}'): - if file.endswith('.index') and 'added' in file: - log_file = file - index_found = True - if model_found and index_found: - return [f'./assets/weights/{model}.pth', f'./logs/{model}/{log_file}'], "Done" - elif model_found and not index_found: - return f'./assets/weights/{model}.pth', "Could not find Index file." - elif index_found and not model_found: - return f'./logs/{model}/{log_file}', f'Make sure the Voice Name is correct. I could not find {model}.pth' - else: - return None, f'Could not find {model}.pth or corresponding Index file.' - -with gr.Blocks(title="🔊",theme=gr.themes.Base(primary_hue="rose",neutral_hue="zinc")) as app: - with gr.Row(): - gr.HTML("image") - with gr.Tabs(): - with gr.TabItem(i18n("模型推理")): - with gr.Row(): - sid0 = gr.Dropdown(label=i18n("推理音色"), choices=sorted(names), value=find_model()) - refresh_button = gr.Button(i18n("刷新音色列表和索引路径"), variant="primary") - #clean_button = gr.Button(i18n("卸载音色省显存"), variant="primary") - spk_item = gr.Slider( - minimum=0, - maximum=2333, - step=1, - label=i18n("请选择说话人id"), - value=0, - visible=False, - interactive=True, - ) - #clean_button.click( - # fn=clean, inputs=[], outputs=[sid0], api_name="infer_clean" - #) - vc_transform0 = gr.Number( - label=i18n("变调(整数, 半音数量, 升八度12降八度-12)"), value=0 - ) - but0 = gr.Button(i18n("转换"), variant="primary") - with gr.Row(): - with gr.Column(): - with gr.Row(): - dropbox = gr.File(label="Drop your audio here & hit the Reload button.") - with gr.Row(): - record_button=gr.Audio(source="microphone", label="OR Record audio.", type="filepath") - with gr.Row(): - input_audio0 = gr.Dropdown( - label=i18n("输入待处理音频文件路径(默认是正确格式示例)"), - value=find_audios(True), - choices=find_audios() - ) - record_button.change(fn=save_wav, inputs=[record_button], outputs=[input_audio0]) - dropbox.upload(fn=save_wav, inputs=[dropbox], outputs=[input_audio0]) - with gr.Column(): - with gr.Accordion(label=i18n("自动检测index路径,下拉式选择(dropdown)"), open=False): - file_index2 = gr.Dropdown( - label=i18n("自动检测index路径,下拉式选择(dropdown)"), - choices=get_indexes(), - interactive=True, - value=get_index() - ) - index_rate1 = gr.Slider( - minimum=0, - maximum=1, - label=i18n("检索特征占比"), - value=0.66, - interactive=True, - ) - vc_output2 = gr.Audio(label=i18n("输出音频(右下角三个点,点了可以下载)")) - with gr.Accordion(label=i18n("常规设置"), open=False): - f0method0 = gr.Radio( - label=i18n( - "选择音高提取算法,输入歌声可用pm提速,harvest低音好但巨慢无比,crepe效果好但吃GPU,rmvpe效果最好且微吃GPU" - ), - choices=["pm", "harvest", "crepe", "rmvpe"] - if config.dml == False - else ["pm", "harvest", "rmvpe"], - value="rmvpe", - interactive=True, - ) - filter_radius0 = gr.Slider( - minimum=0, - maximum=7, - label=i18n(">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音"), - value=3, - step=1, - interactive=True, - ) - resample_sr0 = gr.Slider( - minimum=0, - maximum=48000, - label=i18n("后处理重采样至最终采样率,0为不进行重采样"), - value=0, - step=1, - interactive=True, - visible=False - ) - rms_mix_rate0 = gr.Slider( - minimum=0, - maximum=1, - label=i18n("输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络"), - value=0.21, - interactive=True, - ) - protect0 = gr.Slider( - minimum=0, - maximum=0.5, - label=i18n( - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可���降低索引效果" - ), - value=0.33, - step=0.01, - interactive=True, - ) - file_index1 = gr.Textbox( - label=i18n("特征检索库文件路径,为空则使用下拉的选择结果"), - value="", - interactive=True, - visible=False - ) - refresh_button.click( - fn=change_choices, - inputs=[], - outputs=[sid0, file_index2, input_audio0], - api_name="infer_refresh", - ) - # file_big_npy1 = gr.Textbox( - # label=i18n("特征文件路径"), - # value="E:\\codes\py39\\vits_vc_gpu_train\\logs\\mi-test-1key\\total_fea.npy", - # interactive=True, - # ) - with gr.Row(): - f0_file = gr.File(label=i18n("F0曲线文件, 可选, 一行一个音高, 代替默认F0及升降调"), visible=False) - with gr.Row(): - vc_output1 = gr.Textbox(label=i18n("输出信息")) - but0.click( - vc.vc_single, - [ - spk_item, - input_audio0, - vc_transform0, - f0_file, - f0method0, - file_index1, - file_index2, - # file_big_npy1, - index_rate1, - filter_radius0, - resample_sr0, - rms_mix_rate0, - protect0, - ], - [vc_output1, vc_output2], - api_name="infer_convert", - ) - with gr.Row(): - with gr.Accordion(open=False, label=i18n("批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ")): - with gr.Row(): - opt_input = gr.Textbox(label=i18n("指定输出文件夹"), value="opt") - vc_transform1 = gr.Number( - label=i18n("变调(整数, 半音数量, 升八度12降八度-12)"), value=0 - ) - f0method1 = gr.Radio( - label=i18n( - "选择音高提取算法,输入歌声可用pm提速,harvest低音好但巨慢无比,crepe效果好但吃GPU,rmvpe效果最好且微吃GPU" - ), - choices=["pm", "harvest", "crepe", "rmvpe"] - if config.dml == False - else ["pm", "harvest", "rmvpe"], - value="pm", - interactive=True, - ) - with gr.Row(): - filter_radius1 = gr.Slider( - minimum=0, - maximum=7, - label=i18n(">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音"), - value=3, - step=1, - interactive=True, - visible=False - ) - with gr.Row(): - file_index3 = gr.Textbox( - label=i18n("特征检索库文件路径,为空则使用下拉的选择结果"), - value="", - interactive=True, - visible=False - ) - file_index4 = gr.Dropdown( - label=i18n("自动检测index路径,下拉式选择(dropdown)"), - choices=sorted(index_paths), - interactive=True, - visible=False - ) - refresh_button.click( - fn=lambda: change_choices()[1], - inputs=[], - outputs=file_index4, - api_name="infer_refresh_batch", - ) - # file_big_npy2 = gr.Textbox( - # label=i18n("特征文件路径"), - # value="E:\\codes\\py39\\vits_vc_gpu_train\\logs\\mi-test-1key\\total_fea.npy", - # interactive=True, - # ) - index_rate2 = gr.Slider( - minimum=0, - maximum=1, - label=i18n("检索特征占比"), - value=1, - interactive=True, - visible=False - ) - with gr.Row(): - resample_sr1 = gr.Slider( - minimum=0, - maximum=48000, - label=i18n("后处理重采样至最终采样率,0为不进行重采样"), - value=0, - step=1, - interactive=True, - visible=False - ) - rms_mix_rate1 = gr.Slider( - minimum=0, - maximum=1, - label=i18n("输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络"), - value=0.21, - interactive=True, - ) - protect1 = gr.Slider( - minimum=0, - maximum=0.5, - label=i18n( - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果" - ), - value=0.33, - step=0.01, - interactive=True, - ) - with gr.Row(): - dir_input = gr.Textbox( - label=i18n("输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)"), - value="./audios", - ) - inputs = gr.File( - file_count="multiple", label=i18n("也可批量输入音频文件, 二选一, 优先读文件夹") - ) - with gr.Row(): - format1 = gr.Radio( - label=i18n("导出文件格式"), - choices=["wav", "flac", "mp3", "m4a"], - value="wav", - interactive=True, - ) - but1 = gr.Button(i18n("转换"), variant="primary") - vc_output3 = gr.Textbox(label=i18n("输出信息")) - but1.click( - vc.vc_multi, - [ - spk_item, - dir_input, - opt_input, - inputs, - vc_transform1, - f0method1, - file_index1, - file_index2, - # file_big_npy2, - index_rate1, - filter_radius1, - resample_sr1, - rms_mix_rate1, - protect1, - format1, - ], - [vc_output3], - api_name="infer_convert_batch", - ) - sid0.change( - fn=vc.get_vc, - inputs=[sid0, protect0, protect1], - outputs=[spk_item, protect0, protect1, file_index2, file_index4], - ) - with gr.TabItem("Download Model"): - with gr.Row(): - url=gr.Textbox(label="Enter the URL to the Model:") - with gr.Row(): - model = gr.Textbox(label="Name your model:") - download_button=gr.Button("Download") - with gr.Row(): - status_bar=gr.Textbox(label="") - download_button.click(fn=download_from_url, inputs=[url, model], outputs=[status_bar]) - with gr.Row(): - gr.Markdown( - """ - ❤️ If you use this and like it, help me keep it.❤️ - https://paypal.me/lesantillan - """ - ) - with gr.TabItem(i18n("训练")): - with gr.Row(): - with gr.Column(): - exp_dir1 = gr.Textbox(label=i18n("输入实验名"), value="My-Voice") - np7 = gr.Slider( - minimum=0, - maximum=config.n_cpu, - step=1, - label=i18n("提取音高和处理数据使用的CPU进程数"), - value=int(np.ceil(config.n_cpu / 1.5)), - interactive=True, - ) - sr2 = gr.Radio( - label=i18n("目标采样率"), - choices=["40k", "48k"], - value="40k", - interactive=True, - visible=False - ) - if_f0_3 = gr.Radio( - label=i18n("模型是否带音高指导(唱歌一定要, 语音可以不要)"), - choices=[True, False], - value=True, - interactive=True, - visible=False - ) - version19 = gr.Radio( - label=i18n("版本"), - choices=["v1", "v2"], - value="v2", - interactive=True, - visible=False, - ) - trainset_dir4 = gr.Textbox( - label=i18n("输入训练文件夹路径"), value='./dataset/'+datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") - ) - easy_uploader = gr.Files(label=i18n("也可批量输入音频文件, 二选一, 优先读文件夹"),file_types=['audio']) - but1 = gr.Button(i18n("处理数据"), variant="primary") - info1 = gr.Textbox(label=i18n("输出信息"), value="") - easy_uploader.upload(fn=upload_to_dataset, inputs=[easy_uploader, trainset_dir4], outputs=[info1, trainset_dir4]) - gpus6 = gr.Textbox( - label=i18n("以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2"), - value=gpus, - interactive=True, - visible=F0GPUVisible, - ) - gpu_info9 = gr.Textbox( - label=i18n("显卡信息"), value=gpu_info, visible=F0GPUVisible - ) - spk_id5 = gr.Slider( - minimum=0, - maximum=4, - step=1, - label=i18n("请指定说话人id"), - value=0, - interactive=True, - visible=False - ) - but1.click( - preprocess_dataset, - [trainset_dir4, exp_dir1, sr2, np7], - [info1], - api_name="train_preprocess", - ) - with gr.Column(): - f0method8 = gr.Radio( - label=i18n( - "选择音高提取算法:输入歌声可用pm提速,高质量语音但CPU差可用dio提速,harvest质量更好但慢,rmvpe效果最好且微吃CPU/GPU" - ), - choices=["pm", "harvest", "dio", "rmvpe", "rmvpe_gpu"], - value="rmvpe_gpu", - interactive=True, - ) - gpus_rmvpe = gr.Textbox( - label=i18n( - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程" - ), - value="%s-%s" % (gpus, gpus), - interactive=True, - visible=F0GPUVisible, - ) - but2 = gr.Button(i18n("特征提取"), variant="primary") - info2 = gr.Textbox(label=i18n("输出信息"), value="", max_lines=8) - f0method8.change( - fn=change_f0_method, - inputs=[f0method8], - outputs=[gpus_rmvpe], - ) - but2.click( - extract_f0_feature, - [ - gpus6, - np7, - f0method8, - if_f0_3, - exp_dir1, - version19, - gpus_rmvpe, - ], - [info2], - api_name="train_extract_f0_feature", - ) - with gr.Column(): - total_epoch11 = gr.Slider( - minimum=2, - maximum=1000, - step=1, - label=i18n("总训练轮数total_epoch"), - value=150, - interactive=True, - ) - gpus16 = gr.Textbox( - label=i18n("以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2"), - value="0", - interactive=True, - visible=True - ) - but3 = gr.Button(i18n("训练模型"), variant="primary") - but4 = gr.Button(i18n("训练特征索引"), variant="primary") - info3 = gr.Textbox(label=i18n("输出信息"), value="", max_lines=10) - with gr.Accordion(label=i18n("常规设置"), open=False): - save_epoch10 = gr.Slider( - minimum=1, - maximum=50, - step=1, - label=i18n("保存频率save_every_epoch"), - value=25, - interactive=True, - ) - batch_size12 = gr.Slider( - minimum=1, - maximum=40, - step=1, - label=i18n("每张显卡的batch_size"), - value=default_batch_size, - interactive=True, - ) - if_save_latest13 = gr.Radio( - label=i18n("是否仅保存最新的ckpt文件以节省硬盘空间"), - choices=[i18n("是"), i18n("否")], - value=i18n("是"), - interactive=True, - visible=False - ) - if_cache_gpu17 = gr.Radio( - label=i18n( - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速" - ), - choices=[i18n("是"), i18n("否")], - value=i18n("否"), - interactive=True, - ) - if_save_every_weights18 = gr.Radio( - label=i18n("是否在每次保存时间点将最终小模型保存至weights文件夹"), - choices=[i18n("是"), i18n("否")], - value=i18n("是"), - interactive=True, - ) - with gr.Row(): - download_model = gr.Button('5.Download Model') - with gr.Row(): - model_files = gr.Files(label='Your Model and Index file can be downloaded here:') - download_model.click(fn=download_model_files, inputs=[exp_dir1], outputs=[model_files, info3]) - with gr.Row(): - pretrained_G14 = gr.Textbox( - label=i18n("加载预训练底模G路径"), - value="assets/pretrained_v2/f0G40k.pth", - interactive=True, - visible=False - ) - pretrained_D15 = gr.Textbox( - label=i18n("加载预训练底模D路径"), - value="assets/pretrained_v2/f0D40k.pth", - interactive=True, - visible=False - ) - sr2.change( - change_sr2, - [sr2, if_f0_3, version19], - [pretrained_G14, pretrained_D15], - ) - version19.change( - change_version19, - [sr2, if_f0_3, version19], - [pretrained_G14, pretrained_D15, sr2], - ) - if_f0_3.change( - change_f0, - [if_f0_3, sr2, version19], - [f0method8, pretrained_G14, pretrained_D15], - ) - with gr.Row(): - but5 = gr.Button(i18n("一键训练"), variant="primary", visible=False) - but3.click( - click_train, - [ - exp_dir1, - sr2, - if_f0_3, - spk_id5, - save_epoch10, - total_epoch11, - batch_size12, - if_save_latest13, - pretrained_G14, - pretrained_D15, - gpus16, - if_cache_gpu17, - if_save_every_weights18, - version19, - ], - info3, - api_name="train_start", - ) - but4.click(train_index, [exp_dir1, version19], info3) - but5.click( - train1key, - [ - exp_dir1, - sr2, - if_f0_3, - trainset_dir4, - spk_id5, - np7, - f0method8, - save_epoch10, - total_epoch11, - batch_size12, - if_save_latest13, - pretrained_G14, - pretrained_D15, - gpus16, - if_cache_gpu17, - if_save_every_weights18, - version19, - gpus_rmvpe, - ], - info3, - api_name="train_start_all", - ) - - if config.iscolab: - app.queue(concurrency_count=511, max_size=1022).launch(share=True) - else: - app.queue(concurrency_count=511, max_size=1022).launch( - server_name="0.0.0.0", - inbrowser=not config.noautoopen, - server_port=config.listen_port, - quiet=True, - ) \ No newline at end of file +import os, sys +import datetime, subprocess +from mega import Mega +now_dir = os.getcwd() +sys.path.append(now_dir) +import logging +import shutil +import threading +import traceback +import warnings +from random import shuffle +from subprocess import Popen +from time import sleep +import json +import pathlib + +import fairseq +import faiss +import gradio as gr +import numpy as np +import torch +from dotenv import load_dotenv +from sklearn.cluster import MiniBatchKMeans + +from configs.config import Config +from i18n.i18n import I18nAuto +from infer.lib.train.process_ckpt import ( + change_info, + extract_small_model, + merge, + show_info, +) +from infer.modules.uvr5.modules import uvr +from infer.modules.vc.modules import VC +logging.getLogger("numba").setLevel(logging.WARNING) + +logger = logging.getLogger(__name__) + +tmp = os.path.join(now_dir, "TEMP") +shutil.rmtree(tmp, ignore_errors=True) +shutil.rmtree("%s/runtime/Lib/site-packages/infer_pack" % (now_dir), ignore_errors=True) +shutil.rmtree("%s/runtime/Lib/site-packages/uvr5_pack" % (now_dir), ignore_errors=True) +os.makedirs(tmp, exist_ok=True) +os.makedirs(os.path.join(now_dir, "logs"), exist_ok=True) +os.makedirs(os.path.join(now_dir, "assets/weights"), exist_ok=True) +os.environ["TEMP"] = tmp +warnings.filterwarnings("ignore") +torch.manual_seed(114514) + + +load_dotenv() +config = Config() +vc = VC(config) + +if config.dml == True: + + def forward_dml(ctx, x, scale): + ctx.scale = scale + res = x.clone().detach() + return res + + fairseq.modules.grad_multiply.GradMultiply.forward = forward_dml +i18n = I18nAuto() +logger.info(i18n) +# 判断是否有能用来训练和加速推理的N卡 +ngpu = torch.cuda.device_count() +gpu_infos = [] +mem = [] +if_gpu_ok = False + +if torch.cuda.is_available() or ngpu != 0: + for i in range(ngpu): + gpu_name = torch.cuda.get_device_name(i) + if any( + value in gpu_name.upper() + for value in [ + "10", + "16", + "20", + "30", + "40", + "A2", + "A3", + "A4", + "P4", + "A50", + "500", + "A60", + "70", + "80", + "90", + "M4", + "T4", + "TITAN", + ] + ): + # A10#A100#V100#A40#P40#M40#K80#A4500 + if_gpu_ok = True # 至少有一张能用的N卡 + gpu_infos.append("%s\t%s" % (i, gpu_name)) + mem.append( + int( + torch.cuda.get_device_properties(i).total_memory + / 1024 + / 1024 + / 1024 + + 0.4 + ) + ) +if if_gpu_ok and len(gpu_infos) > 0: + gpu_info = "\n".join(gpu_infos) + default_batch_size = min(mem) // 2 +else: + gpu_info = i18n("很遗憾您这没有能用的显卡来支持您训练") + default_batch_size = 1 +gpus = "-".join([i[0] for i in gpu_infos]) + + +class ToolButton(gr.Button, gr.components.FormComponent): + """Small button with single emoji as text, fits inside gradio forms""" + + def __init__(self, **kwargs): + super().__init__(variant="tool", **kwargs) + + def get_block_name(self): + return "button" + + +weight_root = os.getenv("weight_root") +weight_uvr5_root = os.getenv("weight_uvr5_root") +index_root = os.getenv("index_root") + +names = [] +for name in os.listdir(weight_root): + if name.endswith(".pth"): + names.append(name) +index_paths = [] +for root, dirs, files in os.walk(index_root, topdown=False): + for name in files: + if name.endswith(".index") and "trained" not in name: + index_paths.append("%s/%s" % (root, name)) +uvr5_names = [] +for name in os.listdir(weight_uvr5_root): + if name.endswith(".pth") or "onnx" in name: + uvr5_names.append(name.replace(".pth", "")) + + +def change_choices(): + names = [] + for name in os.listdir(weight_root): + if name.endswith(".pth"): + names.append(name) + index_paths = [] + for root, dirs, files in os.walk(index_root, topdown=False): + for name in files: + if name.endswith(".index") and "trained" not in name: + index_paths.append("%s/%s" % (root, name)) + audio_files=[] + for filename in os.listdir("./audios"): + if filename.endswith(('.wav','.mp3','.ogg')): + audio_files.append('./audios/'+filename) + return {"choices": sorted(names), "__type__": "update"}, { + "choices": sorted(index_paths), + "__type__": "update", + }, {"choices": sorted(audio_files), "__type__": "update"} + +def clean(): + return {"value": "", "__type__": "update"} + + +def export_onnx(): + from infer.modules.onnx.export import export_onnx as eo + + eo() + + +sr_dict = { + "32k": 32000, + "40k": 40000, + "48k": 48000, +} + + +def if_done(done, p): + while 1: + if p.poll() is None: + sleep(0.5) + else: + break + done[0] = True + + +def if_done_multi(done, ps): + while 1: + # poll==None代表进程未结束 + # 只要有一个进程未结束都不停 + flag = 1 + for p in ps: + if p.poll() is None: + flag = 0 + sleep(0.5) + break + if flag == 1: + break + done[0] = True + + +def preprocess_dataset(trainset_dir, exp_dir, sr, n_p): + sr = sr_dict[sr] + os.makedirs("%s/logs/%s" % (now_dir, exp_dir), exist_ok=True) + f = open("%s/logs/%s/preprocess.log" % (now_dir, exp_dir), "w") + f.close() + per = 3.0 if config.is_half else 3.7 + cmd = '"%s" infer/modules/train/preprocess.py "%s" %s %s "%s/logs/%s" %s %.1f' % ( + config.python_cmd, + trainset_dir, + sr, + n_p, + now_dir, + exp_dir, + config.noparallel, + per, + ) + logger.info(cmd) + p = Popen(cmd, shell=True) # , stdin=PIPE, stdout=PIPE,stderr=PIPE,cwd=now_dir + ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 + done = [False] + threading.Thread( + target=if_done, + args=( + done, + p, + ), + ).start() + while 1: + with open("%s/logs/%s/preprocess.log" % (now_dir, exp_dir), "r") as f: + yield (f.read()) + sleep(1) + if done[0]: + break + with open("%s/logs/%s/preprocess.log" % (now_dir, exp_dir), "r") as f: + log = f.read() + logger.info(log) + yield log + + +# but2.click(extract_f0,[gpus6,np7,f0method8,if_f0_3,trainset_dir4],[info2]) +def extract_f0_feature(gpus, n_p, f0method, if_f0, exp_dir, version19, gpus_rmvpe): + gpus = gpus.split("-") + os.makedirs("%s/logs/%s" % (now_dir, exp_dir), exist_ok=True) + f = open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "w") + f.close() + if if_f0: + if f0method != "rmvpe_gpu": + cmd = ( + '"%s" infer/modules/train/extract/extract_f0_print.py "%s/logs/%s" %s %s' + % ( + config.python_cmd, + now_dir, + exp_dir, + n_p, + f0method, + ) + ) + logger.info(cmd) + p = Popen( + cmd, shell=True, cwd=now_dir + ) # , stdin=PIPE, stdout=PIPE,stderr=PIPE + ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 + done = [False] + threading.Thread( + target=if_done, + args=( + done, + p, + ), + ).start() + else: + if gpus_rmvpe != "-": + gpus_rmvpe = gpus_rmvpe.split("-") + leng = len(gpus_rmvpe) + ps = [] + for idx, n_g in enumerate(gpus_rmvpe): + cmd = ( + '"%s" infer/modules/train/extract/extract_f0_rmvpe.py %s %s %s "%s/logs/%s" %s ' + % ( + config.python_cmd, + leng, + idx, + n_g, + now_dir, + exp_dir, + config.is_half, + ) + ) + logger.info(cmd) + p = Popen( + cmd, shell=True, cwd=now_dir + ) # , shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=now_dir + ps.append(p) + ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 + done = [False] + threading.Thread( + target=if_done_multi, # + args=( + done, + ps, + ), + ).start() + else: + cmd = ( + config.python_cmd + + ' infer/modules/train/extract/extract_f0_rmvpe_dml.py "%s/logs/%s" ' + % ( + now_dir, + exp_dir, + ) + ) + logger.info(cmd) + p = Popen( + cmd, shell=True, cwd=now_dir + ) # , shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=now_dir + p.wait() + done = [True] + while 1: + with open( + "%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r" + ) as f: + yield (f.read()) + sleep(1) + if done[0]: + break + with open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r") as f: + log = f.read() + logger.info(log) + yield log + ####对不同part分别开多进程 + """ + n_part=int(sys.argv[1]) + i_part=int(sys.argv[2]) + i_gpu=sys.argv[3] + exp_dir=sys.argv[4] + os.environ["CUDA_VISIBLE_DEVICES"]=str(i_gpu) + """ + leng = len(gpus) + ps = [] + for idx, n_g in enumerate(gpus): + cmd = ( + '"%s" infer/modules/train/extract_feature_print.py %s %s %s %s "%s/logs/%s" %s' + % ( + config.python_cmd, + config.device, + leng, + idx, + n_g, + now_dir, + exp_dir, + version19, + ) + ) + logger.info(cmd) + p = Popen( + cmd, shell=True, cwd=now_dir + ) # , shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=now_dir + ps.append(p) + ###煞笔gr, popen read都非得全跑完了再一次性读取, 不用gr就正常读一句输出一句;只能额外弄出一个文本流定时读 + done = [False] + threading.Thread( + target=if_done_multi, + args=( + done, + ps, + ), + ).start() + while 1: + with open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r") as f: + yield (f.read()) + sleep(1) + if done[0]: + break + with open("%s/logs/%s/extract_f0_feature.log" % (now_dir, exp_dir), "r") as f: + log = f.read() + logger.info(log) + yield log + + +def get_pretrained_models(path_str, f0_str, sr2): + if_pretrained_generator_exist = os.access( + "assets/pretrained%s/%sG%s.pth" % (path_str, f0_str, sr2), os.F_OK + ) + if_pretrained_discriminator_exist = os.access( + "assets/pretrained%s/%sD%s.pth" % (path_str, f0_str, sr2), os.F_OK + ) + if not if_pretrained_generator_exist: + logger.warn( + "assets/pretrained%s/%sG%s.pth not exist, will not use pretrained model", + path_str, + f0_str, + sr2, + ) + if not if_pretrained_discriminator_exist: + logger.warn( + "assets/pretrained%s/%sD%s.pth not exist, will not use pretrained model", + path_str, + f0_str, + sr2, + ) + return ( + "assets/pretrained%s/%sG%s.pth" % (path_str, f0_str, sr2) + if if_pretrained_generator_exist + else "", + "assets/pretrained%s/%sD%s.pth" % (path_str, f0_str, sr2) + if if_pretrained_discriminator_exist + else "", + ) + + +def change_sr2(sr2, if_f0_3, version19): + path_str = "" if version19 == "v1" else "_v2" + f0_str = "f0" if if_f0_3 else "" + return get_pretrained_models(path_str, f0_str, sr2) + + +def change_version19(sr2, if_f0_3, version19): + path_str = "" if version19 == "v1" else "_v2" + if sr2 == "32k" and version19 == "v1": + sr2 = "40k" + to_return_sr2 = ( + {"choices": ["40k", "48k"], "__type__": "update", "value": sr2} + if version19 == "v1" + else {"choices": ["40k", "48k", "32k"], "__type__": "update", "value": sr2} + ) + f0_str = "f0" if if_f0_3 else "" + return ( + *get_pretrained_models(path_str, f0_str, sr2), + to_return_sr2, + ) + + +def change_f0(if_f0_3, sr2, version19): # f0method8,pretrained_G14,pretrained_D15 + path_str = "" if version19 == "v1" else "_v2" + return ( + {"visible": if_f0_3, "__type__": "update"}, + *get_pretrained_models(path_str, "f0", sr2), + ) + + +# but3.click(click_train,[exp_dir1,sr2,if_f0_3,save_epoch10,total_epoch11,batch_size12,if_save_latest13,pretrained_G14,pretrained_D15,gpus16]) +def click_train( + exp_dir1, + sr2, + if_f0_3, + spk_id5, + save_epoch10, + total_epoch11, + batch_size12, + if_save_latest13, + pretrained_G14, + pretrained_D15, + gpus16, + if_cache_gpu17, + if_save_every_weights18, + version19, +): + # 生成filelist + exp_dir = "%s/logs/%s" % (now_dir, exp_dir1) + os.makedirs(exp_dir, exist_ok=True) + gt_wavs_dir = "%s/0_gt_wavs" % (exp_dir) + feature_dir = ( + "%s/3_feature256" % (exp_dir) + if version19 == "v1" + else "%s/3_feature768" % (exp_dir) + ) + if if_f0_3: + f0_dir = "%s/2a_f0" % (exp_dir) + f0nsf_dir = "%s/2b-f0nsf" % (exp_dir) + names = ( + set([name.split(".")[0] for name in os.listdir(gt_wavs_dir)]) + & set([name.split(".")[0] for name in os.listdir(feature_dir)]) + & set([name.split(".")[0] for name in os.listdir(f0_dir)]) + & set([name.split(".")[0] for name in os.listdir(f0nsf_dir)]) + ) + else: + names = set([name.split(".")[0] for name in os.listdir(gt_wavs_dir)]) & set( + [name.split(".")[0] for name in os.listdir(feature_dir)] + ) + opt = [] + for name in names: + if if_f0_3: + opt.append( + "%s/%s.wav|%s/%s.npy|%s/%s.wav.npy|%s/%s.wav.npy|%s" + % ( + gt_wavs_dir.replace("\\", "\\\\"), + name, + feature_dir.replace("\\", "\\\\"), + name, + f0_dir.replace("\\", "\\\\"), + name, + f0nsf_dir.replace("\\", "\\\\"), + name, + spk_id5, + ) + ) + else: + opt.append( + "%s/%s.wav|%s/%s.npy|%s" + % ( + gt_wavs_dir.replace("\\", "\\\\"), + name, + feature_dir.replace("\\", "\\\\"), + name, + spk_id5, + ) + ) + fea_dim = 256 if version19 == "v1" else 768 + if if_f0_3: + for _ in range(2): + opt.append( + "%s/logs/mute/0_gt_wavs/mute%s.wav|%s/logs/mute/3_feature%s/mute.npy|%s/logs/mute/2a_f0/mute.wav.npy|%s/logs/mute/2b-f0nsf/mute.wav.npy|%s" + % (now_dir, sr2, now_dir, fea_dim, now_dir, now_dir, spk_id5) + ) + else: + for _ in range(2): + opt.append( + "%s/logs/mute/0_gt_wavs/mute%s.wav|%s/logs/mute/3_feature%s/mute.npy|%s" + % (now_dir, sr2, now_dir, fea_dim, spk_id5) + ) + shuffle(opt) + with open("%s/filelist.txt" % exp_dir, "w") as f: + f.write("\n".join(opt)) + logger.debug("Write filelist done") + # 生成config#无需生成config + # cmd = python_cmd + " train_nsf_sim_cache_sid_load_pretrain.py -e mi-test -sr 40k -f0 1 -bs 4 -g 0 -te 10 -se 5 -pg pretrained/f0G40k.pth -pd pretrained/f0D40k.pth -l 1 -c 0" + logger.info("Use gpus: %s", str(gpus16)) + if pretrained_G14 == "": + logger.info("No pretrained Generator") + if pretrained_D15 == "": + logger.info("No pretrained Discriminator") + if version19 == "v1" or sr2 == "40k": + config_path = "v1/%s.json" % sr2 + else: + config_path = "v2/%s.json" % sr2 + config_save_path = os.path.join(exp_dir, "config.json") + if not pathlib.Path(config_save_path).exists(): + with open(config_save_path, "w", encoding="utf-8") as f: + json.dump( + config.json_config[config_path], + f, + ensure_ascii=False, + indent=4, + sort_keys=True, + ) + f.write("\n") + if gpus16: + cmd = ( + '"%s" infer/modules/train/train.py -e "%s" -sr %s -f0 %s -bs %s -g %s -te %s -se %s %s %s -l %s -c %s -sw %s -v %s' + % ( + config.python_cmd, + exp_dir1, + sr2, + 1 if if_f0_3 else 0, + batch_size12, + gpus16, + total_epoch11, + save_epoch10, + "-pg %s" % pretrained_G14 if pretrained_G14 != "" else "", + "-pd %s" % pretrained_D15 if pretrained_D15 != "" else "", + 1 if if_save_latest13 == i18n("是") else 0, + 1 if if_cache_gpu17 == i18n("是") else 0, + 1 if if_save_every_weights18 == i18n("是") else 0, + version19, + ) + ) + else: + cmd = ( + '"%s" infer/modules/train/train.py -e "%s" -sr %s -f0 %s -bs %s -te %s -se %s %s %s -l %s -c %s -sw %s -v %s' + % ( + config.python_cmd, + exp_dir1, + sr2, + 1 if if_f0_3 else 0, + batch_size12, + total_epoch11, + save_epoch10, + "-pg %s" % pretrained_G14 if pretrained_G14 != "" else "", + "-pd %s" % pretrained_D15 if pretrained_D15 != "" else "", + 1 if if_save_latest13 == i18n("是") else 0, + 1 if if_cache_gpu17 == i18n("是") else 0, + 1 if if_save_every_weights18 == i18n("是") else 0, + version19, + ) + ) + logger.info(cmd) + p = Popen(cmd, shell=True, cwd=now_dir) + p.wait() + return "训练结束, 您可查看控制台训练日志或实验文件夹下的train.log" + + +# but4.click(train_index, [exp_dir1], info3) +def train_index(exp_dir1, version19): + # exp_dir = "%s/logs/%s" % (now_dir, exp_dir1) + exp_dir = "logs/%s" % (exp_dir1) + os.makedirs(exp_dir, exist_ok=True) + feature_dir = ( + "%s/3_feature256" % (exp_dir) + if version19 == "v1" + else "%s/3_feature768" % (exp_dir) + ) + if not os.path.exists(feature_dir): + return "请先进行特征提取!" + listdir_res = list(os.listdir(feature_dir)) + if len(listdir_res) == 0: + return "请先进行特征提取!" + infos = [] + npys = [] + for name in sorted(listdir_res): + phone = np.load("%s/%s" % (feature_dir, name)) + npys.append(phone) + big_npy = np.concatenate(npys, 0) + big_npy_idx = np.arange(big_npy.shape[0]) + np.random.shuffle(big_npy_idx) + big_npy = big_npy[big_npy_idx] + if big_npy.shape[0] > 2e5: + infos.append("Trying doing kmeans %s shape to 10k centers." % big_npy.shape[0]) + yield "\n".join(infos) + try: + big_npy = ( + MiniBatchKMeans( + n_clusters=10000, + verbose=True, + batch_size=256 * config.n_cpu, + compute_labels=False, + init="random", + ) + .fit(big_npy) + .cluster_centers_ + ) + except: + info = traceback.format_exc() + logger.info(info) + infos.append(info) + yield "\n".join(infos) + + np.save("%s/total_fea.npy" % exp_dir, big_npy) + n_ivf = min(int(16 * np.sqrt(big_npy.shape[0])), big_npy.shape[0] // 39) + infos.append("%s,%s" % (big_npy.shape, n_ivf)) + yield "\n".join(infos) + index = faiss.index_factory(256 if version19 == "v1" else 768, "IVF%s,Flat" % n_ivf) + # index = faiss.index_factory(256if version19=="v1"else 768, "IVF%s,PQ128x4fs,RFlat"%n_ivf) + infos.append("training") + yield "\n".join(infos) + index_ivf = faiss.extract_index_ivf(index) # + index_ivf.nprobe = 1 + index.train(big_npy) + faiss.write_index( + index, + "%s/trained_IVF%s_Flat_nprobe_%s_%s_%s.index" + % (exp_dir, n_ivf, index_ivf.nprobe, exp_dir1, version19), + ) + + infos.append("adding") + yield "\n".join(infos) + batch_size_add = 8192 + for i in range(0, big_npy.shape[0], batch_size_add): + index.add(big_npy[i : i + batch_size_add]) + faiss.write_index( + index, + "%s/added_IVF%s_Flat_nprobe_%s_%s_%s.index" + % (exp_dir, n_ivf, index_ivf.nprobe, exp_dir1, version19), + ) + infos.append( + "成功构建索引,added_IVF%s_Flat_nprobe_%s_%s_%s.index" + % (n_ivf, index_ivf.nprobe, exp_dir1, version19) + ) + # faiss.write_index(index, '%s/added_IVF%s_Flat_FastScan_%s.index'%(exp_dir,n_ivf,version19)) + # infos.append("成功构建索引,added_IVF%s_Flat_FastScan_%s.index"%(n_ivf,version19)) + yield "\n".join(infos) + + +# but5.click(train1key, [exp_dir1, sr2, if_f0_3, trainset_dir4, spk_id5, gpus6, np7, f0method8, save_epoch10, total_epoch11, batch_size12, if_save_latest13, pretrained_G14, pretrained_D15, gpus16, if_cache_gpu17], info3) +def train1key( + exp_dir1, + sr2, + if_f0_3, + trainset_dir4, + spk_id5, + np7, + f0method8, + save_epoch10, + total_epoch11, + batch_size12, + if_save_latest13, + pretrained_G14, + pretrained_D15, + gpus16, + if_cache_gpu17, + if_save_every_weights18, + version19, + gpus_rmvpe, +): + infos = [] + + def get_info_str(strr): + infos.append(strr) + return "\n".join(infos) + + ####### step1:处理数据 + yield get_info_str(i18n("step1:正在处理数据")) + [get_info_str(_) for _ in preprocess_dataset(trainset_dir4, exp_dir1, sr2, np7)] + + ####### step2a:提取音高 + yield get_info_str(i18n("step2:正在提取音高&正在提取特征")) + [ + get_info_str(_) + for _ in extract_f0_feature( + gpus16, np7, f0method8, if_f0_3, exp_dir1, version19, gpus_rmvpe + ) + ] + + ####### step3a:训练模型 + yield get_info_str(i18n("step3a:正在训练模型")) + click_train( + exp_dir1, + sr2, + if_f0_3, + spk_id5, + save_epoch10, + total_epoch11, + batch_size12, + if_save_latest13, + pretrained_G14, + pretrained_D15, + gpus16, + if_cache_gpu17, + if_save_every_weights18, + version19, + ) + yield get_info_str(i18n("训练结束, 您可查看控制台训练日志或实验文件夹下的train.log")) + + ####### step3b:训练索引 + [get_info_str(_) for _ in train_index(exp_dir1, version19)] + yield get_info_str(i18n("全流程结束!")) + + +# ckpt_path2.change(change_info_,[ckpt_path2],[sr__,if_f0__]) +def change_info_(ckpt_path): + if not os.path.exists(ckpt_path.replace(os.path.basename(ckpt_path), "train.log")): + return {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"} + try: + with open( + ckpt_path.replace(os.path.basename(ckpt_path), "train.log"), "r" + ) as f: + info = eval(f.read().strip("\n").split("\n")[0].split("\t")[-1]) + sr, f0 = info["sample_rate"], info["if_f0"] + version = "v2" if ("version" in info and info["version"] == "v2") else "v1" + return sr, str(f0), version + except: + traceback.print_exc() + return {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"} + + +F0GPUVisible = config.dml == False + + +def change_f0_method(f0method8): + if f0method8 == "rmvpe_gpu": + visible = F0GPUVisible + else: + visible = False + return {"visible": visible, "__type__": "update"} + +def find_model(): + if len(names) > 0: + vc.get_vc(sorted(names)[0],None,None) + return sorted(names)[0] + else: + try: + gr.Info("Do not forget to choose a model.") + except: + pass + return '' + +def find_audios(index=False): + audio_files=[] + if not os.path.exists('./audios'): os.mkdir("./audios") + for filename in os.listdir("./audios"): + if filename.endswith(('.wav','.mp3','.ogg')): + audio_files.append("./audios/"+filename) + if index: + if len(audio_files) > 0: return sorted(audio_files)[0] + else: return "" + elif len(audio_files) > 0: return sorted(audio_files) + else: return [] + +def get_index(): + if find_model() != '': + chosen_model=sorted(names)[0].split(".")[0] + logs_path="./logs/"+chosen_model + if os.path.exists(logs_path): + for file in os.listdir(logs_path): + if file.endswith(".index"): + return os.path.join(logs_path, file) + return '' + else: + return '' + +def get_indexes(): + indexes_list=[] + for dirpath, dirnames, filenames in os.walk("./logs/"): + for filename in filenames: + if filename.endswith(".index"): + indexes_list.append(os.path.join(dirpath,filename)) + if len(indexes_list) > 0: + return indexes_list + else: + return '' + +def save_wav(file): + try: + file_path=file.name + shutil.move(file_path,'./audios') + return './audios/'+os.path.basename(file_path) + except AttributeError: + try: + new_name = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")+'.wav' + new_path='./audios/'+new_name + shutil.move(file,new_path) + return new_path + except TypeError: + return None + +def download_from_url(url, model): + if url == '': + return "URL cannot be left empty." + if model =='': + return "You need to name your model. For example: My-Model" + url = url.strip() + zip_dirs = ["zips", "unzips"] + for directory in zip_dirs: + if os.path.exists(directory): + shutil.rmtree(directory) + os.makedirs("zips", exist_ok=True) + os.makedirs("unzips", exist_ok=True) + zipfile = model + '.zip' + zipfile_path = './zips/' + zipfile + try: + if "drive.google.com" in url: + subprocess.run(["gdown", url, "--fuzzy", "-O", zipfile_path]) + elif "mega.nz" in url: + m = Mega() + m.download_url(url, './zips') + else: + subprocess.run(["wget", url, "-O", zipfile_path]) + for filename in os.listdir("./zips"): + if filename.endswith(".zip"): + zipfile_path = os.path.join("./zips/",filename) + shutil.unpack_archive(zipfile_path, "./unzips", 'zip') + else: + return "No zipfile found." + for root, dirs, files in os.walk('./unzips'): + for file in files: + file_path = os.path.join(root, file) + if file.endswith(".index"): + os.mkdir(f'./logs/{model}') + shutil.copy2(file_path,f'./logs/{model}') + elif "G_" not in file and "D_" not in file and file.endswith(".pth"): + shutil.copy(file_path,f'./assets/weights/{model}.pth') + shutil.rmtree("zips") + shutil.rmtree("unzips") + return "Success." + except: + return "There's been an error." + +def upload_to_dataset(files, dir): + if dir == '': + dir = './dataset/'+datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.exists(dir): + os.makedirs(dir) + for file in files: + path=file.name + shutil.copy2(path,dir) + try: + gr.Info(i18n("处理数据")) + except: + pass + return i18n("处理数据"), {"value":dir,"__type__":"update"} + +def download_model_files(model): + model_found = False + index_found = False + if os.path.exists(f'./assets/weights/{model}.pth'): model_found = True + if os.path.exists(f'./logs/{model}'): + for file in os.listdir(f'./logs/{model}'): + if file.endswith('.index') and 'added' in file: + log_file = file + index_found = True + if model_found and index_found: + return [f'./assets/weights/{model}.pth', f'./logs/{model}/{log_file}'], "Done" + elif model_found and not index_found: + return f'./assets/weights/{model}.pth', "Could not find Index file." + elif index_found and not model_found: + return f'./logs/{model}/{log_file}', f'Make sure the Voice Name is correct. I could not find {model}.pth' + else: + return None, f'Could not find {model}.pth or corresponding Index file.' + +with gr.Blocks(title="🔊",theme=gr.themes.Base(primary_hue="rose",neutral_hue="zinc")) as app: + with gr.Row(): + gr.HTML("image") + with gr.Tabs(): + with gr.TabItem(i18n("模型推理")): + with gr.Row(): + sid0 = gr.Dropdown(label=i18n("推理音色"), choices=sorted(names), value=find_model()) + refresh_button = gr.Button(i18n("刷新音色列表和索引路径"), variant="primary") + #clean_button = gr.Button(i18n("卸载音色省显存"), variant="primary") + spk_item = gr.Slider( + minimum=0, + maximum=2333, + step=1, + label=i18n("请选择说话人id"), + value=0, + visible=False, + interactive=True, + ) + #clean_button.click( + # fn=clean, inputs=[], outputs=[sid0], api_name="infer_clean" + #) + vc_transform0 = gr.Number( + label=i18n("变调(整数, 半音数量, 升八度12降八度-12)"), value=0 + ) + but0 = gr.Button(i18n("转换"), variant="primary") + with gr.Row(): + with gr.Column(): + with gr.Row(): + dropbox = gr.File(label="Drop your audio here & hit the Reload button.") + with gr.Row(): + record_button=gr.Audio(source="microphone", label="OR Record audio.", type="filepath") + with gr.Row(): + input_audio0 = gr.Dropdown( + label=i18n("输入待处理音频文件路径(默认是正确格式示例)"), + value=find_audios(True), + choices=find_audios() + ) + record_button.change(fn=save_wav, inputs=[record_button], outputs=[input_audio0]) + dropbox.upload(fn=save_wav, inputs=[dropbox], outputs=[input_audio0]) + with gr.Column(): + with gr.Accordion(label=i18n("自动检测index路径,下拉式选择(dropdown)"), open=False): + file_index2 = gr.Dropdown( + label=i18n("自动检测index路径,下拉式选择(dropdown)"), + choices=get_indexes(), + interactive=True, + value=get_index() + ) + index_rate1 = gr.Slider( + minimum=0, + maximum=1, + label=i18n("检索特征占比"), + value=0.66, + interactive=True, + ) + vc_output2 = gr.Audio(label=i18n("输出音频(右下角三个点,点了可以下载)")) + with gr.Accordion(label=i18n("常规设置"), open=False): + f0method0 = gr.Radio( + label=i18n( + "选择音高提取算法,输入歌声可用pm提速,harvest低音好但巨慢无比,crepe效果好但吃GPU,rmvpe效果最好且微吃GPU" + ), + choices=["pm", "harvest", "crepe", "rmvpe"] + if config.dml == False + else ["pm", "harvest", "rmvpe"], + value="rmvpe", + interactive=True, + ) + filter_radius0 = gr.Slider( + minimum=0, + maximum=7, + label=i18n(">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音"), + value=3, + step=1, + interactive=True, + ) + resample_sr0 = gr.Slider( + minimum=0, + maximum=48000, + label=i18n("后处理重采样至最终采样率,0为不进行重采样"), + value=0, + step=1, + interactive=True, + visible=False + ) + rms_mix_rate0 = gr.Slider( + minimum=0, + maximum=1, + label=i18n("输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络"), + value=0.21, + interactive=True, + ) + protect0 = gr.Slider( + minimum=0, + maximum=0.5, + label=i18n( + "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果" + ), + value=0.33, + step=0.01, + interactive=True, + ) + file_index1 = gr.Textbox( + label=i18n("特征检索库文件路径,为空则使用下拉的选择结果"), + value="", + interactive=True, + visible=False + ) + refresh_button.click( + fn=change_choices, + inputs=[], + outputs=[sid0, file_index2, input_audio0], + api_name="infer_refresh", + ) + # file_big_npy1 = gr.Textbox( + # label=i18n("特征文件路径"), + # value="E:\\codes\py39\\vits_vc_gpu_train\\logs\\mi-test-1key\\total_fea.npy", + # interactive=True, + # ) + with gr.Row(): + f0_file = gr.File(label=i18n("F0曲线文件, 可选, 一行一个音高, 代替默认F0及升降调"), visible=False) + with gr.Row(): + vc_output1 = gr.Textbox(label=i18n("输出信息")) + but0.click( + vc.vc_single, + [ + spk_item, + input_audio0, + vc_transform0, + f0_file, + f0method0, + file_index1, + file_index2, + # file_big_npy1, + index_rate1, + filter_radius0, + resample_sr0, + rms_mix_rate0, + protect0, + ], + [vc_output1, vc_output2], + api_name="infer_convert", + ) + with gr.Row(): + with gr.Accordion(open=False, label=i18n("批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ")): + with gr.Row(): + opt_input = gr.Textbox(label=i18n("指定输出文件夹"), value="opt") + vc_transform1 = gr.Number( + label=i18n("变调(整数, 半音数量, 升八度12降八度-12)"), value=0 + ) + f0method1 = gr.Radio( + label=i18n( + "选择音高提���算法,输入歌声可用pm提速,harvest低音好但巨慢无比,crepe效果好但吃GPU,rmvpe效果最好且微吃GPU" + ), + choices=["pm", "harvest", "crepe", "rmvpe"] + if config.dml == False + else ["pm", "harvest", "rmvpe"], + value="pm", + interactive=True, + ) + with gr.Row(): + filter_radius1 = gr.Slider( + minimum=0, + maximum=7, + label=i18n(">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音"), + value=3, + step=1, + interactive=True, + visible=False + ) + with gr.Row(): + file_index3 = gr.Textbox( + label=i18n("特征检索库文件路径,为空则使用下拉的选择结果"), + value="", + interactive=True, + visible=False + ) + file_index4 = gr.Dropdown( + label=i18n("自动检测index路径,下拉式选择(dropdown)"), + choices=sorted(index_paths), + interactive=True, + visible=False + ) + refresh_button.click( + fn=lambda: change_choices()[1], + inputs=[], + outputs=file_index4, + api_name="infer_refresh_batch", + ) + # file_big_npy2 = gr.Textbox( + # label=i18n("特征文件路径"), + # value="E:\\codes\\py39\\vits_vc_gpu_train\\logs\\mi-test-1key\\total_fea.npy", + # interactive=True, + # ) + index_rate2 = gr.Slider( + minimum=0, + maximum=1, + label=i18n("检索特征占比"), + value=1, + interactive=True, + visible=False + ) + with gr.Row(): + resample_sr1 = gr.Slider( + minimum=0, + maximum=48000, + label=i18n("后处理重采样至最终采样率,0为不进行重采样"), + value=0, + step=1, + interactive=True, + visible=False + ) + rms_mix_rate1 = gr.Slider( + minimum=0, + maximum=1, + label=i18n("输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络"), + value=0.21, + interactive=True, + ) + protect1 = gr.Slider( + minimum=0, + maximum=0.5, + label=i18n( + "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果" + ), + value=0.33, + step=0.01, + interactive=True, + ) + with gr.Row(): + dir_input = gr.Textbox( + label=i18n("输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)"), + value="./audios", + ) + inputs = gr.File( + file_count="multiple", label=i18n("也可批量输入音频文件, 二选一, 优先读文件夹") + ) + with gr.Row(): + format1 = gr.Radio( + label=i18n("导出文件格式"), + choices=["wav", "flac", "mp3", "m4a"], + value="wav", + interactive=True, + ) + but1 = gr.Button(i18n("转换"), variant="primary") + vc_output3 = gr.Textbox(label=i18n("输出信息")) + but1.click( + vc.vc_multi, + [ + spk_item, + dir_input, + opt_input, + inputs, + vc_transform1, + f0method1, + file_index1, + file_index2, + # file_big_npy2, + index_rate1, + filter_radius1, + resample_sr1, + rms_mix_rate1, + protect1, + format1, + ], + [vc_output3], + api_name="infer_convert_batch", + ) + sid0.change( + fn=vc.get_vc, + inputs=[sid0, protect0, protect1], + outputs=[spk_item, protect0, protect1, file_index2, file_index4], + ) + with gr.TabItem("Download Model"): + with gr.Row(): + url=gr.Textbox(label="Enter the URL to the Model:") + with gr.Row(): + model = gr.Textbox(label="Name your model:") + download_button=gr.Button("Download") + with gr.Row(): + status_bar=gr.Textbox(label="") + download_button.click(fn=download_from_url, inputs=[url, model], outputs=[status_bar]) + with gr.Row(): + gr.Markdown( + """ + ❤️ If you use this and like it, help me keep it.❤️ + https://paypal.me/lesantillan + """ + ) + with gr.TabItem(i18n("训练")): + with gr.Row(): + with gr.Column(): + exp_dir1 = gr.Textbox(label=i18n("输入实验名"), value="My-Voice") + np7 = gr.Slider( + minimum=0, + maximum=config.n_cpu, + step=1, + label=i18n("提取音高和处理数据使用的CPU进程数"), + value=int(np.ceil(config.n_cpu / 1.5)), + interactive=True, + ) + sr2 = gr.Radio( + label=i18n("目标采样率"), + choices=["40k", "48k"], + value="40k", + interactive=True, + visible=False + ) + if_f0_3 = gr.Radio( + label=i18n("模型是否带音高指导(唱歌一定要, 语音可以不要)"), + choices=[True, False], + value=True, + interactive=True, + visible=False + ) + version19 = gr.Radio( + label=i18n("版本"), + choices=["v1", "v2"], + value="v2", + interactive=True, + visible=False, + ) + trainset_dir4 = gr.Textbox( + label=i18n("输入训练文件夹路径"), value='./dataset/'+datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + ) + easy_uploader = gr.Files(label=i18n("也可批量输入音频文件, 二选一, 优先读文件夹"),file_types=['audio']) + but1 = gr.Button(i18n("处理数据"), variant="primary") + info1 = gr.Textbox(label=i18n("输出信息"), value="") + easy_uploader.upload(fn=upload_to_dataset, inputs=[easy_uploader, trainset_dir4], outputs=[info1, trainset_dir4]) + gpus6 = gr.Textbox( + label=i18n("以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2"), + value=gpus, + interactive=True, + visible=F0GPUVisible, + ) + gpu_info9 = gr.Textbox( + label=i18n("显卡信息"), value=gpu_info, visible=F0GPUVisible + ) + spk_id5 = gr.Slider( + minimum=0, + maximum=4, + step=1, + label=i18n("请指定说话人id"), + value=0, + interactive=True, + visible=False + ) + but1.click( + preprocess_dataset, + [trainset_dir4, exp_dir1, sr2, np7], + [info1], + api_name="train_preprocess", + ) + with gr.Column(): + f0method8 = gr.Radio( + label=i18n( + "选择音高提取算法:输入歌声可用pm提速,高质量语音但CPU差可用dio提速,harvest质量更好但慢,rmvpe效果最好且微吃CPU/GPU" + ), + choices=["pm", "harvest", "dio", "rmvpe", "rmvpe_gpu"], + value="rmvpe_gpu", + interactive=True, + ) + gpus_rmvpe = gr.Textbox( + label=i18n( + "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程" + ), + value="%s-%s" % (gpus, gpus), + interactive=True, + visible=F0GPUVisible, + ) + but2 = gr.Button(i18n("特征提取"), variant="primary") + info2 = gr.Textbox(label=i18n("输出信息"), value="", max_lines=8) + f0method8.change( + fn=change_f0_method, + inputs=[f0method8], + outputs=[gpus_rmvpe], + ) + but2.click( + extract_f0_feature, + [ + gpus6, + np7, + f0method8, + if_f0_3, + exp_dir1, + version19, + gpus_rmvpe, + ], + [info2], + api_name="train_extract_f0_feature", + ) + with gr.Column(): + total_epoch11 = gr.Slider( + minimum=2, + maximum=1000, + step=1, + label=i18n("总训练轮数total_epoch"), + value=150, + interactive=True, + ) + gpus16 = gr.Textbox( + label=i18n("以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2"), + value="0", + interactive=True, + visible=True + ) + but3 = gr.Button(i18n("训练模型"), variant="primary") + but4 = gr.Button(i18n("训练特征索引"), variant="primary") + info3 = gr.Textbox(label=i18n("输出信息"), value="", max_lines=10) + with gr.Accordion(label=i18n("常规设置"), open=False): + save_epoch10 = gr.Slider( + minimum=1, + maximum=50, + step=1, + label=i18n("保存频率save_every_epoch"), + value=25, + interactive=True, + ) + batch_size12 = gr.Slider( + minimum=1, + maximum=40, + step=1, + label=i18n("每张显卡的batch_size"), + value=default_batch_size, + interactive=True, + ) + if_save_latest13 = gr.Radio( + label=i18n("是否仅保存最新的ckpt文件以节省硬盘空间"), + choices=[i18n("是"), i18n("否")], + value=i18n("是"), + interactive=True, + visible=False + ) + if_cache_gpu17 = gr.Radio( + label=i18n( + "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速" + ), + choices=[i18n("是"), i18n("否")], + value=i18n("否"), + interactive=True, + ) + if_save_every_weights18 = gr.Radio( + label=i18n("是否在每次保存时间点将最终小模型保存至weights文件夹"), + choices=[i18n("是"), i18n("否")], + value=i18n("是"), + interactive=True, + ) + with gr.Row(): + download_model = gr.Button('5.Download Model') + with gr.Row(): + model_files = gr.Files(label='Your Model and Index file can be downloaded here:') + download_model.click(fn=download_model_files, inputs=[exp_dir1], outputs=[model_files, info3]) + with gr.Row(): + pretrained_G14 = gr.Textbox( + label=i18n("加载预训练底模G路径"), + value="assets/pretrained_v2/f0G40k.pth", + interactive=True, + visible=False + ) + pretrained_D15 = gr.Textbox( + label=i18n("加载预训练底模D路径"), + value="assets/pretrained_v2/f0D40k.pth", + interactive=True, + visible=False + ) + sr2.change( + change_sr2, + [sr2, if_f0_3, version19], + [pretrained_G14, pretrained_D15], + ) + version19.change( + change_version19, + [sr2, if_f0_3, version19], + [pretrained_G14, pretrained_D15, sr2], + ) + if_f0_3.change( + change_f0, + [if_f0_3, sr2, version19], + [f0method8, pretrained_G14, pretrained_D15], + ) + with gr.Row(): + but5 = gr.Button(i18n("一键训练"), variant="primary", visible=False) + but3.click( + click_train, + [ + exp_dir1, + sr2, + if_f0_3, + spk_id5, + save_epoch10, + total_epoch11, + batch_size12, + if_save_latest13, + pretrained_G14, + pretrained_D15, + gpus16, + if_cache_gpu17, + if_save_every_weights18, + version19, + ], + info3, + api_name="train_start", + ) + but4.click(train_index, [exp_dir1, version19], info3) + but5.click( + train1key, + [ + exp_dir1, + sr2, + if_f0_3, + trainset_dir4, + spk_id5, + np7, + f0method8, + save_epoch10, + total_epoch11, + batch_size12, + if_save_latest13, + pretrained_G14, + pretrained_D15, + gpus16, + if_cache_gpu17, + if_save_every_weights18, + version19, + gpus_rmvpe, + ], + info3, + api_name="train_start_all", + ) + + if config.iscolab: + app.queue(concurrency_count=511, max_size=1022).launch(share=True) + else: + app.queue(concurrency_count=511, max_size=1022).launch( + server_name="0.0.0.0", + inbrowser=not config.noautoopen, + server_port=config.listen_port, + quiet=True, + )