Merge pull request #146 from liruk/alpha
音声合成画面において、複数のヌルモデルを実行時マージする機能を追加
This commit is contained in:
14
README.md
14
README.md
@@ -58,7 +58,7 @@ Pythonライブラリとしてのpipでのインストールや使用例は[libr
|
|||||||
|
|
||||||
Windowsを前提としています。
|
Windowsを前提としています。
|
||||||
|
|
||||||
1. [このzipファイル](https://github.com/litagin02/Style-Bert-VITS2/releases/download/2.5.0/sbv2.zip)を**パスに日本語や空白が含まれない場所に**ダウンロードして展開します。
|
1. [このzipファイル](https://github.com/litagin02/Style-Bert-VITS2/releases/download/2.6.0/sbv2.zip)を**パスに日本語や空白が含まれない場所に**ダウンロードして展開します。
|
||||||
- グラボがある方は、`Install-Style-Bert-VITS2.bat`をダブルクリックします。
|
- グラボがある方は、`Install-Style-Bert-VITS2.bat`をダブルクリックします。
|
||||||
- グラボがない方は、`Install-Style-Bert-VITS2-CPU.bat`をダブルクリックします。CPU版では学習はできませんが、音声合成とマージは可能です。
|
- グラボがない方は、`Install-Style-Bert-VITS2-CPU.bat`をダブルクリックします。CPU版では学習はできませんが、音声合成とマージは可能です。
|
||||||
2. 待つと自動で必要な環境がインストールされます。
|
2. 待つと自動で必要な環境がインストールされます。
|
||||||
@@ -92,7 +92,7 @@ python initialize.py # 必要なモデルとデフォルトTTSモデルをダ
|
|||||||
|
|
||||||
エディター部分は[別リポジトリ](https://github.com/litagin02/Style-Bert-VITS2-Editor)に分かれています。
|
エディター部分は[別リポジトリ](https://github.com/litagin02/Style-Bert-VITS2-Editor)に分かれています。
|
||||||
|
|
||||||
バージョン2.2以前での音声合成WebUIは、`App.bat`をダブルクリックか、`python app.py`するとWebUIが起動します。
|
バージョン2.2以前での音声合成WebUIは、`App.bat`をダブルクリックか、`python app.py`するとWebUIが起動します。または`Inference.bat`でも音声合成単独タブが開きます。
|
||||||
|
|
||||||
音声合成に必要なモデルファイルたちの構造は以下の通りです(手動で配置する必要はありません)。
|
音声合成に必要なモデルファイルたちの構造は以下の通りです(手動で配置する必要はありません)。
|
||||||
```
|
```
|
||||||
@@ -123,18 +123,18 @@ model_assets
|
|||||||
|
|
||||||
#### データセット作り
|
#### データセット作り
|
||||||
|
|
||||||
- `App.bat`をダブルクリックか`python app.py`したところの「データセット作成」タブから、音声ファイルを適切な長さにスライスし、その後に文字の書き起こしを自動で行えます。
|
- `App.bat`をダブルクリックか`python app.py`したところの「データセット作成」タブから、音声ファイルを適切な長さにスライスし、その後に文字の書き起こしを自動で行えます。または`Dataset.bat`をダブルクリックでもその単独タブが開きます。
|
||||||
- 指示に従った後、下の「学習」タブでそのまま学習を行うことができます。
|
- 指示に従った後、下の「学習」タブでそのまま学習を行うことができます。
|
||||||
|
|
||||||
#### 学習WebUI
|
#### 学習WebUI
|
||||||
|
|
||||||
- `App.bat`をダブルクリックか`python app.py`して開くWebUIの「学習」タブから指示に従ってください。
|
- `App.bat`をダブルクリックか`python app.py`して開くWebUIの「学習」タブから指示に従ってください。または`Train.bat`をダブルクリックでもその単独タブが開きます。
|
||||||
|
|
||||||
### スタイルの生成
|
### スタイルの生成
|
||||||
|
|
||||||
- デフォルトでは、デフォルトスタイル「Neutral」の他、学習フォルダのフォルダ分けに応じたスタイルが生成されます。
|
- デフォルトでは、デフォルトスタイル「Neutral」の他、学習フォルダのフォルダ分けに応じたスタイルが生成されます。
|
||||||
- それ以外の方法で手動でスタイルを作成したい人向けです。
|
- それ以外の方法で手動でスタイルを作成したい人向けです。
|
||||||
- `App.bat`をダブルクリックか`python app.py`して開くWebUIの「スタイル作成」タブから、音声ファイルを使ってスタイルを生成できます。
|
- `App.bat`をダブルクリックか`python app.py`して開くWebUIの「スタイル作成」タブから、音声ファイルを使ってスタイルを生成できます。または`StyleVectors.bat`をダブルクリックでもその単独タブが開きます。
|
||||||
- 学習とは独立しているので、学習中でもできるし、学習が終わっても何度もやりなおせます(前処理は終わらせている必要があります)。
|
- 学習とは独立しているので、学習中でもできるし、学習が終わっても何度もやりなおせます(前処理は終わらせている必要があります)。
|
||||||
|
|
||||||
### API Server
|
### API Server
|
||||||
@@ -151,8 +151,8 @@ API仕様は起動後に`/docs`にて確認ください。
|
|||||||
|
|
||||||
### マージ
|
### マージ
|
||||||
|
|
||||||
2つのモデルを、「声質」「声の高さ」「感情表現」「テンポ」の4点で混ぜ合わせて、新しいモデルを作ることが出来ます。
|
2つのモデルを、「声質」「声の高さ」「感情表現」「テンポ」の4点で混ぜ合わせて、新しいモデルを作ったり、また「あるモデルに、別の2つのモデルの差分を足す」等の操作ができます。
|
||||||
`App.bat`をダブルクリックか`python app.py`して開くWebUIの「マージ」タブから、2つのモデルを選択してマージすることができます。
|
`App.bat`をダブルクリックか`python app.py`して開くWebUIの「マージ」タブから、2つのモデルを選択してマージすることができます。または`Merge.bat`をダブルクリックでもその単独タブが開きます。
|
||||||
|
|
||||||
### 自然性評価
|
### 自然性評価
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
### 新機能
|
### 新機能
|
||||||
モデルのマージ時に、今までの `new = (1 - weight) * A + weight * B` の他に、次を追加
|
モデルのマージ時に、今までの `new = (1 - weight) * A + weight * B` の他に、次を追加
|
||||||
|
|
||||||
- `new = A + weight * (B - C)`: 差分マージ
|
- `new = A + weight * (B - C)`: 差分マージ
|
||||||
- `new = a * A + b * B + c * C`: 加重和マージ
|
- `new = a * A + b * B + c * C`: 加重和マージ
|
||||||
- `new = A + weight * B`: ヌルモデルのマージ
|
- `new = A + weight * B`: ヌルモデルのマージ
|
||||||
|
|
||||||
差分マージは、例えばBを「Cと同じ話者だけど囁いているモデル」とすると、`B - C`が囁きベクトル的なものだと思えるので、それをAに足すことで、Aの話者が囁いているような音声を生成できるようになります。
|
差分マージは、例えばBを「Cと同じ話者だけど囁いているモデル」とすると、`B - C`が囁きベクトル的なものだと思えるので、それをAに足すことで、Aの話者が囁いているような音声を生成できるようになります。
|
||||||
|
|
||||||
また、加重和で`new = A - B`を作って、それをヌルモデルマージで別のモデルに足せば、実質差分マージを実現できます。また謎に`new = -A`や`new = 41 * A`等のモデルも作ることができます。
|
また、加重和で`new = A - B`を作って、それをヌルモデルマージで別のモデルに足せば、実質差分マージを実現できます。また謎に`new = -A`や`new = 41 * A`等のモデルも作ることができます。
|
||||||
@@ -15,8 +17,9 @@
|
|||||||
|
|
||||||
囁きについて実験的に作ったヌルモデルを[こちら](https://huggingface.co/litagin/sbv2_null_models)に置いています。これをヌルモデルマージで使うことで、任意のモデルを囁きモデルにある程度は変換できます。
|
囁きについて実験的に作ったヌルモデルを[こちら](https://huggingface.co/litagin/sbv2_null_models)に置いています。これをヌルモデルマージで使うことで、任意のモデルを囁きモデルにある程度は変換できます。
|
||||||
|
|
||||||
### 改善?
|
### 改善
|
||||||
|
|
||||||
|
- スタイルベクトルのマージ部分のUIの改善
|
||||||
- WebUIの`App.bat`の起動が少し重いので、それぞれの機能を分割した`Dataset.bat`, `Inference.bat`, `Merge.bat`, `StyleVectors.bat`, `Train.bat`を追加 (今までの`App.bat`もこれまで通り使えます)
|
- WebUIの`App.bat`の起動が少し重いので、それぞれの機能を分割した`Dataset.bat`, `Inference.bat`, `Merge.bat`, `StyleVectors.bat`, `Train.bat`を追加 (今までの`App.bat`もこれまで通り使えます)
|
||||||
|
|
||||||
## v2.5.1 (2024-06-14)
|
## v2.5.1 (2024-06-14)
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
Google Colabのノートブックは以前のバージョンのノートブックのコピーを使っていませんか?
|
Google Colabのノートブックは以前のバージョンのノートブックのコピーを使っていませんか?
|
||||||
Colabノートブックは最新のバージョンに合ったノートブックで動かすことを前提としています。ノートブック記載のバージョンを確認して、[最新のcolabノートブック](http://colab.research.google.com/github/litagin02/Style-Bert-VITS2/blob/master/colab.ipynb)(を必要ならコピーして)から使うようにしてください。
|
Colabノートブックは最新のバージョンに合ったノートブックで動かすことを前提としています。ノートブック記載のバージョンを確認して、[最新のcolabノートブック](http://colab.research.google.com/github/litagin02/Style-Bert-VITS2/blob/master/colab.ipynb)(を必要ならコピーして)から使うようにしてください。
|
||||||
|
|
||||||
|
## `ModuleNotFoundError: No module named '_socket'`と出る
|
||||||
|
|
||||||
|
フォルダ名をインストールした時から変えていませんか?フォルダ名を変えるとパスが変わってしまい、インストール時に指定したパスと異なるためにエラーが出ます。フォルダ名を元に戻してください。
|
||||||
|
|
||||||
## 学習に時間がかかりすぎる
|
## 学習に時間がかかりすぎる
|
||||||
|
|
||||||
デフォルトの100エポックは音声データ量によっては過剰な場合があります。デフォルトでは1000ステップごとにモデルが保存されるはずなので、途中で学習を中断してみて途中のもので試してみてもいいでしょう。
|
デフォルトの100エポックは音声データ量によっては過剰な場合があります。デフォルトでは1000ステップごとにモデルが保存されるはずなので、途中で学習を中断してみて途中のもので試してみてもいいでしょう。
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
from typing import Optional
|
from typing import Optional, Any, Union
|
||||||
|
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
|
||||||
@@ -185,7 +185,10 @@ style_md = f"""
|
|||||||
- どのくらいに強さがいいかはモデルやスタイルによって異なるようです。
|
- どのくらいに強さがいいかはモデルやスタイルによって異なるようです。
|
||||||
- 音声ファイルを入力する場合は、学習データと似た声音の話者(特に同じ性別)でないとよい効果が出ないかもしれません。
|
- 音声ファイルを入力する場合は、学習データと似た声音の話者(特に同じ性別)でないとよい効果が出ないかもしれません。
|
||||||
"""
|
"""
|
||||||
|
voice_keys = ["dec"]
|
||||||
|
voice_pitch_keys = ["flow"]
|
||||||
|
speech_style_keys = ["enc_p"]
|
||||||
|
tempo_keys = ["sdp", "dp"]
|
||||||
|
|
||||||
def make_interactive():
|
def make_interactive():
|
||||||
return gr.update(interactive=True, value="音声合成")
|
return gr.update(interactive=True, value="音声合成")
|
||||||
@@ -201,6 +204,26 @@ def gr_util(item):
|
|||||||
else:
|
else:
|
||||||
return (gr.update(visible=False), gr.update(visible=True))
|
return (gr.update(visible=False), gr.update(visible=True))
|
||||||
|
|
||||||
|
null_models_frame = 0
|
||||||
|
def change_null_model_row(null_model_index:int, null_model_name:str, null_model_path:str,null_voice_weights:float,
|
||||||
|
null_voice_pitch_weights:float, null_speech_style_weights:float,null_tempo_weights:float,
|
||||||
|
null_models:dict[int,dict[str, Any]]):
|
||||||
|
#logger.debug("change_null_model_row:sta"+str(null_models))
|
||||||
|
mid_result={}
|
||||||
|
mid_result["name"]=null_model_name
|
||||||
|
mid_result["path"]=null_model_path
|
||||||
|
mid_result["weight"]=null_tempo_weights
|
||||||
|
mid_result["pitch"]=null_voice_pitch_weights
|
||||||
|
mid_result["style"]=null_speech_style_weights
|
||||||
|
mid_result["tempo"]=null_tempo_weights
|
||||||
|
null_models[null_model_index] = mid_result
|
||||||
|
#logger.debug("decreasing:"+str(null_models_frame)+":"+str(len(null_models.keys())))
|
||||||
|
if null_models_frame < len(null_models.keys()):
|
||||||
|
for i in range(null_models_frame ,len(null_models.keys())):
|
||||||
|
_ = null_models.pop(i, None)
|
||||||
|
result = null_models
|
||||||
|
#logger.debug("change_null_model_row:res"+str(null_models))
|
||||||
|
return result, True
|
||||||
|
|
||||||
def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
||||||
def tts_fn(
|
def tts_fn(
|
||||||
@@ -225,6 +248,8 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
speaker,
|
speaker,
|
||||||
pitch_scale,
|
pitch_scale,
|
||||||
intonation_scale,
|
intonation_scale,
|
||||||
|
null_models:dict[int, dict[str, Union[str, float]]],
|
||||||
|
force_reload_model:bool
|
||||||
):
|
):
|
||||||
model_holder.get_model(model_name, model_path)
|
model_holder.get_model(model_name, model_path)
|
||||||
assert model_holder.current_model is not None
|
assert model_holder.current_model is not None
|
||||||
@@ -282,6 +307,8 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
speaker_id=speaker_id,
|
speaker_id=speaker_id,
|
||||||
pitch_scale=pitch_scale,
|
pitch_scale=pitch_scale,
|
||||||
intonation_scale=intonation_scale,
|
intonation_scale=intonation_scale,
|
||||||
|
null_model_params = null_models,
|
||||||
|
force_reload_model = force_reload_model
|
||||||
)
|
)
|
||||||
except InvalidToneError as e:
|
except InvalidToneError as e:
|
||||||
logger.error(f"Tone error: {e}")
|
logger.error(f"Tone error: {e}")
|
||||||
@@ -303,7 +330,7 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
message = f"Success, time: {duration} seconds."
|
message = f"Success, time: {duration} seconds."
|
||||||
if wrong_tone_message != "":
|
if wrong_tone_message != "":
|
||||||
message = wrong_tone_message + "\n" + message
|
message = wrong_tone_message + "\n" + message
|
||||||
return message, (sr, audio), kata_tone_json_str
|
return message, (sr, audio), kata_tone_json_str, False
|
||||||
|
|
||||||
model_names = model_holder.model_names
|
model_names = model_holder.model_names
|
||||||
if len(model_names) == 0:
|
if len(model_names) == 0:
|
||||||
@@ -323,6 +350,8 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
with gr.Blocks(theme=GRADIO_THEME) as app:
|
with gr.Blocks(theme=GRADIO_THEME) as app:
|
||||||
gr.Markdown(initial_md)
|
gr.Markdown(initial_md)
|
||||||
gr.Markdown(terms_of_use_md)
|
gr.Markdown(terms_of_use_md)
|
||||||
|
null_models = gr.State({})
|
||||||
|
force_reload_model = gr.State(False)
|
||||||
with gr.Accordion(label="使い方", open=False):
|
with gr.Accordion(label="使い方", open=False):
|
||||||
gr.Markdown(how_to_md)
|
gr.Markdown(how_to_md)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
@@ -436,6 +465,142 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
inputs=[use_assist_text],
|
inputs=[use_assist_text],
|
||||||
outputs=[assist_text, assist_text_weight],
|
outputs=[assist_text, assist_text_weight],
|
||||||
)
|
)
|
||||||
|
with gr.Accordion(label="ヌルモデル", open=False):
|
||||||
|
with gr.Row() as null_row:
|
||||||
|
null_models_count = gr.Number(label="ヌルモデルの数", value=0, step=1)
|
||||||
|
with gr.Column(variant="panel") as null_column:
|
||||||
|
@gr.render(
|
||||||
|
inputs=[
|
||||||
|
null_models_count,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def render_style(
|
||||||
|
null_models_count:int,
|
||||||
|
):
|
||||||
|
global null_models_frame
|
||||||
|
null_models_frame = null_models_count
|
||||||
|
for i in range(0, null_models_count):
|
||||||
|
with gr.Row():
|
||||||
|
null_model_index = gr.Number(
|
||||||
|
value=i,
|
||||||
|
key=f"null_model_index_{i}",
|
||||||
|
visible=False
|
||||||
|
)
|
||||||
|
null_model_name = gr.Dropdown(
|
||||||
|
label="モデル一覧",
|
||||||
|
choices=model_names,
|
||||||
|
key=f"null_model_name_{i}",
|
||||||
|
value=model_names[initial_id],
|
||||||
|
interactive=True
|
||||||
|
)
|
||||||
|
if i in null_models.value:
|
||||||
|
logger.debug(f"null model parameter exists in index {i}")
|
||||||
|
null_model_name.value=null_models.value[i]["name"]
|
||||||
|
null_model_path = gr.Dropdown(
|
||||||
|
label="モデルファイル",
|
||||||
|
choices=initial_pth_files,
|
||||||
|
key=f"null_model_path_{i}",
|
||||||
|
value=initial_pth_files[0],
|
||||||
|
interactive=True
|
||||||
|
)
|
||||||
|
if i in null_models.value:
|
||||||
|
#null_model_path.choices = #ToDo
|
||||||
|
null_model_path.value=null_models.value[i]["path"]
|
||||||
|
null_voice_weights = gr.Slider(
|
||||||
|
minimum=0,
|
||||||
|
maximum=1,
|
||||||
|
value=1,
|
||||||
|
step=0.1,
|
||||||
|
key=f"null_voice_weights_{i}",
|
||||||
|
label="声質",
|
||||||
|
interactive=True
|
||||||
|
)
|
||||||
|
if i in null_models.value:
|
||||||
|
null_voice_weights.value=null_models.value[i]["weight"]
|
||||||
|
null_voice_pitch_weights = gr.Slider(
|
||||||
|
minimum=0,
|
||||||
|
maximum=1,
|
||||||
|
value=1,
|
||||||
|
step=0.1,
|
||||||
|
key=f"null_voice_pitch_weights_{i}",
|
||||||
|
label="声の高さ",
|
||||||
|
interactive=True
|
||||||
|
)
|
||||||
|
if i in null_models.value:
|
||||||
|
null_voice_pitch_weights.value=null_models.value[i]["pitch"]
|
||||||
|
null_speech_style_weights = gr.Slider(
|
||||||
|
minimum=0,
|
||||||
|
maximum=1,
|
||||||
|
value=1,
|
||||||
|
step=0.1,
|
||||||
|
key=f"null_speech_style_weights_{i}",
|
||||||
|
label="話し方",
|
||||||
|
interactive=True
|
||||||
|
)
|
||||||
|
if i in null_models.value:
|
||||||
|
null_speech_style_weights.value=null_models.value[i]["style"]
|
||||||
|
null_tempo_weights = gr.Slider(
|
||||||
|
minimum=0,
|
||||||
|
maximum=1,
|
||||||
|
value=1,
|
||||||
|
step=0.1,
|
||||||
|
key=f"null_tempo_weights_{i}",
|
||||||
|
label="テンポ",
|
||||||
|
interactive=True
|
||||||
|
)
|
||||||
|
if i in null_models.value:
|
||||||
|
null_tempo_weights.value=null_models.value[i]["tempo"]
|
||||||
|
null_model_name.change(
|
||||||
|
model_holder.update_model_files_for_gradio,
|
||||||
|
inputs=[null_model_name],
|
||||||
|
outputs=[null_model_path],
|
||||||
|
)
|
||||||
|
#null_model_name.change(model_holder.refresh, outputs=[])
|
||||||
|
null_model_path.change(make_non_interactive, outputs=[tts_button])
|
||||||
|
#愚直すぎるのでもう少しなんとかしたい
|
||||||
|
null_model_path.change(change_null_model_row,
|
||||||
|
inputs=[null_model_index, null_model_name, null_model_path,null_voice_weights,
|
||||||
|
null_voice_pitch_weights, null_speech_style_weights,null_tempo_weights,
|
||||||
|
null_models],
|
||||||
|
outputs=[null_models,force_reload_model]
|
||||||
|
)
|
||||||
|
null_voice_weights.change(change_null_model_row,
|
||||||
|
inputs=[null_model_index, null_model_name, null_model_path,null_voice_weights,
|
||||||
|
null_voice_pitch_weights, null_speech_style_weights,null_tempo_weights,
|
||||||
|
null_models],
|
||||||
|
outputs=[null_models,force_reload_model]
|
||||||
|
)
|
||||||
|
null_voice_pitch_weights.change(change_null_model_row,
|
||||||
|
inputs=[null_model_index, null_model_name, null_model_path,null_voice_weights,
|
||||||
|
null_voice_pitch_weights, null_speech_style_weights,null_tempo_weights,
|
||||||
|
null_models],
|
||||||
|
outputs=[null_models,force_reload_model]
|
||||||
|
)
|
||||||
|
null_speech_style_weights.change(change_null_model_row,
|
||||||
|
inputs=[null_model_index, null_model_name, null_model_path,null_voice_weights,
|
||||||
|
null_voice_pitch_weights, null_speech_style_weights,null_tempo_weights,
|
||||||
|
null_models],
|
||||||
|
outputs=[null_models,force_reload_model]
|
||||||
|
)
|
||||||
|
null_tempo_weights.change(change_null_model_row,
|
||||||
|
inputs=[null_model_index, null_model_name, null_model_path,null_voice_weights,
|
||||||
|
null_voice_pitch_weights, null_speech_style_weights,null_tempo_weights,
|
||||||
|
null_models],
|
||||||
|
outputs=[null_models,force_reload_model]
|
||||||
|
)
|
||||||
|
add_btn = gr.Button("ヌルモデルを増やす")
|
||||||
|
del_btn = gr.Button("ヌルモデルを減らす")
|
||||||
|
add_btn.click(
|
||||||
|
lambda x: x + 1,
|
||||||
|
inputs=[null_models_count],
|
||||||
|
outputs=[null_models_count],
|
||||||
|
)
|
||||||
|
del_btn.click(
|
||||||
|
lambda x: x - 1 if x > 0 else 0,
|
||||||
|
inputs=[null_models_count],
|
||||||
|
outputs=[null_models_count],
|
||||||
|
)
|
||||||
|
|
||||||
with gr.Column():
|
with gr.Column():
|
||||||
with gr.Accordion("スタイルについて詳細", open=False):
|
with gr.Accordion("スタイルについて詳細", open=False):
|
||||||
gr.Markdown(style_md)
|
gr.Markdown(style_md)
|
||||||
@@ -493,8 +658,10 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
speaker,
|
speaker,
|
||||||
pitch_scale,
|
pitch_scale,
|
||||||
intonation_scale,
|
intonation_scale,
|
||||||
|
null_models,
|
||||||
|
force_reload_model
|
||||||
],
|
],
|
||||||
outputs=[text_output, audio_output, tone],
|
outputs=[text_output, audio_output, tone, force_reload_model],
|
||||||
)
|
)
|
||||||
|
|
||||||
model_name.change(
|
model_name.change(
|
||||||
@@ -524,7 +691,6 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from config import get_path_config
|
from config import get_path_config
|
||||||
import torch
|
import torch
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
cmudict
|
cmudict
|
||||||
cn2an
|
cn2an
|
||||||
g2p_en
|
g2p_en
|
||||||
gradio
|
gradio>=4.32
|
||||||
jieba
|
jieba
|
||||||
librosa==0.9.2
|
librosa==0.9.2
|
||||||
loguru
|
loguru
|
||||||
num2words
|
num2words
|
||||||
|
numpy<2
|
||||||
onnxruntime
|
onnxruntime
|
||||||
pyannote.audio>=3.1.0
|
pyannote.audio>=3.1.0
|
||||||
pyloudnorm
|
pyloudnorm
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ jieba
|
|||||||
# librosa==0.9.2
|
# librosa==0.9.2
|
||||||
loguru
|
loguru
|
||||||
num2words
|
num2words
|
||||||
|
numpy<2
|
||||||
# protobuf==4.25
|
# protobuf==4.25
|
||||||
psutil
|
psutil
|
||||||
# punctuators
|
# punctuators
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ cn2an
|
|||||||
faster-whisper==0.10.1
|
faster-whisper==0.10.1
|
||||||
g2p_en
|
g2p_en
|
||||||
GPUtil
|
GPUtil
|
||||||
gradio
|
gradio>=4.32
|
||||||
jieba
|
jieba
|
||||||
librosa==0.9.2
|
librosa==0.9.2
|
||||||
loguru
|
loguru
|
||||||
num2words
|
num2words
|
||||||
|
numpy<2
|
||||||
protobuf==4.25
|
protobuf==4.25
|
||||||
psutil
|
psutil
|
||||||
punctuators
|
punctuators
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class TTSModel:
|
|||||||
|
|
||||||
self.model_path: Path = model_path
|
self.model_path: Path = model_path
|
||||||
self.device: str = device
|
self.device: str = device
|
||||||
|
self.null_model_params: dict[int, dict[str,Union[float, str]]] = {}
|
||||||
|
|
||||||
# ハイパーパラメータの Pydantic モデルが直接指定された
|
# ハイパーパラメータの Pydantic モデルが直接指定された
|
||||||
if isinstance(config_path, HyperParameters):
|
if isinstance(config_path, HyperParameters):
|
||||||
@@ -113,6 +114,36 @@ class TTSModel:
|
|||||||
device=self.device,
|
device=self.device,
|
||||||
hps=self.hyper_parameters,
|
hps=self.hyper_parameters,
|
||||||
)
|
)
|
||||||
|
if(len(self.null_model_params.keys())==0):
|
||||||
|
return
|
||||||
|
|
||||||
|
for index, null_model in enumerate(self.null_model_params.keys()):
|
||||||
|
null_model_add = get_net_g(
|
||||||
|
model_path=str(self.null_model_params[index]["path"]),
|
||||||
|
version=self.hyper_parameters.version,
|
||||||
|
device=self.device,
|
||||||
|
hps=self.hyper_parameters,
|
||||||
|
)
|
||||||
|
#愚直。もっと上手い方法ありそう
|
||||||
|
print(str(self.null_model_params[index]["weight"]))
|
||||||
|
params = zip(self.__net_g.dec.parameters(), null_model_add.dec.parameters())
|
||||||
|
for v in params:
|
||||||
|
v[0].data.add_(v[1].data,alpha=float(self.null_model_params[index]["weight"]))
|
||||||
|
params = zip(self.__net_g.flow.parameters(), null_model_add.flow.parameters())
|
||||||
|
for v in params:
|
||||||
|
v[0].data.add_(v[1].data,alpha=float(self.null_model_params[index]["pitch"]))
|
||||||
|
|
||||||
|
params = zip(self.__net_g.enc_p.parameters(), null_model_add.enc_p.parameters())
|
||||||
|
for v in params:
|
||||||
|
v[0].data.add_(v[1].data,alpha=float(self.null_model_params[index]["style"]))
|
||||||
|
#テンポはsdpとdp二つあるからとりあえずどっちも足す
|
||||||
|
params = zip(self.__net_g.sdp.parameters(), null_model_add.sdp.parameters())
|
||||||
|
for v in params:
|
||||||
|
v[0].data.add_(v[1].data,alpha=float(self.null_model_params[index]["tempo"]))
|
||||||
|
params = zip(self.__net_g.dp.parameters(), null_model_add.dp.parameters())
|
||||||
|
for v in params:
|
||||||
|
v[0].data.add_(v[1].data,alpha=float(self.null_model_params[index]["tempo"]))
|
||||||
|
|
||||||
|
|
||||||
def __get_style_vector(self, style_id: int, weight: float = 1.0) -> NDArray[Any]:
|
def __get_style_vector(self, style_id: int, weight: float = 1.0) -> NDArray[Any]:
|
||||||
"""
|
"""
|
||||||
@@ -227,6 +258,8 @@ class TTSModel:
|
|||||||
given_tone: Optional[list[int]] = None,
|
given_tone: Optional[list[int]] = None,
|
||||||
pitch_scale: float = 1.0,
|
pitch_scale: float = 1.0,
|
||||||
intonation_scale: float = 1.0,
|
intonation_scale: float = 1.0,
|
||||||
|
null_model_params: dict[int,dict[str,Union[str, float]]] = {},
|
||||||
|
force_reload_model:bool = False
|
||||||
) -> tuple[int, NDArray[Any]]:
|
) -> tuple[int, NDArray[Any]]:
|
||||||
"""
|
"""
|
||||||
テキストから音声を合成する。
|
テキストから音声を合成する。
|
||||||
@@ -251,7 +284,7 @@ class TTSModel:
|
|||||||
given_tone (Optional[list[int]], optional): アクセントのトーンのリスト. Defaults to None.
|
given_tone (Optional[list[int]], optional): アクセントのトーンのリスト. Defaults to None.
|
||||||
pitch_scale (float, optional): ピッチの高さ (1.0 から変更すると若干音質が低下する). Defaults to 1.0.
|
pitch_scale (float, optional): ピッチの高さ (1.0 から変更すると若干音質が低下する). Defaults to 1.0.
|
||||||
intonation_scale (float, optional): 抑揚の平均からの変化幅 (1.0 から変更すると若干音質が低下する). Defaults to 1.0.
|
intonation_scale (float, optional): 抑揚の平均からの変化幅 (1.0 から変更すると若干音質が低下する). Defaults to 1.0.
|
||||||
|
null_model_params(dict[int,dict[str,Union[str,float]],optional):推論時に使用するヌルモデルの名前、適用割合のdictが入ったdict。
|
||||||
Returns:
|
Returns:
|
||||||
tuple[int, NDArray[Any]]: サンプリングレートと音声データ (16bit PCM)
|
tuple[int, NDArray[Any]]: サンプリングレートと音声データ (16bit PCM)
|
||||||
"""
|
"""
|
||||||
@@ -265,7 +298,12 @@ class TTSModel:
|
|||||||
reference_audio_path = None
|
reference_audio_path = None
|
||||||
if assist_text == "" or not use_assist_text:
|
if assist_text == "" or not use_assist_text:
|
||||||
assist_text = None
|
assist_text = None
|
||||||
|
if null_model_params is not {}:
|
||||||
|
self.null_model_params = null_model_params
|
||||||
|
else:
|
||||||
|
self.null_model_params = {}
|
||||||
|
if force_reload_model is True:
|
||||||
|
self.__net_g = None
|
||||||
if self.__net_g is None:
|
if self.__net_g is None:
|
||||||
self.load()
|
self.load()
|
||||||
assert self.__net_g is not None
|
assert self.__net_g is not None
|
||||||
|
|||||||
Reference in New Issue
Block a user