推論時ヌルモデルマージ(まだ動かないよ)

This commit is contained in:
liruk
2024-06-18 19:15:20 +09:00
parent a1fcb433e7
commit 86c2a1b087
2 changed files with 187 additions and 3 deletions

View File

@@ -185,7 +185,12 @@ style_md = f"""
- どのくらいに強さがいいかはモデルやスタイルによって異なるようです。
- 音声ファイルを入力する場合は、学習データと似た声音の話者(特に同じ性別)でないとよい効果が出ないかもしれません。
"""
voice_keys = ["dec"]
voice_pitch_keys = ["flow"]
speech_style_keys = ["enc_p"]
tempo_keys = ["sdp", "dp"]
null_models = {}#グローバルに置いてるけどもっと良い置き場所ありそう
def make_interactive():
return gr.update(interactive=True, value="音声合成")
@@ -228,6 +233,14 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
):
model_holder.get_model(model_name, model_path)
assert model_holder.current_model is not None
#null_model_paths,
#null_voice_weights,
#null_voice_pitch_weights,
#null_speech_style_weights,
#null_tempo_weights
if len(null_models) > 0 and len(null_models["names"].keys()) > 0:
model_holder.get_null_models(null_models)
assert len(model_holder.current_null_models) > 0
wrong_tone_message = ""
kata_tone: Optional[list[tuple[str, int]]] = None
@@ -282,6 +295,7 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
speaker_id=speaker_id,
pitch_scale=pitch_scale,
intonation_scale=intonation_scale,
null_model_params = null_models
)
except InvalidToneError as e:
logger.error(f"Tone error: {e}")
@@ -436,6 +450,113 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
inputs=[use_assist_text],
outputs=[assist_text, assist_text_weight],
)
with gr.Accordion(label="ヌルモデル", open=False):
#null_voice_weights,
#null_voice_pitch_weights,
#null_speech_style_weights,
#null_tempo_weights
with gr.Row():
style_count = gr.Number(label="作るスタイルの数", value=0, step=1)
with gr.Column(variant="panel"):
@gr.render(
inputs=[
style_count,
]
)
def render_style(
style_count
):
name_components = {}
path_components = {}
weight_components = {}
pitch_components = {}
style_components = {}
tempo_components = {}
for i in range(style_count):
with gr.Row():
null_model_name = gr.Dropdown(
label="モデル一覧",
choices=model_names,
key=f"null_model_name_{i}",
value=model_names[initial_id],
interactive=True
)
null_model_path = gr.Dropdown(
label="モデルファイル",
choices=initial_pth_files,
key=f"null_model_path_{i}",
value=initial_pth_files[0],
interactive=True
)
null_voice_weights = gr.Slider(
minimum=0,
maximum=1,
value=1,
step=0.1,
key=f"null_voice_weights_{i}",
label="声質",
interactive=True
)
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
)
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
)
null_tempo_weights = gr.Slider(
minimum=0,
maximum=1,
value=1,
step=0.1,
key=f"null_tempo_weights_{i}",
label="テンポ",
interactive=True
)
null_model_name.change(
model_holder.update_model_files_for_gradio,
inputs=[null_model_name],
outputs=[null_model_path],
)
null_model_path.change(make_non_interactive, outputs=[tts_button])
#もっといい方法ありそう
name_components[str(i)]=(null_model_name)
path_components[str(i)]=(null_model_path)
weight_components[str(i)]=(null_voice_weights)
pitch_components[str(i)]=(null_voice_pitch_weights)
style_components[str(i)]=(null_speech_style_weights)
tempo_components[str(i)]=(null_tempo_weights)
null_models["names"]=(name_components)
null_models["paths"]=(path_components)
null_models["weights"]=(weight_components)
null_models["pitchs"]=(pitch_components)
null_models["styles"]=(style_components)
null_models["tempos"]=(tempo_components)
add_btn = gr.Button("ヌルモデルを増やす")
del_btn = gr.Button("ヌルモデルを減らす")
add_btn.click(
lambda x: x + 1,
inputs=[style_count],
outputs=[style_count],
)
del_btn.click(
lambda x: x - 1 if x > 0 else 0,
inputs=[style_count],
outputs=[style_count],
)
with gr.Column():
with gr.Accordion("スタイルについて詳細", open=False):
gr.Markdown(style_md)
@@ -524,7 +645,6 @@ def create_inference_app(model_holder: TTSModelHolder) -> gr.Blocks:
return app
if __name__ == "__main__":
from config import get_path_config
import torch

View File

