Fmt only (maybe)

This commit is contained in:
litagin02
2024-05-25 18:15:36 +09:00
parent acf93b80ce
commit 2274087da4
33 changed files with 216 additions and 166 deletions

2
app.py
View File

@@ -4,6 +4,7 @@ from pathlib import Path
import gradio as gr import gradio as gr
import torch import torch
from config import get_path_config
from gradio_tabs.dataset import create_dataset_app from gradio_tabs.dataset import create_dataset_app
from gradio_tabs.inference import create_inference_app from gradio_tabs.inference import create_inference_app
from gradio_tabs.merge import create_merge_app from gradio_tabs.merge import create_merge_app
@@ -13,7 +14,6 @@ from style_bert_vits2.constants import GRADIO_THEME, VERSION
from style_bert_vits2.nlp.japanese import pyopenjtalk_worker from style_bert_vits2.nlp.japanese import pyopenjtalk_worker
from style_bert_vits2.nlp.japanese.user_dict import update_dict from style_bert_vits2.nlp.japanese.user_dict import update_dict
from style_bert_vits2.tts_model import TTSModelHolder from style_bert_vits2.tts_model import TTSModelHolder
from config import get_path_config
# このプロセスからはワーカーを起動して辞書を使いたいので、ここで初期化 # このプロセスからはワーカーを起動して辞書を使いたいので、ここで初期化

View File

@@ -10,10 +10,7 @@ from style_bert_vits2.constants import Languages
from style_bert_vits2.logging import logger from style_bert_vits2.logging import logger
from style_bert_vits2.models import commons from style_bert_vits2.models import commons
from style_bert_vits2.models.hyper_parameters import HyperParameters from style_bert_vits2.models.hyper_parameters import HyperParameters
from style_bert_vits2.nlp import ( from style_bert_vits2.nlp import cleaned_text_to_sequence, extract_bert_feature
cleaned_text_to_sequence,
extract_bert_feature,
)
from style_bert_vits2.nlp.japanese import pyopenjtalk_worker from style_bert_vits2.nlp.japanese import pyopenjtalk_worker
from style_bert_vits2.nlp.japanese.user_dict import update_dict from style_bert_vits2.nlp.japanese.user_dict import update_dict
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
@@ -77,10 +74,10 @@ if __name__ == "__main__":
config_path = args.config config_path = args.config
hps = HyperParameters.load_from_json(config_path) hps = HyperParameters.load_from_json(config_path)
lines: list[str] = [] lines: list[str] = []
with open(hps.data.training_files, "r", encoding="utf-8") as f: with open(hps.data.training_files, encoding="utf-8") as f:
lines.extend(f.readlines()) lines.extend(f.readlines())
with open(hps.data.validation_files, "r", encoding="utf-8") as f: with open(hps.data.validation_files, encoding="utf-8") as f:
lines.extend(f.readlines()) lines.extend(f.readlines())
add_blank = [hps.data.add_blank] * len(lines) add_blank = [hps.data.add_blank] * len(lines)

View File

