From ab2a5708b08d270cdf8ac5fbf0a21a7528ec8d98 Mon Sep 17 00:00:00 2001 From: DeiantV Date: Thu, 24 Aug 2023 17:18:01 -0500 Subject: [PATCH] Revert "Delete All Again" This reverts commit a47df9198cc51cf527c8d186289aa3be9d71ea5f. --- .gitignore | 42 + Dockerfile | 13 + Fixes/local_fixes.py | 144 + Fixes/tensor-launch.py | 15 + LICENSE | 22 + LazyImport.py | 13 + MDXNet.py | 272 ++ ...4\250\345\272\223\345\215\217\350\256\256" | 45 + Makefile | 63 + README.md | 53 + Retrieval_based_Voice_Conversion_WebUI.ipynb | 381 ++ ...eval_based_Voice_Conversion_WebUI_v2.ipynb | 401 ++ app.py | 319 ++ audio-outputs/readme.txt | 1 + audios/.gitignore | 0 avoid-shutdown.ipynb | 60 + config.py | 213 + configs/32k.json | 46 + configs/32k_v2.json | 46 + configs/40k.json | 46 + configs/48k.json | 46 + configs/48k_v2.json | 46 + csvdb/stop.csv | 1 + docs/README.en.md | 110 + docs/README.ja.md | 104 + docs/README.ko.han.md | 100 + docs/README.ko.md | 112 + docs/faiss_tips_en.md | 102 + docs/faiss_tips_ja.md | 101 + docs/faiss_tips_ko.md | 132 + docs/faq.md | 89 + docs/faq_en.md | 95 + docs/training_tips_en.md | 65 + docs/training_tips_ja.md | 64 + docs/training_tips_ko.md | 53 + ...0\346\230\223\346\225\231\347\250\213.doc" | Bin 0 -> 602624 bytes easy_infer.py | 1503 +++++++ environment_dml.yaml | 186 + extract_f0_print.py | 294 ++ extract_feature_print.py | 123 + extract_locale.py | 34 + ...ur formantshift presets here as a txt file | 0 formantshiftcfg/f2m.txt | 2 + formantshiftcfg/m2f.txt | 2 + formantshiftcfg/random.txt | 2 + go-realtime-gui-v0.bat | 2 + go-realtime-gui-v1.bat | 2 + go-web.bat | 32 + go-web.ps1 | 29 + gui_v0.py | 787 ++++ gui_v1.py | 637 +++ guidml.py | 710 +++ i18n.py | 43 + i18n/en_US.json | 227 + i18n/es_ES.json | 226 + i18n/it_IT.json | 130 + i18n/ja_JP.json | 126 + i18n/locale_diff.py | 45 + i18n/ru-RU.json | 130 + i18n/tr_TR.json | 130 + i18n/zh_CN.json | 132 + i18n/zh_HK.json | 132 + i18n/zh_SG.json | 132 + i18n/zh_TW.json | 132 + icon.png | Bin 0 -> 21150 bytes infer-web.py | 2559 +++++++++++ infer_batch_rvc.py | 215 + infer_uvr5.py | 363 ++ inference-presets.json | 20 + install_Applio.bat | 206 + lib/globals/globals.py | 5 + lib/infer_pack/attentions.py | 417 ++ lib/infer_pack/commons.py | 166 + lib/infer_pack/models.py | 1142 +++++ lib/infer_pack/models_dml.py | 1124 +++++ lib/infer_pack/models_onnx.py | 819 ++++ lib/infer_pack/modules.py | 522 +++ .../modules/F0Predictor/DioF0Predictor.py | 90 + .../modules/F0Predictor/F0Predictor.py | 16 + .../modules/F0Predictor/HarvestF0Predictor.py | 86 + .../modules/F0Predictor/PMF0Predictor.py | 97 + .../modules/F0Predictor/__init__.py | 0 lib/infer_pack/onnx_inference.py | 145 + lib/infer_pack/transforms.py | 209 + lib/uvr5_pack/lib_v5/dataset.py | 183 + lib/uvr5_pack/lib_v5/layers.py | 118 + lib/uvr5_pack/lib_v5/layers_123812KB .py | 118 + lib/uvr5_pack/lib_v5/layers_123821KB.py | 118 + lib/uvr5_pack/lib_v5/layers_33966KB.py | 126 + lib/uvr5_pack/lib_v5/layers_537227KB.py | 126 + lib/uvr5_pack/lib_v5/layers_537238KB.py | 126 + lib/uvr5_pack/lib_v5/layers_new.py | 125 + lib/uvr5_pack/lib_v5/model_param_init.py | 69 + .../modelparams/1band_sr16000_hl512.json | 19 + .../modelparams/1band_sr32000_hl512.json | 19 + .../modelparams/1band_sr33075_hl384.json | 19 + .../modelparams/1band_sr44100_hl1024.json | 19 + .../modelparams/1band_sr44100_hl256.json | 19 + .../modelparams/1band_sr44100_hl512.json | 19 + .../modelparams/1band_sr44100_hl512_cut.json | 19 + .../lib_v5/modelparams/2band_32000.json | 30 + .../lib_v5/modelparams/2band_44100_lofi.json | 30 + .../lib_v5/modelparams/2band_48000.json | 30 + .../lib_v5/modelparams/3band_44100.json | 42 + .../lib_v5/modelparams/3band_44100_mid.json | 43 + .../lib_v5/modelparams/3band_44100_msb2.json | 43 + .../lib_v5/modelparams/4band_44100.json | 54 + .../lib_v5/modelparams/4band_44100_mid.json | 55 + .../lib_v5/modelparams/4band_44100_msb.json | 55 + .../lib_v5/modelparams/4band_44100_msb2.json | 55 + .../modelparams/4band_44100_reverse.json | 55 + .../lib_v5/modelparams/4band_44100_sw.json | 55 + .../lib_v5/modelparams/4band_v2.json | 54 + .../lib_v5/modelparams/4band_v2_sn.json | 55 + .../lib_v5/modelparams/4band_v3.json | 54 + .../lib_v5/modelparams/ensemble.json | 43 + lib/uvr5_pack/lib_v5/nets.py | 123 + lib/uvr5_pack/lib_v5/nets_123812KB.py | 122 + lib/uvr5_pack/lib_v5/nets_123821KB.py | 122 + lib/uvr5_pack/lib_v5/nets_33966KB.py | 122 + lib/uvr5_pack/lib_v5/nets_537227KB.py | 123 + lib/uvr5_pack/lib_v5/nets_537238KB.py | 123 + lib/uvr5_pack/lib_v5/nets_61968KB.py | 122 + lib/uvr5_pack/lib_v5/nets_new.py | 132 + lib/uvr5_pack/lib_v5/spec_utils.py | 667 +++ lib/uvr5_pack/name_params.json | 263 ++ lib/uvr5_pack/utils.py | 120 + logs/mute/0_gt_wavs/mute32k.wav | Bin 0 -> 192078 bytes logs/mute/0_gt_wavs/mute40k.wav | Bin 0 -> 240078 bytes logs/mute/0_gt_wavs/mute48k.wav | Bin 0 -> 288078 bytes logs/mute/1_16k_wavs/mute.wav | Bin 0 -> 96078 bytes logs/mute/2a_f0/mute.wav.npy | Bin 0 -> 1332 bytes logs/mute/2b-f0nsf/mute.wav.npy | Bin 0 -> 2536 bytes logs/mute/3_feature256/mute.npy | Bin 0 -> 152704 bytes logs/mute/3_feature768/mute.npy | Bin 0 -> 457856 bytes mangio_utils/Readme.txt | 1 + mangio_utils/donate.png | Bin 0 -> 30907 bytes mangio_utils/inference_batcher.py | 5 + mangio_utils/lol.png | Bin 0 -> 43167 bytes mangio_utils/segment-outputs/Readme.txt | 2 + my_utils.py | 99 + poetry.lock | 3881 +++++++++++++++++ pretrained/.gitignore | 2 + pretrained_v2/.gitignore | 2 + pyproject.toml | 62 + requirements-gpu.txt | 46 + requirements-win-for-realtime_vc_gui.txt | 29 + requirements.txt | 49 + rmvpe.py | 434 ++ run.sh | 153 + rvc_for_realtime.py | 297 ++ slicer2.py | 260 ++ stftpitchshift | Bin 0 -> 1822104 bytes stftpitchshift.exe | Bin 0 -> 275456 bytes tensorlowest.py | 123 + tools/dlmodels.bat | 348 ++ tools/dlmodels.sh | 546 +++ tools/infer/infer-pm-index256.py | 199 + tools/infer/train-index-v2.py | 72 + tools/infer/train-index.py | 36 + tools/infer/trans_weights.py | 16 + train/cmd.txt | 1 + train/data_utils.py | 512 +++ train/losses.py | 59 + train/mel_processing.py | 130 + train/process_ckpt.py | 259 ++ train/utils.py | 500 +++ train_nsf_sim_cache_sid_load_pretrain.py | 510 +++ trainset_preprocess_pipeline_print.py | 155 + uvr5_weights/.gitignore | 2 + vc_infer_pipeline.py | 594 +++ venv.sh | 1 + weights/.gitignore | 2 + 173 files changed, 30967 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Fixes/local_fixes.py create mode 100644 Fixes/tensor-launch.py create mode 100644 LICENSE create mode 100644 LazyImport.py create mode 100644 MDXNet.py create mode 100644 "MIT\345\215\217\350\256\256\346\232\250\347\233\270\345\205\263\345\274\225\347\224\250\345\272\223\345\215\217\350\256\256" create mode 100644 Makefile create mode 100644 README.md create mode 100644 Retrieval_based_Voice_Conversion_WebUI.ipynb create mode 100644 Retrieval_based_Voice_Conversion_WebUI_v2.ipynb create mode 100644 app.py create mode 100644 audio-outputs/readme.txt create mode 100644 audios/.gitignore create mode 100644 avoid-shutdown.ipynb create mode 100644 config.py create mode 100644 configs/32k.json create mode 100644 configs/32k_v2.json create mode 100644 configs/40k.json create mode 100644 configs/48k.json create mode 100644 configs/48k_v2.json create mode 100644 csvdb/stop.csv create mode 100644 docs/README.en.md create mode 100644 docs/README.ja.md create mode 100644 docs/README.ko.han.md create mode 100644 docs/README.ko.md create mode 100644 docs/faiss_tips_en.md create mode 100644 docs/faiss_tips_ja.md create mode 100644 docs/faiss_tips_ko.md create mode 100644 docs/faq.md create mode 100644 docs/faq_en.md create mode 100644 docs/training_tips_en.md create mode 100644 docs/training_tips_ja.md create mode 100644 docs/training_tips_ko.md create mode 100644 "docs/\345\260\217\347\231\275\347\256\200\346\230\223\346\225\231\347\250\213.doc" create mode 100644 easy_infer.py create mode 100644 environment_dml.yaml create mode 100644 extract_f0_print.py create mode 100644 extract_feature_print.py create mode 100644 extract_locale.py create mode 100644 formantshiftcfg/Put your formantshift presets here as a txt file create mode 100644 formantshiftcfg/f2m.txt create mode 100644 formantshiftcfg/m2f.txt create mode 100644 formantshiftcfg/random.txt create mode 100644 go-realtime-gui-v0.bat create mode 100644 go-realtime-gui-v1.bat create mode 100644 go-web.bat create mode 100644 go-web.ps1 create mode 100644 gui_v0.py create mode 100644 gui_v1.py create mode 100644 guidml.py create mode 100644 i18n.py create mode 100644 i18n/en_US.json create mode 100644 i18n/es_ES.json create mode 100644 i18n/it_IT.json create mode 100644 i18n/ja_JP.json create mode 100644 i18n/locale_diff.py create mode 100644 i18n/ru-RU.json create mode 100644 i18n/tr_TR.json create mode 100644 i18n/zh_CN.json create mode 100644 i18n/zh_HK.json create mode 100644 i18n/zh_SG.json create mode 100644 i18n/zh_TW.json create mode 100644 icon.png create mode 100644 infer-web.py create mode 100644 infer_batch_rvc.py create mode 100644 infer_uvr5.py create mode 100644 inference-presets.json create mode 100644 install_Applio.bat create mode 100644 lib/globals/globals.py create mode 100644 lib/infer_pack/attentions.py create mode 100644 lib/infer_pack/commons.py create mode 100644 lib/infer_pack/models.py create mode 100644 lib/infer_pack/models_dml.py create mode 100644 lib/infer_pack/models_onnx.py create mode 100644 lib/infer_pack/modules.py create mode 100644 lib/infer_pack/modules/F0Predictor/DioF0Predictor.py create mode 100644 lib/infer_pack/modules/F0Predictor/F0Predictor.py create mode 100644 lib/infer_pack/modules/F0Predictor/HarvestF0Predictor.py create mode 100644 lib/infer_pack/modules/F0Predictor/PMF0Predictor.py create mode 100644 lib/infer_pack/modules/F0Predictor/__init__.py create mode 100644 lib/infer_pack/onnx_inference.py create mode 100644 lib/infer_pack/transforms.py create mode 100644 lib/uvr5_pack/lib_v5/dataset.py create mode 100644 lib/uvr5_pack/lib_v5/layers.py create mode 100644 lib/uvr5_pack/lib_v5/layers_123812KB .py create mode 100644 lib/uvr5_pack/lib_v5/layers_123821KB.py create mode 100644 lib/uvr5_pack/lib_v5/layers_33966KB.py create mode 100644 lib/uvr5_pack/lib_v5/layers_537227KB.py create mode 100644 lib/uvr5_pack/lib_v5/layers_537238KB.py create mode 100644 lib/uvr5_pack/lib_v5/layers_new.py create mode 100644 lib/uvr5_pack/lib_v5/model_param_init.py create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr16000_hl512.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr32000_hl512.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr33075_hl384.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr44100_hl1024.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr44100_hl256.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr44100_hl512.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/1band_sr44100_hl512_cut.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/2band_32000.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/2band_44100_lofi.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/2band_48000.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/3band_44100.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/3band_44100_mid.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/3band_44100_msb2.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_44100.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_44100_mid.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_44100_msb.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_44100_msb2.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_44100_reverse.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_44100_sw.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_v2.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_v2_sn.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/4band_v3.json create mode 100644 lib/uvr5_pack/lib_v5/modelparams/ensemble.json create mode 100644 lib/uvr5_pack/lib_v5/nets.py create mode 100644 lib/uvr5_pack/lib_v5/nets_123812KB.py create mode 100644 lib/uvr5_pack/lib_v5/nets_123821KB.py create mode 100644 lib/uvr5_pack/lib_v5/nets_33966KB.py create mode 100644 lib/uvr5_pack/lib_v5/nets_537227KB.py create mode 100644 lib/uvr5_pack/lib_v5/nets_537238KB.py create mode 100644 lib/uvr5_pack/lib_v5/nets_61968KB.py create mode 100644 lib/uvr5_pack/lib_v5/nets_new.py create mode 100644 lib/uvr5_pack/lib_v5/spec_utils.py create mode 100644 lib/uvr5_pack/name_params.json create mode 100644 lib/uvr5_pack/utils.py create mode 100644 logs/mute/0_gt_wavs/mute32k.wav create mode 100644 logs/mute/0_gt_wavs/mute40k.wav create mode 100644 logs/mute/0_gt_wavs/mute48k.wav create mode 100644 logs/mute/1_16k_wavs/mute.wav create mode 100644 logs/mute/2a_f0/mute.wav.npy create mode 100644 logs/mute/2b-f0nsf/mute.wav.npy create mode 100644 logs/mute/3_feature256/mute.npy create mode 100644 logs/mute/3_feature768/mute.npy create mode 100644 mangio_utils/Readme.txt create mode 100644 mangio_utils/donate.png create mode 100644 mangio_utils/inference_batcher.py create mode 100644 mangio_utils/lol.png create mode 100644 mangio_utils/segment-outputs/Readme.txt create mode 100644 my_utils.py create mode 100644 poetry.lock create mode 100644 pretrained/.gitignore create mode 100644 pretrained_v2/.gitignore create mode 100644 pyproject.toml create mode 100644 requirements-gpu.txt create mode 100644 requirements-win-for-realtime_vc_gui.txt create mode 100644 requirements.txt create mode 100644 rmvpe.py create mode 100644 run.sh create mode 100644 rvc_for_realtime.py create mode 100644 slicer2.py create mode 100644 stftpitchshift create mode 100644 stftpitchshift.exe create mode 100644 tensorlowest.py create mode 100644 tools/dlmodels.bat create mode 100644 tools/dlmodels.sh create mode 100644 tools/infer/infer-pm-index256.py create mode 100644 tools/infer/train-index-v2.py create mode 100644 tools/infer/train-index.py create mode 100644 tools/infer/trans_weights.py create mode 100644 train/cmd.txt create mode 100644 train/data_utils.py create mode 100644 train/losses.py create mode 100644 train/mel_processing.py create mode 100644 train/process_ckpt.py create mode 100644 train/utils.py create mode 100644 train_nsf_sim_cache_sid_load_pretrain.py create mode 100644 trainset_preprocess_pipeline_print.py create mode 100644 uvr5_weights/.gitignore create mode 100644 vc_infer_pipeline.py create mode 100644 venv.sh create mode 100644 weights/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..4e622170b --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +.DS_Store +__pycache__ +/TEMP +/DATASETS +/RUNTIME +*.pyd +hubert_base.pt +.venv +alexforkINSTALL.bat +Changelog_CN.md +Changelog_EN.md +Changelog_KO.md +difdep.py +EasierGUI.py +envfilescheck.bat +export_onnx.py +export_onnx_old.py +ffmpeg.exe +ffprobe.exe +Fixes/Launch_Tensorboard.bat +Fixes/LOCAL_CREPE_FIX.bat +Fixes/local_fixes.py +Fixes/tensor-launch.py +gui.py +infer-web — backup.py +infer-webbackup.py +install_easy_dependencies.py +install_easyGUI.bat +installstft.bat +Launch_Tensorboard.bat +listdepend.bat +LOCAL_CREPE_FIX.bat +local_fixes.py +oldinfer.py +onnx_inference_demo.py +Praat.exe +requirementsNEW.txt +rmvpe.pt +run_easiergui.bat +tensor-launch.py +values1.json +使用需遵守的协议-LICENSE.txt \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..49f62d5f9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:1 + +FROM python:3.10-bullseye + +EXPOSE 7865 + +WORKDIR /app + +COPY . . + +RUN pip3 install -r requirements.txt + +CMD ["python3", "infer-web.py"] \ No newline at end of file diff --git a/Fixes/local_fixes.py b/Fixes/local_fixes.py new file mode 100644 index 000000000..e29d06efc --- /dev/null +++ b/Fixes/local_fixes.py @@ -0,0 +1,144 @@ +import os +import sys +import time +import shutil +import requests +import zipfile + +file_name2 = 'go-web.bat' +text_to_insert2 = """python infer-web.py --pycmd runtime\python.exe --port 7897 +pause""" + +with open(file_name2, 'w') as archivo: + archivo.write(text_to_insert2) +print(f"Se ha modificado el contenido de '{file_name2}'.") + +def insert_new_line(file_name, line_to_find, text_to_insert): + lines = [] + with open(file_name, 'r', encoding='utf-8') as read_obj: + lines = read_obj.readlines() + already_exists = False + with open(file_name + '.tmp', 'w', encoding='utf-8') as write_obj: + for i in range(len(lines)): + write_obj.write(lines[i]) + if lines[i].strip() == line_to_find: + # If next line exists and starts with sys.path.append, skip + if i+1 < len(lines) and lines[i+1].strip().startswith("sys.path.append"): + print('¡Ya estaba arreglado! Se salta añadir una línea...') + already_exists = True + break + else: + write_obj.write(text_to_insert + '\n') + # If no existing sys.path.append line was found, replace the original file + if not already_exists: + os.replace(file_name + '.tmp', file_name) + return True + else: + # If existing line was found, delete temporary file + os.remove(file_name + '.tmp') + return False + +def replace_in_file(file_name, old_text, new_text): + with open(file_name, 'r', encoding='utf-8') as file: + file_contents = file.read() + + if old_text in file_contents: + file_contents = file_contents.replace(old_text, new_text) + with open(file_name, 'w', encoding='utf-8') as file: + file.write(file_contents) + return True + + return False + +if __name__ == "__main__": + current_path = os.getcwd() + file_name = 'extract_f0_print.py' + line_to_find = 'import numpy as np, logging' + text_to_insert = "sys.path.append(r'" + current_path + "')" + + + success_1 = insert_new_line(file_name, line_to_find, text_to_insert) + if success_1: + print('¡La primera operación fue un éxito!') + else: + print('¡Se saltó la primera operación porque ya estaba arreglada!') + + file_name = 'infer-web.py' + old_text = 'with gr.Blocks(theme=gr.themes.Soft()) as app:' + new_text = 'with gr.Blocks() as app:' + + success_2 = replace_in_file(file_name, old_text, new_text) + if success_2: + print('¡La segunda operación fue un éxito!') + else: + print('¡La segunda operación se omitió porque ya estaba arreglada!') + + print('¡Correcciones locales exitosas! Ahora debería poder inferir y entrenar localmente en Applio RVC Fork.') + + time.sleep(5) + +def find_torchcrepe_directory(directory): + """ + Busca recursivamente la carpeta de mayor jerarquía denominada 'torchcrepe' dentro de un directorio. + Devuelve la ruta del directorio encontrado o Ninguno si no se encuentra. + """ + for root, dirs, files in os.walk(directory): + if 'torchcrepe' in dirs: + return os.path.join(root, 'torchcrepe') + return None + +def download_and_extract_torchcrepe(): + url = 'https://github.com/maxrmorrison/torchcrepe/archive/refs/heads/master.zip' + temp_dir = 'temp_torchcrepe' + destination_dir = os.getcwd() + + try: + torchcrepe_dir_path = os.path.join(destination_dir, 'torchcrepe') + + if os.path.exists(torchcrepe_dir_path): + print("Saltando la descarga de torchcrepe. La carpeta ya existe.") + return + + # Download the file + print("Iniciando la descarga de torchcrepe...") + response = requests.get(url) + + # Raise an error if the GET request was unsuccessful + response.raise_for_status() + print("Descarga finalizada.") + + # Save the downloaded file + zip_file_path = os.path.join(temp_dir, 'master.zip') + os.makedirs(temp_dir, exist_ok=True) + with open(zip_file_path, 'wb') as file: + file.write(response.content) + print(f"Archivo zip guardado en {zip_file_path}") + + # Extract the zip file + print("Extrayendo contenidos...") + with zipfile.ZipFile(zip_file_path, 'r') as zip_file: + zip_file.extractall(temp_dir) + print("Extracción finalizada.") + + # Locate the torchcrepe folder and move it to the destination directory + torchcrepe_dir = find_torchcrepe_directory(temp_dir) + if torchcrepe_dir: + shutil.move(torchcrepe_dir, destination_dir) + print(f"Se movió el directorio torchcrepe a {destination_dir}!") + else: + print("No se pudo localizar el directorio de torchcrepe.") + + except Exception as e: + print("Torchcrepe no descargado con éxito?", e) + + # Clean up temporary directory + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) + +# Run the function +download_and_extract_torchcrepe() + +temp_dir = 'temp_torchcrepe' + +if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) diff --git a/Fixes/tensor-launch.py b/Fixes/tensor-launch.py new file mode 100644 index 000000000..23f6107f8 --- /dev/null +++ b/Fixes/tensor-launch.py @@ -0,0 +1,15 @@ +import threading +import time +from tensorboard import program +import os + +log_path = "logs" + +if __name__ == "__main__": + tb = program.TensorBoard() + tb.configure(argv=[None, '--logdir', log_path]) + url = tb.launch() + print(f'Tensorboard can be accessed at: {url}') + + while True: + time.sleep(600) # Keep the main thread running \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..2b8d8ce41 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 liujing04 +Copyright (c) 2023 源文雨 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LazyImport.py b/LazyImport.py new file mode 100644 index 000000000..5bdb05ddd --- /dev/null +++ b/LazyImport.py @@ -0,0 +1,13 @@ +from importlib.util import find_spec, LazyLoader, module_from_spec +from sys import modules + +def lazyload(name): + if name in modules: + return modules[name] + else: + spec = find_spec(name) + loader = LazyLoader(spec.loader) + module = module_from_spec(spec) + modules[name] = module + loader.exec_module(module) + return module \ No newline at end of file diff --git a/MDXNet.py b/MDXNet.py new file mode 100644 index 000000000..9b7eb4384 --- /dev/null +++ b/MDXNet.py @@ -0,0 +1,272 @@ +import soundfile as sf +import torch, pdb, os, warnings, librosa +import numpy as np +import onnxruntime as ort +from tqdm import tqdm +import torch + +dim_c = 4 + + +class Conv_TDF_net_trim: + def __init__( + self, device, model_name, target_name, L, dim_f, dim_t, n_fft, hop=1024 + ): + super(Conv_TDF_net_trim, self).__init__() + + self.dim_f = dim_f + self.dim_t = 2**dim_t + self.n_fft = n_fft + self.hop = hop + self.n_bins = self.n_fft // 2 + 1 + self.chunk_size = hop * (self.dim_t - 1) + self.window = torch.hann_window(window_length=self.n_fft, periodic=True).to( + device + ) + self.target_name = target_name + self.blender = "blender" in model_name + + out_c = dim_c * 4 if target_name == "*" else dim_c + self.freq_pad = torch.zeros( + [1, out_c, self.n_bins - self.dim_f, self.dim_t] + ).to(device) + + self.n = L // 2 + + def stft(self, x): + x = x.reshape([-1, self.chunk_size]) + x = torch.stft( + x, + n_fft=self.n_fft, + hop_length=self.hop, + window=self.window, + center=True, + return_complex=True, + ) + x = torch.view_as_real(x) + x = x.permute([0, 3, 1, 2]) + x = x.reshape([-1, 2, 2, self.n_bins, self.dim_t]).reshape( + [-1, dim_c, self.n_bins, self.dim_t] + ) + return x[:, :, : self.dim_f] + + def istft(self, x, freq_pad=None): + freq_pad = ( + self.freq_pad.repeat([x.shape[0], 1, 1, 1]) + if freq_pad is None + else freq_pad + ) + x = torch.cat([x, freq_pad], -2) + c = 4 * 2 if self.target_name == "*" else 2 + x = x.reshape([-1, c, 2, self.n_bins, self.dim_t]).reshape( + [-1, 2, self.n_bins, self.dim_t] + ) + x = x.permute([0, 2, 3, 1]) + x = x.contiguous() + x = torch.view_as_complex(x) + x = torch.istft( + x, n_fft=self.n_fft, hop_length=self.hop, window=self.window, center=True + ) + return x.reshape([-1, c, self.chunk_size]) + + +def get_models(device, dim_f, dim_t, n_fft): + return Conv_TDF_net_trim( + device=device, + model_name="Conv-TDF", + target_name="vocals", + L=11, + dim_f=dim_f, + dim_t=dim_t, + n_fft=n_fft, + ) + + +warnings.filterwarnings("ignore") +cpu = torch.device("cpu") +if torch.cuda.is_available(): + device = torch.device("cuda:0") +elif torch.backends.mps.is_available(): + device = torch.device("mps") +else: + device = torch.device("cpu") + + +class Predictor: + def __init__(self, args): + self.args = args + self.model_ = get_models( + device=cpu, dim_f=args.dim_f, dim_t=args.dim_t, n_fft=args.n_fft + ) + self.model = ort.InferenceSession( + os.path.join(args.onnx, self.model_.target_name + ".onnx"), + providers=["CUDAExecutionProvider", "CPUExecutionProvider"], + ) + print("onnx load done") + + def demix(self, mix): + samples = mix.shape[-1] + margin = self.args.margin + chunk_size = self.args.chunks * 44100 + assert not margin == 0, "margin cannot be zero!" + if margin > chunk_size: + margin = chunk_size + + segmented_mix = {} + + if self.args.chunks == 0 or samples < chunk_size: + chunk_size = samples + + counter = -1 + for skip in range(0, samples, chunk_size): + counter += 1 + + s_margin = 0 if counter == 0 else margin + end = min(skip + chunk_size + margin, samples) + + start = skip - s_margin + + segmented_mix[skip] = mix[:, start:end].copy() + if end == samples: + break + + sources = self.demix_base(segmented_mix, margin_size=margin) + """ + mix:(2,big_sample) + segmented_mix:offset->(2,small_sample) + sources:(1,2,big_sample) + """ + return sources + + def demix_base(self, mixes, margin_size): + chunked_sources = [] + progress_bar = tqdm(total=len(mixes)) + progress_bar.set_description("Processing") + for mix in mixes: + cmix = mixes[mix] + sources = [] + n_sample = cmix.shape[1] + model = self.model_ + trim = model.n_fft // 2 + gen_size = model.chunk_size - 2 * trim + pad = gen_size - n_sample % gen_size + mix_p = np.concatenate( + (np.zeros((2, trim)), cmix, np.zeros((2, pad)), np.zeros((2, trim))), 1 + ) + mix_waves = [] + i = 0 + while i < n_sample + pad: + waves = np.array(mix_p[:, i : i + model.chunk_size]) + mix_waves.append(waves) + i += gen_size + mix_waves = torch.tensor(mix_waves, dtype=torch.float32).to(cpu) + with torch.no_grad(): + _ort = self.model + spek = model.stft(mix_waves) + if self.args.denoise: + spec_pred = ( + -_ort.run(None, {"input": -spek.cpu().numpy()})[0] * 0.5 + + _ort.run(None, {"input": spek.cpu().numpy()})[0] * 0.5 + ) + tar_waves = model.istft(torch.tensor(spec_pred)) + else: + tar_waves = model.istft( + torch.tensor(_ort.run(None, {"input": spek.cpu().numpy()})[0]) + ) + tar_signal = ( + tar_waves[:, :, trim:-trim] + .transpose(0, 1) + .reshape(2, -1) + .numpy()[:, :-pad] + ) + + start = 0 if mix == 0 else margin_size + end = None if mix == list(mixes.keys())[::-1][0] else -margin_size + if margin_size == 0: + end = None + sources.append(tar_signal[:, start:end]) + + progress_bar.update(1) + + chunked_sources.append(sources) + _sources = np.concatenate(chunked_sources, axis=-1) + # del self.model + progress_bar.close() + return _sources + + def prediction(self, m, vocal_root, others_root, format): + os.makedirs(vocal_root, exist_ok=True) + os.makedirs(others_root, exist_ok=True) + basename = os.path.basename(m) + mix, rate = librosa.load(m, mono=False, sr=44100) + if mix.ndim == 1: + mix = np.asfortranarray([mix, mix]) + mix = mix.T + sources = self.demix(mix.T) + opt = sources[0].T + if format in ["wav", "flac"]: + sf.write( + "%s/%s_main_vocal.%s" % (vocal_root, basename, format), mix - opt, rate + ) + sf.write("%s/%s_others.%s" % (others_root, basename, format), opt, rate) + else: + path_vocal = "%s/%s_main_vocal.wav" % (vocal_root, basename) + path_other = "%s/%s_others.wav" % (others_root, basename) + sf.write(path_vocal, mix - opt, rate) + sf.write(path_other, opt, rate) + if os.path.exists(path_vocal): + os.system( + "ffmpeg -i %s -vn %s -q:a 2 -y" + % (path_vocal, path_vocal[:-4] + ".%s" % format) + ) + if os.path.exists(path_other): + os.system( + "ffmpeg -i %s -vn %s -q:a 2 -y" + % (path_other, path_other[:-4] + ".%s" % format) + ) + + +class MDXNetDereverb: + def __init__(self, chunks): + self.onnx = "uvr5_weights/onnx_dereverb_By_FoxJoy" + self.shifts = 10 #'Predict with randomised equivariant stabilisation' + self.mixing = "min_mag" # ['default','min_mag','max_mag'] + self.chunks = chunks + self.margin = 44100 + self.dim_t = 9 + self.dim_f = 3072 + self.n_fft = 6144 + self.denoise = True + self.pred = Predictor(self) + + def _path_audio_(self, input, vocal_root, others_root, format): + self.pred.prediction(input, vocal_root, others_root, format) + + +if __name__ == "__main__": + dereverb = MDXNetDereverb(15) + from time import time as ttime + + t0 = ttime() + dereverb._path_audio_( + "雪雪伴奏对消HP5.wav", + "vocal", + "others", + ) + t1 = ttime() + print(t1 - t0) + + +""" + +runtime\python.exe MDXNet.py + +6G: +15/9:0.8G->6.8G +14:0.8G->6.5G +25:炸 + +half15:0.7G->6.6G,22.69s +fp32-15:0.7G->6.6G,20.85s + +""" diff --git "a/MIT\345\215\217\350\256\256\346\232\250\347\233\270\345\205\263\345\274\225\347\224\250\345\272\223\345\215\217\350\256\256" "b/MIT\345\215\217\350\256\256\346\232\250\347\233\270\345\205\263\345\274\225\347\224\250\345\272\223\345\215\217\350\256\256" new file mode 100644 index 000000000..dbb6c6d51 --- /dev/null +++ "b/MIT\345\215\217\350\256\256\346\232\250\347\233\270\345\205\263\345\274\225\347\224\250\345\272\223\345\215\217\350\256\256" @@ -0,0 +1,45 @@ +本软件及其相关代码以MIT协议开源,作者不对软件具备任何控制力,使用软件者、传播软件导出的声音者自负全责。 +如不认可该条款,则不能使用或引用软件包内任何代码和文件。 + +特此授予任何获得本软件和相关文档文件(以下简称“软件”)副本的人免费使用、复制、修改、合并、出版、分发、再授权和/或销售本软件的权利,以及授予本软件所提供的人使用本软件的权利,但须符合以下条件: +上述版权声明和本许可声明应包含在软件的所有副本或实质部分中。 +软件是“按原样”提供的,没有任何明示或暗示的保证,包括但不限于适销性、适用于特定目的和不侵权的保证。在任何情况下,作者或版权持有人均不承担因软件或软件的使用或其他交易而产生、产生或与之相关的任何索赔、损害赔偿或其他责任,无论是在合同诉讼、侵权诉讼还是其他诉讼中。 + + +The LICENCEs for related libraries are as follows. +相关引用库协议如下: + +ContentVec +https://github.com/auspicious3000/contentvec/blob/main/LICENSE +MIT License + +VITS +https://github.com/jaywalnut310/vits/blob/main/LICENSE +MIT License + +HIFIGAN +https://github.com/jik876/hifi-gan/blob/master/LICENSE +MIT License + +gradio +https://github.com/gradio-app/gradio/blob/main/LICENSE +Apache License 2.0 + +ffmpeg +https://github.com/FFmpeg/FFmpeg/blob/master/COPYING.LGPLv3 +https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2021-02-28-12-32/ffmpeg-n4.3.2-160-gfbb9368226-win64-lgpl-4.3.zip +LPGLv3 License +MIT License + +ultimatevocalremovergui +https://github.com/Anjok07/ultimatevocalremovergui/blob/master/LICENSE +https://github.com/yang123qwe/vocal_separation_by_uvr5 +MIT License + +audio-slicer +https://github.com/openvpi/audio-slicer/blob/main/LICENSE +MIT License + +PySimpleGUI +https://github.com/PySimpleGUI/PySimpleGUI/blob/master/license.txt +LPGLv3 License diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..44de020e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +.PHONY: +.ONESHELL: + +help: ## Show this help and exit + @grep -hE '^[A-Za-z0-9_ \-]*?:.*##.*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +install: ## Install dependencies (Do everytime you start up a paperspace machine) + apt-get -y install build-essential python3-dev ffmpeg + pip install --upgrade setuptools wheel + pip install --upgrade pip + pip install faiss-gpu fairseq gradio ffmpeg ffmpeg-python praat-parselmouth pyworld numpy==1.23.5 numba==0.56.4 librosa==0.9.1 + pip install -r requirements.txt + pip install --upgrade lxml + apt-get update + apt -y install -qq aria2 + +basev1: ## Download version 1 pre-trained models (Do only once after cloning the fork) + mkdir -p pretrained uvr5_weights + git pull + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D32k.pth -d pretrained -o D32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D40k.pth -d pretrained -o D40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D48k.pth -d pretrained -o D48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G32k.pth -d pretrained -o G32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G40k.pth -d pretrained -o G40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G48k.pth -d pretrained -o G48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D32k.pth -d pretrained -o f0D32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D40k.pth -d pretrained -o f0D40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D48k.pth -d pretrained -o f0D48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G32k.pth -d pretrained -o f0G32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G40k.pth -d pretrained -o f0G40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G48k.pth -d pretrained -o f0G48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP2-人声vocals+非人声instrumentals.pth -d uvr5_weights -o HP2-人声vocals+非人声instrumentals.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP5-主旋律人声vocals+其他instrumentals.pth -d uvr5_weights -o HP5-主旋律人声vocals+其他instrumentals.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/hubert_base.pt -d ./ -o hubert_base.pt + +basev2: ## Download version 2 pre-trained models (Do only once after cloning the fork) + mkdir -p pretrained_v2 uvr5_weights + git pull + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/D32k.pth -d pretrained_v2 -o D32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/D40k.pth -d pretrained_v2 -o D40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/D48k.pth -d pretrained_v2 -o D48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/G32k.pth -d pretrained_v2 -o G32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/G40k.pth -d pretrained_v2 -o G40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/G48k.pth -d pretrained_v2 -o G48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0D32k.pth -d pretrained_v2 -o f0D32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0D40k.pth -d pretrained_v2 -o f0D40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0D48k.pth -d pretrained_v2 -o f0D48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0G32k.pth -d pretrained_v2 -o f0G32k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0G40k.pth -d pretrained_v2 -o f0G40k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0G48k.pth -d pretrained_v2 -o f0G48k.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP2-人声vocals+非人声instrumentals.pth -d uvr5_weights -o HP2-人声vocals+非人声instrumentals.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP5-主旋律人声vocals+其他instrumentals.pth -d uvr5_weights -o HP5-主旋律人声vocals+其他instrumentals.pth + aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/hubert_base.pt -d ./ -o hubert_base.pt + +run-ui: ## Run the python GUI + python infer-web.py --paperspace --pycmd python + +run-cli: ## Run the python CLI + python infer-web.py --pycmd python --is_cli + +tensorboard: ## Start the tensorboard (Run on separate terminal) + echo https://tensorboard-$$(hostname).clg07azjl.paperspacegradient.com + tensorboard --logdir logs --bind_all \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..6c16d3c96 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +
+

