diff --git a/.gitignore b/.gitignore index 85c0cf2..a1763c9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ venv/ *.csv *.bak /mos_results/ + +safetensors.ipynb diff --git a/README.md b/README.md index 1fd0e26..3e7d012 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ https://github.com/litagin02/Style-Bert-VITS2/assets/139731664/e853f9a2-db4a-420 - [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](http://colab.research.google.com/github/litagin02/Style-Bert-VITS2/blob/master/colab.ipynb) - [🤗 オンラインデモはこちらから](https://huggingface.co/spaces/litagin/Style-Bert-VITS2-JVNV) -- [**リリースページ**](https://github.com/litagin02/Style-Bert-VITS2/releases/tag/2.0)、[更新履歴](docs/CHANGELOG.md) +- [**リリースページ**](https://github.com/litagin02/Style-Bert-VITS2/releases/)、[更新履歴](docs/CHANGELOG.md) - - 2024-02-05: ver 2.0.1 + - 2024-02-07: ver 2.1 - 2024-02-03: ver 2.0 - 2024-01-09: ver 1.3 - 2023-12-31: ver 1.2 @@ -25,7 +25,7 @@ This repository is based on [Bert-VITS2](https://github.com/fishaudio/Bert-VITS2 - GitやPythonがない人でも(Windowsユーザーなら)簡単にインストールでき、学習もできます (多くを[EasyBertVits2](https://github.com/Zuntan03/EasyBertVits2/)からお借りしました)。またGoogle Colabでの学習もサポートしています: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](http://colab.research.google.com/github/litagin02/Style-Bert-VITS2/blob/master/colab.ipynb) - 音声合成のみに使う場合は、グラボがなくてもCPUで動作します。 - 他との連携に使えるAPIサーバーも同梱しています ([@darai0512](https://github.com/darai0512) 様によるPRです、ありがとうございます)。 -- 元々が「楽しそうな文章は楽しそうに、悲しそうな文章は悲しそうに」読むのがBert-VITS2の強みですので、このフォークで付加されたスタイル指定を無理に使わずとも感情豊かな音声を生成することができます。 +- 元々「楽しそうな文章は楽しそうに、悲しそうな文章は悲しそうに」読むのがBert-VITS2の強みですので、スタイル指定がデフォルトでも感情豊かな音声を生成することができます。 ## 使い方 @@ -141,7 +141,7 @@ python speech_mos.py -m - [EasyBertVits2](https://github.com/Zuntan03/EasyBertVits2)のように、PythonやGitを知らない人でも簡単に使える。 - 感情埋め込みのモデルを変更(256次元の[wespeaker-voxceleb-resnet34-LM](https://huggingface.co/pyannote/wespeaker-voxceleb-resnet34-LM)へ、感情埋め込みというよりは話者識別のための埋め込み) -- 埋め込みもベクトル量子化を取り払い、単なる全結合層に。 +- 感情埋め込みもベクトル量子化を取り払い、単なる全結合層に。 - スタイルベクトルファイル`style_vectors.npy`を作ることで、そのスタイルを使って効果の強さも連続的に指定しつつ音声を生成することができる。 - 各種WebUIを作成 - bf16での学習のサポート @@ -149,15 +149,12 @@ python speech_mos.py -m - その他軽微なbugfixやリファクタリング ## TODO -- [ ] デフォルトのJVNVモデルにJP-Extra版のものを追加 +- [x] デフォルトのJVNVモデルにJP-Extra版のものを追加 - [x] LinuxやWSL等、Windowsの通常環境以外でのサポート ← おそらく問題ないとの報告あり - [x] 複数話者学習での音声合成対応(学習は現在でも可能) -- [ ] 本家のver 2.1, 2.2, 2.3モデルの推論対応?(ver 2.1以外は明らかにめんどいのでたぶんやらない) - [x] `server_fastapi.py`の対応、とくにAPIで使えるようになると嬉しい人が増えるのかもしれない - [x] モデルのマージで声音と感情表現を混ぜる機能の実装 - [ ] 英語等多言語対応? -- [ ] ONNX対応 - ## References In addition to the original reference (written below), I used the following repositories: diff --git a/app.py b/app.py index 284098f..92c2e13 100644 --- a/app.py +++ b/app.py @@ -19,6 +19,7 @@ from common.constants import ( DEFAULT_SPLIT_INTERVAL, DEFAULT_STYLE, DEFAULT_STYLE_WEIGHT, + LATEST_VERSION, Languages, ) from common.log import logger @@ -36,6 +37,8 @@ languages = [l.value for l in Languages] def tts_fn( + model_name, + model_path, text, language, reference_audio_path, @@ -54,7 +57,7 @@ def tts_fn( use_tone, speaker, ): - assert model_holder.current_model is not None + model_holder.load_model_gr(model_name, model_path) wrong_tone_message = "" kata_tone: Optional[list[tuple[str, int]]] = None @@ -190,8 +193,8 @@ examples = [ ], ] -initial_md = """ -# Style-Bert-VITS2 ver 2.0 音声合成 +initial_md = f""" +# Style-Bert-VITS2 ver {LATEST_VERSION} 音声合成 注意: 初期からある[jvnvのモデル](https://huggingface.co/litagin/style_bert_vits2_jvnv)は、[JVNVコーパス(言語音声と非言語音声を持つ日本語感情音声コーパス)](https://sites.google.com/site/shinnosuketakamichi/research-topics/jvnv_corpus)で学習されたモデルです。ライセンスは[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.ja)です。 """ @@ -418,6 +421,8 @@ if __name__ == "__main__": tts_button.click( tts_fn, inputs=[ + model_name, + model_path, text_input, language, ref_audio_path, diff --git a/clustering.ipynb b/clustering.ipynb index 955f44a..12e728e 100644 --- a/clustering.ipynb +++ b/clustering.ipynb @@ -10,6 +10,8 @@ "もっといろいろ足したりいろんなスタイルベクトルを作って遊べると思います。\n", "ある程度慣れている人向けです。\n", "\n", + "JVNVコーパスのように**スタイルが既にファイル名等で分かれている場合は、最後の方のセルを使えばそれを利用してスタイルを作ることができます。**\n", + "\n", "例では[JVNVコーパス](https://sites.google.com/site/shinnosuketakamichi/research-topics/jvnv_corpus)のjvnv-M1を使います。\n", "\n", "## そもそもスタイルベクトルとは\n", @@ -204,6 +206,14 @@ "np.save(\"model_assets/jvnv-M1/style_vectors.npy\", save_vectors)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 正解ラベルがファイル名から分かる場合の作り方\n", + "JVNVコーパス等でファイル名によってスタイルラベルが分かる場合、以下のようにしてスタイルベクトルを作ることができます(デフォルトのJVNVモデルのスタイルはこれで作成しています)。" + ] + }, { "cell_type": "code", "execution_count": 8, @@ -211,24 +221,9 @@ "outputs": [], "source": [ "# JVNVコーパスの場合は正解はファイル名の最初の方から分かる。それを使って正解ラベルを作成\n", - "y_true = [name[3:6] for name in names]\n", + "label_dict = {\"ang\": 0, \"dis\": 1, \"fea\": 2, \"hap\": 3, \"sad\": 4, \"sur\": 5}\n", "\n", - "for i, y in enumerate(y_true):\n", - " if y == \"ang\":\n", - " y_true[i] = 0\n", - " elif y == \"dis\":\n", - " y_true[i] = 1\n", - " elif y == \"fea\":\n", - " y_true[i] = 2\n", - " elif y == \"hap\":\n", - " y_true[i] = 3\n", - " elif y == \"sad\":\n", - " y_true[i] = 4\n", - " elif y == \"sur\":\n", - " y_true[i] = 5\n", - " else:\n", - " print(y)\n", - " raise ValueError" + "y_true = [label_dict[name[3:6]] for name in names]" ] }, { diff --git a/colab.ipynb b/colab.ipynb index 30cf3cd..fb1a401 100644 --- a/colab.ipynb +++ b/colab.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Style-Bert-VITS2 (ver 2.0) のGoogle Colabでの学習\n", + "# Style-Bert-VITS2 (ver 2.1) のGoogle Colabでの学習\n", "\n", "Google Colab上でStyle-Bert-VITS2の学習を行うことができます。\n", "\n", diff --git a/common/constants.py b/common/constants.py index f000095..3571f51 100644 --- a/common/constants.py +++ b/common/constants.py @@ -1,5 +1,6 @@ import enum +LATEST_VERSION: str = "2.1" DEFAULT_STYLE: str = "Neutral" DEFAULT_STYLE_WEIGHT: float = 5.0 diff --git a/common/tts_model.py b/common/tts_model.py index 7f44256..c148598 100644 --- a/common/tts_model.py +++ b/common/tts_model.py @@ -209,6 +209,18 @@ class ModelHolder: raise ValueError(f"Model `{model_name}` is not found") if model_path not in self.model_files_dict[model_name]: raise ValueError(f"Model file `{model_path}` is not found") + if ( + self.current_model is not None + and self.current_model.model_path == model_path + ): + # Already loaded + speakers = list(self.current_model.spk2id.keys()) + styles = list(self.current_model.style2id.keys()) + return ( + gr.Dropdown(choices=styles, value=styles[0]), + gr.Button(interactive=True, value="音声合成"), + gr.Dropdown(choices=speakers, value=speakers[0]), + ) self.current_model = Model( model_path=model_path, config_path=os.path.join(self.root_dir, model_name, "config.json"), diff --git a/config.py b/config.py index 123e4c9..056e7f1 100644 --- a/config.py +++ b/config.py @@ -1,15 +1,19 @@ """ @Desc: 全局配置文件读取 """ -import argparse + import os import shutil from typing import Dict, List +import torch import yaml from common.log import logger +# If not cuda available, set possible devices to cpu +cuda_available = torch.cuda.is_available() + class Resample_config: """重采样配置""" @@ -44,13 +48,23 @@ class Preprocess_text_config: max_val_total: int = 10000, clean: bool = True, ): - self.transcription_path: str = transcription_path # 原始文本文件路径,文本格式应为{wav_path}|{speaker_name}|{language}|{text}。 - self.cleaned_path: str = cleaned_path # 数据清洗后文本路径,可以不填。不填则将在原始文本目录生成 - self.train_path: str = train_path # 训练集路径,可以不填。不填则将在原始文本目录生成 - self.val_path: str = val_path # 验证集路径,可以不填。不填则将在原始文本目录生成 + self.transcription_path: str = ( + transcription_path # 原始文本文件路径,文本格式应为{wav_path}|{speaker_name}|{language}|{text}。 + ) + self.cleaned_path: str = ( + cleaned_path # 数据清洗后文本路径,可以不填。不填则将在原始文本目录生成 + ) + self.train_path: str = ( + train_path # 训练集路径,可以不填。不填则将在原始文本目录生成 + ) + self.val_path: str = ( + val_path # 验证集路径,可以不填。不填则将在原始文本目录生成 + ) self.config_path: str = config_path # 配置文件路径 self.val_per_lang: int = val_per_lang # 每个speaker的验证集条数 - self.max_val_total: int = max_val_total # 验证集最大条数,多于的会被截断并放到训练集中 + self.max_val_total: int = ( + max_val_total # 验证集最大条数,多于的会被截断并放到训练集中 + ) self.clean: bool = clean # 是否进行数据清洗 @classmethod @@ -83,6 +97,8 @@ class Bert_gen_config: ): self.config_path = config_path self.num_processes = num_processes + if not cuda_available: + device = "cpu" self.device = device self.use_multi_device = use_multi_device @@ -104,6 +120,8 @@ class Style_gen_config: ): self.config_path = config_path self.num_processes = num_processes + if not cuda_available: + device = "cpu" self.device = device @classmethod @@ -143,7 +161,7 @@ class Train_ms_config: class Webui_config: - """webui 配置""" + """webui 配置 (for webui.py, not supported now)""" def __init__( self, @@ -155,6 +173,8 @@ class Webui_config: share: bool = False, debug: bool = False, ): + if not cuda_available: + device = "cpu" self.device: str = device self.model: str = model # 端口号 self.config_path: str = config_path # 是否公开部署,对外网开放 @@ -182,6 +202,8 @@ class Server_config: origins: List[str] = None, ): self.port: int = port + if not cuda_available: + device = "cpu" self.device: str = device self.language: str = language self.limit: int = limit diff --git a/configs/config.json b/configs/config.json index 1b00c64..c125074 100644 --- a/configs/config.json +++ b/configs/config.json @@ -67,5 +67,5 @@ "use_spectral_norm": false, "gin_channels": 256 }, - "version": "2.0.1" + "version": "2.1" } diff --git a/configs/configs_jp_extra.json b/configs/configs_jp_extra.json index f60b39e..efd4634 100644 --- a/configs/configs_jp_extra.json +++ b/configs/configs_jp_extra.json @@ -74,5 +74,5 @@ "initial_channel": 64 } }, - "version": "2.0.1-JP-Extra" + "version": "2.1-JP-Extra" } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b010a33..00a890c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v2.1 (2024-02-07) + +### 変更 +- 学習の際、デフォルトではbfloat16オプションを使わないよう変更(学習が発散したり質が下がることがある模様) +- 学習の際のメモリ使用量を削減しようと頑張った + +### バグ修正や改善 +- 音声合成(やそのAPI)において、同時に別の話者が選択され音声合成がリクエストされた場合に発生するエラーを修正 +- モデルマージ時に、そのレシピを`recipe.json`ファイルへ保存するように変更 +- 「改行で分けて生成」がより感情が乗る旨の明記等、軽微な説明文の改善 + ## v2.0.1 (2024-02-05) 軽微なバグ修正や改善 diff --git a/initialize.py b/initialize.py index 6dfd03d..c163ef9 100644 --- a/initialize.py +++ b/initialize.py @@ -90,17 +90,18 @@ def download_jvnv_models(): ) -parser = argparse.ArgumentParser() -parser.add_argument("--skip_jvnv", action="store_true") -args = parser.parse_args() +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--skip_jvnv", action="store_true") + args = parser.parse_args() -download_bert_models() + download_bert_models() -download_slm_model() + download_slm_model() -download_pretrained_models() + download_pretrained_models() -download_jp_extra_pretrained_models() + download_jp_extra_pretrained_models() -if not args.skip_jvnv: - download_jvnv_models() + if not args.skip_jvnv: + download_jvnv_models() diff --git a/requirements.txt b/requirements.txt index fbf8489..aa84daf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ gradio jaconv jieba langid -librosa +librosa==0.9.2 loguru matplotlib mecab-python3 diff --git a/safetensors.ipynb b/safetensors.ipynb deleted file mode 100644 index 6722654..0000000 --- a/safetensors.ipynb +++ /dev/null @@ -1,115 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "\n", - "model_dir = \"pretrained-Japanese-Extra\"\n", - "step = 0\n", - "\n", - "g_model = torch.load(f\"{model_dir}/G_{step}.pth\", map_location=\"cpu\")\n", - "d_model = torch.load(f\"{model_dir}/D_{step}.pth\", map_location=\"cpu\")\n", - "wd_model = torch.load(f\"{model_dir}/WD_{step}.pth\", map_location=\"cpu\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "skip enc_p.in_feature_net.0.weight\n", - "skip enc_p.in_feature_net.2.weight\n", - "skip enc_p.in_feature_net.2.bias\n", - "skip enc_p.in_feature_net.3.norm.weight\n", - "skip enc_p.in_feature_net.3.norm.bias\n", - "skip enc_p.in_feature_net.3.mlp.c_fc1.weight\n", - "skip enc_p.in_feature_net.3.mlp.c_fc2.weight\n", - "skip enc_p.in_feature_net.3.mlp.c_proj.weight\n", - "skip enc_p.in_feature_net.4.weight\n", - "skip enc_p.emo_vq._codebook.initted\n", - "skip enc_p.emo_vq._codebook.cluster_size\n", - "skip enc_p.emo_vq._codebook.embed_avg\n", - "skip enc_p.emo_vq._codebook.embed\n", - "skip enc_p.out_feature_net.weight\n", - "skip enc_p.out_feature_net.bias\n" - ] - } - ], - "source": [ - "g_dict = {}\n", - "skip_list = [\"enc_p.in_feature_net.\", \"enc_p.emo_vq.\", \"enc_p.out_feature_net.\"]\n", - "for key in g_model[\"model\"].keys():\n", - " if any([key.startswith(s) for s in skip_list]):\n", - " print(f\"skip {key}\")\n", - " continue\n", - " else:\n", - " g_dict[key] = g_model[\"model\"][key]" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "d_dict = {}\n", - "for key in d_model[\"model\"].keys():\n", - " d_dict[key] = d_model[\"model\"][key]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "wd_dict = {}\n", - "for key in wd_model[\"model\"].keys():\n", - " wd_dict[key] = wd_model[\"model\"][key]" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "from safetensors.torch import save_file\n", - "\n", - "\n", - "save_file(g_dict, f\"G_0.safetensors\")\n", - "save_file (d_dict, f\"D_0.safetensors\")\n", - "save_file (wd_dict, f\"WD_0.safetensors\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "venv", - "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", - "version": "3.10.11" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/scripts/Update-to-JP-Extra.bat b/scripts/Update-to-JP-Extra.bat index 7033e63..95738c6 100644 --- a/scripts/Update-to-JP-Extra.bat +++ b/scripts/Update-to-JP-Extra.bat @@ -42,7 +42,7 @@ pushd Style-Bert-VITS2 @REM 初期化(必要なモデルのダウンロード) python initialize.py -echo Style-Bert-VITS2の2.0.1へのアップデートが完了しました。 +echo Style-Bert-VITS2の2.xへのアップデートが完了しました。 pause diff --git a/train_ms.py b/train_ms.py index ca18667..57eb5f6 100644 --- a/train_ms.py +++ b/train_ms.py @@ -79,6 +79,11 @@ def run(): action="store_true", help="Do not show the progress bar while training.", ) + parser.add_argument( + "--speedup", + action="store_true", + help="Speed up training by disabling logging and evaluation.", + ) args = parser.parse_args() # Set log file @@ -115,8 +120,9 @@ def run(): n_gpus = dist.get_world_size() hps = utils.get_hparams_from_file(args.config) - # This is needed because we have to pass `model_dir` to `train_and_evaluate()` + # This is needed because we have to pass values to `train_and_evaluate()` hps.model_dir = model_dir + hps.speedup = args.speedup # 比较路径是否相同 if os.path.realpath(args.config) != os.path.realpath( @@ -161,7 +167,9 @@ def run(): torch.cuda.set_device(local_rank) global global_step - if rank == 0: + writer = None + writer_eval = None + if rank == 0 and not args.speedup: # logger = utils.get_logger(hps.model_dir) # logger.info(hps) utils.check_git_hash(model_dir) @@ -179,17 +187,20 @@ def run(): collate_fn = TextAudioSpeakerCollate() train_loader = DataLoader( train_dataset, - # num_workers=min(config.train_ms_config.num_workers, os.cpu_count() - 1), - # Slow and often freezes, so use only half of the cores. - num_workers=min(config.train_ms_config.num_workers, os.cpu_count() // 2), + # メモリ消費量を減らそうとnum_workersを1にしてみる + # num_workers=min(config.train_ms_config.num_workers, os.cpu_count() // 2), + num_workers=1, shuffle=False, pin_memory=True, collate_fn=collate_fn, batch_sampler=train_sampler, persistent_workers=True, - prefetch_factor=4, + # これもメモリ消費量を減らそうとしてコメントアウト + # prefetch_factor=4, ) # DataLoader config could be adjusted. - if rank == 0: + eval_dataset = None + eval_loader = None + if rank == 0 and not args.speedup: eval_dataset = TextAudioSpeakerLoader(hps.data.validation_files, hps.data) eval_loader = DataLoader( eval_dataset, @@ -647,7 +658,7 @@ def train_and_evaluate( scaler.update() if rank == 0: - if global_step % hps.train.log_interval == 0: + if global_step % hps.train.log_interval == 0 and not hps.speedup: lr = optim_g.param_groups[0]["lr"] losses = [loss_disc, loss_gen, loss_fm, loss_mel, loss_dur, loss_kl] # logger.info( @@ -708,7 +719,8 @@ def train_and_evaluate( and global_step != 0 and initial_step != global_step ): - evaluate(hps, net_g, eval_loader, writer_eval) + if not hps.speedup: + evaluate(hps, net_g, eval_loader, writer_eval) utils.save_checkpoint( net_g, optim_g, diff --git a/train_ms_jp_extra.py b/train_ms_jp_extra.py index a689fc9..e20868f 100644 --- a/train_ms_jp_extra.py +++ b/train_ms_jp_extra.py @@ -82,6 +82,11 @@ def run(): action="store_true", help="Do not show the progress bar while training.", ) + parser.add_argument( + "--speedup", + action="store_true", + help="Speed up training by disabling logging and evaluation.", + ) args = parser.parse_args() # Set log file @@ -118,8 +123,9 @@ def run(): n_gpus = dist.get_world_size() hps = utils.get_hparams_from_file(args.config) - # This is needed because we have to pass `model_dir` to `train_and_evaluate()` + # This is needed because we have to pass values to `train_and_evaluate() hps.model_dir = model_dir + hps.speedup = args.speedup # 比较路径是否相同 if os.path.realpath(args.config) != os.path.realpath( @@ -164,7 +170,9 @@ def run(): torch.cuda.set_device(local_rank) global global_step - if rank == 0: + writer = None + writer_eval = None + if rank == 0 and not args.speedup: # logger = utils.get_logger(hps.model_dir) # logger.info(hps) utils.check_git_hash(model_dir) @@ -182,17 +190,20 @@ def run(): collate_fn = TextAudioSpeakerCollate(use_jp_extra=True) train_loader = DataLoader( train_dataset, - # num_workers=min(config.train_ms_config.num_workers, os.cpu_count() - 1), - # Slow and often freezes, so use only half of the cores. - num_workers=min(config.train_ms_config.num_workers, os.cpu_count() // 2), + # メモリ消費量を減らそうとnum_workersを1にしてみる + # num_workers=min(config.train_ms_config.num_workers, os.cpu_count() // 2), + num_workers=1, shuffle=False, pin_memory=True, collate_fn=collate_fn, batch_sampler=train_sampler, persistent_workers=True, - prefetch_factor=6, + # これもメモリ消費量を減らそうとしてコメントアウト + # prefetch_factor=6, ) # DataLoader config could be adjusted. - if rank == 0: + eval_dataset = None + eval_loader = None + if rank == 0 and not args.speedup: eval_dataset = TextAudioSpeakerLoader(hps.data.validation_files, hps.data) eval_loader = DataLoader( eval_dataset, @@ -297,16 +308,28 @@ def run(): ) else: optim_wd = None - net_g = DDP(net_g, device_ids=[local_rank], bucket_cap_mb=512) - net_d = DDP(net_d, device_ids=[local_rank], bucket_cap_mb=512) + net_g = DDP( + net_g, + device_ids=[local_rank], + # bucket_cap_mb=512 + ) + net_d = DDP( + net_d, + device_ids=[local_rank], + # bucket_cap_mb=512 + ) if net_dur_disc is not None: net_dur_disc = DDP( net_dur_disc, device_ids=[local_rank], - bucket_cap_mb=512, + # bucket_cap_mb=512, ) if net_wd is not None: - net_wd = DDP(net_wd, device_ids=[local_rank], bucket_cap_mb=512) + net_wd = DDP( + net_wd, + device_ids=[local_rank], + # bucket_cap_mb=512 + ) if utils.is_resuming(model_dir): if net_dur_disc is not None: @@ -748,7 +771,7 @@ def train_and_evaluate( scaler.update() if rank == 0: - if global_step % hps.train.log_interval == 0: + if global_step % hps.train.log_interval == 0 and not hps.speedup: lr = optim_g.param_groups[0]["lr"] losses = [loss_disc, loss_gen, loss_fm, loss_mel, loss_dur, loss_kl] # logger.info( @@ -842,7 +865,8 @@ def train_and_evaluate( and global_step != 0 and initial_step != global_step ): - evaluate(hps, net_g, eval_loader, writer_eval) + if not hps.speedup: + evaluate(hps, net_g, eval_loader, writer_eval) utils.save_checkpoint( net_g, optim_g, diff --git a/webui_dataset.py b/webui_dataset.py index ca50d1b..5b25afe 100644 --- a/webui_dataset.py +++ b/webui_dataset.py @@ -52,7 +52,7 @@ def do_transcribe( return "Error: モデル名を入力してください。" if initial_prompt == "": initial_prompt = "こんにちは。元気、ですかー?私は……ふふっ、ちゃんと元気だよ!" - logger.debug(f"initial_prompt: {initial_prompt}") + # logger.debug(f"initial_prompt: {initial_prompt}") if input_dir == "": input_dir = os.path.join(dataset_root, model_name, "raw") output_file = os.path.join(dataset_root, model_name, "esd.list") @@ -117,7 +117,9 @@ Style-Bert-VITS2の学習用データセットを作成するためのツール with gr.Blocks(theme="NoCrypt/miku") as app: gr.Markdown(initial_md) - model_name = gr.Textbox(label="モデル名を入力してください(話者名としても使われます)。") + model_name = gr.Textbox( + label="モデル名を入力してください(話者名としても使われます)。" + ) with gr.Accordion("音声のスライス"): with gr.Row(): with gr.Column(): @@ -127,10 +129,18 @@ with gr.Blocks(theme="NoCrypt/miku") as app: info="下記フォルダにwavファイルを入れておいてください", ) min_sec = gr.Slider( - minimum=0, maximum=10, value=2, step=0.5, label="この秒数未満は切り捨てる" + minimum=0, + maximum=10, + value=2, + step=0.5, + label="この秒数未満は切り捨てる", ) max_sec = gr.Slider( - minimum=0, maximum=15, value=12, step=0.5, label="この秒数以上は切り捨てる" + minimum=0, + maximum=15, + value=12, + step=0.5, + label="この秒数以上は切り捨てる", ) min_silence_dur_ms = gr.Slider( minimum=0, diff --git a/webui_merge.py b/webui_merge.py index 2f35f73..96fc366 100644 --- a/webui_merge.py +++ b/webui_merge.py @@ -87,6 +87,17 @@ def merge_style(model_name_a, model_name_b, weight, output_name, style_triple_li ) as f: json.dump(new_config, f, indent=2, ensure_ascii=False) + # recipe.jsonを読み込んで、style_triple_listを追記 + info_path = os.path.join(assets_root, output_name, "recipe.json") + if os.path.exists(info_path): + with open(info_path, encoding="utf-8") as f: + info = json.load(f) + else: + info = {} + info["style_triple_list"] = style_triple_list + with open(info_path, "w", encoding="utf-8") as f: + json.dump(info, f, indent=2, ensure_ascii=False) + return output_style_path, list(new_style2id.keys()) @@ -133,6 +144,19 @@ def merge_models( ) os.makedirs(os.path.dirname(merged_model_path), exist_ok=True) save_file(merged_model_weight, merged_model_path) + + info = { + "model_a": model_path_a, + "model_b": model_path_b, + "voice_weight": voice_weight, + "voice_pitch_weight": voice_pitch_weight, + "speech_style_weight": speech_style_weight, + "tempo_weight": tempo_weight, + } + with open( + os.path.join(assets_root, output_name, "recipe.json"), "w", encoding="utf-8" + ) as f: + json.dump(info, f, indent=2, ensure_ascii=False) return merged_model_path @@ -235,6 +259,8 @@ initial_md = """ 以上でマージは完了で、`model_assets/マージ後のモデル名`にマージ後のモデルが保存され、音声合成のときに使えます。 +また`model_asses/マージ後のモデル名/recipe.json`には、マージの配合レシピが記録されます(推論にはいらないので配合メモ用です)。 + 一番下にマージしたモデルによる簡易的な音声合成機能もつけています。 ## 注意 diff --git a/webui_train.py b/webui_train.py index b278cde..77301ba 100644 --- a/webui_train.py +++ b/webui_train.py @@ -8,6 +8,7 @@ from multiprocessing import cpu_count import gradio as gr import yaml +from common.constants import LATEST_VERSION from common.log import logger from common.subprocess_utils import run_script_with_log, second_elem_of @@ -315,8 +316,8 @@ def train(model_name, skip_style=False, use_jp_extra=True, speedup=False): return True, "Success: 学習が完了しました" -initial_md = """ -# Style-Bert-VITS2 ver 2.0 学習用WebUI +initial_md = f""" +# Style-Bert-VITS2 ver {LATEST_VERSION} 学習用WebUI ## 使い方