@@ -61,6 +61,7 @@ class TTSModel:
self.model_path: Path = model_path
self.device: str = device
self.null_model_params: dict[str, dict[str,Any]] = {}
# ハイパーパラメータの Pydantic モデルが直接指定された
if isinstance(config_path, HyperParameters):
@@ -113,6 +114,36 @@ class TTSModel:
device=self.device,
hps=self.hyper_parameters,
)
if(len(self.null_model_params.keys())==0):
return
for index, null_model in enumerate(self.null_model_params["names"].keys()):
null_model_add = get_net_g(
model_path=str(self.null_model_params["paths"][str(index)].value),
version=self.hyper_parameters.version,
device=self.device,
hps=self.hyper_parameters,
)
#愚直。もっと上手い方法ありそう
params = zip(self.__net_g.dec.parameters(), null_model_add.dec.parameters())
for v in params:
v[0].data.add(v[1].data,alpha=self.null_model_params["weights"][str(index)].value)
params = zip(self.__net_g.flow.parameters(), null_model_add.flow.parameters())
for v in params:
v[0].data.add(v[1].data,alpha=self.null_model_params["pitchs"][str(index)].value)
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=self.null_model_params["styles"][str(index)].value)
#テンポは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=self.null_model_params["tempos"][str(index)].value)
params = zip(self.__net_g.dp.parameters(), null_model_add.dp.parameters())
for v in params:
v[0].data.add(v[1].data,alpha=self.null_model_params["tempos"][str(index)].value)
def __get_style_vector(self, style_id: int, weight: float = 1.0) -> NDArray[Any]:
"""
@@ -227,6 +258,7 @@ class TTSModel:
given_tone: Optional[list[int]] = None,
pitch_scale: float = 1.0,
intonation_scale: float = 1.0,
null_model_params: dict[str,dict[str,Any]] = {}
) -> tuple[int, NDArray[Any]]:
"""
テキストから音声を合成する。
@@ -251,7 +283,7 @@ class TTSModel:
given_tone (Optional[list[int]], optional): アクセントのトーンのリスト. Defaults to None.
pitch_scale (float, optional): ピッチの高さ (1.0 から変更すると若干音質が低下する). Defaults to 1.0.
intonation_scale (float, optional): 抑揚の平均からの変化幅 (1.0 から変更すると若干音質が低下する). Defaults to 1.0.
null_model_params(dict[str,dict[str,gr.Component],optional):推論時に使用するヌルモデルの名前、重みのdictが入ったdict。
Returns:
tuple[int, NDArray[Any]]: サンプリングレートと音声データ (16bit PCM)
"""
@@ -265,7 +297,10 @@ class TTSModel:
reference_audio_path = None
if assist_text == "" or not use_assist_text:
assist_text = None
if null_model_params is not {}:
self.null_model_params = null_model_params
else:
self.null_model_params = {}
if self.__net_g is None:
self.load()
assert self.__net_g is not None
@@ -372,6 +407,8 @@ class TTSModelHolder:
self.device: str = device
self.model_files_dict: dict[str, list[Path]] = {}
self.current_model: Optional[TTSModel] = None
self.current_null_models: dict[str,TTSModel] = {}
self.null_models_params: dict[str,dict[str,Any]] = {}
self.model_names: list[str] = []
self.models_info: list[TTSModelInfo] = []
self.refresh()
@@ -384,6 +421,8 @@ class TTSModelHolder:
self.model_files_dict = {}
self.model_names = []
self.current_model = None
self.current_null_models = {}
self.null_models_params = {}
self.models_info = []
model_dirs = [d for d in self.root_dir.iterdir() if d.is_dir()]
@@ -445,6 +484,29 @@ class TTSModelHolder:
)
return self.current_model
def get_null_models(self, null_model_index:dict[str,dict[str,Any]]) -> dict[str, TTSModel]:
"""
get_modelをヌルモデル用に改変。複数まとめて使うかも知れないのでdictで戻す
"""
self.current_null_models = {}
self.null_models_params = null_model_index
for index, value in enumerate(null_model_index["names"]):
model_path = Path(null_model_index["paths"][str(index)].value)
model_name = null_model_index["names"][str(index)].value
if model_name not in self.model_files_dict:
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 len(self.current_null_models) == 0 or model_path not in self.current_null_models.keys():
self.current_null_models[model_name] = TTSModel(
model_path=model_path,
config_path=self.root_dir / model_name / "config.json",
style_vec_path=self.root_dir / model_name / "style_vectors.npy",
device=self.device,
)
return self.current_null_models
def get_model_for_gradio(self, model_name: str, model_path_str: str):
import gradio as gr
@@ -474,6 +536,8 @@ class TTSModelHolder:
)
speakers = list(self.current_model.spk2id.keys())
styles = list(self.current_model.style2id.keys())
#if len(null_models.keys())!=0:
# self.get_null_models(null_models)
return (
gr.Dropdown(choices=styles, value=styles[0]), # type: ignore
gr.Button(interactive=True, value="音声合成"),