🍏 Applio (Mangio-RVC-Fork)

+

+ Applio is a user-friendly fork of Mangio, designed to provide an intuitive interface, especially for newcomers. +

+
+ +
+

Links

+
+ +
+ Repository +
+ External Code +
+ Google Colab +
+ +
+

Credits

+
+ +
+ RVC +
+ Mangio-RVC-Fork +
+ ContentVec +
+ VITS +
+ HIFIGAN +
+ Gradio +
+ FFmpeg +
+ Ultimate Vocal Remover +
+ audio-slicer +
+ +
+

Contributors

+
+ +
+ + + + +
diff --git a/Retrieval_based_Voice_Conversion_WebUI.ipynb b/Retrieval_based_Voice_Conversion_WebUI.ipynb new file mode 100644 index 000000000..4890daf77 --- /dev/null +++ b/Retrieval_based_Voice_Conversion_WebUI.ipynb @@ -0,0 +1,381 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "private_outputs": true, + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU", + "gpuClass": "standard" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/Retrieval_based_Voice_Conversion_WebUI.ipynb)" + ], + "metadata": { + "id": "ZFFCx5J80SGa" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GmFP6bN9dvOq" + }, + "outputs": [], + "source": [ + "#@title 查看显卡\n", + "!nvidia-smi" + ] + }, + { + "cell_type": "code", + "source": [ + "#@title 安装依赖\n", + "!apt-get -y install build-essential python3-dev ffmpeg\n", + "!pip3 install --upgrade setuptools wheel\n", + "!pip3 install --upgrade pip\n", + "!pip3 install faiss-cpu==1.7.2 fairseq gradio==3.14.0 ffmpeg ffmpeg-python praat-parselmouth pyworld numpy==1.23.5 numba==0.56.4 librosa==0.9.2" + ], + "metadata": { + "id": "wjddIFr1oS3W" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 克隆仓库\n", + "\n", + "!git clone --depth=1 -b stable https://github.com/fumiama/Retrieval-based-Voice-Conversion-WebUI\n", + "%cd /content/Retrieval-based-Voice-Conversion-WebUI\n", + "!mkdir -p pretrained uvr5_weights" + ], + "metadata": { + "id": "ge_97mfpgqTm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 更新仓库(一般无需执行)\n", + "!git pull" + ], + "metadata": { + "id": "BLDEZADkvlw1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 安装aria2\n", + "!apt -y install -qq aria2" + ], + "metadata": { + "id": "pqE0PrnuRqI2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 下载底模\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o D32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o D40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o D48k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o G32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o G40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o G48k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0D32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0D40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0D48k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0G32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0G40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0G48k.pth" + ], + "metadata": { + "id": "UG3XpUwEomUz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 下载人声分离模型\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP2-人声vocals+非人声instrumentals.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/uvr5_weights -o HP2-人声vocals+非人声instrumentals.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP5-主旋律人声vocals+其他instrumentals.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/uvr5_weights -o HP5-主旋律人声vocals+其他instrumentals.pth" + ], + "metadata": { + "id": "HugjmZqZRuiF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 下载hubert_base\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/hubert_base.pt -d /content/Retrieval-based-Voice-Conversion-WebUI -o hubert_base.pt" + ], + "metadata": { + "id": "2RCaT9FTR0ej" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 挂载谷歌云盘\n", + "\n", + "from google.colab import drive\n", + "drive.mount('/content/drive')" + ], + "metadata": { + "id": "jwu07JgqoFON" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 从谷歌云盘加载打包好的数据集到/content/dataset\n", + "\n", + "#@markdown 数据集位置\n", + "DATASET = \"/content/drive/MyDrive/dataset/lulu20230327_32k.zip\" #@param {type:\"string\"}\n", + "\n", + "!mkdir -p /content/dataset\n", + "!unzip -d /content/dataset -B {DATASET}" + ], + "metadata": { + "id": "Mwk7Q0Loqzjx" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 重命名数据集中的重名文件\n", + "!ls -a /content/dataset/\n", + "!rename 's/(\\w+)\\.(\\w+)~(\\d*)/$1_$3.$2/' /content/dataset/*.*~*" + ], + "metadata": { + "id": "PDlFxWHWEynD" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 启动web\n", + "%cd /content/Retrieval-based-Voice-Conversion-WebUI\n", + "# %load_ext tensorboard\n", + "# %tensorboard --logdir /content/Retrieval-based-Voice-Conversion-WebUI/logs\n", + "!python3 infer-web.py --colab --pycmd python3" + ], + "metadata": { + "id": "7vh6vphDwO0b" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 手动将训练后的模型文件备份到谷歌云盘\n", + "#@markdown 需要自己查看logs文件夹下模型的文件名,手动修改下方命令末尾的文件名\n", + "\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 模型epoch\n", + "MODELEPOCH = 9600 #@param {type:\"integer\"}\n", + "\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth /content/drive/MyDrive/{MODELNAME}_D_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth /content/drive/MyDrive/{MODELNAME}_G_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/added_*.index /content/drive/MyDrive/\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/total_*.npy /content/drive/MyDrive/\n", + "\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/weights/{MODELNAME}.pth /content/drive/MyDrive/{MODELNAME}{MODELEPOCH}.pth" + ], + "metadata": { + "id": "FgJuNeAwx5Y_" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 从谷歌云盘恢复pth\n", + "#@markdown 需要自己查看logs文件夹下模型的文件名,手动修改下方命令末尾的文件名\n", + "\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 模型epoch\n", + "MODELEPOCH = 7500 #@param {type:\"integer\"}\n", + "\n", + "!mkdir -p /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}\n", + "\n", + "!cp /content/drive/MyDrive/{MODELNAME}_D_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth\n", + "!cp /content/drive/MyDrive/{MODELNAME}_G_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth\n", + "!cp /content/drive/MyDrive/*.index /content/\n", + "!cp /content/drive/MyDrive/*.npy /content/\n", + "!cp /content/drive/MyDrive/{MODELNAME}{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/weights/{MODELNAME}.pth" + ], + "metadata": { + "id": "OVQoLQJXS7WX" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 手动预处理(不推荐)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 采样率\n", + "BITRATE = 48000 #@param {type:\"integer\"}\n", + "#@markdown 使用的进程数\n", + "THREADCOUNT = 8 #@param {type:\"integer\"}\n", + "\n", + "!python3 trainset_preprocess_pipeline_print.py /content/dataset {BITRATE} {THREADCOUNT} logs/{MODELNAME} True\n" + ], + "metadata": { + "id": "ZKAyuKb9J6dz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 手动提取特征(不推荐)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 使用的进程数\n", + "THREADCOUNT = 8 #@param {type:\"integer\"}\n", + "#@markdown 音高提取算法\n", + "ALGO = \"harvest\" #@param {type:\"string\"}\n", + "\n", + "!python3 extract_f0_print.py logs/{MODELNAME} {THREADCOUNT} {ALGO}\n", + "\n", + "!python3 extract_feature_print.py cpu 1 0 0 logs/{MODELNAME}\n" + ], + "metadata": { + "id": "CrxJqzAUKmPJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 手动训练(不推荐)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 使用的GPU\n", + "USEGPU = \"0\" #@param {type:\"string\"}\n", + "#@markdown 批大小\n", + "BATCHSIZE = 32 #@param {type:\"integer\"}\n", + "#@markdown 停止的epoch\n", + "MODELEPOCH = 3200 #@param {type:\"integer\"}\n", + "#@markdown 保存epoch间隔\n", + "EPOCHSAVE = 100 #@param {type:\"integer\"}\n", + "#@markdown 采样率\n", + "MODELSAMPLE = \"48k\" #@param {type:\"string\"}\n", + "#@markdown 是否缓存训练集\n", + "CACHEDATA = 1 #@param {type:\"integer\"}\n", + "#@markdown 是否仅保存最新的ckpt文件\n", + "ONLYLATEST = 0 #@param {type:\"integer\"}\n", + "\n", + "!python3 train_nsf_sim_cache_sid_load_pretrain.py -e lulu -sr {MODELSAMPLE} -f0 1 -bs {BATCHSIZE} -g {USEGPU} -te {MODELEPOCH} -se {EPOCHSAVE} -pg pretrained/f0G{MODELSAMPLE}.pth -pd pretrained/f0D{MODELSAMPLE}.pth -l {ONLYLATEST} -c {CACHEDATA}\n" + ], + "metadata": { + "id": "IMLPLKOaKj58" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 删除其它pth,只留选中的(慎点,仔细看代码)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 选中模型epoch\n", + "MODELEPOCH = 9600 #@param {type:\"integer\"}\n", + "\n", + "!echo \"备份选中的模型。。。\"\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth /content/{MODELNAME}_D_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth /content/{MODELNAME}_G_{MODELEPOCH}.pth\n", + "\n", + "!echo \"正在删除。。。\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}\n", + "!rm /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/*.pth\n", + "\n", + "!echo \"恢复选中的模型。。。\"\n", + "!mv /content/{MODELNAME}_D_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth \n", + "!mv /content/{MODELNAME}_G_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth\n", + "\n", + "!echo \"删除完成\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}" + ], + "metadata": { + "id": "haYA81hySuDl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#@title 清除项目下所有文件,只留选中的模型(慎点,仔细看代码)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 选中模型epoch\n", + "MODELEPOCH = 9600 #@param {type:\"integer\"}\n", + "\n", + "!echo \"备份选中的模型。。。\"\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth /content/{MODELNAME}_D_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth /content/{MODELNAME}_G_{MODELEPOCH}.pth\n", + "\n", + "!echo \"正在删除。。。\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}\n", + "!rm -rf /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/*\n", + "\n", + "!echo \"恢复选中的模型。。。\"\n", + "!mv /content/{MODELNAME}_D_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth \n", + "!mv /content/{MODELNAME}_G_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth\n", + "\n", + "!echo \"删除完成\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}" + ], + "metadata": { + "id": "QhSiPTVPoIRh" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/Retrieval_based_Voice_Conversion_WebUI_v2.ipynb b/Retrieval_based_Voice_Conversion_WebUI_v2.ipynb new file mode 100644 index 000000000..9fad92cb5 --- /dev/null +++ b/Retrieval_based_Voice_Conversion_WebUI_v2.ipynb @@ -0,0 +1,401 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ZFFCx5J80SGa" + }, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/Retrieval_based_Voice_Conversion_WebUI_v2.ipynb)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GmFP6bN9dvOq" + }, + "outputs": [], + "source": [ + "#@title 查看显卡\n", + "!nvidia-smi" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wjddIFr1oS3W" + }, + "outputs": [], + "source": [ + "#@title 安装依赖\n", + "!apt-get -y install build-essential python3-dev ffmpeg\n", + "!pip3 install --upgrade setuptools wheel\n", + "!pip3 install --upgrade pip\n", + "!pip3 install faiss-cpu==1.7.2 fairseq gradio==3.14.0 ffmpeg ffmpeg-python praat-parselmouth pyworld numpy==1.23.5 numba==0.56.4 librosa==0.9.2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ge_97mfpgqTm" + }, + "outputs": [], + "source": [ + "#@title 克隆仓库\n", + "\n", + "!mkdir Retrieval-based-Voice-Conversion-WebUI\n", + "%cd /content/Retrieval-based-Voice-Conversion-WebUI\n", + "!git init\n", + "!git remote add origin https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI.git\n", + "!git fetch origin cfd984812804ddc9247d65b14c82cd32e56c1133 --depth=1 \n", + "!git reset --hard FETCH_HEAD" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BLDEZADkvlw1" + }, + "outputs": [], + "source": [ + "#@title 更新仓库(一般无需执行)\n", + "!git pull" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pqE0PrnuRqI2" + }, + "outputs": [], + "source": [ + "#@title 安装aria2\n", + "!apt -y install -qq aria2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UG3XpUwEomUz" + }, + "outputs": [], + "source": [ + "#@title 下载底模\n", + "\n", + "# v1\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o D32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o D40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/D48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o D48k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o G32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o G40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/G48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o G48k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0D32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0D40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0D48k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0G32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0G40k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained -o f0G48k.pth\n", + "\n", + "#v2\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/D32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o D32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/D40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o D40k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/D48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o D48k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/G32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o G32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/G40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o G40k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/G48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o G48k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0D32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o f0D32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0D40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o f0D40k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0D48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o f0D48k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0G32k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o f0G32k.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0G40k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o f0G40k.pth\n", + "# !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained_v2/f0G48k.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/pretrained_v2 -o f0G48k.pth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HugjmZqZRuiF" + }, + "outputs": [], + "source": [ + "#@title 下载人声分离模型\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP2-人声vocals+非人声instrumentals.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/uvr5_weights -o HP2-人声vocals+非人声instrumentals.pth\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/uvr5_weights/HP5-主旋律人声vocals+其他instrumentals.pth -d /content/Retrieval-based-Voice-Conversion-WebUI/uvr5_weights -o HP5-主旋律人声vocals+其他instrumentals.pth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2RCaT9FTR0ej" + }, + "outputs": [], + "source": [ + "#@title 下载hubert_base\n", + "!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/hubert_base.pt -d /content/Retrieval-based-Voice-Conversion-WebUI -o hubert_base.pt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jwu07JgqoFON" + }, + "outputs": [], + "source": [ + "#@title 挂载谷歌云盘\n", + "\n", + "from google.colab import drive\n", + "drive.mount('/content/drive')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Mwk7Q0Loqzjx" + }, + "outputs": [], + "source": [ + "#@title 从谷歌云盘加载打包好的数据集到/content/dataset\n", + "\n", + "#@markdown 数据集位置\n", + "DATASET = \"/content/drive/MyDrive/dataset/lulu20230327_32k.zip\" #@param {type:\"string\"}\n", + "\n", + "!mkdir -p /content/dataset\n", + "!unzip -d /content/dataset -B {DATASET}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PDlFxWHWEynD" + }, + "outputs": [], + "source": [ + "#@title 重命名数据集中的重名文件\n", + "!ls -a /content/dataset/\n", + "!rename 's/(\\w+)\\.(\\w+)~(\\d*)/$1_$3.$2/' /content/dataset/*.*~*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7vh6vphDwO0b" + }, + "outputs": [], + "source": [ + "#@title 启动web\n", + "%cd /content/Retrieval-based-Voice-Conversion-WebUI\n", + "# %load_ext tensorboard\n", + "# %tensorboard --logdir /content/Retrieval-based-Voice-Conversion-WebUI/logs\n", + "!python3 infer-web.py --colab --pycmd python3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FgJuNeAwx5Y_" + }, + "outputs": [], + "source": [ + "#@title 手动将训练后的模型文件备份到谷歌云盘\n", + "#@markdown 需要自己查看logs文件夹下模型的文件名,手动修改下方命令末尾的文件名\n", + "\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 模型epoch\n", + "MODELEPOCH = 9600 #@param {type:\"integer\"}\n", + "\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth /content/drive/MyDrive/{MODELNAME}_D_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth /content/drive/MyDrive/{MODELNAME}_G_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/added_*.index /content/drive/MyDrive/\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/total_*.npy /content/drive/MyDrive/\n", + "\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/weights/{MODELNAME}.pth /content/drive/MyDrive/{MODELNAME}{MODELEPOCH}.pth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OVQoLQJXS7WX" + }, + "outputs": [], + "source": [ + "#@title 从谷歌云盘恢复pth\n", + "#@markdown 需要自己查看logs文件夹下模型的文件名,手动修改下方命令末尾的文件名\n", + "\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 模型epoch\n", + "MODELEPOCH = 7500 #@param {type:\"integer\"}\n", + "\n", + "!mkdir -p /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}\n", + "\n", + "!cp /content/drive/MyDrive/{MODELNAME}_D_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth\n", + "!cp /content/drive/MyDrive/{MODELNAME}_G_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth\n", + "!cp /content/drive/MyDrive/*.index /content/\n", + "!cp /content/drive/MyDrive/*.npy /content/\n", + "!cp /content/drive/MyDrive/{MODELNAME}{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/weights/{MODELNAME}.pth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZKAyuKb9J6dz" + }, + "outputs": [], + "source": [ + "#@title 手动预处理(不推荐)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 采样率\n", + "BITRATE = 48000 #@param {type:\"integer\"}\n", + "#@markdown 使用的进程数\n", + "THREADCOUNT = 8 #@param {type:\"integer\"}\n", + "\n", + "!python3 trainset_preprocess_pipeline_print.py /content/dataset {BITRATE} {THREADCOUNT} logs/{MODELNAME} True\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CrxJqzAUKmPJ" + }, + "outputs": [], + "source": [ + "#@title 手动提取特征(不推荐)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 使用的进程数\n", + "THREADCOUNT = 8 #@param {type:\"integer\"}\n", + "#@markdown 音高提取算法\n", + "ALGO = \"harvest\" #@param {type:\"string\"}\n", + "\n", + "!python3 extract_f0_print.py logs/{MODELNAME} {THREADCOUNT} {ALGO}\n", + "\n", + "!python3 extract_feature_print.py cpu 1 0 0 logs/{MODELNAME}\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IMLPLKOaKj58" + }, + "outputs": [], + "source": [ + "#@title 手动训练(不推荐)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 使用的GPU\n", + "USEGPU = \"0\" #@param {type:\"string\"}\n", + "#@markdown 批大小\n", + "BATCHSIZE = 32 #@param {type:\"integer\"}\n", + "#@markdown 停止的epoch\n", + "MODELEPOCH = 3200 #@param {type:\"integer\"}\n", + "#@markdown 保存epoch间隔\n", + "EPOCHSAVE = 100 #@param {type:\"integer\"}\n", + "#@markdown 采样率\n", + "MODELSAMPLE = \"48k\" #@param {type:\"string\"}\n", + "#@markdown 是否缓存训练集\n", + "CACHEDATA = 1 #@param {type:\"integer\"}\n", + "#@markdown 是否仅保存最新的ckpt文件\n", + "ONLYLATEST = 0 #@param {type:\"integer\"}\n", + "\n", + "!python3 train_nsf_sim_cache_sid_load_pretrain.py -e lulu -sr {MODELSAMPLE} -f0 1 -bs {BATCHSIZE} -g {USEGPU} -te {MODELEPOCH} -se {EPOCHSAVE} -pg pretrained/f0G{MODELSAMPLE}.pth -pd pretrained/f0D{MODELSAMPLE}.pth -l {ONLYLATEST} -c {CACHEDATA}\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "haYA81hySuDl" + }, + "outputs": [], + "source": [ + "#@title 删除其它pth,只留选中的(慎点,仔细看代码)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 选中模型epoch\n", + "MODELEPOCH = 9600 #@param {type:\"integer\"}\n", + "\n", + "!echo \"备份选中的模型。。。\"\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth /content/{MODELNAME}_D_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth /content/{MODELNAME}_G_{MODELEPOCH}.pth\n", + "\n", + "!echo \"正在删除。。。\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}\n", + "!rm /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/*.pth\n", + "\n", + "!echo \"恢复选中的模型。。。\"\n", + "!mv /content/{MODELNAME}_D_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth \n", + "!mv /content/{MODELNAME}_G_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth\n", + "\n", + "!echo \"删除完成\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QhSiPTVPoIRh" + }, + "outputs": [], + "source": [ + "#@title 清除项目下所有文件,只留选中的模型(慎点,仔细看代码)\n", + "#@markdown 模型名\n", + "MODELNAME = \"lulu\" #@param {type:\"string\"}\n", + "#@markdown 选中模型epoch\n", + "MODELEPOCH = 9600 #@param {type:\"integer\"}\n", + "\n", + "!echo \"备份选中的模型。。。\"\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth /content/{MODELNAME}_D_{MODELEPOCH}.pth\n", + "!cp /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth /content/{MODELNAME}_G_{MODELEPOCH}.pth\n", + "\n", + "!echo \"正在删除。。。\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}\n", + "!rm -rf /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/*\n", + "\n", + "!echo \"恢复选中的模型。。。\"\n", + "!mv /content/{MODELNAME}_D_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/G_{MODELEPOCH}.pth \n", + "!mv /content/{MODELNAME}_G_{MODELEPOCH}.pth /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}/D_{MODELEPOCH}.pth\n", + "\n", + "!echo \"删除完成\"\n", + "!ls /content/Retrieval-based-Voice-Conversion-WebUI/logs/{MODELNAME}" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "private_outputs": true, + "provenance": [] + }, + "gpuClass": "standard", + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/app.py b/app.py new file mode 100644 index 000000000..d8264b895 --- /dev/null +++ b/app.py @@ -0,0 +1,319 @@ +import os +import torch + +# os.system("wget -P cvec/ https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/hubert_base.pt") +import gradio as gr +import librosa +import numpy as np +import logging +from fairseq import checkpoint_utils +from vc_infer_pipeline import VC +import traceback +from config import Config +from lib.infer_pack.models import ( + SynthesizerTrnMs256NSFsid, + SynthesizerTrnMs256NSFsid_nono, + SynthesizerTrnMs768NSFsid, + SynthesizerTrnMs768NSFsid_nono, +) +from i18n import I18nAuto + +logging.getLogger("numba").setLevel(logging.WARNING) +logging.getLogger("markdown_it").setLevel(logging.WARNING) +logging.getLogger("urllib3").setLevel(logging.WARNING) +logging.getLogger("matplotlib").setLevel(logging.WARNING) + +i18n = I18nAuto() +i18n.print() + +config = Config() + +weight_root = "weights" +weight_uvr5_root = "uvr5_weights" +index_root = "logs" +names = [] +hubert_model = None +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)) + + +def get_vc(sid): + global n_spk, tgt_sr, net_g, vc, cpt, version + if sid == "" or sid == []: + global hubert_model + if hubert_model != None: # 考虑到轮询, 需要加个判断看是否 sid 是由有模型切换到无模型的 + print("clean_empty_cache") + del net_g, n_spk, vc, hubert_model, tgt_sr # ,cpt + hubert_model = net_g = n_spk = vc = hubert_model = tgt_sr = None + if torch.cuda.is_available(): + torch.cuda.empty_cache() + ###楼下不这么折腾清理不干净 + if_f0 = cpt.get("f0", 1) + version = cpt.get("version", "v1") + if version == "v1": + if if_f0 == 1: + net_g = SynthesizerTrnMs256NSFsid( + *cpt["config"], is_half=config.is_half + ) + else: + net_g = SynthesizerTrnMs256NSFsid_nono(*cpt["config"]) + elif version == "v2": + if if_f0 == 1: + net_g = SynthesizerTrnMs768NSFsid( + *cpt["config"], is_half=config.is_half + ) + else: + net_g = SynthesizerTrnMs768NSFsid_nono(*cpt["config"]) + del net_g, cpt + if torch.cuda.is_available(): + torch.cuda.empty_cache() + cpt = None + return {"visible": False, "__type__": "update"} + person = "%s/%s" % (weight_root, sid) + print("loading %s" % person) + cpt = torch.load(person, map_location="cpu") + tgt_sr = cpt["config"][-1] + cpt["config"][-3] = cpt["weight"]["emb_g.weight"].shape[0] # n_spk + if_f0 = cpt.get("f0", 1) + version = cpt.get("version", "v1") + if version == "v1": + if if_f0 == 1: + net_g = SynthesizerTrnMs256NSFsid(*cpt["config"], is_half=config.is_half) + else: + net_g = SynthesizerTrnMs256NSFsid_nono(*cpt["config"]) + elif version == "v2": + if if_f0 == 1: + net_g = SynthesizerTrnMs768NSFsid(*cpt["config"], is_half=config.is_half) + else: + net_g = SynthesizerTrnMs768NSFsid_nono(*cpt["config"]) + del net_g.enc_q + print(net_g.load_state_dict(cpt["weight"], strict=False)) + net_g.eval().to(config.device) + if config.is_half: + net_g = net_g.half() + else: + net_g = net_g.float() + vc = VC(tgt_sr, config) + n_spk = cpt["config"][-3] + return {"visible": True, "maximum": n_spk, "__type__": "update"} + + +def load_hubert(): + global hubert_model + models, _, _ = checkpoint_utils.load_model_ensemble_and_task( + ["hubert_base.pt"], + suffix="", + ) + hubert_model = models[0] + hubert_model = hubert_model.to(config.device) + if config.is_half: + hubert_model = hubert_model.half() + else: + hubert_model = hubert_model.float() + hubert_model.eval() + + +def vc_single( + sid, + input_audio_path, + f0_up_key, + f0_file, + f0_method, + file_index, + file_index2, + # file_big_npy, + index_rate, + filter_radius, + resample_sr, + rms_mix_rate, + protect, +): # spk_item, input_audio0, vc_transform0,f0_file,f0method0 + global tgt_sr, net_g, vc, hubert_model, version + if input_audio_path is None: + return "You need to upload an audio", None + f0_up_key = int(f0_up_key) + try: + audio = input_audio_path[1] / 32768.0 + if len(audio.shape) == 2: + audio = np.mean(audio, -1) + audio = librosa.resample(audio, orig_sr=input_audio_path[0], target_sr=16000) + audio_max = np.abs(audio).max() / 0.95 + if audio_max > 1: + audio /= audio_max + times = [0, 0, 0] + if hubert_model == None: + load_hubert() + if_f0 = cpt.get("f0", 1) + file_index = ( + ( + file_index.strip(" ") + .strip('"') + .strip("\n") + .strip('"') + .strip(" ") + .replace("trained", "added") + ) + if file_index != "" + else file_index2 + ) # 防止小白写错,自动帮他替换掉 + # file_big_npy = ( + # file_big_npy.strip(" ").strip('"').strip("\n").strip('"').strip(" ") + # ) + audio_opt = vc.pipeline( + hubert_model, + net_g, + sid, + audio, + input_audio_path, + times, + f0_up_key, + f0_method, + file_index, + # file_big_npy, + index_rate, + if_f0, + filter_radius, + tgt_sr, + resample_sr, + rms_mix_rate, + version, + protect, + f0_file=f0_file, + ) + if resample_sr >= 16000 and tgt_sr != resample_sr: + tgt_sr = resample_sr + index_info = ( + "Using index:%s." % file_index + if os.path.exists(file_index) + else "Index not used." + ) + return "Success.\n %s\nTime:\n npy:%ss, f0:%ss, infer:%ss" % ( + index_info, + times[0], + times[1], + times[2], + ), (tgt_sr, audio_opt) + except: + info = traceback.format_exc() + print(info) + return info, (None, None) + + +app = gr.Blocks() +with app: + with gr.Tabs(): + with gr.TabItem("在线demo"): + gr.Markdown( + value=""" + RVC 在线demo + """ + ) + sid = gr.Dropdown(label=i18n("推理音色"), choices=sorted(names)) + with gr.Column(): + spk_item = gr.Slider( + minimum=0, + maximum=2333, + step=1, + label=i18n("请选择说话人id"), + value=0, + visible=False, + interactive=True, + ) + sid.change( + fn=get_vc, + inputs=[sid], + outputs=[spk_item], + ) + gr.Markdown( + value=i18n("男转女推荐+12key, 女转男推荐-12key, 如果音域爆炸导致音色失真也可以自己调整到合适音域. ") + ) + vc_input3 = gr.Audio(label="上传音频(长度小于90秒)") + vc_transform0 = gr.Number(label=i18n("变调(整数, 半音数量, 升八度12降八度-12)"), value=0) + f0method0 = gr.Radio( + label=i18n("选择音高提取算法,输入歌声可用pm提速,harvest低音好但巨慢无比,crepe效果好但吃GPU"), + choices=["pm", "harvest", "crepe"], + value="pm", + interactive=True, + ) + filter_radius0 = gr.Slider( + minimum=0, + maximum=7, + label=i18n(">=3则使用对harvest音高识别的结果使用中值滤波,数值为滤波半径,使用可以削弱哑音"), + value=3, + step=1, + interactive=True, + ) + with gr.Column(): + file_index1 = gr.Textbox( + label=i18n("特征检索库文件路径,为空则使用下拉的选择结果"), + value="", + interactive=False, + visible=False, + ) + file_index2 = gr.Dropdown( + label=i18n("自动检测index路径,下拉式选择(dropdown)"), + choices=sorted(index_paths), + interactive=True, + ) + index_rate1 = gr.Slider( + minimum=0, + maximum=1, + label=i18n("检索特征占比"), + value=0.88, + interactive=True, + ) + resample_sr0 = gr.Slider( + minimum=0, + maximum=48000, + label=i18n("后处理重采样至最终采样率,0为不进行重采样"), + value=0, + step=1, + interactive=True, + ) + rms_mix_rate0 = gr.Slider( + minimum=0, + maximum=1, + label=i18n("输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络"), + value=1, + interactive=True, + ) + protect0 = gr.Slider( + minimum=0, + maximum=0.5, + label=i18n("保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果"), + value=0.33, + step=0.01, + interactive=True, + ) + f0_file = gr.File(label=i18n("F0曲线文件, 可选, 一行一个音高, 代替默认F0及升降调")) + but0 = gr.Button(i18n("转换"), variant="primary") + vc_output1 = gr.Textbox(label=i18n("输出信息")) + vc_output2 = gr.Audio(label=i18n("输出音频(右下角三个点,点了可以下载)")) + but0.click( + vc_single, + [ + spk_item, + vc_input3, + 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], + ) + + +app.launch() diff --git a/audio-outputs/readme.txt b/audio-outputs/readme.txt new file mode 100644 index 000000000..516cf6fa3 --- /dev/null +++ b/audio-outputs/readme.txt @@ -0,0 +1 @@ +All audio output files if inferred with the CLI will save here. (Mangio-RVC-Fork Feature) \ No newline at end of file diff --git a/audios/.gitignore b/audios/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/avoid-shutdown.ipynb b/avoid-shutdown.ipynb new file mode 100644 index 000000000..1190b3d60 --- /dev/null +++ b/avoid-shutdown.ipynb @@ -0,0 +1,60 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mangio-RVC-Fork" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prevent Interactivity Automatic Shutdown" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "time.sleep(1000 * 60 * 60 * 24)" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "provenance": [ + { + "file_id": "https://github.com/34j/so-vits-svc-fork/blob/feat%2Fmain-feat/so-vits-svc-fork-4.0.ipynb", + "timestamp": 1678970434570 + } + ] + }, + "gpuClass": "standard", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/config.py b/config.py new file mode 100644 index 000000000..f1144b187 --- /dev/null +++ b/config.py @@ -0,0 +1,213 @@ +import argparse +import sys +import torch +import json +from multiprocessing import cpu_count + +global usefp16 +usefp16 = False + +def decide_fp_config(): + global usefp16 + usefp16 = False + device_capability = 0 + if torch.cuda.is_available(): + device = torch.device("cuda:0") # Assuming you have only one GPU (index 0). + device_capability = torch.cuda.get_device_capability(device)[0] + if device_capability >= 7: + usefp16 = True + for config_file in ["32k.json", "40k.json", "48k.json"]: + with open(f"configs/{config_file}", "r") as d: + data = json.load(d) + + if "train" in data and "fp16_run" in data["train"]: + data["train"]["fp16_run"] = True + + with open(f"configs/{config_file}", "w") as d: + json.dump(data, d, indent=4) + + + + with open( + "trainset_preprocess_pipeline_print.py", "r", encoding="utf-8" + ) as f: + strr = f.read() + + strr = strr.replace("3.0", "3.7") + + with open( + "trainset_preprocess_pipeline_print.py", "w", encoding="utf-8" + ) as f: + f.write(strr) + else: + for config_file in ["32k.json", "40k.json", "48k.json"]: + with open(f"configs/{config_file}", "r") as f: + data = json.load(f) + + if "train" in data and "fp16_run" in data["train"]: + data["train"]["fp16_run"] = False + + with open(f"configs/{config_file}", "w") as d: + json.dump(data, d, indent=4) + + print(f"Set fp16_run to false in {config_file}") + + with open( + "trainset_preprocess_pipeline_print.py", "r", encoding="utf-8" + ) as f: + strr = f.read() + + strr = strr.replace("3.7", "3.0") + + with open( + "trainset_preprocess_pipeline_print.py", "w", encoding="utf-8" + ) as f: + f.write(strr) + else: + print( + "CUDA is not available. Make sure you have an NVIDIA GPU and CUDA installed." + ) + return (usefp16, device_capability) + +class Config: + def __init__(self): + self.device = "cuda:0" + self.is_half = True + self.n_cpu = 0 + self.gpu_name = None + self.gpu_mem = None + ( + self.python_cmd, + self.listen_port, + self.iscolab, + self.noparallel, + self.noautoopen, + self.paperspace, + self.is_cli, + self.grtheme, + ) = self.arg_parse() + + self.x_pad, self.x_query, self.x_center, self.x_max = self.device_config() + + @staticmethod + def arg_parse() -> tuple: + exe = sys.executable or "python" + parser = argparse.ArgumentParser() + parser.add_argument("--port", type=int, default=7865, help="Listen port") + parser.add_argument("--pycmd", type=str, default=exe, help="Python command") + parser.add_argument("--colab", action="store_true", help="Launch in colab") + parser.add_argument( + "--noparallel", action="store_true", help="Disable parallel processing" + ) + parser.add_argument( + "--noautoopen", + action="store_true", + help="Do not open in browser automatically", + ) + parser.add_argument( # Fork Feature. Paperspace integration for web UI + "--paperspace", + action="store_true", + help="Note that this argument just shares a gradio link for the web UI. Thus can be used on other non-local CLI systems.", + ) + parser.add_argument( # Fork Feature. Embed a CLI into the infer-web.py + "--is_cli", + action="store_true", + help="Use the CLI instead of setting up a gradio UI. This flag will launch an RVC text interface where you can execute functions from infer-web.py!", + ) + + parser.add_argument( + "-t", + "--theme", + help = "Theme for Gradio. Format - `JohnSmith9982/small_and_pretty` (no backticks)", + default = "gradio/soft", + type = str + ) + + cmd_opts = parser.parse_args() + + cmd_opts.port = cmd_opts.port if 0 <= cmd_opts.port <= 65535 else 7865 + + return ( + cmd_opts.pycmd, + cmd_opts.port, + cmd_opts.colab, + cmd_opts.noparallel, + cmd_opts.noautoopen, + cmd_opts.paperspace, + cmd_opts.is_cli, + cmd_opts.theme, + ) + + # has_mps is only available in nightly pytorch (for now) and MasOS 12.3+. + # check `getattr` and try it for compatibility + @staticmethod + def has_mps() -> bool: + if not torch.backends.mps.is_available(): + return False + try: + torch.zeros(1).to(torch.device("mps")) + return True + except Exception: + return False + + def device_config(self) -> tuple: + if torch.cuda.is_available(): + i_device = int(self.device.split(":")[-1]) + self.gpu_name = torch.cuda.get_device_name(i_device) + if ( + ("16" in self.gpu_name and "V100" not in self.gpu_name.upper()) + or "P40" in self.gpu_name.upper() + or "1060" in self.gpu_name + or "1070" in self.gpu_name + # or "1080" in self.gpu_name / This is commented out because fp16 apparently runs fast on 1080 + ): + print("Found GPU", self.gpu_name, ", force to fp32") + self.is_half = False + else: + decide_fp_config() + self.gpu_mem = int( + torch.cuda.get_device_properties(i_device).total_memory + / 1024 + / 1024 + / 1024 + + 0.4 + ) + if self.gpu_mem <= 4: + with open("trainset_preprocess_pipeline_print.py", "r") as f: + strr = f.read().replace("3.7", "3.0") + with open("trainset_preprocess_pipeline_print.py", "w") as f: + f.write(strr) + elif self.has_mps(): + print("No supported Nvidia GPU found, using MPS instead") + self.device = "mps" + self.is_half = False + decide_fp_config() + else: + print("No supported Nvidia GPU found, using CPU instead") + self.device = "cpu" + self.is_half = False + decide_fp_config() + + if self.n_cpu == 0: + self.n_cpu = cpu_count() + + if self.is_half: + # 6G显存配置 + x_pad = 3 + x_query = 10 + x_center = 60 + x_max = 65 + else: + # 5G显存配置 + x_pad = 1 + x_query = 6 + x_center = 38 + x_max = 41 + + if self.gpu_mem != None and self.gpu_mem <= 4: + x_pad = 1 + x_query = 5 + x_center = 30 + x_max = 32 + + return x_pad, x_query, x_center, x_max diff --git a/configs/32k.json b/configs/32k.json new file mode 100644 index 000000000..400b6be80 --- /dev/null +++ b/configs/32k.json @@ -0,0 +1,46 @@ +{ + "train": { + "log_interval": 200, + "seed": 1234, + "epochs": 20000, + "learning_rate": 1e-4, + "betas": [0.8, 0.99], + "eps": 1e-9, + "batch_size": 4, + "fp16_run": false, + "lr_decay": 0.999875, + "segment_size": 12800, + "init_lr_ratio": 1, + "warmup_epochs": 0, + "c_mel": 45, + "c_kl": 1.0 + }, + "data": { + "max_wav_value": 32768.0, + "sampling_rate": 32000, + "filter_length": 1024, + "hop_length": 320, + "win_length": 1024, + "n_mel_channels": 80, + "mel_fmin": 0.0, + "mel_fmax": null + }, + "model": { + "inter_channels": 192, + "hidden_channels": 192, + "filter_channels": 768, + "n_heads": 2, + "n_layers": 6, + "kernel_size": 3, + "p_dropout": 0, + "resblock": "1", + "resblock_kernel_sizes": [3,7,11], + "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], + "upsample_rates": [10,4,2,2,2], + "upsample_initial_channel": 512, + "upsample_kernel_sizes": [16,16,4,4,4], + "use_spectral_norm": false, + "gin_channels": 256, + "spk_embed_dim": 109 + } +} diff --git a/configs/32k_v2.json b/configs/32k_v2.json new file mode 100644 index 000000000..70e534f4c --- /dev/null +++ b/configs/32k_v2.json @@ -0,0 +1,46 @@ +{ + "train": { + "log_interval": 200, + "seed": 1234, + "epochs": 20000, + "learning_rate": 1e-4, + "betas": [0.8, 0.99], + "eps": 1e-9, + "batch_size": 4, + "fp16_run": true, + "lr_decay": 0.999875, + "segment_size": 12800, + "init_lr_ratio": 1, + "warmup_epochs": 0, + "c_mel": 45, + "c_kl": 1.0 + }, + "data": { + "max_wav_value": 32768.0, + "sampling_rate": 32000, + "filter_length": 1024, + "hop_length": 320, + "win_length": 1024, + "n_mel_channels": 80, + "mel_fmin": 0.0, + "mel_fmax": null + }, + "model": { + "inter_channels": 192, + "hidden_channels": 192, + "filter_channels": 768, + "n_heads": 2, + "n_layers": 6, + "kernel_size": 3, + "p_dropout": 0, + "resblock": "1", + "resblock_kernel_sizes": [3,7,11], + "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], + "upsample_rates": [10,8,2,2], + "upsample_initial_channel": 512, + "upsample_kernel_sizes": [20,16,4,4], + "use_spectral_norm": false, + "gin_channels": 256, + "spk_embed_dim": 109 + } +} diff --git a/configs/40k.json b/configs/40k.json new file mode 100644 index 000000000..cb30b8be4 --- /dev/null +++ b/configs/40k.json @@ -0,0 +1,46 @@ +{ + "train": { + "log_interval": 200, + "seed": 1234, + "epochs": 20000, + "learning_rate": 1e-4, + "betas": [0.8, 0.99], + "eps": 1e-9, + "batch_size": 4, + "fp16_run": false, + "lr_decay": 0.999875, + "segment_size": 12800, + "init_lr_ratio": 1, + "warmup_epochs": 0, + "c_mel": 45, + "c_kl": 1.0 + }, + "data": { + "max_wav_value": 32768.0, + "sampling_rate": 40000, + "filter_length": 2048, + "hop_length": 400, + "win_length": 2048, + "n_mel_channels": 125, + "mel_fmin": 0.0, + "mel_fmax": null + }, + "model": { + "inter_channels": 192, + "hidden_channels": 192, + "filter_channels": 768, + "n_heads": 2, + "n_layers": 6, + "kernel_size": 3, + "p_dropout": 0, + "resblock": "1", + "resblock_kernel_sizes": [3,7,11], + "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], + "upsample_rates": [10,10,2,2], + "upsample_initial_channel": 512, + "upsample_kernel_sizes": [16,16,4,4], + "use_spectral_norm": false, + "gin_channels": 256, + "spk_embed_dim": 109 + } +} diff --git a/configs/48k.json b/configs/48k.json new file mode 100644 index 000000000..687599100 --- /dev/null +++ b/configs/48k.json @@ -0,0 +1,46 @@ +{ + "train": { + "log_interval": 200, + "seed": 1234, + "epochs": 20000, + "learning_rate": 1e-4, + "betas": [0.8, 0.99], + "eps": 1e-9, + "batch_size": 4, + "fp16_run": false, + "lr_decay": 0.999875, + "segment_size": 11520, + "init_lr_ratio": 1, + "warmup_epochs": 0, + "c_mel": 45, + "c_kl": 1.0 + }, + "data": { + "max_wav_value": 32768.0, + "sampling_rate": 48000, + "filter_length": 2048, + "hop_length": 480, + "win_length": 2048, + "n_mel_channels": 128, + "mel_fmin": 0.0, + "mel_fmax": null + }, + "model": { + "inter_channels": 192, + "hidden_channels": 192, + "filter_channels": 768, + "n_heads": 2, + "n_layers": 6, + "kernel_size": 3, + "p_dropout": 0, + "resblock": "1", + "resblock_kernel_sizes": [3,7,11], + "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], + "upsample_rates": [10,6,2,2,2], + "upsample_initial_channel": 512, + "upsample_kernel_sizes": [16,16,4,4,4], + "use_spectral_norm": false, + "gin_channels": 256, + "spk_embed_dim": 109 + } +} diff --git a/configs/48k_v2.json b/configs/48k_v2.json new file mode 100644 index 000000000..75f770cda --- /dev/null +++ b/configs/48k_v2.json @@ -0,0 +1,46 @@ +{ + "train": { + "log_interval": 200, + "seed": 1234, + "epochs": 20000, + "learning_rate": 1e-4, + "betas": [0.8, 0.99], + "eps": 1e-9, + "batch_size": 4, + "fp16_run": true, + "lr_decay": 0.999875, + "segment_size": 17280, + "init_lr_ratio": 1, + "warmup_epochs": 0, + "c_mel": 45, + "c_kl": 1.0 + }, + "data": { + "max_wav_value": 32768.0, + "sampling_rate": 48000, + "filter_length": 2048, + "hop_length": 480, + "win_length": 2048, + "n_mel_channels": 128, + "mel_fmin": 0.0, + "mel_fmax": null + }, + "model": { + "inter_channels": 192, + "hidden_channels": 192, + "filter_channels": 768, + "n_heads": 2, + "n_layers": 6, + "kernel_size": 3, + "p_dropout": 0, + "resblock": "1", + "resblock_kernel_sizes": [3,7,11], + "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], + "upsample_rates": [12,10,2,2], + "upsample_initial_channel": 512, + "upsample_kernel_sizes": [24,20,4,4], + "use_spectral_norm": false, + "gin_channels": 256, + "spk_embed_dim": 109 + } +} diff --git a/csvdb/stop.csv b/csvdb/stop.csv new file mode 100644 index 000000000..bc59c12aa --- /dev/null +++ b/csvdb/stop.csv @@ -0,0 +1 @@ +False diff --git a/docs/README.en.md b/docs/README.en.md new file mode 100644 index 000000000..40b357e1e --- /dev/null +++ b/docs/README.en.md @@ -0,0 +1,110 @@ +
+ +

Retrieval-based-Voice-Conversion-WebUI

+An easy-to-use Voice Conversion framework based on VITS.

+ +[![madewithlove](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI) + +
+ +[![Open In Colab](https://img.shields.io/badge/Colab-F9AB00?style=for-the-badge&logo=googlecolab&color=525252)](https://colab.research.google.com/github/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/Retrieval_based_Voice_Conversion_WebUI.ipynb) +[![Licence](https://img.shields.io/github/license/RVC-Project/Retrieval-based-Voice-Conversion-WebUI?style=for-the-badge)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/LICENSE) +[![Huggingface](https://img.shields.io/badge/🤗%20-Spaces-yellow.svg?style=for-the-badge)](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/) + +[![Discord](https://img.shields.io/badge/RVC%20Developers-Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/HcsmBBGyVk) + +
+ +------ +[**Changelog**](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/docs/Changelog_EN.md) | [**FAQ (Frequently Asked Questions)**](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/wiki/FAQ-(Frequently-Asked-Questions)) + +[**English**](./README.en.md) | [**中文简体**](../README.md) | [**日本語**](./README.ja.md) | [**한국어**](./README.ko.md) ([**韓國語**](./README.ko.han.md)) + + +Check our [Demo Video](https://www.bilibili.com/video/BV1pm4y1z7Gm/) here! + +Realtime Voice Conversion Software using RVC : [w-okada/voice-changer](https://github.com/w-okada/voice-changer) + +> A online demo using RVC that convert Vocal to Acoustic Guitar audio:https://huggingface.co/spaces/lj1995/vocal2guitar + +> Vocal2Guitar demo video:https://www.bilibili.com/video/BV19W4y1D7tT/ + +> The dataset for the pre-training model uses nearly 50 hours of high quality VCTK open source dataset. + +> High quality licensed song datasets will be added to training-set one after another for your use, without worrying about copyright infringement. + +## Summary +This repository has the following features: ++ Reduce tone leakage by replacing source feature to training-set feature using top1 retrieval; ++ Easy and fast training, even on relatively poor graphics cards; ++ Training with a small amount of data also obtains relatively good results (>=10min low noise speech recommended); ++ Supporting model fusion to change timbres (using ckpt processing tab->ckpt merge); ++ Easy-to-use Webui interface; ++ Use the UVR5 model to quickly separate vocals and instruments. +## Preparing the environment +We recommend you install the dependencies through poetry. + +The following commands need to be executed in the environment of Python version 3.8 or higher: +```bash +# Install PyTorch-related core dependencies, skip if installed +# Reference: https://pytorch.org/get-started/locally/ +pip install torch torchvision torchaudio + +#For Windows + Nvidia Ampere Architecture(RTX30xx), you need to specify the cuda version corresponding to pytorch according to the experience of https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/issues/21 +#pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117 + +# Install the Poetry dependency management tool, skip if installed +# Reference: https://python-poetry.org/docs/#installation +curl -sSL https://install.python-poetry.org | python3 - + +# Install the project dependencies +poetry install +``` +You can also use pip to install the dependencies + +```bash +pip install -r requirements.txt +``` + +## Preparation of other Pre-models +RVC requires other pre-models to infer and train. + +You need to download them from our [Huggingface space](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/). + +Here's a list of Pre-models and other files that RVC needs: +```bash +hubert_base.pt + +./pretrained + +./uvr5_weights + +If you want to test the v2 version model (the v2 version model has changed the input from the 256 dimensional feature of 9-layer Hubert+final_proj to the 768 dimensional feature of 12-layer Hubert, and has added 3 period discriminators), you will need to download additional features + +./pretrained_v2 + +#If you are using Windows, you may also need this dictionary, skip if FFmpeg is installed +ffmpeg.exe +``` +Then use this command to start Webui: +```bash +python infer-web.py +``` +If you are using Windows, you can download and extract `RVC-beta.7z` to use RVC directly and use `go-web.bat` to start Webui. + +There's also a tutorial on RVC in Chinese and you can check it out if needed. + +## Credits ++ [ContentVec](https://github.com/auspicious3000/contentvec/) ++ [VITS](https://github.com/jaywalnut310/vits) ++ [HIFIGAN](https://github.com/jik876/hifi-gan) ++ [Gradio](https://github.com/gradio-app/gradio) ++ [FFmpeg](https://github.com/FFmpeg/FFmpeg) ++ [Ultimate Vocal Remover](https://github.com/Anjok07/ultimatevocalremovergui) ++ [audio-slicer](https://github.com/openvpi/audio-slicer) +## Thanks to all contributors for their efforts + + + + + diff --git a/docs/README.ja.md b/docs/README.ja.md new file mode 100644 index 000000000..26ce3af19 --- /dev/null +++ b/docs/README.ja.md @@ -0,0 +1,104 @@ +
+ +

Retrieval-based-Voice-Conversion-WebUI

+VITSに基づく使いやすい音声変換(voice changer)framework

+ +[![madewithlove](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI) + +
+ +[![Open In Colab](https://img.shields.io/badge/Colab-F9AB00?style=for-the-badge&logo=googlecolab&color=525252)](https://colab.research.google.com/github/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/Retrieval_based_Voice_Conversion_WebUI.ipynb) +[![Licence](https://img.shields.io/github/license/RVC-Project/Retrieval-based-Voice-Conversion-WebUI?style=for-the-badge)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/LICENSE) +[![Huggingface](https://img.shields.io/badge/🤗%20-Spaces-yellow.svg?style=for-the-badge)](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/) + +[![Discord](https://img.shields.io/badge/RVC%20Developers-Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/HcsmBBGyVk) + +
+ +------ + +[**更新日誌**](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/docs/Changelog_CN.md) + +[**English**](./README.en.md) | [**中文简体**](../README.md) | [**日本語**](./README.ja.md) | [**한국어**](./README.ko.md) ([**韓國語**](./README.ko.han.md)) + +> デモ動画は[こちら](https://www.bilibili.com/video/BV1pm4y1z7Gm/)でご覧ください。 + +> RVCによるリアルタイム音声変換: [w-okada/voice-changer](https://github.com/w-okada/voice-changer) + +> 著作権侵害を心配することなく使用できるように、基底モデルは約50時間の高品質なオープンソースデータセットで訓練されています。 + +> 今後も、次々と使用許可のある高品質な歌声の資料集を追加し、基底モデルを訓練する予定です。 + +## はじめに +本リポジトリには下記の特徴があります。 + ++ Top1検索を用いることで、生の特徴量を訓練用データセット特徴量に変換し、トーンリーケージを削減します。 ++ 比較的貧弱なGPUでも、高速かつ簡単に訓練できます。 ++ 少量のデータセットからでも、比較的良い結果を得ることができます。(10分以上のノイズの少ない音声を推奨します。) ++ モデルを融合することで、音声を混ぜることができます。(ckpt processingタブの、ckpt mergeを使用します。) ++ 使いやすいWebUI。 ++ UVR5 Modelも含んでいるため、人の声とBGMを素早く分離できます。 + +## 環境構築 +Poetryで依存関係をインストールすることをお勧めします。 + +下記のコマンドは、Python3.8以上の環境で実行する必要があります: +```bash +# PyTorch関連の依存関係をインストール。インストール済の場合は省略。 +# 参照先: https://pytorch.org/get-started/locally/ +pip install torch torchvision torchaudio + +#Windows+ Nvidia Ampere Architecture(RTX30xx)の場合、 #21 に従い、pytorchに対応するcuda versionを指定する必要があります。 +#pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117 + +# PyTorch関連の依存関係をインストール。インストール済の場合は省略。 +# 参照先: https://python-poetry.org/docs/#installation +curl -sSL https://install.python-poetry.org | python3 - + +# Poetry経由で依存関係をインストール +poetry install +``` + +pipでも依存関係のインストールが可能です: + +```bash +pip install -r requirements.txt +``` + +## 基底modelsを準備 +RVCは推論/訓練のために、様々な事前訓練を行った基底モデルを必要とします。 + +modelsは[Hugging Face space](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/)からダウンロードできます。 + +以下は、RVCに必要な基底モデルやその他のファイルの一覧です。 +```bash +hubert_base.pt + +./pretrained + +./uvr5_weights + +# ffmpegがすでにinstallされている場合は省略 +./ffmpeg +``` +その後、下記のコマンドでWebUIを起動します。 +```bash +python infer-web.py +``` +Windowsをお使いの方は、直接`RVC-beta.7z`をダウンロード後に展開し、`go-web.bat`をクリックすることで、WebUIを起動することができます。(7zipが必要です。) + +また、リポジトリに[小白简易教程.doc](./小白简易教程.doc)がありますので、参考にしてください(中国語版のみ)。 + +## 参考プロジェクト ++ [ContentVec](https://github.com/auspicious3000/contentvec/) ++ [VITS](https://github.com/jaywalnut310/vits) ++ [HIFIGAN](https://github.com/jik876/hifi-gan) ++ [Gradio](https://github.com/gradio-app/gradio) ++ [FFmpeg](https://github.com/FFmpeg/FFmpeg) ++ [Ultimate Vocal Remover](https://github.com/Anjok07/ultimatevocalremovergui) ++ [audio-slicer](https://github.com/openvpi/audio-slicer) + +## 貢献者(contributor)の皆様の尽力に感謝します + + + diff --git a/docs/README.ko.han.md b/docs/README.ko.han.md new file mode 100644 index 000000000..cac9d70c4 --- /dev/null +++ b/docs/README.ko.han.md @@ -0,0 +1,100 @@ +
+ +

Retrieval-based-Voice-Conversion-WebUI

+VITS基盤의 簡單하고使用하기 쉬운音聲變換틀

+ +[![madewithlove](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI) + +
+ +[![Open In Colab](https://img.shields.io/badge/Colab-F9AB00?style=for-the-badge&logo=googlecolab&color=525252)](https://colab.research.google.com/github/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/Retrieval_based_Voice_Conversion_WebUI.ipynb) +[![Licence](https://img.shields.io/github/license/RVC-Project/Retrieval-based-Voice-Conversion-WebUI?style=for-the-badge)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/LICENSE) +[![Huggingface](https://img.shields.io/badge/🤗%20-Spaces-yellow.svg?style=for-the-badge)](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/) + +[![Discord](https://img.shields.io/badge/RVC%20Developers-Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/HcsmBBGyVk) + +
+ +------ +[**更新日誌**](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/docs/Changelog_KO.md) + +[**English**](./README.en.md) | [**中文简体**](../README.md) | [**日本語**](./README.ja.md) | [**한국어**](./README.ko.md) ([**韓國語**](./README.ko.han.md)) + +> [示範映像](https://www.bilibili.com/video/BV1pm4y1z7Gm/)을 確認해 보세요! + +> RVC를活用한實時間音聲變換: [w-okada/voice-changer](https://github.com/w-okada/voice-changer) + +> 基本모델은 50時間假量의 高品質 오픈 소스 VCTK 데이터셋을 使用하였으므로, 著作權上의 念慮가 없으니 安心하고 使用하시기 바랍니다. + +> 著作權問題가 없는 高品質의 노래를 以後에도 繼續해서 訓練할 豫定입니다. + +## 紹介 +本Repo는 다음과 같은 特徵을 가지고 있습니다: ++ top1檢索을利用하여 入力音色特徵을 訓練세트音色特徵으로 代替하여 音色의漏出을 防止; ++ 相對的으로 낮은性能의 GPU에서도 빠른訓練可能; ++ 적은量의 데이터로 訓練해도 좋은 結果를 얻을 수 있음 (最小10分以上의 低雜음音聲데이터를 使用하는 것을 勸獎); ++ 모델融合을通한 音色의 變調可能 (ckpt處理탭->ckpt混合選擇); ++ 使用하기 쉬운 WebUI (웹 使用者인터페이스); ++ UVR5 모델을 利用하여 목소리와 背景音樂의 빠른 分離; + +## 環境의準備 +poetry를通해 依存를設置하는 것을 勸獎합니다. + +다음命令은 Python 버전3.8以上의環境에서 實行되어야 합니다: +```bash +# PyTorch 關聯主要依存設置, 이미設置되어 있는 境遇 건너뛰기 可能 +# 參照: https://pytorch.org/get-started/locally/ +pip install torch torchvision torchaudio + +# Windows + Nvidia Ampere Architecture(RTX30xx)를 使用하고 있다面, #21 에서 명시된 것과 같이 PyTorch에 맞는 CUDA 버전을 指定해야 합니다. +#pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117 + +# Poetry 設置, 이미設置되어 있는 境遇 건너뛰기 可能 +# Reference: https://python-poetry.org/docs/#installation +curl -sSL https://install.python-poetry.org | python3 - + +# 依存設置 +poetry install +``` +pip를 活用하여依存를 設置하여도 無妨합니다. + +```bash +pip install -r requirements.txt +``` + +## 其他預備모델準備 +RVC 모델은 推論과訓練을 依하여 다른 預備모델이 必要합니다. + +[Huggingface space](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/)를 通해서 다운로드 할 수 있습니다. + +다음은 RVC에 必要한 預備모델 및 其他 파일 目錄입니다: +```bash +hubert_base.pt + +./pretrained + +./uvr5_weights + +# Windows를 使用하는境遇 이 사전도 必要할 수 있습니다. FFmpeg가 設置되어 있으면 건너뛰어도 됩니다. +ffmpeg.exe +``` +그後 以下의 命令을 使用하여 WebUI를 始作할 수 있습니다: +```bash +python infer-web.py +``` +Windows를 使用하는境遇 `RVC-beta.7z`를 다운로드 및 壓縮解除하여 RVC를 直接使用하거나 `go-web.bat`을 使用하여 WebUi를 直接할 수 있습니다. + +## 參考 ++ [ContentVec](https://github.com/auspicious3000/contentvec/) ++ [VITS](https://github.com/jaywalnut310/vits) ++ [HIFIGAN](https://github.com/jik876/hifi-gan) ++ [Gradio](https://github.com/gradio-app/gradio) ++ [FFmpeg](https://github.com/FFmpeg/FFmpeg) ++ [Ultimate Vocal Remover](https://github.com/Anjok07/ultimatevocalremovergui) ++ [audio-slicer](https://github.com/openvpi/audio-slicer) +## 모든寄與者분들의勞力에感謝드립니다 + + + + + diff --git a/docs/README.ko.md b/docs/README.ko.md new file mode 100644 index 000000000..abea8e6a2 --- /dev/null +++ b/docs/README.ko.md @@ -0,0 +1,112 @@ +
+ +

Retrieval-based-Voice-Conversion-WebUI

+VITS 기반의 간단하고 사용하기 쉬운 음성 변환 프레임워크.

+ +[![madewithlove](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI) + +
+ +[![Open In Colab](https://img.shields.io/badge/Colab-F9AB00?style=for-the-badge&logo=googlecolab&color=525252)](https://colab.research.google.com/github/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/Retrieval_based_Voice_Conversion_WebUI.ipynb) +[![Licence](https://img.shields.io/github/license/RVC-Project/Retrieval-based-Voice-Conversion-WebUI?style=for-the-badge)](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/LICENSE) +[![Huggingface](https://img.shields.io/badge/🤗%20-Spaces-yellow.svg?style=for-the-badge)](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/) + +[![Discord](https://img.shields.io/badge/RVC%20Developers-Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/HcsmBBGyVk) + +
+ +--- + +[**업데이트 로그**](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/main/docs/Changelog_KO.md) + +[**English**](./README.en.md) | [**中文简体**](../README.md) | [**日本語**](./README.ja.md) | [**한국어**](./README.ko.md) ([**韓國語**](./README.ko.han.md)) + +> [데모 영상](https://www.bilibili.com/video/BV1pm4y1z7Gm/)을 확인해 보세요! + +> RVC를 활용한 실시간 음성변환: [w-okada/voice-changer](https://github.com/w-okada/voice-changer) + +> 기본 모델은 50시간 가량의 고퀄리티 오픈 소스 VCTK 데이터셋을 사용하였으므로, 저작권상의 염려가 없으니 안심하고 사용하시기 바랍니다. + +> 저작권 문제가 없는 고퀄리티의 노래를 이후에도 계속해서 훈련할 예정입니다. + +## 소개 + +본 Repo는 다음과 같은 특징을 가지고 있습니다: + +- top1 검색을 이용하여 입력 음색 특징을 훈련 세트 음색 특징으로 대체하여 음색의 누출을 방지; +- 상대적으로 낮은 성능의 GPU에서도 빠른 훈련 가능; +- 적은 양의 데이터로 훈련해도 좋은 결과를 얻을 수 있음 (최소 10분 이상의 저잡음 음성 데이터를 사용하는 것을 권장); +- 모델 융합을 통한 음색의 변조 가능 (ckpt 처리 탭->ckpt 병합 선택); +- 사용하기 쉬운 WebUI (웹 인터페이스); +- UVR5 모델을 이용하여 목소리와 배경음악의 빠른 분리; + +## 환경의 준비 + +poetry를 통해 dependecies를 설치하는 것을 권장합니다. + +다음 명령은 Python 버전 3.8 이상의 환경에서 실행되어야 합니다: + +```bash +# PyTorch 관련 주요 dependencies 설치, 이미 설치되어 있는 경우 건너뛰기 가능 +# 참조: https://pytorch.org/get-started/locally/ +pip install torch torchvision torchaudio + +# Windows + Nvidia Ampere Architecture(RTX30xx)를 사용하고 있다면, https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/issues/21 에서 명시된 것과 같이 PyTorch에 맞는 CUDA 버전을 지정해야 합니다. +#pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117 + +# Poetry 설치, 이미 설치되어 있는 경우 건너뛰기 가능 +# Reference: https://python-poetry.org/docs/#installation +curl -sSL https://install.python-poetry.org | python3 - + +# Dependecies 설치 +poetry install +``` + +pip를 활용하여 dependencies를 설치하여도 무방합니다. + +```bash +pip install -r requirements.txt +``` + +## 기타 사전 모델 준비 + +RVC 모델은 추론과 훈련을 위하여 다른 사전 모델이 필요합니다. + +[Huggingface space](https://huggingface.co/lj1995/VoiceConversionWebUI/tree/main/)를 통해서 다운로드 할 수 있습니다. + +다음은 RVC에 필요한 사전 모델 및 기타 파일 목록입니다: + +```bash +hubert_base.pt + +./pretrained + +./uvr5_weights + +# Windows를 사용하는 경우 이 사전도 필요할 수 있습니다. FFmpeg가 설치되어 있으면 건너뛰어도 됩니다. +ffmpeg.exe +``` + +그 후 이하의 명령을 사용하여 WebUI를 시작할 수 있습니다: + +```bash +python infer-web.py +``` + +Windows를 사용하는 경우 `RVC-beta.7z`를 다운로드 및 압축 해제하여 RVC를 직접 사용하거나 `go-web.bat`을 사용하여 WebUi를 시작할 수 있습니다. + +## 참고 + +- [ContentVec](https://github.com/auspicious3000/contentvec/) +- [VITS](https://github.com/jaywalnut310/vits) +- [HIFIGAN](https://github.com/jik876/hifi-gan) +- [Gradio](https://github.com/gradio-app/gradio) +- [FFmpeg](https://github.com/FFmpeg/FFmpeg) +- [Ultimate Vocal Remover](https://github.com/Anjok07/ultimatevocalremovergui) +- [audio-slicer](https://github.com/openvpi/audio-slicer) + +## 모든 기여자 분들의 노력에 감사드립니다. + + + + diff --git a/docs/faiss_tips_en.md b/docs/faiss_tips_en.md new file mode 100644 index 000000000..aafad6ed6 --- /dev/null +++ b/docs/faiss_tips_en.md @@ -0,0 +1,102 @@ +faiss tuning TIPS +================== +# about faiss +faiss is a library of neighborhood searches for dense vectors, developed by facebook research, which efficiently implements many approximate neighborhood search methods. +Approximate Neighbor Search finds similar vectors quickly while sacrificing some accuracy. + +## faiss in RVC +In RVC, for the embedding of features converted by HuBERT, we search for embeddings similar to the embedding generated from the training data and mix them to achieve a conversion that is closer to the original speech. However, since this search takes time if performed naively, high-speed conversion is realized by using approximate neighborhood search. + +# implementation overview +In '/logs/your-experiment/3_feature256' where the model is located, features extracted by HuBERT from each voice data are located. +From here we read the npy files in order sorted by filename and concatenate the vectors to create big_npy. (This vector has shape [N, 256].) +After saving big_npy as /logs/your-experiment/total_fea.npy, train it with faiss. + +In this article, I will explain the meaning of these parameters. + +# Explanation of the method +## index factory +An index factory is a unique faiss notation that expresses a pipeline that connects multiple approximate neighborhood search methods as a string. +This allows you to try various approximate neighborhood search methods simply by changing the index factory string. +In RVC it is used like this: + +```python +index = faiss.index_factory(256, "IVF%s,Flat" % n_ivf) +``` +Among the arguments of index_factory, the first is the number of dimensions of the vector, the second is the index factory string, and the third is the distance to use. + +For more detailed notation +https://github.com/facebookresearch/faiss/wiki/The-index-factory + +## index for distance +There are two typical indexes used as similarity of embedding as follows. + +- Euclidean distance (METRIC_L2) +- inner product (METRIC_INNER_PRODUCT) + +Euclidean distance takes the squared difference in each dimension, sums the differences in all dimensions, and then takes the square root. This is the same as the distance in 2D and 3D that we use on a daily basis. +The inner product is not used as an index of similarity as it is, and the cosine similarity that takes the inner product after being normalized by the L2 norm is generally used. + +Which is better depends on the case, but cosine similarity is often used in embedding obtained by word2vec and similar image retrieval models learned by ArcFace. If you want to do l2 normalization on vector X with numpy, you can do it with the following code with eps small enough to avoid 0 division. + +```python +X_normed = X / np.maximum(eps, np.linalg.norm(X, ord=2, axis=-1, keepdims=True)) +``` + +Also, for the index factory, you can change the distance index used for calculation by choosing the value to pass as the third argument. + +```python +index = faiss.index_factory(dimention, text, faiss.METRIC_INNER_PRODUCT) +``` + +## IVF +IVF (Inverted file indexes) is an algorithm similar to the inverted index in full-text search. +During learning, the search target is clustered with kmeans, and Voronoi partitioning is performed using the cluster center. Each data point is assigned a cluster, so we create a dictionary that looks up the data points from the clusters. + +For example, if clusters are assigned as follows +|index|Cluster| +|-----|-------| +|1|A| +|2|B| +|3|A| +|4|C| +|5|B| + +The resulting inverted index looks like this: + +|cluster|index| +|-------|-----| +|A|1, 3| +|B|2, 5| +|C|4| + +When searching, we first search n_probe clusters from the clusters, and then calculate the distances for the data points belonging to each cluster. + +# recommend parameter +There are official guidelines on how to choose an index, so I will explain accordingly. +https://github.com/facebookresearch/faiss/wiki/Guidelines-to-choose-an-index + +For datasets below 1M, 4bit-PQ is the most efficient method available in faiss as of April 2023. +Combining this with IVF, narrowing down the candidates with 4bit-PQ, and finally recalculating the distance with an accurate index can be described by using the following index factory. + +```python +index = faiss.index_factory(256, "IVF1024,PQ128x4fs,RFlat") +``` + +## Recommended parameters for IVF +Consider the case of too many IVFs. For example, if coarse quantization by IVF is performed for the number of data, this is the same as a naive exhaustive search and is inefficient. +For 1M or less, IVF values are recommended between 4*sqrt(N) ~ 16*sqrt(N) for N number of data points. + +Since the calculation time increases in proportion to the number of n_probes, please consult with the accuracy and choose appropriately. Personally, I don't think RVC needs that much accuracy, so n_probe = 1 is fine. + +## FastScan +FastScan is a method that enables high-speed approximation of distances by Cartesian product quantization by performing them in registers. +Cartesian product quantization performs clustering independently for each d dimension (usually d = 2) during learning, calculates the distance between clusters in advance, and creates a lookup table. At the time of prediction, the distance of each dimension can be calculated in O(1) by looking at the lookup table. +So the number you specify after PQ usually specifies half the dimension of the vector. + +For a more detailed description of FastScan, please refer to the official documentation. +https://github.com/facebookresearch/faiss/wiki/Fast-accumulation-of-PQ-and-AQ-codes-(FastScan) + +## RFlat +RFlat is an instruction to recalculate the rough distance calculated by FastScan with the exact distance specified by the third argument of index factory. +When getting k neighbors, k*k_factor points are recalculated. diff --git a/docs/faiss_tips_ja.md b/docs/faiss_tips_ja.md new file mode 100644 index 000000000..89cf5ba56 --- /dev/null +++ b/docs/faiss_tips_ja.md @@ -0,0 +1,101 @@ +faiss tuning TIPS +================== +# about faiss +faissはfacebook researchの開発する、密なベクトルに対する近傍探索をまとめたライブラリで、多くの近似近傍探索の手法を効率的に実装しています。 +近似近傍探索はある程度精度を犠牲にしながら高速に類似するベクトルを探します。 + +## faiss in RVC +RVCではHuBERTで変換した特徴量のEmbeddingに対し、学習データから生成されたEmbeddingと類似するものを検索し、混ぜることでより元の音声に近い変換を実現しています。ただ、この検索は愚直に行うと時間がかかるため、近似近傍探索を用いることで高速な変換を実現しています。 + +# 実装のoverview +モデルが配置されている '/logs/your-experiment/3_feature256'には各音声データからHuBERTで抽出された特徴量が配置されています。 +ここからnpyファイルをファイル名でソートした順番で読み込み、ベクトルを連結してbig_npyを作成しfaissを学習させます。(このベクトルのshapeは[N, 256]です。) + +本Tipsではまずこれらのパラメータの意味を解説します。 + +# 手法の解説 +## index factory +index factoryは複数の近似近傍探索の手法を繋げるパイプラインをstringで表記するfaiss独自の記法です。 +これにより、index factoryの文字列を変更するだけで様々な近似近傍探索の手法を試せます。 +RVCでは以下のように使われています。 + +```python +index = faiss.index_factory(256, "IVF%s,Flat" % n_ivf) +``` +index_factoryの引数のうち、1つ目はベクトルの次元数、2つ目はindex factoryの文字列で、3つ目には用いる距離を指定することができます。 + +より詳細な記法については +https://github.com/facebookresearch/faiss/wiki/The-index-factory + +## 距離指標 +embeddingの類似度として用いられる代表的な指標として以下の二つがあります。 + +- ユークリッド距離(METRIC_L2) +- 内積(METRIC_INNER_PRODUCT) + +ユークリッド距離では各次元において二乗の差をとり、全次元の差を足してから平方根をとります。これは日常的に用いる2次元、3次元での距離と同じです。 +内積はこのままでは類似度の指標として用いず、一般的にはL2ノルムで正規化してから内積をとるコサイン類似度を用います。 + +どちらがよいかは場合によりますが、word2vec等で得られるembeddingやArcFace等で学習した類似画像検索のモデルではコサイン類似度が用いられることが多いです。ベクトルXに対してl2正規化をnumpyで行う場合は、0 divisionを避けるために十分に小さな値をepsとして以下のコードで可能です。 + +```python +X_normed = X / np.maximum(eps, np.linalg.norm(X, ord=2, axis=-1, keepdims=True)) +``` + +また、index factoryには第3引数に渡す値を選ぶことで計算に用いる距離指標を変更できます。 + +```python +index = faiss.index_factory(dimention, text, faiss.METRIC_INNER_PRODUCT) +``` + +## IVF +IVF(Inverted file indexes)は全文検索における転置インデックスと似たようなアルゴリズムです。 +学習時には検索対象に対してkmeansでクラスタリングを行い、クラスタ中心を用いてボロノイ分割を行います。各データ点には一つずつクラスタが割り当てられるので、クラスタからデータ点を逆引きする辞書を作成します。 + +例えば以下のようにクラスタが割り当てられた場合 +|index|クラスタ| +|-----|-------| +|1|A| +|2|B| +|3|A| +|4|C| +|5|B| + +作成される転置インデックスは以下のようになります。 + +|クラスタ|index| +|-------|-----| +|A|1, 3| +|B|2, 5| +|C|4| + +検索時にはまずクラスタからn_probe個のクラスタを検索し、次にそれぞれのクラスタに属するデータ点について距離を計算します。 + +# 推奨されるパラメータ +indexの選び方については公式にガイドラインがあるので、それに準じて説明します。 +https://github.com/facebookresearch/faiss/wiki/Guidelines-to-choose-an-index + +1M以下のデータセットにおいては4bit-PQが2023年4月時点ではfaissで利用できる最も効率的な手法です。 +これをIVFと組み合わせ、4bit-PQで候補を絞り、最後に正確な指標で距離を再計算するには以下のindex factoryを用いることで記載できます。 + +```python +index = faiss.index_factory(256, "IVF1024,PQ128x4fs,RFlat") +``` + +## IVFの推奨パラメータ +IVFの数が多すぎる場合、たとえばデータ数の数だけIVFによる粗量子化を行うと、これは愚直な全探索と同じになり効率が悪いです。 +1M以下の場合ではIVFの値はデータ点の数Nに対して4*sqrt(N) ~ 16*sqrt(N)に推奨しています。 + +n_probeはn_probeの数に比例して計算時間が増えるので、精度と相談して適切に選んでください。個人的にはRVCにおいてそこまで精度は必要ないと思うのでn_probe = 1で良いと思います。 + +## FastScan +FastScanは直積量子化で大まかに距離を近似するのを、レジスタ内で行うことにより高速に行うようにした手法です。 +直積量子化は学習時にd次元ごと(通常はd=2)に独立してクラスタリングを行い、クラスタ同士の距離を事前計算してlookup tableを作成します。予測時はlookup tableを見ることで各次元の距離をO(1)で計算できます。 +そのため、PQの次に指定する数字は通常ベクトルの半分の次元を指定します。 + +FastScanに関するより詳細な説明は公式のドキュメントを参照してください。 +https://github.com/facebookresearch/faiss/wiki/Fast-accumulation-of-PQ-and-AQ-codes-(FastScan) + +## RFlat +RFlatはFastScanで計算した大まかな距離を、index factoryの第三引数で指定した正確な距離で再計算する指示です。 +k個の近傍を取得する際は、k*k_factor個の点について再計算が行われます。 diff --git a/docs/faiss_tips_ko.md b/docs/faiss_tips_ko.md new file mode 100644 index 000000000..ecd518ca2 --- /dev/null +++ b/docs/faiss_tips_ko.md @@ -0,0 +1,132 @@ +Facebook AI Similarity Search (Faiss) 팁 +================== +# Faiss에 대하여 +Faiss 는 Facebook Research가 개발하는, 고밀도 벡터 이웃 검색 라이브러리입니다. 근사 근접 탐색법 (Approximate Neigbor Search)은 약간의 정확성을 희생하여 유사 벡터를 고속으로 찾습니다. + +## RVC에 있어서 Faiss +RVC에서는 HuBERT로 변환한 feature의 embedding을 위해 훈련 데이터에서 생성된 embedding과 유사한 embadding을 검색하고 혼합하여 원래의 음성에 더욱 가까운 변환을 달성합니다. 그러나, 이 탐색법은 단순히 수행하면 시간이 다소 소모되므로, 근사 근접 탐색법을 통해 고속 변환을 가능케 하고 있습니다. + +# 구현 개요 +모델이 위치한 `/logs/your-experiment/3_feature256`에는 각 음성 데이터에서 HuBERT가 추출한 feature들이 있습니다. 여기에서 파일 이름별로 정렬된 npy 파일을 읽고, 벡터를 연결하여 big_npy ([N, 256] 모양의 벡터) 를 만듭니다. big_npy를 `/logs/your-experiment/total_fea.npy`로 저장한 후, Faiss로 학습시킵니다. + +2023/04/18 기준으로, Faiss의 Index Factory 기능을 이용해, L2 거리에 근거하는 IVF를 이용하고 있습니다. IVF의 분할수(n_ivf)는 N//39로, n_probe는 int(np.power(n_ivf, 0.3))가 사용되고 있습니다. (infer-web.py의 train_index 주위를 찾으십시오.) + +이 팁에서는 먼저 이러한 매개 변수의 의미를 설명하고, 개발자가 추후 더 나은 index를 작성할 수 있도록 하는 조언을 작성합니다. + +# 방법의 설명 +## Index factory +index factory는 여러 근사 근접 탐색법을 문자열로 연결하는 pipeline을 문자열로 표기하는 Faiss만의 독자적인 기법입니다. 이를 통해 index factory의 문자열을 변경하는 것만으로 다양한 근사 근접 탐색을 시도해 볼 수 있습니다. RVC에서는 다음과 같이 사용됩니다: + +```python +index = Faiss.index_factory(256, "IVF%s,Flat" % n_ivf) +``` +`index_factory`의 인수들 중 첫 번째는 벡터의 차원 수이고, 두번째는 index factory 문자열이며, 세번째에는 사용할 거리를 지정할 수 있습니다. + +기법의 보다 자세한 설명은 https://github.com/facebookresearch/Faiss/wiki/The-index-factory 를 확인해 주십시오. + +## 거리에 대한 index +embedding의 유사도로서 사용되는 대표적인 지표로서 이하의 2개가 있습니다. + +- 유클리드 거리 (METRIC_L2) +- 내적(内積) (METRIC_INNER_PRODUCT) + +유클리드 거리에서는 각 차원에서 제곱의 차를 구하고, 각 차원에서 구한 차를 모두 더한 후 제곱근을 취합니다. 이것은 일상적으로 사용되는 2차원, 3차원에서의 거리의 연산법과 같습니다. 내적은 그 값을 그대로 유사도 지표로 사용하지 않고, L2 정규화를 한 이후 내적을 취하는 코사인 유사도를 사용합니다. + +어느 쪽이 더 좋은지는 경우에 따라 다르지만, word2vec에서 얻은 embedding 및 ArcFace를 활용한 이미지 검색 모델은 코사인 유사성이 이용되는 경우가 많습니다. numpy를 사용하여 벡터 X에 대해 L2 정규화를 하고자 하는 경우, 0 division을 피하기 위해 충분히 작은 값을 eps로 한 뒤 이하에 코드를 활용하면 됩니다. + +```python +X_normed = X / np.maximum(eps, np.linalg.norm(X, ord=2, axis=-1, keepdims=True)) +``` + +또한, `index factory`의 3번째 인수에 건네주는 값을 선택하는 것을 통해 계산에 사용하는 거리 index를 변경할 수 있습니다. + +```python +index = Faiss.index_factory(dimention, text, Faiss.METRIC_INNER_PRODUCT) +``` + +## IVF +IVF (Inverted file indexes)는 역색인 탐색법과 유사한 알고리즘입니다. 학습시에는 검색 대상에 대해 k-평균 군집법을 실시하고 클러스터 중심을 이용해 보로노이 분할을 실시합니다. 각 데이터 포인트에는 클러스터가 할당되므로, 클러스터에서 데이터 포인트를 조회하는 dictionary를 만듭니다. + +예를 들어, 클러스터가 다음과 같이 할당된 경우 +|index|Cluster| +|-----|-------| +|1|A| +|2|B| +|3|A| +|4|C| +|5|B| + +IVF 이후의 결과는 다음과 같습니다: + +|cluster|index| +|-------|-----| +|A|1, 3| +|B|2, 5| +|C|4| + +탐색 시, 우선 클러스터에서 `n_probe`개의 클러스터를 탐색한 다음, 각 클러스터에 속한 데이터 포인트의 거리를 계산합니다. + +# 권장 매개변수 +index의 선택 방법에 대해서는 공식적으로 가이드 라인이 있으므로, 거기에 준해 설명합니다. +https://github.com/facebookresearch/Faiss/wiki/Guidelines-to-choose-an-index + +1M 이하의 데이터 세트에 있어서는 4bit-PQ가 2023년 4월 시점에서는 Faiss로 이용할 수 있는 가장 효율적인 수법입니다. 이것을 IVF와 조합해, 4bit-PQ로 후보를 추려내고, 마지막으로 이하의 index factory를 이용하여 정확한 지표로 거리를 재계산하면 됩니다. + +```python +index = Faiss.index_factory(256, "IVF1024,PQ128x4fs,RFlat") +``` + +## IVF 권장 매개변수 +IVF의 수가 너무 많으면, 가령 데이터 수의 수만큼 IVF로 양자화(Quantization)를 수행하면, 이것은 완전탐색과 같아져 효율이 나빠지게 됩니다. 1M 이하의 경우 IVF 값은 데이터 포인트 수 N에 대해 4sqrt(N) ~ 16sqrt(N)를 사용하는 것을 권장합니다. + +n_probe는 n_probe의 수에 비례하여 계산 시간이 늘어나므로 정확도와 시간을 적절히 균형을 맞추어 주십시오. 개인적으로 RVC에 있어서 그렇게까지 정확도는 필요 없다고 생각하기 때문에 n_probe = 1이면 된다고 생각합니다. + +## FastScan +FastScan은 직적 양자화를 레지스터에서 수행함으로써 거리의 고속 근사를 가능하게 하는 방법입니다.직적 양자화는 학습시에 d차원마다(보통 d=2)에 독립적으로 클러스터링을 실시해, 클러스터끼리의 거리를 사전 계산해 lookup table를 작성합니다. 예측시는 lookup table을 보면 각 차원의 거리를 O(1)로 계산할 수 있습니다. 따라서 PQ 다음에 지정하는 숫자는 일반적으로 벡터의 절반 차원을 지정합니다. + +FastScan에 대한 자세한 설명은 공식 문서를 참조하십시오. +https://github.com/facebookresearch/Faiss/wiki/Fast-accumulation-of-PQ-and-AQ-codes-(FastScan) + +## RFlat +RFlat은 FastScan이 계산한 대략적인 거리를 index factory의 3번째 인수로 지정한 정확한 거리로 다시 계산하라는 인스트럭션입니다. k개의 근접 변수를 가져올 때 k*k_factor개의 점에 대해 재계산이 이루어집니다. + +# Embedding 테크닉 +## Alpha 쿼리 확장 +퀴리 확장이란 탐색에서 사용되는 기술로, 예를 들어 전문 탐색 시, 입력된 검색문에 단어를 몇 개를 추가함으로써 검색 정확도를 올리는 방법입니다. 백터 탐색을 위해서도 몇가지 방법이 제안되었는데, 그 중 α-쿼리 확장은 추가 학습이 필요 없는 매우 효과적인 방법으로 알려져 있습니다. [Attention-Based Query Expansion Learning](https://arxiv.org/abs/2007.08019)와 [2nd place solution of kaggle shopee competition](https://www.kaggle.com/code/lyakaap/2nd-place-solution/notebook) 논문에서 소개된 바 있습니다.. + +α-쿼리 확장은 한 벡터에 인접한 벡터를 유사도의 α곱한 가중치로 더해주면 됩니다. 코드로 예시를 들어 보겠습니다. big_npy를 α query expansion로 대체합니다. + +```python +alpha = 3. +index = Faiss.index_factory(256, "IVF512,PQ128x4fs,RFlat") +original_norm = np.maximum(np.linalg.norm(big_npy, ord=2, axis=1, keepdims=True), 1e-9) +big_npy /= original_norm +index.train(big_npy) +index.add(big_npy) +dist, neighbor = index.search(big_npy, num_expand) + +expand_arrays = [] +ixs = np.arange(big_npy.shape[0]) +for i in range(-(-big_npy.shape[0]//batch_size)): + ix = ixs[i*batch_size:(i+1)*batch_size] + weight = np.power(np.einsum("nd,nmd->nm", big_npy[ix], big_npy[neighbor[ix]]), alpha) + expand_arrays.append(np.sum(big_npy[neighbor[ix]] * np.expand_dims(weight, axis=2),axis=1)) +big_npy = np.concatenate(expand_arrays, axis=0) + +# index version 정규화 +big_npy = big_npy / np.maximum(np.linalg.norm(big_npy, ord=2, axis=1, keepdims=True), 1e-9) +``` + +위 테크닉은 탐색을 수행하는 쿼리에도, 탐색 대상 DB에도 적응 가능한 테크닉입니다. + +## MiniBatch KMeans에 의한 embedding 압축 + +total_fea.npy가 너무 클 경우 K-means를 이용하여 벡터를 작게 만드는 것이 가능합니다. 이하 코드로 embedding의 압축이 가능합니다. n_clusters에 압축하고자 하는 크기를 지정하고 batch_size에 256 * CPU의 코어 수를 지정함으로써 CPU 병렬화의 혜택을 충분히 얻을 수 있습니다. + +```python +import multiprocessing +from sklearn.cluster import MiniBatchKMeans +kmeans = MiniBatchKMeans(n_clusters=10000, batch_size=256 * multiprocessing.cpu_count(), init="random") +kmeans.fit(big_npy) +sample_npy = kmeans.cluster_centers_ +``` \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 000000000..74eff82d9 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,89 @@ +## Q1:ffmpeg error/utf8 error. + +大概率不是ffmpeg问题,而是音频路径问题;
+ffmpeg读取路径带空格、()等特殊符号,可能出现ffmpeg error;训练集音频带中文路径,在写入filelist.txt的时候可能出现utf8 error;
+ +## Q2:一键训练结束没有索引 + +显示"Training is done. The program is closed."则模型训练成功,后续紧邻的报错是假的;
+ +一键训练结束完成没有added开头的索引文件,可能是因为训练集太大卡住了添加索引的步骤;已通过批处理add索引解决内存add索引对内存需求过大的问题。临时可尝试再次点击"训练索引"按钮。
+ +## Q3:训练结束推理没看到训练集的音色 +点刷新音色再看看,如果还没有看看训练有没有报错,控制台和webui的截图,logs/实验名下的log,都可以发给开发者看看。
+ +## Q4:如何分享模型 +  rvc_root/logs/实验名 下面存储的pth不是用来分享模型用来推理的,而是为了存储实验状态供复现,以及继续训练用的。用来分享的模型应该是weights文件夹下大小为60+MB的pth文件;
+  后续将把weights/exp_name.pth和logs/exp_name/added_xxx.index合并打包成weights/exp_name.zip省去填写index的步骤,那么zip文件用来分享,不要分享pth文件,除非是想换机器继续训练;
+  如果你把logs文件夹下的几百MB的pth文件复制/分享到weights文件夹下强行用于推理,可能会出现f0,tgt_sr等各种key不存在的报错。你需要用ckpt选项卡最下面,手工或自动(本地logs下如果能找到相关信息则会自动)选择是否携带音高、目标音频采样率的选项后进行ckpt小模型提取(输入路径填G开头的那个),提取完在weights文件夹下会出现60+MB的pth文件,刷新音色后可以选择使用。
+ +## Q5:Connection Error. +也许你关闭了控制台(黑色窗口)。
+ +## Q6:WebUI弹出Expecting value: line 1 column 1 (char 0). +请关闭系统局域网代理/全局代理。
+ +这个不仅是客户端的代理,也包括服务端的代理(例如你使用autodl设置了http_proxy和https_proxy学术加速,使用时也需要unset关掉)
+ +## Q7:不用WebUI如何通过命令训练推理 +训练脚本:
+可先跑通WebUI,消息窗内会显示数据集处理和训练用命令行;
+ +推理脚本:
+https://huggingface.co/lj1995/VoiceConversionWebUI/blob/main/myinfer.py
+ +例子:
+ +runtime\python.exe myinfer.py 0 "E:\codes\py39\RVC-beta\todo-songs\1111.wav" "E:\codes\py39\logs\mi-test\added_IVF677_Flat_nprobe_7.index" harvest "test.wav" "weights/mi-test.pth" 0.6 cuda:0 True
+ +f0up_key=sys.argv[1]
+input_path=sys.argv[2]
+index_path=sys.argv[3]
+f0method=sys.argv[4]#harvest or pm
+opt_path=sys.argv[5]
+model_path=sys.argv[6]
+index_rate=float(sys.argv[7])
+device=sys.argv[8]
+is_half=bool(sys.argv[9])
+ +## Q8:Cuda error/Cuda out of memory. +小概率是cuda配置问题、设备不支持;大概率是显存不够(out of memory);
+ +训练的话缩小batch size(如果缩小到1还不够只能更换显卡训练),推理的话酌情缩小config.py结尾的x_pad,x_query,x_center,x_max。4G以下显存(例如1060(3G)和各种2G显卡)可以直接放弃,4G显存显卡还有救。
+ +## Q9:total_epoch调多少比较好 + +如果训练集音质差底噪大,20~30足够了,调太高,底模音质无法带高你的低音质训练集
+如果训练集音质高底噪低时长多,可以调高,200是ok的(训练速度很快,既然你有条件准备高音质训练集,显卡想必条件也不错,肯定不在乎多一些训练时间)
+ +## Q10:需要多少训练集时长 +  推荐10min至50min
+  保证音质高底噪低的情况下,如果有个人特色的音色统一,则多多益善
+  高水平的训练集(精简+音色有特色),5min至10min也是ok的,仓库作者本人就经常这么玩
+  也有人拿1min至2min的数据来训练并且训练成功的,但是成功经验是其他人不可复现的,不太具备参考价值。这要求训练集音色特色非常明显(比如说高频气声较明显的萝莉少女音),且音质高;
+  1min以下时长数据目前没见有人尝试(成功)过。不建议进行这种鬼畜行为。
+ +## Q11:index rate干嘛用的,怎么调(科普) +  如果底模和推理源的音质高于训练集的音质,他们可以带高推理结果的音质,但代价可能是音色往底模/推理源的音色靠,这种现象叫做"音色泄露";
+  index rate用来削减/解决音色泄露问题。调到1,则理论上不存在推理源的音色泄露问题,但音质更倾向于训练集。如果训练集音质比推理源低,则index rate调高可能降低音质。调到0,则不具备利用检索混合来保护训练集音色的效果;
+  如果训练集优质时长多,可调高total_epoch,此时模型本身不太会引用推理源和底模的音色,很少存在"音色泄露"问题,此时index_rate不重要,你甚至可以不建立/分享index索引文件。
+ +## Q11:推理怎么选gpu +config.py文件里device cuda:后面选择卡号;
+卡号和显卡的映射关系,在训练选项卡的显卡信息栏里能看到。
+ +## Q12:如何推理训练中间保存的pth +通过ckpt选项卡最下面提取小模型。
+ + +## Q13:如何中断和继续训练 +现阶段只能关闭WebUI控制台双击go-web.bat重启程序。网页参数也要刷新重新填写;
+继续训练:相同网页参数点训练模型,就会接着上次的checkpoint继续训练。
+ +## Q14:训练时出现文件页面/内存error +进程开太多了,内存炸了。你可能可以通过如下方式解决
+1、"提取音高和处理数据使用的CPU进程数" 酌情拉低;
+2、训练集音频手工切一下,不要太长。
+ + + diff --git a/docs/faq_en.md b/docs/faq_en.md new file mode 100644 index 000000000..05f03ec04 --- /dev/null +++ b/docs/faq_en.md @@ -0,0 +1,95 @@ +## Q1:ffmpeg error/utf8 error. +It is most likely not a FFmpeg issue, but rather an audio path issue; + +FFmpeg may encounter an error when reading paths containing special characters like spaces and (), which may cause an FFmpeg error; and when the training set's audio contains Chinese paths, writing it into filelist.txt may cause a utf8 error.
+ +## Q2:Cannot find index file after "One-click Training". +If it displays "Training is done. The program is closed," then the model has been trained successfully, and the subsequent errors are fake; + +The lack of an 'added' index file after One-click training may be due to the training set being too large, causing the addition of the index to get stuck; this has been resolved by using batch processing to add the index, which solves the problem of memory overload when adding the index. As a temporary solution, try clicking the "Train Index" button again.
+ +## Q3:Cannot find the model in “Inferencing timbre” after training +Click “Refresh timbre list” and check again; if still not visible, check if there are any errors during training and send screenshots of the console, web UI, and logs/experiment_name/*.log to the developers for further analysis.
+ +## Q4:How to share a model/How to use others' models? +The pth files stored in rvc_root/logs/experiment_name are not meant for sharing or inference, but for storing the experiment checkpoits for reproducibility and further training. The model to be shared should be the 60+MB pth file in the weights folder; + +In the future, weights/exp_name.pth and logs/exp_name/added_xxx.index will be merged into a single weights/exp_name.zip file to eliminate the need for manual index input; so share the zip file, not the pth file, unless you want to continue training on a different machine; + +Copying/sharing the several hundred MB pth files from the logs folder to the weights folder for forced inference may result in errors such as missing f0, tgt_sr, or other keys. You need to use the ckpt tab at the bottom to manually or automatically (if the information is found in the logs/exp_name), select whether to include pitch infomation and target audio sampling rate options and then extract the smaller model. After extraction, there will be a 60+ MB pth file in the weights folder, and you can refresh the voices to use it.
+ +## Q5:Connection Error. +You may have closed the console (black command line window).
+ +## Q6:WebUI popup 'Expecting value: line 1 column 1 (char 0)'. +Please disable system LAN proxy/global proxy and then refresh.
+ +## Q7:How to train and infer without the WebUI? +Training script:
+You can run training in WebUI first, and the command-line versions of dataset preprocessing and training will be displayed in the message window.
+ +Inference script:
+https://huggingface.co/lj1995/VoiceConversionWebUI/blob/main/myinfer.py
+ + +e.g.
+ +runtime\python.exe myinfer.py 0 "E:\codes\py39\RVC-beta\todo-songs\1111.wav" "E:\codes\py39\logs\mi-test\added_IVF677_Flat_nprobe_7.index" harvest "test.wav" "weights/mi-test.pth" 0.6 cuda:0 True
+ + +f0up_key=sys.argv[1]
+input_path=sys.argv[2]
+index_path=sys.argv[3]
+f0method=sys.argv[4]#harvest or pm
+opt_path=sys.argv[5]
+model_path=sys.argv[6]
+index_rate=float(sys.argv[7])
+device=sys.argv[8]
+is_half=bool(sys.argv[9])
+ +## Q8:Cuda error/Cuda out of memory. +There is a small chance that there is a problem with the CUDA configuration or the device is not supported; more likely, there is not enough memory (out of memory).
+ +For training, reduce the batch size (if reducing to 1 is still not enough, you may need to change the graphics card); for inference, adjust the x_pad, x_query, x_center, and x_max settings in the config.py file as needed. 4G or lower memory cards (e.g. 1060(3G) and various 2G cards) can be abandoned, while 4G memory cards still have a chance.
+ +## Q9:How many total_epoch are optimal? +If the training dataset's audio quality is poor and the noise floor is high, 20-30 epochs are sufficient. Setting it too high won't improve the audio quality of your low-quality training set.
+ +If the training set audio quality is high, the noise floor is low, and there is sufficient duration, you can increase it. 200 is acceptable (since training is fast, and if you're able to prepare a high-quality training set, your GPU likely can handle a longer training duration without issue).
+ +## Q10:How much training set duration is needed? + +A dataset of around 10min to 50min is recommended.
+ +With guaranteed high sound quality and low bottom noise, more can be added if the dataset's timbre is uniform.
+ +For a high-level training set (lean + distinctive tone), 5min to 10min is fine.
+ +There are some people who have trained successfully with 1min to 2min data, but the success is not reproducible by others and is not very informative.
This requires that the training set has a very distinctive timbre (e.g. a high-frequency airy anime girl sound) and the quality of the audio is high; +Data of less than 1min duration has not been successfully attempted so far. This is not recommended.
+ + +## Q11:What is the index rate for and how to adjust it? +If the tone quality of the pre-trained model and inference source is higher than that of the training set, they can bring up the tone quality of the inference result, but at the cost of a possible tone bias towards the tone of the underlying model/inference source rather than the tone of the training set, which is generally referred to as "tone leakage".
+ +The index rate is used to reduce/resolve the timbre leakage problem. If the index rate is set to 1, theoretically there is no timbre leakage from the inference source and the timbre quality is more biased towards the training set. If the training set has a lower sound quality than the inference source, then a higher index rate may reduce the sound quality. Turning it down to 0 does not have the effect of using retrieval blending to protect the training set tones.
+ +If the training set has good audio quality and long duration, turn up the total_epoch, when the model itself is less likely to refer to the inferred source and the pretrained underlying model, and there is little "tone leakage", the index_rate is not important and you can even not create/share the index file.
+ +## Q12:How to choose the gpu when inferring? +In the config.py file, select the card number after "device cuda:".
+ +The mapping between card number and graphics card can be seen in the graphics card information section of the training tab.
+ +## Q13:How to use the model saved in the middle of training? +Save via model extraction at the bottom of the ckpt processing tab. + +## Q14:File/memory error(when training)? +Too many processes and your memory is not enough. You may fix it by: + +1、decrease the input in field "Threads of CPU". + +2、pre-cut trainset to shorter audio files. + + + diff --git a/docs/training_tips_en.md b/docs/training_tips_en.md new file mode 100644 index 000000000..ab9b1f876 --- /dev/null +++ b/docs/training_tips_en.md @@ -0,0 +1,65 @@ +Instructions and tips for RVC training +====================================== +This TIPS explains how data training is done. + +# Training flow +I will explain along the steps in the training tab of the GUI. + +## step1 +Set the experiment name here. + +You can also set here whether the model should take pitch into account. +If the model doesn't consider pitch, the model will be lighter, but not suitable for singing. + +Data for each experiment is placed in `/logs/your-experiment-name/`. + +## step2a +Loads and preprocesses audio. + +### load audio +If you specify a folder with audio, the audio files in that folder will be read automatically. +For example, if you specify `C:Users\hoge\voices`, `C:Users\hoge\voices\voice.mp3` will be loaded, but `C:Users\hoge\voices\dir\voice.mp3` will Not loaded. + +Since ffmpeg is used internally for reading audio, if the extension is supported by ffmpeg, it will be read automatically. +After converting to int16 with ffmpeg, convert to float32 and normalize between -1 to 1. + +### denoising +The audio is smoothed by scipy's filtfilt. + +### Audio Split +First, the input audio is divided by detecting parts of silence that last longer than a certain period (max_sil_kept=5 seconds?). After splitting the audio on silence, split the audio every 4 seconds with an overlap of 0.3 seconds. For audio separated within 4 seconds, after normalizing the volume, convert the wav file to `/logs/your-experiment-name/0_gt_wavs` and then convert it to 16k sampling rate to `/logs/your-experiment-name/1_16k_wavs ` as a wav file. + +## step2b +### Extract pitch +Extract pitch information from wav files. Extract the pitch information (=f0) using the method built into parselmouth or pyworld and save it in `/logs/your-experiment-name/2a_f0`. Then logarithmically convert the pitch information to an integer between 1 and 255 and save it in `/logs/your-experiment-name/2b-f0nsf`. + +### Extract feature_print +Convert the wav file to embedding in advance using HuBERT. Read the wav file saved in `/logs/your-experiment-name/1_16k_wavs`, convert the wav file to 256-dimensional features with HuBERT, and save in npy format in `/logs/your-experiment-name/3_feature256`. + +## step3 +train the model. +### Glossary for Beginners +In deep learning, the data set is divided and the learning proceeds little by little. In one model update (step), batch_size data are retrieved and predictions and error corrections are performed. Doing this once for a dataset counts as one epoch. + +Therefore, the learning time is the learning time per step x (the number of data in the dataset / batch size) x the number of epochs. In general, the larger the batch size, the more stable the learning becomes (learning time per step ÷ batch size) becomes smaller, but it uses more GPU memory. GPU RAM can be checked with the nvidia-smi command. Learning can be done in a short time by increasing the batch size as much as possible according to the machine of the execution environment. + +### Specify pretrained model +RVC starts training the model from pretrained weights instead of from 0, so it can be trained with a small dataset. + +By default + +- If you consider pitch, it loads `rvc-location/pretrained/f0G40k.pth` and `rvc-location/pretrained/f0D40k.pth`. +- If you don't consider pitch, it loads `rvc-location/pretrained/f0G40k.pth` and `rvc-location/pretrained/f0D40k.pth`. + +When learning, model parameters are saved in `logs/your-experiment-name/G_{}.pth` and `logs/your-experiment-name/D_{}.pth` for each save_every_epoch, but by specifying this path, you can start learning. You can restart or start training from model weights learned in a different experiment. + +### learning index +RVC saves the HuBERT feature values used during training, and during inference, searches for feature values that are similar to the feature values used during learning to perform inference. In order to perform this search at high speed, the index is learned in advance. +For index learning, we use the approximate neighborhood search library faiss. Read the feature value of `logs/your-experiment-name/3_feature256` and use it to learn the index, and save it as `logs/your-experiment-name/add_XXX.index`. + +(From the 20230428update version, it is read from the index, and saving / specifying is no longer necessary.) + +### Button description +- Train model: After executing step2b, press this button to train the model. +- Train feature index: After training the model, perform index learning. +- One-click training: step2b, model training and feature index training all at once. \ No newline at end of file diff --git a/docs/training_tips_ja.md b/docs/training_tips_ja.md new file mode 100644 index 000000000..c5b06f2fd --- /dev/null +++ b/docs/training_tips_ja.md @@ -0,0 +1,64 @@ +RVCの訓練における説明、およびTIPS +=============================== +本TIPSではどのようにデータの訓練が行われているかを説明します。 + +# 訓練の流れ +GUIの訓練タブのstepに沿って説明します。 + +## step1 +実験名の設定を行います。 + +また、モデルに音高ガイド(ピッチ)を考慮させるかもここで設定できます。考慮させない場合はモデルは軽量になりますが、歌唱には向かなくなります。 + +各実験のデータは`/logs/実験名/`に配置されます。 + +## step2a +音声の読み込みと前処理を行います。 + +### load audio +音声のあるフォルダを指定すると、そのフォルダ内にある音声ファイルを自動で読み込みます。 +例えば`C:Users\hoge\voices`を指定した場合、`C:Users\hoge\voices\voice.mp3`は読み込まれますが、`C:Users\hoge\voices\dir\voice.mp3`は読み込まれません。 + +音声の読み込みには内部でffmpegを利用しているので、ffmpegで対応している拡張子であれば自動的に読み込まれます。 +ffmpegでint16に変換した後、float32に変換し、-1 ~ 1の間に正規化されます。 + +### denoising +音声についてscipyのfiltfiltによる平滑化を行います。 + +### 音声の分割 +入力した音声はまず、一定期間(max_sil_kept=5秒?)より長く無音が続く部分を検知して音声を分割します。無音で音声を分割した後は、0.3秒のoverlapを含む4秒ごとに音声を分割します。4秒以内に区切られた音声は、音量の正規化を行った後wavファイルを`/logs/実験名/0_gt_wavs`に、そこから16kのサンプリングレートに変換して`/logs/実験名/1_16k_wavs`にwavファイルで保存します。 + +## step2b +### ピッチの抽出 +wavファイルからピッチ(音の高低)の情報を抽出します。parselmouthやpyworldに内蔵されている手法でピッチ情報(=f0)を抽出し、`/logs/実験名/2a_f0`に保存します。その後、ピッチ情報を対数で変換して1~255の整数に変換し、`/logs/実験名/2b-f0nsf`に保存します。 + +### feature_printの抽出 +HuBERTを用いてwavファイルを事前にembeddingに変換します。`/logs/実験名/1_16k_wavs`に保存したwavファイルを読み込み、HuBERTでwavファイルを256次元の特徴量に変換し、npy形式で`/logs/実験名/3_feature256`に保存します。 + +## step3 +モデルのトレーニングを行います。 +### 初心者向け用語解説 +深層学習ではデータセットを分割し、少しずつ学習を進めていきます。一回のモデルの更新(step)では、batch_size個のデータを取り出し予測と誤差の修正を行います。これをデータセットに対して一通り行うと一epochと数えます。 + +そのため、学習時間は 1step当たりの学習時間 x (データセット内のデータ数 ÷ バッチサイズ) x epoch数 かかります。一般にバッチサイズを大きくするほど学習は安定し、(1step当たりの学習時間÷バッチサイズ)は小さくなりますが、その分GPUのメモリを多く使用します。GPUのRAMはnvidia-smiコマンド等で確認できます。実行環境のマシンに合わせてバッチサイズをできるだけ大きくするとより短時間で学習が可能です。 + +### pretrained modelの指定 +RVCではモデルの訓練を0からではなく、事前学習済みの重みから開始するため、少ないデータセットで学習を行えます。 + +デフォルトでは + +- 音高ガイドを考慮する場合、`RVCのある場所/pretrained/f0G40k.pth`と`RVCのある場所/pretrained/f0D40k.pth`を読み込みます。 +- 音高ガイドを考慮しない場合、`RVCのある場所/pretrained/G40k.pth`と`RVCのある場所/pretrained/D40k.pth`を読み込みます。 + +学習時はsave_every_epochごとにモデルのパラメータが`logs/実験名/G_{}.pth`と`logs/実験名/D_{}.pth`に保存されますが、このパスを指定することで学習を再開したり、もしくは違う実験で学習したモデルの重みから学習を開始できます。 + +### indexの学習 +RVCでは学習時に使われたHuBERTの特徴量を保存し、推論時は学習時の特徴量から近い特徴量を探してきて推論を行います。この検索を高速に行うために事前にindexの学習を行います。 +indexの学習には近似近傍探索ライブラリのfaissを用います。`/logs/実験名/3_feature256`の特徴量を読み込み、それを用いて学習したindexを`/logs/実験名/add_XXX.index`として保存します。 +(20230428updateよりtotal_fea.npyはindexから読み込むので不要になりました。) + +### ボタンの説明 +- モデルのトレーニング: step2bまでを実行した後、このボタンを押すとモデルの学習を行います。 +- 特徴インデックスのトレーニング: モデルのトレーニング後、indexの学習を行います。 +- ワンクリックトレーニング: step2bまでとモデルのトレーニング、特徴インデックスのトレーニングを一括で行います。 + diff --git a/docs/training_tips_ko.md b/docs/training_tips_ko.md new file mode 100644 index 000000000..8b3b62458 --- /dev/null +++ b/docs/training_tips_ko.md @@ -0,0 +1,53 @@ +RVC 훈련에 대한 설명과 팁들 +====================================== +본 팁에서는 어떻게 데이터 훈련이 이루어지고 있는지 설명합니다. + +# 훈련의 흐름 +GUI의 훈련 탭의 단계를 따라 설명합니다. + +## step1 +실험 이름을 지정합니다. 또한, 모델이 피치(소리의 높낮이)를 고려해야 하는지 여부를 여기에서 설정할 수도 있습니다.. +각 실험을 위한 데이터는 `/logs/experiment name/`에 배치됩니다.. + +## step2a +음성 파일을 불러오고 전처리합니다. + +### 음성 파일 불러오기 +음성 파일이 있는 폴더를 지정하면 해당 폴더에 있는 음성 파일이 자동으로 가져와집니다. +예를 들어 `C:Users\hoge\voices`를 지정하면 `C:Users\hoge\voices\voice.mp3`가 읽히지만 `C:Users\hoge\voices\dir\voice.mp3`는 읽히지 않습니다. + +음성 로드에는 내부적으로 ffmpeg를 이용하고 있으므로, ffmpeg로 대응하고 있는 확장자라면 자동적으로 읽힙니다. +ffmpeg에서 int16으로 변환한 후 float32로 변환하고 -1과 1 사이에 정규화됩니다. + +### 잡음 제거 +음성 파일에 대해 scipy의 filtfilt를 이용하여 잡음을 처리합니다. + +### 음성 분할 +입력한 음성 파일은 먼저 일정 기간(max_sil_kept=5초?)보다 길게 무음이 지속되는 부분을 감지하여 음성을 분할합니다.무음으로 음성을 분할한 후에는 0.3초의 overlap을 포함하여 4초마다 음성을 분할합니다.4초 이내에 구분된 음성은 음량의 정규화를 실시한 후 wav 파일을 `/logs/실험명/0_gt_wavs`로, 거기에서 16k의 샘플링 레이트로 변환해 `/logs/실험명/1_16k_wavs`에 wav 파일로 저장합니다. + +## step2b +### 피치 추출 +wav 파일에서 피치(소리의 높낮이) 정보를 추출합니다. parselmouth나 pyworld에 내장되어 있는 메서드으로 피치 정보(=f0)를 추출해, `/logs/실험명/2a_f0`에 저장합니다. 그 후 피치 정보를 로그로 변환하여 1~255 정수로 변환하고 `/logs/실험명/2b-f0nsf`에 저장합니다. + +### feature_print 추출 +HuBERT를 이용하여 wav 파일을 미리 embedding으로 변환합니다. `/logs/실험명/1_16k_wavs`에 저장한 wav 파일을 읽고 HuBERT에서 wav 파일을 256차원 feature들로 변환한 후 npy 형식으로 `/logs/실험명/3_feature256`에 저장합니다. + +## step3 +모델의 훈련을 진행합니다. + +### 초보자용 용어 해설 +심층학습(딥러닝)에서는 데이터셋을 분할하여 조금씩 학습을 진행합니다.한 번의 모델 업데이트(step) 단계 당 batch_size개의 데이터를 탐색하여 예측과 오차를 수정합니다. 데이터셋 전부에 대해 이 작업을 한 번 수행하는 이를 하나의 epoch라고 계산합니다. + +따라서 학습 시간은 단계당 학습 시간 x (데이터셋 내 데이터의 수 / batch size) x epoch 수가 소요됩니다. 일반적으로 batch size가 클수록 학습이 안정적이게 됩니다. (step당 학습 시간 ÷ batch size)는 작아지지만 GPU 메모리를 더 많이 사용합니다. GPU RAM은 nvidia-smi 명령어를 통해 확인할 수 있습니다. 실행 환경에 따라 배치 크기를 최대한 늘리면 짧은 시간 내에 학습이 가능합니다. + +### 사전 학습된 모델 지정 +RVC는 적은 데이터셋으로도 훈련이 가능하도록 사전 훈련된 가중치에서 모델 훈련을 시작합니다. 기본적으로 `rvc-location/pretrained/f0G40k.pth` 및 `rvc-location/pretrained/f0D40k.pth`를 불러옵니다. 학습을 할 시에, 모델 파라미터는 각 save_every_epoch별로 `logs/experiment name/G_{}.pth` 와 `logs/experiment name/D_{}.pth`로 저장이 되는데, 이 경로를 지정함으로써 학습을 재개하거나, 다른 실험에서 학습한 모델의 가중치에서 학습을 시작할 수 있습니다. + +### index의 학습 +RVC에서는 학습시에 사용된 HuBERT의 feature값을 저장하고, 추론 시에는 학습 시 사용한 feature값과 유사한 feature 값을 탐색해 추론을 진행합니다. 이 탐색을 고속으로 수행하기 위해 사전에 index을 학습하게 됩니다. +Index 학습에는 근사 근접 탐색법 라이브러리인 Faiss를 사용하게 됩니다. `/logs/실험명/3_feature256`의 feature값을 불러와, 이를 모두 결합시킨 feature값을 `/logs/실험명/total_fea.npy`로서 저장, 그것을 사용해 학습한 index를`/logs/실험명/add_XXX.index`로 저장합니다. + +### 버튼 설명 +- モデルのトレーニング (모델 학습): step2b까지 실행한 후, 이 버튼을 눌러 모델을 학습합니다. +- 特徴インデックスのトレーニング (특징 지수 훈련): 모델의 훈련 후, index를 학습합니다. +- ワンクリックトレーニング (원클릭 트레이닝): step2b까지의 모델 훈련, feature index 훈련을 일괄로 실시합니다. \ No newline at end of file diff --git "a/docs/\345\260\217\347\231\275\347\256\200\346\230\223\346\225\231\347\250\213.doc" "b/docs/\345\260\217\347\231\275\347\256\200\346\230\223\346\225\231\347\250\213.doc" new file mode 100644 index 0000000000000000000000000000000000000000..2e291891303f0f805c36a463a3fecbde8d82c4de GIT binary patch literal 602624 zcmeF(bzBx*zc6~dZB!5eK@d>7k(O4vk#0~@T3TAALAqN>0Rcfem2RXPq`Rf-{f+l? z@BN(T*?Ygw`#JlMv(Gt;&-a?SCa#%Tvu4ejwbt;X3*+a|`2QdN9})wnupgJ< zJR#@s5)A#}0~x;xBK9Dr@1t95Y6(DKp03hkFomy|1tdD57;;|{}OD32!_Z# z2u1qBqa6P_*K6l<(il43^24srWjySxoyp8RtgmSya~dNbqg;_o3g?vem%0A?Izra{ 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