@@ -56,8 +56,13 @@ class Preprocess_text_config:
clean: bool = True, clean: bool = True,
): ):
self.transcription_path = Path(transcription_path) self.transcription_path = Path(transcription_path)
self.cleaned_path = Path(cleaned_path)
self.train_path = Path(train_path) self.train_path = Path(train_path)
if cleaned_path == "" or cleaned_path is None:
self.cleaned_path = self.transcription_path.with_name(
self.transcription_path.name + ".cleaned"
)
else:
self.cleaned_path = Path(cleaned_path)
self.val_path = Path(val_path) self.val_path = Path(val_path)
self.config_path = Path(config_path) self.config_path = Path(config_path)
self.val_per_lang = val_per_lang self.val_per_lang = val_per_lang
@@ -70,7 +75,7 @@ class Preprocess_text_config:
data["transcription_path"] = dataset_path / data["transcription_path"] data["transcription_path"] = dataset_path / data["transcription_path"]
if data["cleaned_path"] == "" or data["cleaned_path"] is None: if data["cleaned_path"] == "" or data["cleaned_path"] is None:
data["cleaned_path"] = None data["cleaned_path"] = ""
else: else:
data["cleaned_path"] = dataset_path / data["cleaned_path"] data["cleaned_path"] = dataset_path / data["cleaned_path"]
data["train_path"] = dataset_path / data["train_path"] data["train_path"] = dataset_path / data["train_path"]
@@ -232,7 +237,7 @@ class Config:
"Please do not modify default_config.yml. Instead, modify config.yml." "Please do not modify default_config.yml. Instead, modify config.yml."
) )
# sys.exit(0) # sys.exit(0)
with open(config_path, "r", encoding="utf-8") as file: with open(config_path, encoding="utf-8") as file:
yaml_config: dict[str, Any] = yaml.safe_load(file.read()) yaml_config: dict[str, Any] = yaml.safe_load(file.read())
model_name: str = yaml_config["model_name"] model_name: str = yaml_config["model_name"]
self.model_name: str = model_name self.model_name: str = model_name
@@ -241,6 +246,7 @@ class Config:
else: else:
dataset_path = path_config.dataset_root / model_name dataset_path = path_config.dataset_root / model_name
self.dataset_path = dataset_path self.dataset_path = dataset_path
self.dataset_root = path_config.dataset_root
self.assets_root = path_config.assets_root self.assets_root = path_config.assets_root
self.out_dir = self.assets_root / model_name self.out_dir = self.assets_root / model_name
self.resample_config: Resample_config = Resample_config.from_dict( self.resample_config: Resample_config = Resample_config.from_dict(
@@ -284,7 +290,7 @@ def get_path_config() -> PathConfig:
logger.info( logger.info(
"Please do not modify configs/default_paths.yml. Instead, modify configs/paths.yml." "Please do not modify configs/default_paths.yml. Instead, modify configs/paths.yml."
) )
with open(path_config_path, "r", encoding="utf-8") as file: with open(path_config_path, encoding="utf-8") as file:
path_config_dict: dict[str, str] = yaml.safe_load(file.read()) path_config_dict: dict[str, str] = yaml.safe_load(file.read())
return PathConfig(**path_config_dict) return PathConfig(**path_config_dict)

View File

@@ -7,7 +7,7 @@ import torch
import torch.utils.data import torch.utils.data
from tqdm import tqdm from tqdm import tqdm
from config import config from config import get_config
from mel_processing import mel_spectrogram_torch, spectrogram_torch from mel_processing import mel_spectrogram_torch, spectrogram_torch
from style_bert_vits2.logging import logger from style_bert_vits2.logging import logger
from style_bert_vits2.models import commons from style_bert_vits2.models import commons
@@ -16,6 +16,7 @@ from style_bert_vits2.models.utils import load_filepaths_and_text, load_wav_to_t
from style_bert_vits2.nlp import cleaned_text_to_sequence from style_bert_vits2.nlp import cleaned_text_to_sequence
config = get_config()
"""Multi speaker version""" """Multi speaker version"""
@@ -120,9 +121,7 @@ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
audio, sampling_rate = load_wav_to_torch(filename) audio, sampling_rate = load_wav_to_torch(filename)
if sampling_rate != self.sampling_rate: if sampling_rate != self.sampling_rate:
raise ValueError( raise ValueError(
"{} {} SR doesn't match target {} SR".format( f"{filename} {sampling_rate} SR doesn't match target {self.sampling_rate} SR"
filename, sampling_rate, self.sampling_rate
)
) )
audio_norm = audio / self.max_wav_value audio_norm = audio / self.max_wav_value
audio_norm = audio_norm.unsqueeze(0) audio_norm = audio_norm.unsqueeze(0)

View File

@@ -33,7 +33,7 @@ def save_neutral_vector(wav_dir: Union[Path, str], output_path: Union[Path, str]
np.save(output_path, only_mean) np.save(output_path, only_mean)
logger.info(f"Saved mean style vector to {output_path}") logger.info(f"Saved mean style vector to {output_path}")
with open(json_path, "r", encoding="utf-8") as f: with open(json_path, encoding="utf-8") as f:
json_dict = json.load(f) json_dict = json.load(f)
json_dict["data"]["num_styles"] = 1 json_dict["data"]["num_styles"] = 1
json_dict["data"]["style2id"] = {DEFAULT_STYLE: 0} json_dict["data"]["style2id"] = {DEFAULT_STYLE: 0}
@@ -50,7 +50,7 @@ def save_styles_by_dirs(wav_dir: Union[Path, str], output_dir: Union[Path, str])
subdirs = [d for d in wav_dir.iterdir() if d.is_dir()] subdirs = [d for d in wav_dir.iterdir() if d.is_dir()]
subdirs.sort() subdirs.sort()
if len(subdirs) in (0, 1): if not subdirs:
logger.warning("No style directories found. Saving only neutral style.") logger.warning("No style directories found. Saving only neutral style.")
save_neutral_vector(wav_dir, output_dir) save_neutral_vector(wav_dir, output_dir)
@@ -85,7 +85,7 @@ def save_styles_by_dirs(wav_dir: Union[Path, str], output_dir: Union[Path, str])
# Save style2id config to json # Save style2id config to json
style2id = {name: i for i, name in enumerate(names)} style2id = {name: i for i, name in enumerate(names)}
with open(json_path, "r", encoding="utf-8") as f: with open(json_path, encoding="utf-8") as f:
json_dict = json.load(f) json_dict = json.load(f)
json_dict["data"]["num_styles"] = len(names) json_dict["data"]["num_styles"] = len(names)
json_dict["data"]["style2id"] = style2id json_dict["data"]["style2id"] = style2id

View File

@@ -22,7 +22,7 @@ args = parser.parse_args()
def gen_yaml(model_name, dataset_path): def gen_yaml(model_name, dataset_path):
if not os.path.exists("config.yml"): if not os.path.exists("config.yml"):
shutil.copy(src="default_config.yml", dst="config.yml") shutil.copy(src="default_config.yml", dst="config.yml")
with open("config.yml", "r", encoding="utf-8") as f: with open("config.yml", encoding="utf-8") as f:
yml_data = yaml.safe_load(f) yml_data = yaml.safe_load(f)
yml_data["model_name"] = model_name yml_data["model_name"] = model_name
yml_data["dataset_path"] = dataset_path yml_data["dataset_path"] = dataset_path

View File

@@ -47,9 +47,9 @@ def merge_style(
style_vectors_b = np.load( style_vectors_b = np.load(
assets_root / model_name_b / "style_vectors.npy" assets_root / model_name_b / "style_vectors.npy"
) # (style_num_b, 256) ) # (style_num_b, 256)
with open(assets_root / model_name_a / "config.json", "r", encoding="utf-8") as f: with open(assets_root / model_name_a / "config.json", encoding="utf-8") as f:
config_a = json.load(f) config_a = json.load(f)
with open(assets_root / model_name_b / "config.json", "r", encoding="utf-8") as f: with open(assets_root / model_name_b / "config.json", encoding="utf-8") as f:
config_b = json.load(f) config_b = json.load(f)
style2id_a = config_a["data"]["style2id"] style2id_a = config_a["data"]["style2id"]
style2id_b = config_b["data"]["style2id"] style2id_b = config_b["data"]["style2id"]
@@ -83,7 +83,7 @@ def merge_style(
# recipe.jsonを読み込んで、style_triple_listを追記 # recipe.jsonを読み込んで、style_triple_listを追記
info_path = assets_root / output_name / "recipe.json" info_path = assets_root / output_name / "recipe.json"
if info_path.exists(): if info_path.exists():
with open(info_path, "r", encoding="utf-8") as f: with open(info_path, encoding="utf-8") as f:
info = json.load(f) info = json.load(f)
else: else:
info = {} info = {}
@@ -143,7 +143,7 @@ def merge_models(
merged_model_weight = model_a_weight.copy() merged_model_weight = model_a_weight.copy()
for key in model_a_weight.keys(): for key in model_a_weight:
if any([key.startswith(prefix) for prefix in voice_keys]): if any([key.startswith(prefix) for prefix in voice_keys]):
weight = voice_weight weight = voice_weight
elif any([key.startswith(prefix) for prefix in voice_pitch_keys]): elif any([key.startswith(prefix) for prefix in voice_pitch_keys]):
@@ -256,12 +256,12 @@ def update_two_model_names_dropdown(model_holder: TTSModelHolder):
def load_styles_gr(model_name_a: str, model_name_b: str): def load_styles_gr(model_name_a: str, model_name_b: str):
config_path_a = assets_root / model_name_a / "config.json" config_path_a = assets_root / model_name_a / "config.json"
with open(config_path_a, "r", encoding="utf-8") as f: with open(config_path_a, encoding="utf-8") as f:
config_a = json.load(f) config_a = json.load(f)
styles_a = list(config_a["data"]["style2id"].keys()) styles_a = list(config_a["data"]["style2id"].keys())
config_path_b = assets_root / model_name_b / "config.json" config_path_b = assets_root / model_name_b / "config.json"
with open(config_path_b, "r", encoding="utf-8") as f: with open(config_path_b, encoding="utf-8") as f:
config_b = json.load(f) config_b = json.load(f)
styles_b = list(config_b["data"]["style2id"].keys()) styles_b = list(config_b["data"]["style2id"].keys())

View File

@@ -5,13 +5,14 @@ import subprocess
import sys import sys
import time import time
import webbrowser import webbrowser
from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from multiprocessing import cpu_count from multiprocessing import cpu_count
from pathlib import Path from pathlib import Path
import gradio as gr import gradio as gr
import yaml import yaml
from dataclasses import dataclass
from config import get_path_config from config import get_path_config
from style_bert_vits2.logging import logger from style_bert_vits2.logging import logger
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
@@ -75,7 +76,7 @@ def initialize(
"configs/config.json" if not use_jp_extra else "configs/config_jp_extra.json" "configs/config.json" if not use_jp_extra else "configs/config_jp_extra.json"
) )
with open(default_config_path, "r", encoding="utf-8") as f: with open(default_config_path, encoding="utf-8") as f:
config = json.load(f) config = json.load(f)
config["model_name"] = model_name config["model_name"] = model_name
config["data"]["training_files"] = str(paths.train_path) config["data"]["training_files"] = str(paths.train_path)
@@ -121,7 +122,7 @@ def initialize(
json.dump(config, f, indent=2, ensure_ascii=False) json.dump(config, f, indent=2, ensure_ascii=False)
if not Path("config.yml").exists(): if not Path("config.yml").exists():
shutil.copy(src="default_config.yml", dst="config.yml") shutil.copy(src="default_config.yml", dst="config.yml")
with open("config.yml", "r", encoding="utf-8") as f: with open("config.yml", encoding="utf-8") as f:
yml_data = yaml.safe_load(f) yml_data = yaml.safe_load(f)
yml_data["model_name"] = model_name yml_data["model_name"] = model_name
yml_data["dataset_path"] = str(paths.dataset_path) yml_data["dataset_path"] = str(paths.dataset_path)
@@ -331,7 +332,7 @@ def train(
): ):
paths = get_path(model_name) paths = get_path(model_name)
# 学習再開の場合を考えて念のためconfig.ymlの名前等を更新 # 学習再開の場合を考えて念のためconfig.ymlの名前等を更新
with open("config.yml", "r", encoding="utf-8") as f: with open("config.yml", encoding="utf-8") as f:
yml_data = yaml.safe_load(f) yml_data = yaml.safe_load(f)
yml_data["model_name"] = model_name yml_data["model_name"] = model_name
yml_data["dataset_path"] = str(paths.dataset_path) yml_data["dataset_path"] = str(paths.dataset_path)

View File

@@ -10,7 +10,7 @@ from style_bert_vits2.logging import logger
def download_bert_models(): def download_bert_models():
with open("bert/bert_models.json", "r", encoding="utf-8") as fp: with open("bert/bert_models.json", encoding="utf-8") as fp:
models = json.load(fp) models = json.load(fp)
for k, v in models.items(): for k, v in models.items():
local_path = Path("bert").joinpath(k) local_path = Path("bert").joinpath(k)
@@ -113,7 +113,7 @@ def main():
return return
# Change default paths if necessary # Change default paths if necessary
with open(paths_yml, "r", encoding="utf-8") as f: with open(paths_yml, encoding="utf-8") as f:
yml_data = yaml.safe_load(f) yml_data = yaml.safe_load(f)
if args.assets_root is not None: if args.assets_root is not None:
yml_data["assets_root"] = args.assets_root yml_data["assets_root"] = args.assets_root

View File

@@ -145,7 +145,7 @@ def preprocess(
spk_utt_map[spk].append(line) spk_utt_map[spk].append(line)
# 新しい話者が出てきたら話者IDを割り当て、current_sidを1増やす # 新しい話者が出てきたら話者IDを割り当て、current_sidを1増やす
if spk not in spk_id_map.keys(): if spk not in spk_id_map:
spk_id_map[spk] = current_sid spk_id_map[spk] = current_sid
current_sid += 1 current_sid += 1
if count_same > 0 or count_not_found > 0: if count_same > 0 or count_not_found > 0:

View File

@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "style-bert-vits2" name = "style-bert-vits2"
dynamic = ["version"] dynamic = ["version"]
description = 'Style-Bert-VITS2: Bert-VITS2 with more controllable voice styles.' description = "Style-Bert-VITS2: Bert-VITS2 with more controllable voice styles."
readme = "README.md" readme = "README.md"
requires-python = ">=3.9" requires-python = ">=3.9"
license = "AGPL-3.0" license = "AGPL-3.0"
@@ -22,21 +22,21 @@ classifiers = [
"Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: CPython",
] ]
dependencies = [ dependencies = [
'cmudict', "cmudict",
'cn2an', "cn2an",
'g2p_en', "g2p_en",
'jieba', "jieba",
'loguru', "loguru",
'num2words', "num2words",
'numba', "numba",
'numpy', "numpy",
'pydantic>=2.0', "pydantic>=2.0",
'pyopenjtalk-dict', "pyopenjtalk-dict",
'pypinyin', "pypinyin",
'pyworld-prebuilt', "pyworld-prebuilt",
'safetensors', "safetensors",
'torch>=2.1', "torch>=2.1",
'transformers', "transformers",
] ]
[project.urls] [project.urls]
@@ -59,42 +59,26 @@ only-include = [
"pyproject.toml", "pyproject.toml",
"README.md", "README.md",
] ]
exclude = [ exclude = [".git", ".gitignore", ".gitattributes"]
".git",
".gitignore",
".gitattributes",
]
[tool.hatch.build.targets.wheel] [tool.hatch.build.targets.wheel]
packages = ["style_bert_vits2"] packages = ["style_bert_vits2"]
[tool.hatch.envs.test] [tool.hatch.envs.test]
dependencies = [ dependencies = ["coverage[toml]>=6.5", "pytest"]
"coverage[toml]>=6.5",
"pytest",
]
[tool.hatch.envs.test.scripts] [tool.hatch.envs.test.scripts]
# Usage: `hatch run test:test` # Usage: `hatch run test:test`
test = "pytest {args:tests}" test = "pytest {args:tests}"
# Usage: `hatch run test:coverage` # Usage: `hatch run test:coverage`
test-cov = "coverage run -m pytest {args:tests}" test-cov = "coverage run -m pytest {args:tests}"
# Usage: `hatch run test:cov-report` # Usage: `hatch run test:cov-report`
cov-report = [ cov-report = ["- coverage combine", "coverage report"]
"- coverage combine",
"coverage report",
]
# Usage: `hatch run test:cov` # Usage: `hatch run test:cov`
cov = [ cov = ["test-cov", "cov-report"]
"test-cov",
"cov-report",
]
[tool.hatch.envs.style] [tool.hatch.envs.style]
detached = true detached = true
dependencies = [ dependencies = ["black", "isort"]
"black",
"isort",
]
[tool.hatch.envs.style.scripts] [tool.hatch.envs.style.scripts]
check = [ check = [
"black --check --diff .", "black --check --diff .",
@@ -113,17 +97,17 @@ python = ["3.9", "3.10", "3.11"]
source_pkgs = ["style_bert_vits2", "tests"] source_pkgs = ["style_bert_vits2", "tests"]
branch = true branch = true
parallel = true parallel = true
omit = [ omit = ["style_bert_vits2/constants.py"]
"style_bert_vits2/constants.py",
]
[tool.coverage.paths] [tool.coverage.paths]
style_bert_vits2 = ["style_bert_vits2", "*/style-bert-vits2/style_bert_vits2"] style_bert_vits2 = ["style_bert_vits2", "*/style-bert-vits2/style_bert_vits2"]
tests = ["tests", "*/style-bert-vits2/tests"] tests = ["tests", "*/style-bert-vits2/tests"]
[tool.coverage.report] [tool.coverage.report]
exclude_lines = [ exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"]
"no cov",
"if __name__ == .__main__.:", [tool.ruff]
"if TYPE_CHECKING:", extend-select = ["I"]
]
[tool.ruff.lint.isort]
lines-after-imports = 2

View File

@@ -127,7 +127,7 @@ def download_and_extract(url, extract_to: Path):
def new_release_available(latest_release): def new_release_available(latest_release):
if LAST_DOWNLOAD_FILE.exists(): if LAST_DOWNLOAD_FILE.exists():
with open(LAST_DOWNLOAD_FILE, "r") as file: with open(LAST_DOWNLOAD_FILE) as file:
last_download_str = file.read().strip() last_download_str = file.read().strip()
# 'Z'を除去して日時オブジェクトに変換 # 'Z'を除去して日時オブジェクトに変換
last_download_str = last_download_str.replace("Z", "+00:00") last_download_str = last_download_str.replace("Z", "+00:00")

View File

@@ -7,7 +7,6 @@ from typing import Any, Optional
import soundfile as sf import soundfile as sf
import torch import torch
import yaml
from tqdm import tqdm from tqdm import tqdm
from config import get_path_config from config import get_path_config

View File

@@ -125,5 +125,5 @@ class HyperParameters(BaseModel):
HyperParameters: ハイパーパラメータ HyperParameters: ハイパーパラメータ
""" """
with open(json_path, "r", encoding="utf-8") as f: with open(json_path, encoding="utf-8") as f:
return HyperParameters.model_validate_json(f.read()) return HyperParameters.model_validate_json(f.read())

View File

@@ -786,7 +786,7 @@ class ReferenceEncoder(nn.Module):
for i in range(K) for i in range(K)
] ]
self.convs = nn.ModuleList(convs) self.convs = nn.ModuleList(convs)
# self.wns = nn.ModuleList([weight_norm(num_features=ref_enc_filters[i]) for i in range(K)]) # noqa: E501 # self.wns = nn.ModuleList([weight_norm(num_features=ref_enc_filters[i]) for i in range(K)])
out_channels = self.calculate_channels(spec_channels, 3, 2, 1, K) out_channels = self.calculate_channels(spec_channels, 3, 2, 1, K)
self.gru = nn.GRU( self.gru = nn.GRU(

View File

@@ -844,7 +844,7 @@ class ReferenceEncoder(nn.Module):
for i in range(K) for i in range(K)
] ]
self.convs = nn.ModuleList(convs) self.convs = nn.ModuleList(convs)
# self.wns = nn.ModuleList([weight_norm(num_features=ref_enc_filters[i]) for i in range(K)]) # noqa: E501 # self.wns = nn.ModuleList([weight_norm(num_features=ref_enc_filters[i]) for i in range(K)])
out_channels = self.calculate_channels(spec_channels, 3, 2, 1, K) out_channels = self.calculate_channels(spec_channels, 3, 2, 1, K)
self.gru = nn.GRU( self.gru = nn.GRU(

View File

@@ -186,7 +186,7 @@ def load_filepaths_and_text(
list[list[str]]: ファイルパスとテキストのリスト list[list[str]]: ファイルパスとテキストのリスト
""" """
with open(filename, "r", encoding="utf-8") as f: with open(filename, encoding="utf-8") as f:
filepaths_and_text = [line.strip().split(split) for line in f] filepaths_and_text = [line.strip().split(split) for line in f]
return filepaths_and_text return filepaths_and_text
@@ -245,9 +245,7 @@ def check_git_hash(model_dir_path: Union[str, Path]) -> None:
source_dir = os.path.dirname(os.path.realpath(__file__)) source_dir = os.path.dirname(os.path.realpath(__file__))
if not os.path.exists(os.path.join(source_dir, ".git")): if not os.path.exists(os.path.join(source_dir, ".git")):
logger.warning( logger.warning(
"{} is not a git repository, therefore hash value comparison will be ignored.".format( f"{source_dir} is not a git repository, therefore hash value comparison will be ignored."
source_dir
)
) )
return return
@@ -255,13 +253,11 @@ def check_git_hash(model_dir_path: Union[str, Path]) -> None:
path = os.path.join(model_dir_path, "githash") path = os.path.join(model_dir_path, "githash")
if os.path.exists(path): if os.path.exists(path):
with open(path, "r", encoding="utf-8") as f: with open(path, encoding="utf-8") as f:
saved_hash = f.read() saved_hash = f.read()
if saved_hash != cur_hash: if saved_hash != cur_hash:
logger.warning( logger.warning(
"git hash values are different. {}(saved) != {}(current)".format( f"git hash values are different. {saved_hash[:8]}(saved) != {cur_hash[:8]}(current)"
saved_hash[:8], cur_hash[:8]
)
) )
else: else:
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:

View File

@@ -77,7 +77,7 @@ def save_safetensors(
keys = [] keys = []
for k in state_dict: for k in state_dict:
if "enc_q" in k and for_infer: if "enc_q" in k and for_infer:
continue # noqa: E701 continue
keys.append(k) keys.append(k)
new_dict = ( new_dict = (

View File

@@ -8,7 +8,7 @@ from style_bert_vits2.nlp.chinese.tone_sandhi import ToneSandhi
from style_bert_vits2.nlp.symbols import PUNCTUATIONS from style_bert_vits2.nlp.symbols import PUNCTUATIONS
with open(Path(__file__).parent / "opencpop-strict.txt", "r", encoding="utf-8") as f: with open(Path(__file__).parent / "opencpop-strict.txt", encoding="utf-8") as f:
__PINYIN_TO_SYMBOL_MAP = { __PINYIN_TO_SYMBOL_MAP = {
line.split("\t")[0]: line.strip().split("\t")[1] for line in f.readlines() line.split("\t")[0]: line.strip().split("\t")[1] for line in f.readlines()
} }
@@ -73,7 +73,7 @@ def __g2p(segments: list[str]) -> tuple[list[str], list[int], list[int]]:
"iou": "iu", "iou": "iu",
"uen": "un", "uen": "un",
} }
if v_without_tone in v_rep_map.keys(): if v_without_tone in v_rep_map:
pinyin = c + v_rep_map[v_without_tone] pinyin = c + v_rep_map[v_without_tone]
else: else:
# 单音节 # 单音节
@@ -83,7 +83,7 @@ def __g2p(segments: list[str]) -> tuple[list[str], list[int], list[int]]:
"in": "yin", "in": "yin",
"u": "wu", "u": "wu",
} }
if pinyin in pinyin_rep_map.keys(): if pinyin in pinyin_rep_map:
pinyin = pinyin_rep_map[pinyin] pinyin = pinyin_rep_map[pinyin]
else: else:
single_rep_map = { single_rep_map = {
@@ -92,10 +92,10 @@ def __g2p(segments: list[str]) -> tuple[list[str], list[int], list[int]]:
"i": "y", "i": "y",
"u": "w", "u": "w",
} }
if pinyin[0] in single_rep_map.keys(): if pinyin[0] in single_rep_map:
pinyin = single_rep_map[pinyin[0]] + pinyin[1:] pinyin = single_rep_map[pinyin[0]] + pinyin[1:]
assert pinyin in __PINYIN_TO_SYMBOL_MAP.keys(), ( assert pinyin in __PINYIN_TO_SYMBOL_MAP, (
pinyin, pinyin,
seg, seg,
raw_pinyin, raw_pinyin,

View File

@@ -51,7 +51,7 @@ def normalize_text(text: str) -> str:
def replace_punctuation(text: str) -> str: def replace_punctuation(text: str) -> str:
text = text.replace("", "").replace("", "") text = text.replace("", "").replace("", "")
pattern = re.compile("|".join(re.escape(p) for p in __REPLACE_MAP.keys())) pattern = re.compile("|".join(re.escape(p) for p in __REPLACE_MAP))
replaced_text = pattern.sub(lambda x: __REPLACE_MAP[x.group()], text) replaced_text = pattern.sub(lambda x: __REPLACE_MAP[x.group()], text)

View File

@@ -471,26 +471,27 @@ class ToneSandhi:
): ):
finals[j] = finals[j][:-1] + "5" finals[j] = finals[j][:-1] + "5"
ge_idx = word.find("") ge_idx = word.find("")
if len(word) >= 1 and word[-1] in "吧呢啊呐噻嘛吖嗨呐哦哒额滴哩哟喽啰耶喔诶": if (
finals[-1] = finals[-1][:-1] + "5" len(word) >= 1
elif len(word) >= 1 and word[-1] in "的地得": and word[-1] in "吧呢啊呐噻嘛吖嗨呐哦哒额滴哩哟喽啰耶喔诶"
finals[-1] = finals[-1][:-1] + "5" or len(word) >= 1
# e.g. 走了, 看着, 去过 and word[-1] in "的地得"
# elif len(word) == 1 and word in "了着过" and pos in {"ul", "uz", "ug"}: or (
# finals[-1] = finals[-1][:-1] + "5" (
elif ( len(word) > 1
len(word) > 1 and word[-1] in "们子"
and word[-1] in "们子" and pos in {"r", "n"}
and pos in {"r", "n"} and word not in self.must_not_neural_tone_words
and word not in self.must_not_neural_tone_words )
or len(word) > 1
and word[-1] in "上下里"
and pos in {"s", "l", "f"}
)
or len(word) > 1
and word[-1] in "来去"
and word[-2] in "上下进出回过起开"
): ):
finals[-1] = finals[-1][:-1] + "5" finals[-1] = finals[-1][:-1] + "5"
# e.g. 桌上, 地下, 家里
elif len(word) > 1 and word[-1] in "上下里" and pos in {"s", "l", "f"}:
finals[-1] = finals[-1][:-1] + "5"
# e.g. 上来, 下去
elif len(word) > 1 and word[-1] in "来去" and word[-2] in "上下进出回过起开":
finals[-1] = finals[-1][:-1] + "5"
# 个做量词 # 个做量词
elif ( elif (
ge_idx >= 1 ge_idx >= 1
@@ -500,12 +501,11 @@ class ToneSandhi:
) )
) or word == "": ) or word == "":
finals[ge_idx] = finals[ge_idx][:-1] + "5" finals[ge_idx] = finals[ge_idx][:-1] + "5"
else: elif (
if ( word in self.must_neural_tone_words
word in self.must_neural_tone_words or word[-2:] in self.must_neural_tone_words
or word[-2:] in self.must_neural_tone_words ):
): finals[-1] = finals[-1][:-1] + "5"
finals[-1] = finals[-1][:-1] + "5"
word_list = self._split_word(word) word_list = self._split_word(word)
finals_list = [finals[: len(word_list[0])], finals[len(word_list[0]) :]] finals_list = [finals[: len(word_list[0])], finals[len(word_list[0]) :]]
@@ -549,10 +549,8 @@ class ToneSandhi:
if finals[i + 1][-1] == "4": if finals[i + 1][-1] == "4":
finals[i] = finals[i][:-1] + "2" finals[i] = finals[i][:-1] + "2"
# "一" before non-tone4 should be yi4, e.g. 一天 # "一" before non-tone4 should be yi4, e.g. 一天
else: elif word[i + 1] not in self.punc:
# "一" 后面如果是标点,还读一声 finals[i] = finals[i][:-1] + "4"
if word[i + 1] not in self.punc:
finals[i] = finals[i][:-1] + "4"
return finals return finals
def _split_word(self, word: str) -> list[str]: def _split_word(self, word: str) -> list[str]:

View File

@@ -20,7 +20,7 @@ def get_dict() -> dict[str, list[list[str]]]:
def read_dict() -> dict[str, list[list[str]]]: def read_dict() -> dict[str, list[list[str]]]:
g2p_dict = {} g2p_dict = {}
start_line = 49 start_line = 49
with open(CMU_DICT_PATH, "r", encoding="utf-8") as f: with open(CMU_DICT_PATH, encoding="utf-8") as f:
line = f.readline() line = f.readline()
line_index = 1 line_index = 1
while line: while line:

View File

@@ -1,23 +1,91 @@
import re import re
from g2p_en import G2p from g2p_en import G2p
from style_bert_vits2.constants import Languages from style_bert_vits2.constants import Languages
from style_bert_vits2.nlp import bert_models from style_bert_vits2.nlp import bert_models
from style_bert_vits2.nlp.english.cmudict import get_dict from style_bert_vits2.nlp.english.cmudict import get_dict
from style_bert_vits2.nlp.symbols import PUNCTUATIONS, SYMBOLS from style_bert_vits2.nlp.symbols import PUNCTUATIONS, SYMBOLS
# Initialize global variables once # Initialize global variables once
ARPA = { ARPA = {
"AH0", "S", "AH1", "EY2", "AE2", "EH0", "OW2", "UH0", "NG", "B", "G", "AY0", "AH0",
"M", "AA0", "F", "AO0", "ER2", "UH1", "IY1", "AH2", "DH", "IY0", "EY1", "S",
"IH0", "K", "N", "W", "IY2", "T", "AA1", "ER1", "EH2", "OY0", "UH2", "UW1", "AH1",
"Z", "AW2", "AW1", "V", "UW2", "AA2", "ER", "AW0", "UW0", "R", "OW1", "EH1", "EY2",
"ZH", "AE0", "IH2", "IH", "Y", "JH", "P", "AY1", "EY0", "OY2", "TH", "HH", "AE2",
"D", "ER0", "CH", "AO1", "AE1", "AO2", "OY1", "AY2", "IH1", "OW0", "L", "EH0",
"SH" "OW2",
"UH0",
"NG",
"B",
"G",
"AY0",
"M",
"AA0",
"F",
"AO0",
"ER2",
"UH1",
"IY1",
"AH2",
"DH",
"IY0",
"EY1",
"IH0",
"K",
"N",
"W",
"IY2",
"T",
"AA1",
"ER1",
"EH2",
"OY0",
"UH2",
"UW1",
"Z",
"AW2",
"AW1",
"V",
"UW2",
"AA2",
"ER",
"AW0",
"UW0",
"R",
"OW1",
"EH1",
"ZH",
"AE0",
"IH2",
"IH",
"Y",
"JH",
"P",
"AY1",
"EY0",
"OY2",
"TH",
"HH",
"D",
"ER0",
"CH",
"AO1",
"AE1",
"AO2",
"OY1",
"AY2",
"IH1",
"OW0",
"L",
"SH",
} }
_g2p = G2p() _g2p = G2p()
eng_dict = get_dict() eng_dict = get_dict()
def g2p(text: str) -> tuple[list[str], list[int], list[int]]: def g2p(text: str) -> tuple[list[str], list[int], list[int]]:
phones = [] phones = []
tones = [] tones = []
@@ -72,9 +140,19 @@ def g2p(text: str) -> tuple[list[str], list[int], list[int]]:
def __post_replace_ph(ph: str) -> str: def __post_replace_ph(ph: str) -> str:
REPLACE_MAP = { REPLACE_MAP = {
"": ",", "": ",", "": ",", "": ".", "": "!", "": "?", "": ",",
"\n": ".", "·": ",", "": ",", "": "...", "···": "...", "": ",",
"・・・": "...", "v": "V" "": ",",
"": ".",
"": "!",
"": "?",
"\n": ".",
"·": ",",
"": ",",
"": "...",
"···": "...",
"・・・": "...",
"v": "V",
} }
if ph in REPLACE_MAP: if ph in REPLACE_MAP:
ph = REPLACE_MAP[ph] ph = REPLACE_MAP[ph]
@@ -120,21 +198,22 @@ def __text_to_words(text: str) -> list[list[str]]:
for idx, t in enumerate(tokens): for idx, t in enumerate(tokens):
if t.startswith(""): if t.startswith(""):
words.append([t[1:]]) words.append([t[1:]])
else: elif t in PUNCTUATIONS:
if t in PUNCTUATIONS: if idx == len(tokens) - 1:
if idx == len(tokens) - 1: words.append([f"{t}"])
words.append([f"{t}"]) elif (
else: not tokens[idx + 1].startswith("")
if not tokens[idx + 1].startswith("") and tokens[idx + 1] not in PUNCTUATIONS: and tokens[idx + 1] not in PUNCTUATIONS
if idx == 0: ):
words.append([])
words[-1].append(f"{t}")
else:
words.append([f"{t}"])
else:
if idx == 0: if idx == 0:
words.append([]) words.append([])
words[-1].append(f"{t}") words[-1].append(f"{t}")
else:
words.append([f"{t}"])
else:
if idx == 0:
words.append([])
words[-1].append(f"{t}")
return words return words
@@ -149,4 +228,3 @@ if __name__ == "__main__":
# for ph in group: # for ph in group:
# all_phones.add(ph) # all_phones.add(ph)
# print(all_phones) # print(all_phones)

View File

@@ -58,7 +58,7 @@ def replace_punctuation(text: str) -> str:
"": "'", "": "'",
"": "'", "": "'",
} }
pattern = re.compile("|".join(re.escape(p) for p in REPLACE_MAP.keys())) pattern = re.compile("|".join(re.escape(p) for p in REPLACE_MAP))
replaced_text = pattern.sub(lambda x: REPLACE_MAP[x.group()], text) replaced_text = pattern.sub(lambda x: REPLACE_MAP[x.group()], text)
# replaced_text = re.sub( # replaced_text = re.sub(
# r"[^\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\u3005" # r"[^\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\u3005"

View File

@@ -719,5 +719,3 @@ class YomiError(Exception):
基本的に「学習の前処理のテキスト処理時」には発生させ、そうでない場合は、 基本的に「学習の前処理のテキスト処理時」には発生させ、そうでない場合は、
ignore_yomi_error=True にしておいて、この例外を発生させないようにする。 ignore_yomi_error=True にしておいて、この例外を発生させないようにする。
""" """
pass

View File

@@ -60,7 +60,7 @@ __REPLACE_MAP = {
"": "'", "": "'",
} }
# 記号類の正規化パターン # 記号類の正規化パターン
__REPLACE_PATTERN = re.compile("|".join(re.escape(p) for p in __REPLACE_MAP.keys())) __REPLACE_PATTERN = re.compile("|".join(re.escape(p) for p in __REPLACE_MAP))
# 句読点等の正規化パターン # 句読点等の正規化パターン
__PUNCTUATION_CLEANUP_PATTERN = re.compile( __PUNCTUATION_CLEANUP_PATTERN = re.compile(
# ↓ ひらがな、カタカナ、漢字 # ↓ ひらがな、カタカナ、漢字

View File

@@ -88,7 +88,7 @@ def initialize_worker(port: int = WORKER_PORT) -> None:
client = None client = None
try: try:
client = WorkerClient(port) client = WorkerClient(port)
except (socket.timeout, socket.error): except (OSError, socket.timeout):
logger.debug("try starting pyopenjtalk worker server") logger.debug("try starting pyopenjtalk worker server")
import os import os
import subprocess import subprocess
@@ -120,7 +120,7 @@ def initialize_worker(port: int = WORKER_PORT) -> None:
try: try:
client = WorkerClient(port) client = WorkerClient(port)
break break
except socket.error: except OSError:
time.sleep(0.5) time.sleep(0.5)
count += 1 count += 1
# 20: max number of retries # 20: max number of retries

View File

@@ -114,7 +114,7 @@ class PartOfSpeechDetail(BaseModel):
part_of_speech_detail_2: str = Field(title="品詞細分類2") part_of_speech_detail_2: str = Field(title="品詞細分類2")
part_of_speech_detail_3: str = Field(title="品詞細分類3") part_of_speech_detail_3: str = Field(title="品詞細分類3")
# context_idは辞書の左・右文脈IDのこと # context_idは辞書の左・右文脈IDのこと
# https://github.com/VOICEVOX/open_jtalk/blob/427cfd761b78efb6094bea3c5bb8c968f0d711ab/src/mecab-naist-jdic/_left-id.def # noqa # https://github.com/VOICEVOX/open_jtalk/blob/427cfd761b78efb6094bea3c5bb8c968f0d711ab/src/mecab-naist-jdic/_left-id.def
context_id: int = Field(title="文脈ID") context_id: int = Field(title="文脈ID")
cost_candidates: List[int] = Field(title="コストのパーセンタイル") cost_candidates: List[int] = Field(title="コストのパーセンタイル")
accent_associative_rules: List[str] = Field(title="アクセント結合規則の一覧") accent_associative_rules: List[str] = Field(title="アクセント結合規則の一覧")

View File

@@ -1,5 +1,5 @@
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Any, Optional, Union from typing import Any, Optional, Union
import numpy as np import numpy as np
import torch import torch

View File

@@ -27,6 +27,7 @@ def run_script_with_log(
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
text=True, text=True,
encoding="utf-8", encoding="utf-8",
check=False,
) )
if result.returncode != 0: if result.returncode != 0:
logger.error(f"Error: {' '.join(cmd)}\n{result.stderr}") logger.error(f"Error: {' '.join(cmd)}\n{result.stderr}")

View File

@@ -26,7 +26,6 @@ class NaNValueError(ValueError):
"""カスタム例外クラス。NaN値が見つかった場合に使用されます。""" """カスタム例外クラス。NaN値が見つかった場合に使用されます。"""
# 推論時にインポートするために短いが関数を書く # 推論時にインポートするために短いが関数を書く
def get_style_vector(wav_path: str) -> NDArray[Any]: def get_style_vector(wav_path: str) -> NDArray[Any]:
return inference(wav_path) # type: ignore return inference(wav_path) # type: ignore

View File

@@ -17,11 +17,7 @@ from tqdm import tqdm
# logging.getLogger("numba").setLevel(logging.WARNING) # logging.getLogger("numba").setLevel(logging.WARNING)
import default_style import default_style
from config import get_config from config import get_config
from data_utils import ( from data_utils import TextAudioSpeakerCollate, TextAudioSpeakerLoader
DistributedBucketSampler,
TextAudioSpeakerCollate,
TextAudioSpeakerLoader,
)
from losses import WavLMLoss, discriminator_loss, feature_loss, generator_loss, kl_loss from losses import WavLMLoss, discriminator_loss, feature_loss, generator_loss, kl_loss
from mel_processing import mel_spectrogram_torch, spec_to_mel_torch from mel_processing import mel_spectrogram_torch, spec_to_mel_torch
from style_bert_vits2.logging import logger from style_bert_vits2.logging import logger

View File

@@ -1,10 +1,8 @@
import argparse import argparse
import os
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Any, Optional
import yaml
from torch.utils.data import Dataset from torch.utils.data import Dataset
from tqdm import tqdm from tqdm import tqdm