Refactor: Use PathConfig and pathlib instead of paths.yml loading
This commit is contained in:
10
app.py
10
app.py
@@ -3,7 +3,6 @@ from pathlib import Path
|
||||
|
||||
import gradio as gr
|
||||
import torch
|
||||
import yaml
|
||||
|
||||
from gradio_tabs.dataset import create_dataset_app
|
||||
from gradio_tabs.inference import create_inference_app
|
||||
@@ -14,6 +13,7 @@ from style_bert_vits2.constants import GRADIO_THEME, VERSION
|
||||
from style_bert_vits2.nlp.japanese import pyopenjtalk_worker
|
||||
from style_bert_vits2.nlp.japanese.user_dict import update_dict
|
||||
from style_bert_vits2.tts_model import TTSModelHolder
|
||||
from config import get_path_config
|
||||
|
||||
|
||||
# このプロセスからはワーカーを起動して辞書を使いたいので、ここで初期化
|
||||
@@ -22,11 +22,6 @@ pyopenjtalk_worker.initialize_worker()
|
||||
# dict_data/ 以下の辞書データを pyopenjtalk に適用
|
||||
update_dict()
|
||||
|
||||
# Get path settings
|
||||
with Path("configs/paths.yml").open("r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
# dataset_root = path_config["dataset_root"]
|
||||
assets_root = path_config["assets_root"]
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--device", type=str, default="cuda")
|
||||
@@ -40,7 +35,8 @@ device = args.device
|
||||
if device == "cuda" and not torch.cuda.is_available():
|
||||
device = "cpu"
|
||||
|
||||
model_holder = TTSModelHolder(Path(assets_root), device)
|
||||
path_config = get_path_config()
|
||||
model_holder = TTSModelHolder(Path(path_config.assets_root), device)
|
||||
|
||||
with gr.Blocks(theme=GRADIO_THEME) as app:
|
||||
gr.Markdown(f"# Style-Bert-VITS2 WebUI (version {VERSION})")
|
||||
|
||||
@@ -5,13 +5,12 @@ import torch
|
||||
import torch.multiprocessing as mp
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import config
|
||||
from config import get_config
|
||||
from style_bert_vits2.constants import Languages
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.models import commons
|
||||
from style_bert_vits2.models.hyper_parameters import HyperParameters
|
||||
from style_bert_vits2.nlp import (
|
||||
bert_models,
|
||||
cleaned_text_to_sequence,
|
||||
extract_bert_feature,
|
||||
)
|
||||
@@ -20,6 +19,7 @@ from style_bert_vits2.nlp.japanese.user_dict import update_dict
|
||||
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
|
||||
|
||||
|
||||
config = get_config()
|
||||
# このプロセスからはワーカーを起動して辞書を使いたいので、ここで初期化
|
||||
pyopenjtalk_worker.initialize_worker()
|
||||
|
||||
@@ -61,7 +61,7 @@ def process_line(x: tuple[str, bool]):
|
||||
bert = torch.load(bert_path)
|
||||
assert bert.shape[-1] == len(phone)
|
||||
except Exception:
|
||||
bert = extract_bert_feature(text, word2ph, language_str, device)
|
||||
bert = extract_bert_feature(text, word2ph, Languages(language_str), device)
|
||||
assert bert.shape[-1] == len(phone)
|
||||
torch.save(bert, bert_path)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Style-Bert-VITS2 (ver 2.4.1) のGoogle Colabでの学習\n",
|
||||
"# Style-Bert-VITS2 (ver 2.5.0) のGoogle Colabでの学習\n",
|
||||
"\n",
|
||||
"Google Colab上でStyle-Bert-VITS2の学習を行うことができます。\n",
|
||||
"\n",
|
||||
|
||||
159
config.py
159
config.py
@@ -2,9 +2,9 @@
|
||||
@Desc: 全局配置文件读取
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from typing import Dict, List
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import torch
|
||||
import yaml
|
||||
@@ -12,6 +12,12 @@ import yaml
|
||||
from style_bert_vits2.logging import logger
|
||||
|
||||
|
||||
class PathConfig:
|
||||
def __init__(self, dataset_root: str, assets_root: str):
|
||||
self.dataset_root = Path(dataset_root)
|
||||
self.assets_root = Path(assets_root)
|
||||
|
||||
|
||||
# If not cuda available, set possible devices to cpu
|
||||
cuda_available = torch.cuda.is_available()
|
||||
|
||||
@@ -20,17 +26,17 @@ class Resample_config:
|
||||
"""重采样配置"""
|
||||
|
||||
def __init__(self, in_dir: str, out_dir: str, sampling_rate: int = 44100):
|
||||
self.sampling_rate: int = sampling_rate # 目标采样率
|
||||
self.in_dir: str = in_dir # 待处理音频目录路径
|
||||
self.out_dir: str = out_dir # 重采样输出路径
|
||||
self.sampling_rate = sampling_rate # 目标采样率
|
||||
self.in_dir = Path(in_dir) # 待处理音频目录路径
|
||||
self.out_dir = Path(out_dir) # 重采样输出路径
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
||||
def from_dict(cls, dataset_path: Path, data: dict[str, Any]):
|
||||
"""从字典中生成实例"""
|
||||
|
||||
# 不检查路径是否有效,此逻辑在resample.py中处理
|
||||
data["in_dir"] = os.path.join(dataset_path, data["in_dir"])
|
||||
data["out_dir"] = os.path.join(dataset_path, data["out_dir"])
|
||||
data["in_dir"] = dataset_path / data["in_dir"]
|
||||
data["out_dir"] = dataset_path / data["out_dir"]
|
||||
|
||||
return cls(**data)
|
||||
|
||||
@@ -49,39 +55,27 @@ 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.config_path: str = config_path # 配置文件路径
|
||||
self.val_per_lang: int = val_per_lang # 每个speaker的验证集条数
|
||||
self.max_val_total: int = (
|
||||
max_val_total # 验证集最大条数,多于的会被截断并放到训练集中
|
||||
)
|
||||
self.clean: bool = clean # 是否进行数据清洗
|
||||
self.transcription_path = Path(transcription_path)
|
||||
self.cleaned_path = Path(cleaned_path)
|
||||
self.train_path = Path(train_path)
|
||||
self.val_path = Path(val_path)
|
||||
self.config_path = Path(config_path)
|
||||
self.val_per_lang = val_per_lang
|
||||
self.max_val_total = max_val_total
|
||||
self.clean = clean
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
||||
def from_dict(cls, dataset_path: Path, data: dict[str, Any]):
|
||||
"""从字典中生成实例"""
|
||||
|
||||
data["transcription_path"] = os.path.join(
|
||||
dataset_path, data["transcription_path"]
|
||||
)
|
||||
data["transcription_path"] = dataset_path / data["transcription_path"]
|
||||
if data["cleaned_path"] == "" or data["cleaned_path"] is None:
|
||||
data["cleaned_path"] = None
|
||||
else:
|
||||
data["cleaned_path"] = os.path.join(dataset_path, data["cleaned_path"])
|
||||
data["train_path"] = os.path.join(dataset_path, data["train_path"])
|
||||
data["val_path"] = os.path.join(dataset_path, data["val_path"])
|
||||
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
||||
data["cleaned_path"] = dataset_path / data["cleaned_path"]
|
||||
data["train_path"] = dataset_path / data["train_path"]
|
||||
data["val_path"] = dataset_path / data["val_path"]
|
||||
data["config_path"] = dataset_path / data["config_path"]
|
||||
|
||||
return cls(**data)
|
||||
|
||||
@@ -96,7 +90,7 @@ class Bert_gen_config:
|
||||
device: str = "cuda",
|
||||
use_multi_device: bool = False,
|
||||
):
|
||||
self.config_path = config_path
|
||||
self.config_path = Path(config_path)
|
||||
self.num_processes = num_processes
|
||||
if not cuda_available:
|
||||
device = "cpu"
|
||||
@@ -104,8 +98,8 @@ class Bert_gen_config:
|
||||
self.use_multi_device = use_multi_device
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
||||
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
||||
def from_dict(cls, dataset_path: Path, data: dict[str, Any]):
|
||||
data["config_path"] = dataset_path / data["config_path"]
|
||||
|
||||
return cls(**data)
|
||||
|
||||
@@ -119,15 +113,15 @@ class Style_gen_config:
|
||||
num_processes: int = 4,
|
||||
device: str = "cuda",
|
||||
):
|
||||
self.config_path = config_path
|
||||
self.config_path = Path(config_path)
|
||||
self.num_processes = num_processes
|
||||
if not cuda_available:
|
||||
device = "cpu"
|
||||
self.device = device
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
||||
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
||||
def from_dict(cls, dataset_path: Path, data: dict[str, Any]):
|
||||
data["config_path"] = dataset_path / data["config_path"]
|
||||
|
||||
return cls(**data)
|
||||
|
||||
@@ -138,7 +132,7 @@ class Train_ms_config:
|
||||
def __init__(
|
||||
self,
|
||||
config_path: str,
|
||||
env: Dict[str, any],
|
||||
env: dict[str, Any],
|
||||
# base: Dict[str, any],
|
||||
model_dir: str,
|
||||
num_workers: int,
|
||||
@@ -147,16 +141,18 @@ class Train_ms_config:
|
||||
):
|
||||
self.env = env # 需要加载的环境变量
|
||||
# self.base = base # 底模配置
|
||||
self.model_dir = model_dir # 训练模型存储目录,该路径为相对于dataset_path的路径,而非项目根目录
|
||||
self.config_path = config_path # 配置文件路径
|
||||
self.model_dir = Path(
|
||||
model_dir
|
||||
) # 训练模型存储目录,该路径为相对于dataset_path的路径,而非项目根目录
|
||||
self.config_path = Path(config_path) # 配置文件路径
|
||||
self.num_workers = num_workers # worker数量
|
||||
self.spec_cache = spec_cache # 是否启用spec缓存
|
||||
self.keep_ckpts = keep_ckpts # ckpt数量
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
||||
def from_dict(cls, dataset_path: Path, data: dict[str, Any]):
|
||||
# data["model"] = os.path.join(dataset_path, data["model"])
|
||||
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
||||
data["config_path"] = dataset_path / data["config_path"]
|
||||
|
||||
return cls(**data)
|
||||
|
||||
@@ -176,20 +172,18 @@ class Webui_config:
|
||||
):
|
||||
if not cuda_available:
|
||||
device = "cpu"
|
||||
self.device: str = device
|
||||
self.model: str = model # 端口号
|
||||
self.config_path: str = config_path # 是否公开部署,对外网开放
|
||||
self.port: int = port # 是否开启debug模式
|
||||
self.share: bool = share # 模型路径
|
||||
self.debug: bool = debug # 配置文件路径
|
||||
self.language_identification_library: str = (
|
||||
language_identification_library # 语种识别库
|
||||
)
|
||||
self.device = device
|
||||
self.model = Path(model)
|
||||
self.config_path = Path(config_path)
|
||||
self.port: int = port
|
||||
self.share: bool = share
|
||||
self.debug: bool = debug
|
||||
self.language_identification_library: str = language_identification_library
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dataset_path: str, data: Dict[str, any]):
|
||||
data["config_path"] = os.path.join(dataset_path, data["config_path"])
|
||||
data["model"] = os.path.join(dataset_path, data["model"])
|
||||
def from_dict(cls, dataset_path: Path, data: dict[str, Any]):
|
||||
data["config_path"] = dataset_path / data["config_path"]
|
||||
data["model"] = dataset_path / data["model"]
|
||||
return cls(**data)
|
||||
|
||||
|
||||
@@ -200,7 +194,7 @@ class Server_config:
|
||||
device: str = "cuda",
|
||||
limit: int = 100,
|
||||
language: str = "JP",
|
||||
origins: List[str] = None,
|
||||
origins: list[str] = ["*"],
|
||||
):
|
||||
self.port: int = port
|
||||
if not cuda_available:
|
||||
@@ -208,10 +202,10 @@ class Server_config:
|
||||
self.device: str = device
|
||||
self.language: str = language
|
||||
self.limit: int = limit
|
||||
self.origins: List[str] = origins
|
||||
self.origins: list[str] = origins
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, any]):
|
||||
def from_dict(cls, data: dict[str, Any]):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
@@ -223,32 +217,32 @@ class Translate_config:
|
||||
self.secret_key = secret_key
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, any]):
|
||||
def from_dict(cls, data: dict[str, Any]):
|
||||
return cls(**data)
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self, config_path: str, path_config: dict[str, str]):
|
||||
if not os.path.isfile(config_path) and os.path.isfile("default_config.yml"):
|
||||
def __init__(self, config_path: str, path_config: PathConfig):
|
||||
if not Path(config_path).exists():
|
||||
shutil.copy(src="default_config.yml", dst=config_path)
|
||||
logger.info(
|
||||
f"A configuration file {config_path} has been generated based on the default configuration file default_config.yml."
|
||||
)
|
||||
logger.info(
|
||||
"If you have no special needs, please do not modify default_config.yml."
|
||||
"Please do not modify default_config.yml. Instead, modify config.yml."
|
||||
)
|
||||
# sys.exit(0)
|
||||
with open(config_path, "r", 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"]
|
||||
self.model_name: str = model_name
|
||||
if "dataset_path" in yaml_config:
|
||||
dataset_path = yaml_config["dataset_path"]
|
||||
dataset_path = Path(yaml_config["dataset_path"])
|
||||
else:
|
||||
dataset_path = os.path.join(path_config["dataset_root"], model_name)
|
||||
self.dataset_path: str = dataset_path
|
||||
self.assets_root: str = path_config["assets_root"]
|
||||
self.out_dir = os.path.join(self.assets_root, model_name)
|
||||
dataset_path = path_config.dataset_root / model_name
|
||||
self.dataset_path = dataset_path
|
||||
self.assets_root = path_config.assets_root
|
||||
self.out_dir = self.assets_root / model_name
|
||||
self.resample_config: Resample_config = Resample_config.from_dict(
|
||||
dataset_path, yaml_config["resample"]
|
||||
)
|
||||
@@ -277,16 +271,31 @@ class Config:
|
||||
# )
|
||||
|
||||
|
||||
with open(os.path.join("configs", "paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
# Should contain the following keys:
|
||||
# - dataset_root: the root directory of the dataset, default to "Data"
|
||||
# - assets_root: the root directory of the assets, default to "model_assets"
|
||||
# Load and initialize the configuration
|
||||
|
||||
|
||||
def get_path_config() -> PathConfig:
|
||||
path_config_path = Path("configs/paths.yml")
|
||||
if not path_config_path.exists():
|
||||
shutil.copy(src="configs/default_paths.yml", dst=path_config_path)
|
||||
logger.info(
|
||||
f"A configuration file {path_config_path} has been generated based on the default configuration file default_paths.yml."
|
||||
)
|
||||
logger.info(
|
||||
"Please do not modify configs/default_paths.yml. Instead, modify configs/paths.yml."
|
||||
)
|
||||
with open(path_config_path, "r", encoding="utf-8") as file:
|
||||
path_config_dict: dict[str, str] = yaml.safe_load(file.read())
|
||||
return PathConfig(**path_config_dict)
|
||||
|
||||
|
||||
def get_config() -> Config:
|
||||
path_config = get_path_config()
|
||||
try:
|
||||
config = Config("config.yml", path_config)
|
||||
except (TypeError, KeyError):
|
||||
logger.warning("Old config.yml found. Replace it with default_config.yml.")
|
||||
shutil.copy(src="default_config.yml", dst="config.yml")
|
||||
config = Config("config.yml", path_config)
|
||||
|
||||
return config
|
||||
|
||||
@@ -69,5 +69,5 @@
|
||||
"use_spectral_norm": false,
|
||||
"gin_channels": 256
|
||||
},
|
||||
"version": "2.4.1"
|
||||
"version": "2.5.0"
|
||||
}
|
||||
|
||||
@@ -76,5 +76,5 @@
|
||||
"initial_channel": 64
|
||||
}
|
||||
},
|
||||
"version": "2.4.1-JP-Extra"
|
||||
"version": "2.5.0-JP-Extra"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import gradio as gr
|
||||
import numpy as np
|
||||
import torch
|
||||
import yaml
|
||||
from safetensors import safe_open
|
||||
from safetensors.torch import save_file
|
||||
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.constants import DEFAULT_STYLE, GRADIO_THEME
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.tts_model import TTSModel, TTSModelHolder
|
||||
@@ -20,15 +19,17 @@ speech_style_keys = ["enc_p"]
|
||||
tempo_keys = ["sdp", "dp"]
|
||||
|
||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
|
||||
# Get path settings
|
||||
with open(os.path.join("configs", "paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
# dataset_root = path_config["dataset_root"]
|
||||
assets_root = path_config["assets_root"]
|
||||
path_config = get_path_config()
|
||||
assets_root = path_config.assets_root
|
||||
|
||||
|
||||
def merge_style(model_name_a, model_name_b, weight, output_name, style_triple_list):
|
||||
def merge_style(
|
||||
model_name_a: str,
|
||||
model_name_b: str,
|
||||
weight: float,
|
||||
output_name: str,
|
||||
style_triple_list: list[tuple[str, str, str]],
|
||||
) -> tuple[Path, list[str]]:
|
||||
"""
|
||||
style_triple_list: list[(model_aでのスタイル名, model_bでのスタイル名, 出力するスタイル名)]
|
||||
"""
|
||||
@@ -41,18 +42,14 @@ def merge_style(model_name_a, model_name_b, weight, output_name, style_triple_li
|
||||
raise ValueError(f"No element with {DEFAULT_STYLE} output style name found.")
|
||||
|
||||
style_vectors_a = np.load(
|
||||
os.path.join(assets_root, model_name_a, "style_vectors.npy")
|
||||
assets_root / model_name_a / "style_vectors.npy"
|
||||
) # (style_num_a, 256)
|
||||
style_vectors_b = np.load(
|
||||
os.path.join(assets_root, model_name_b, "style_vectors.npy")
|
||||
assets_root / model_name_b / "style_vectors.npy"
|
||||
) # (style_num_b, 256)
|
||||
with open(
|
||||
os.path.join(assets_root, model_name_a, "config.json"), "r", encoding="utf-8"
|
||||
) as f:
|
||||
with open(assets_root / model_name_a / "config.json", "r", encoding="utf-8") as f:
|
||||
config_a = json.load(f)
|
||||
with open(
|
||||
os.path.join(assets_root, model_name_b, "config.json"), "r", encoding="utf-8"
|
||||
) as f:
|
||||
with open(assets_root / model_name_b / "config.json", "r", encoding="utf-8") as f:
|
||||
config_b = json.load(f)
|
||||
style2id_a = config_a["data"]["style2id"]
|
||||
style2id_b = config_b["data"]["style2id"]
|
||||
@@ -73,21 +70,19 @@ def merge_style(model_name_a, model_name_b, weight, output_name, style_triple_li
|
||||
new_style2id[style_out] = len(new_style_vecs) - 1
|
||||
new_style_vecs = np.array(new_style_vecs)
|
||||
|
||||
output_style_path = os.path.join(assets_root, output_name, "style_vectors.npy")
|
||||
output_style_path = assets_root / output_name / "style_vectors.npy"
|
||||
np.save(output_style_path, new_style_vecs)
|
||||
|
||||
new_config = config_a.copy()
|
||||
new_config["data"]["num_styles"] = len(new_style2id)
|
||||
new_config["data"]["style2id"] = new_style2id
|
||||
new_config["model_name"] = output_name
|
||||
with open(
|
||||
os.path.join(assets_root, output_name, "config.json"), "w", encoding="utf-8"
|
||||
) as f:
|
||||
with open(assets_root / output_name / "config.json", "w", encoding="utf-8") 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):
|
||||
info_path = assets_root / output_name / "recipe.json"
|
||||
if info_path.exists():
|
||||
with open(info_path, "r", encoding="utf-8") as f:
|
||||
info = json.load(f)
|
||||
else:
|
||||
@@ -99,11 +94,13 @@ def merge_style(model_name_a, model_name_b, weight, output_name, style_triple_li
|
||||
return output_style_path, list(new_style2id.keys())
|
||||
|
||||
|
||||
def lerp_tensors(t, v0, v1):
|
||||
def lerp_tensors(t: float, v0: torch.Tensor, v1: torch.Tensor):
|
||||
return v0 * (1 - t) + v1 * t
|
||||
|
||||
|
||||
def slerp_tensors(t, v0, v1, dot_thres=0.998):
|
||||
def slerp_tensors(
|
||||
t: float, v0: torch.Tensor, v1: torch.Tensor, dot_thres: float = 0.998
|
||||
):
|
||||
device = v0.device
|
||||
v0c = v0.cpu().numpy()
|
||||
v1c = v1.cpu().numpy()
|
||||
@@ -123,23 +120,23 @@ def slerp_tensors(t, v0, v1, dot_thres=0.998):
|
||||
|
||||
|
||||
def merge_models(
|
||||
model_path_a,
|
||||
model_path_b,
|
||||
voice_weight,
|
||||
voice_pitch_weight,
|
||||
speech_style_weight,
|
||||
tempo_weight,
|
||||
output_name,
|
||||
use_slerp_instead_of_lerp,
|
||||
model_path_a: str,
|
||||
model_path_b: str,
|
||||
voice_weight: float,
|
||||
voice_pitch_weight: float,
|
||||
speech_style_weight: float,
|
||||
tempo_weight: float,
|
||||
output_name: str,
|
||||
use_slerp_instead_of_lerp: bool,
|
||||
):
|
||||
"""model Aを起点に、model Bの各要素を重み付けしてマージする。
|
||||
safetensors形式を前提とする。"""
|
||||
model_a_weight = {}
|
||||
model_a_weight: dict[str, torch.Tensor] = {}
|
||||
with safe_open(model_path_a, framework="pt", device="cpu") as f:
|
||||
for k in f.keys():
|
||||
model_a_weight[k] = f.get_tensor(k)
|
||||
|
||||
model_b_weight = {}
|
||||
model_b_weight: dict[str, torch.Tensor] = {}
|
||||
with safe_open(model_path_b, framework="pt", device="cpu") as f:
|
||||
for k in f.keys():
|
||||
model_b_weight[k] = f.get_tensor(k)
|
||||
@@ -161,10 +158,8 @@ def merge_models(
|
||||
slerp_tensors if use_slerp_instead_of_lerp else lerp_tensors
|
||||
)(weight, model_a_weight[key], model_b_weight[key])
|
||||
|
||||
merged_model_path = os.path.join(
|
||||
assets_root, output_name, f"{output_name}.safetensors"
|
||||
)
|
||||
os.makedirs(os.path.dirname(merged_model_path), exist_ok=True)
|
||||
merged_model_path = assets_root / output_name / f"{output_name}.safetensors"
|
||||
merged_model_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
save_file(merged_model_weight, merged_model_path)
|
||||
|
||||
info = {
|
||||
@@ -175,24 +170,22 @@ def merge_models(
|
||||
"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:
|
||||
with open(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
|
||||
|
||||
|
||||
def merge_models_gr(
|
||||
model_name_a,
|
||||
model_path_a,
|
||||
model_name_b,
|
||||
model_path_b,
|
||||
output_name,
|
||||
voice_weight,
|
||||
voice_pitch_weight,
|
||||
speech_style_weight,
|
||||
tempo_weight,
|
||||
use_slerp_instead_of_lerp,
|
||||
model_name_a: str,
|
||||
model_path_a: str,
|
||||
model_name_b: str,
|
||||
model_path_b: str,
|
||||
output_name: str,
|
||||
voice_weight: float,
|
||||
voice_pitch_weight: float,
|
||||
speech_style_weight: float,
|
||||
tempo_weight: float,
|
||||
use_slerp_instead_of_lerp: bool,
|
||||
):
|
||||
if output_name == "":
|
||||
return "Error: 新しいモデル名を入力してください。"
|
||||
@@ -210,10 +203,10 @@ def merge_models_gr(
|
||||
|
||||
|
||||
def merge_style_gr(
|
||||
model_name_a,
|
||||
model_name_b,
|
||||
weight,
|
||||
output_name,
|
||||
model_name_a: str,
|
||||
model_name_b: str,
|
||||
weight: float,
|
||||
output_name: str,
|
||||
style_triple_list_str: str,
|
||||
):
|
||||
if output_name == "":
|
||||
@@ -245,12 +238,14 @@ def merge_style_gr(
|
||||
)
|
||||
|
||||
|
||||
def simple_tts(model_name, text, style=DEFAULT_STYLE, style_weight=1.0):
|
||||
model_path = os.path.join(assets_root, model_name, f"{model_name}.safetensors")
|
||||
config_path = os.path.join(assets_root, model_name, "config.json")
|
||||
style_vec_path = os.path.join(assets_root, model_name, "style_vectors.npy")
|
||||
def simple_tts(
|
||||
model_name: str, text: str, style: str = DEFAULT_STYLE, style_weight: float = 1.0
|
||||
):
|
||||
model_path = assets_root / model_name / f"{model_name}.safetensors"
|
||||
config_path = assets_root / model_name / "config.json"
|
||||
style_vec_path = assets_root / model_name / "style_vectors.npy"
|
||||
|
||||
model = TTSModel(Path(model_path), Path(config_path), Path(style_vec_path), device)
|
||||
model = TTSModel(model_path, config_path, style_vec_path, device)
|
||||
return model.infer(text, style=style, style_weight=style_weight)
|
||||
|
||||
|
||||
@@ -259,13 +254,13 @@ def update_two_model_names_dropdown(model_holder: TTSModelHolder):
|
||||
return new_names, new_files, new_names, new_files
|
||||
|
||||
|
||||
def load_styles_gr(model_name_a, model_name_b):
|
||||
config_path_a = os.path.join(assets_root, model_name_a, "config.json")
|
||||
def load_styles_gr(model_name_a: str, model_name_b: str):
|
||||
config_path_a = assets_root / model_name_a / "config.json"
|
||||
with open(config_path_a, "r", encoding="utf-8") as f:
|
||||
config_a = json.load(f)
|
||||
styles_a = list(config_a["data"]["style2id"].keys())
|
||||
|
||||
config_path_b = os.path.join(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:
|
||||
config_b = json.load(f)
|
||||
styles_b = list(config_b["data"]["style2id"].keys())
|
||||
@@ -336,7 +331,10 @@ def create_merge_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
||||
)
|
||||
return app
|
||||
initial_id = 0
|
||||
initial_model_files = model_holder.model_files_dict[model_names[initial_id]]
|
||||
# initial_model_files = model_holder.model_files_dict[model_names[initial_id]]
|
||||
initial_model_files = [
|
||||
str(f) for f in model_holder.model_files_dict[model_names[initial_id]]
|
||||
]
|
||||
|
||||
with gr.Blocks(theme=GRADIO_THEME) as app:
|
||||
gr.Markdown(
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
import gradio as gr
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import yaml
|
||||
from scipy.spatial.distance import pdist, squareform
|
||||
from sklearn.cluster import DBSCAN, AgglomerativeClustering, KMeans
|
||||
from sklearn.manifold import TSNE
|
||||
from umap import UMAP
|
||||
|
||||
from config import config
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.constants import DEFAULT_STYLE, GRADIO_THEME
|
||||
from style_bert_vits2.logging import logger
|
||||
|
||||
|
||||
# Get path settings
|
||||
with open(os.path.join("configs", "paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
dataset_root = Path(path_config["dataset_root"])
|
||||
# assets_root = path_config["assets_root"]
|
||||
path_config = get_path_config()
|
||||
dataset_root = path_config.dataset_root
|
||||
assets_root = path_config.assets_root
|
||||
|
||||
MAX_CLUSTER_NUM = 10
|
||||
MAX_AUDIO_NUM = 10
|
||||
@@ -39,11 +35,7 @@ centroids = []
|
||||
|
||||
def load(model_name: str, reduction_method: str):
|
||||
global wav_files, x, x_reduced, mean
|
||||
# wavs_dir = os.path.join(dataset_root, model_name, "wavs")
|
||||
wavs_dir = dataset_root / model_name / "wavs"
|
||||
# style_vector_files = [
|
||||
# os.path.join(wavs_dir, f) for f in os.listdir(wavs_dir) if f.endswith(".npy")
|
||||
# ]
|
||||
style_vector_files = [f for f in wavs_dir.rglob("*.npy") if f.is_file()]
|
||||
# foo.wav.npy -> foo.wav
|
||||
wav_files = [f.with_suffix("") for f in style_vector_files]
|
||||
@@ -196,21 +188,21 @@ def do_clustering_gradio(n_clusters=4, method="KMeans"):
|
||||
] * MAX_AUDIO_NUM
|
||||
|
||||
|
||||
def save_style_vectors_from_clustering(model_name, style_names_str: str):
|
||||
def save_style_vectors_from_clustering(model_name: str, style_names_str: str):
|
||||
"""centerとcentroidsを保存する"""
|
||||
result_dir = os.path.join(config.assets_root, model_name)
|
||||
os.makedirs(result_dir, exist_ok=True)
|
||||
result_dir = assets_root / model_name
|
||||
result_dir.mkdir(parents=True, exist_ok=True)
|
||||
style_vectors = np.stack([mean] + centroids)
|
||||
style_vector_path = os.path.join(result_dir, "style_vectors.npy")
|
||||
if os.path.exists(style_vector_path):
|
||||
style_vector_path = result_dir / "style_vectors.npy"
|
||||
if style_vector_path.exists():
|
||||
logger.info(f"Backup {style_vector_path} to {style_vector_path}.bak")
|
||||
shutil.copy(style_vector_path, f"{style_vector_path}.bak")
|
||||
np.save(style_vector_path, style_vectors)
|
||||
logger.success(f"Saved style vectors to {style_vector_path}")
|
||||
|
||||
# config.jsonの更新
|
||||
config_path = os.path.join(result_dir, "config.json")
|
||||
if not os.path.exists(config_path):
|
||||
config_path = result_dir / "config.json"
|
||||
if not config_path.exists():
|
||||
return f"{config_path}が存在しません。"
|
||||
style_names = [name.strip() for name in style_names_str.split(",")]
|
||||
style_name_list = [DEFAULT_STYLE] + style_names
|
||||
@@ -233,7 +225,7 @@ def save_style_vectors_from_clustering(model_name, style_names_str: str):
|
||||
|
||||
|
||||
def save_style_vectors_from_files(
|
||||
model_name, audio_files_str: str, style_names_str: str
|
||||
model_name: str, audio_files_str: str, style_names_str: str
|
||||
):
|
||||
"""音声ファイルからスタイルベクトルを作成して保存する"""
|
||||
global mean
|
||||
@@ -241,8 +233,8 @@ def save_style_vectors_from_files(
|
||||
return "Error: スタイルベクトルを読み込んでください。"
|
||||
mean = np.mean(x, axis=0)
|
||||
|
||||
result_dir = os.path.join(config.assets_root, model_name)
|
||||
os.makedirs(result_dir, exist_ok=True)
|
||||
result_dir = assets_root / model_name
|
||||
result_dir.mkdir(parents=True, exist_ok=True)
|
||||
audio_files = [name.strip() for name in audio_files_str.split(",")]
|
||||
style_names = [name.strip() for name in style_names_str.split(",")]
|
||||
if len(audio_files) != len(style_names):
|
||||
@@ -252,23 +244,23 @@ def save_style_vectors_from_files(
|
||||
return "スタイル名が重複しています。"
|
||||
style_vectors = [mean]
|
||||
|
||||
wavs_dir = os.path.join(dataset_root, model_name, "wavs")
|
||||
wavs_dir = dataset_root / model_name / "wavs"
|
||||
for audio_file in audio_files:
|
||||
path = os.path.join(wavs_dir, audio_file)
|
||||
if not os.path.exists(path):
|
||||
path = wavs_dir / audio_file
|
||||
if not path.exists():
|
||||
return f"{path}が存在しません。"
|
||||
style_vectors.append(np.load(f"{path}.npy"))
|
||||
style_vectors = np.stack(style_vectors)
|
||||
assert len(style_name_list) == len(style_vectors)
|
||||
style_vector_path = os.path.join(result_dir, "style_vectors.npy")
|
||||
if os.path.exists(style_vector_path):
|
||||
style_vector_path = result_dir / "style_vectors.npy"
|
||||
if style_vector_path.exists():
|
||||
logger.info(f"Backup {style_vector_path} to {style_vector_path}.bak")
|
||||
shutil.copy(style_vector_path, f"{style_vector_path}.bak")
|
||||
np.save(style_vector_path, style_vectors)
|
||||
|
||||
# config.jsonの更新
|
||||
config_path = os.path.join(result_dir, "config.json")
|
||||
if not os.path.exists(config_path):
|
||||
config_path = result_dir / "config.json"
|
||||
if not config_path.exists():
|
||||
return f"{config_path}が存在しません。"
|
||||
logger.info(f"Backup {config_path} to {config_path}.bak")
|
||||
shutil.copy(config_path, f"{config_path}.bak")
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
@@ -12,7 +11,8 @@ from pathlib import Path
|
||||
|
||||
import gradio as gr
|
||||
import yaml
|
||||
|
||||
from dataclasses import dataclass
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
|
||||
from style_bert_vits2.utils.subprocess import run_script_with_log, second_elem_of
|
||||
@@ -21,20 +21,27 @@ from style_bert_vits2.utils.subprocess import run_script_with_log, second_elem_o
|
||||
logger_handler = None
|
||||
tensorboard_executed = False
|
||||
|
||||
# Get path settings
|
||||
with open(os.path.join("configs", "paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
dataset_root = Path(path_config["dataset_root"])
|
||||
path_config = get_path_config()
|
||||
dataset_root = path_config.dataset_root
|
||||
|
||||
|
||||
def get_path(model_name: str) -> tuple[Path, Path, Path, Path, Path]:
|
||||
@dataclass
|
||||
class PathsForPreprocess:
|
||||
dataset_path: Path
|
||||
esd_path: Path
|
||||
train_path: Path
|
||||
val_path: Path
|
||||
config_path: Path
|
||||
|
||||
|
||||
def get_path(model_name: str) -> PathsForPreprocess:
|
||||
assert model_name != "", "モデル名は空にできません"
|
||||
dataset_path = dataset_root / model_name
|
||||
lbl_path = dataset_path / "esd.list"
|
||||
esd_path = dataset_path / "esd.list"
|
||||
train_path = dataset_path / "train.list"
|
||||
val_path = dataset_path / "val.list"
|
||||
config_path = dataset_path / "config.json"
|
||||
return dataset_path, lbl_path, train_path, val_path, config_path
|
||||
return PathsForPreprocess(dataset_path, esd_path, train_path, val_path, config_path)
|
||||
|
||||
|
||||
def initialize(
|
||||
@@ -51,14 +58,14 @@ def initialize(
|
||||
log_interval: int,
|
||||
):
|
||||
global logger_handler
|
||||
dataset_path, _, train_path, val_path, config_path = get_path(model_name)
|
||||
paths = get_path(model_name)
|
||||
|
||||
# 前処理のログをファイルに保存する
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
file_name = f"preprocess_{timestamp}.log"
|
||||
if logger_handler is not None:
|
||||
logger.remove(logger_handler)
|
||||
logger_handler = logger.add(os.path.join(dataset_path, file_name))
|
||||
logger_handler = logger.add(paths.dataset_path / file_name)
|
||||
|
||||
logger.info(
|
||||
f"Step 1: start initialization...\nmodel_name: {model_name}, batch_size: {batch_size}, epochs: {epochs}, save_every_steps: {save_every_steps}, freeze_ZH_bert: {freeze_ZH_bert}, freeze_JP_bert: {freeze_JP_bert}, freeze_EN_bert: {freeze_EN_bert}, freeze_style: {freeze_style}, freeze_decoder: {freeze_decoder}, use_jp_extra: {use_jp_extra}"
|
||||
@@ -71,8 +78,8 @@ def initialize(
|
||||
with open(default_config_path, "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
config["model_name"] = model_name
|
||||
config["data"]["training_files"] = str(train_path)
|
||||
config["data"]["validation_files"] = str(val_path)
|
||||
config["data"]["training_files"] = str(paths.train_path)
|
||||
config["data"]["validation_files"] = str(paths.val_path)
|
||||
config["train"]["batch_size"] = batch_size
|
||||
config["train"]["epochs"] = epochs
|
||||
config["train"]["eval_interval"] = save_every_steps
|
||||
@@ -89,14 +96,14 @@ def initialize(
|
||||
# 今はデフォルトであるが、以前は非JP-Extra版になくバグの原因になるので念のため
|
||||
config["data"]["use_jp_extra"] = use_jp_extra
|
||||
|
||||
model_path = dataset_path / "models"
|
||||
model_path = paths.dataset_path / "models"
|
||||
if model_path.exists():
|
||||
logger.warning(
|
||||
f"Step 1: {model_path} already exists, so copy it to backup to {model_path}_backup"
|
||||
)
|
||||
shutil.copytree(
|
||||
src=model_path,
|
||||
dst=dataset_path / "models_backup",
|
||||
dst=paths.dataset_path / "models_backup",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
shutil.rmtree(model_path)
|
||||
@@ -110,14 +117,14 @@ def initialize(
|
||||
logger.error(f"Step 1: {pretrained_dir} folder not found.")
|
||||
return False, f"Step 1, Error: {pretrained_dir}フォルダが見つかりません。"
|
||||
|
||||
with open(config_path, "w", encoding="utf-8") as f:
|
||||
with open(paths.config_path, "w", encoding="utf-8") as f:
|
||||
json.dump(config, f, indent=2, ensure_ascii=False)
|
||||
if not Path("config.yml").exists():
|
||||
shutil.copy(src="default_config.yml", dst="config.yml")
|
||||
with open("config.yml", "r", encoding="utf-8") as f:
|
||||
yml_data = yaml.safe_load(f)
|
||||
yml_data["model_name"] = model_name
|
||||
yml_data["dataset_path"] = str(dataset_path)
|
||||
yml_data["dataset_path"] = str(paths.dataset_path)
|
||||
with open("config.yml", "w", encoding="utf-8") as f:
|
||||
yaml.dump(yml_data, f, allow_unicode=True)
|
||||
logger.success("Step 1: initialization finished.")
|
||||
@@ -126,7 +133,7 @@ def initialize(
|
||||
|
||||
def resample(model_name: str, normalize: bool, trim: bool, num_processes: int):
|
||||
logger.info("Step 2: start resampling...")
|
||||
dataset_path, _, _, _, _ = get_path(model_name)
|
||||
dataset_path = get_path(model_name).dataset_path
|
||||
input_dir = dataset_path / "raw"
|
||||
output_dir = dataset_path / "wavs"
|
||||
cmd = [
|
||||
@@ -159,21 +166,24 @@ def preprocess_text(
|
||||
model_name: str, use_jp_extra: bool, val_per_lang: int, yomi_error: str
|
||||
):
|
||||
logger.info("Step 3: start preprocessing text...")
|
||||
_, lbl_path, train_path, val_path, config_path = get_path(model_name)
|
||||
if not lbl_path.exists():
|
||||
logger.error(f"Step 3: {lbl_path} not found.")
|
||||
return False, f"Step 3, Error: 書き起こしファイル {lbl_path} が見つかりません。"
|
||||
paths = get_path(model_name)
|
||||
if not paths.esd_path.exists():
|
||||
logger.error(f"Step 3: {paths.esd_path} not found.")
|
||||
return (
|
||||
False,
|
||||
f"Step 3, Error: 書き起こしファイル {paths.esd_path} が見つかりません。",
|
||||
)
|
||||
|
||||
cmd = [
|
||||
"preprocess_text.py",
|
||||
"--config-path",
|
||||
str(config_path),
|
||||
str(paths.config_path),
|
||||
"--transcription-path",
|
||||
str(lbl_path),
|
||||
str(paths.esd_path),
|
||||
"--train-path",
|
||||
str(train_path),
|
||||
str(paths.train_path),
|
||||
"--val-path",
|
||||
str(val_path),
|
||||
str(paths.val_path),
|
||||
"--val-per-lang",
|
||||
str(val_per_lang),
|
||||
"--yomi_error",
|
||||
@@ -201,7 +211,7 @@ def preprocess_text(
|
||||
|
||||
def bert_gen(model_name: str):
|
||||
logger.info("Step 4: start bert_gen...")
|
||||
_, _, _, _, config_path = get_path(model_name)
|
||||
config_path = get_path(model_name).config_path
|
||||
success, message = run_script_with_log(
|
||||
["bert_gen.py", "--config", str(config_path)]
|
||||
)
|
||||
@@ -220,7 +230,7 @@ def bert_gen(model_name: str):
|
||||
|
||||
def style_gen(model_name: str, num_processes: int):
|
||||
logger.info("Step 5: start style_gen...")
|
||||
_, _, _, _, config_path = get_path(model_name)
|
||||
config_path = get_path(model_name).config_path
|
||||
success, message = run_script_with_log(
|
||||
[
|
||||
"style_gen.py",
|
||||
@@ -319,17 +329,23 @@ def train(
|
||||
use_jp_extra: bool = True,
|
||||
speedup: bool = False,
|
||||
):
|
||||
dataset_path, _, _, _, config_path = get_path(model_name)
|
||||
paths = get_path(model_name)
|
||||
# 学習再開の場合を考えて念のためconfig.ymlの名前等を更新
|
||||
with open("config.yml", "r", encoding="utf-8") as f:
|
||||
yml_data = yaml.safe_load(f)
|
||||
yml_data["model_name"] = model_name
|
||||
yml_data["dataset_path"] = str(dataset_path)
|
||||
yml_data["dataset_path"] = str(paths.dataset_path)
|
||||
with open("config.yml", "w", encoding="utf-8") as f:
|
||||
yaml.dump(yml_data, f, allow_unicode=True)
|
||||
|
||||
train_py = "train_ms.py" if not use_jp_extra else "train_ms_jp_extra.py"
|
||||
cmd = [train_py, "--config", str(config_path), "--model", str(dataset_path)]
|
||||
cmd = [
|
||||
train_py,
|
||||
"--config",
|
||||
str(paths.config_path),
|
||||
"--model",
|
||||
str(paths.dataset_path),
|
||||
]
|
||||
if skip_style:
|
||||
cmd.append("--skip_default_style")
|
||||
if speedup:
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import Optional
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import Preprocess_text_config, config
|
||||
from config import get_config
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.nlp import clean_text
|
||||
from style_bert_vits2.nlp.japanese import pyopenjtalk_worker
|
||||
@@ -22,7 +22,7 @@ pyopenjtalk_worker.initialize_worker()
|
||||
update_dict()
|
||||
|
||||
|
||||
preprocess_text_config: Preprocess_text_config = config.preprocess_text_config
|
||||
preprocess_text_config = get_config().preprocess_text_config
|
||||
|
||||
|
||||
# Count lines for tqdm
|
||||
|
||||
@@ -12,6 +12,7 @@ matplotlib
|
||||
num2words
|
||||
numba
|
||||
numpy
|
||||
protobuf==4.25
|
||||
psutil
|
||||
pyannote.audio>=3.1.0
|
||||
pydantic>=2.0
|
||||
|
||||
@@ -10,7 +10,7 @@ import soundfile
|
||||
from numpy.typing import NDArray
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import config
|
||||
from config import get_config
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
|
||||
|
||||
@@ -70,6 +70,7 @@ def resample(
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
config = get_config()
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--sr",
|
||||
|
||||
@@ -22,7 +22,6 @@ import numpy as np
|
||||
import requests
|
||||
import torch
|
||||
import uvicorn
|
||||
import yaml
|
||||
from fastapi import APIRouter, FastAPI, HTTPException, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse, Response
|
||||
@@ -30,6 +29,7 @@ from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel
|
||||
from scipy.io import wavfile
|
||||
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.constants import (
|
||||
DEFAULT_ASSIST_TEXT_WEIGHT,
|
||||
DEFAULT_NOISE,
|
||||
@@ -174,22 +174,14 @@ origins = [
|
||||
"http://127.0.0.1:8000",
|
||||
]
|
||||
|
||||
# Get path settings
|
||||
with open(Path("configs/paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
# dataset_root = path_config["dataset_root"]
|
||||
assets_root = path_config["assets_root"]
|
||||
|
||||
path_config = get_path_config()
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--model_dir", type=str, default="model_assets/")
|
||||
parser.add_argument("--model_dir", type=str, default=path_config.assets_root)
|
||||
parser.add_argument("--device", type=str, default="cuda")
|
||||
parser.add_argument("--port", type=int, default=8000)
|
||||
parser.add_argument("--inbrowser", action="store_true")
|
||||
parser.add_argument("--line_length", type=int, default=None)
|
||||
parser.add_argument("--line_count", type=int, default=None)
|
||||
parser.add_argument(
|
||||
"--dir", "-d", type=str, help="Model directory", default=assets_root
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
device = args.device
|
||||
|
||||
@@ -20,7 +20,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, Response
|
||||
from scipy.io import wavfile
|
||||
|
||||
from config import config
|
||||
from config import get_config
|
||||
from style_bert_vits2.constants import (
|
||||
DEFAULT_ASSIST_TEXT_WEIGHT,
|
||||
DEFAULT_LENGTH,
|
||||
@@ -40,6 +40,7 @@ from style_bert_vits2.nlp.japanese.user_dict import update_dict
|
||||
from style_bert_vits2.tts_model import TTSModel, TTSModelHolder
|
||||
|
||||
|
||||
config = get_config()
|
||||
ln = config.server_config.language
|
||||
|
||||
|
||||
@@ -113,6 +114,9 @@ if __name__ == "__main__":
|
||||
load_models(model_holder)
|
||||
|
||||
limit = config.server_config.limit
|
||||
logger.info(
|
||||
f"The maximum length of the text is {limit}. If you want to change it, modify config.yml"
|
||||
)
|
||||
app = FastAPI()
|
||||
allow_origins = config.server_config.origins
|
||||
if allow_origins:
|
||||
|
||||
8
slice.py
8
slice.py
@@ -10,6 +10,7 @@ import torch
|
||||
import yaml
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
|
||||
|
||||
@@ -150,13 +151,12 @@ if __name__ == "__main__":
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(Path("configs/paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
dataset_root = path_config["dataset_root"]
|
||||
path_config = get_path_config()
|
||||
dataset_root = path_config.dataset_root
|
||||
|
||||
model_name = str(args.model_name)
|
||||
input_dir = Path(args.input_dir)
|
||||
output_dir = Path(dataset_root) / model_name / "raw"
|
||||
output_dir = dataset_root / model_name / "raw"
|
||||
min_sec: float = args.min_sec
|
||||
max_sec: float = args.max_sec
|
||||
min_silence_dur_ms: int = args.min_silence_dur_ms
|
||||
|
||||
@@ -10,7 +10,7 @@ import pandas as pd
|
||||
import torch
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import config
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.tts_model import TTSModel
|
||||
|
||||
@@ -35,6 +35,8 @@ test_texts = [
|
||||
"この分野の最新の研究成果を使うと、より自然で表現豊かな音声の生成が可能である。深層学習の応用により、感情やアクセントを含む声質の微妙な変化も再現することが出来る。",
|
||||
]
|
||||
|
||||
path_config = get_path_config()
|
||||
|
||||
predictor = torch.hub.load(
|
||||
"tarepan/SpeechMOS:v1.2.0", "utmos22_strong", trust_repo=True
|
||||
)
|
||||
@@ -48,17 +50,16 @@ args = parser.parse_args()
|
||||
model_name: str = args.model_name
|
||||
device: str = args.device
|
||||
|
||||
model_path = Path(config.assets_root) / model_name
|
||||
|
||||
model_path = path_config.assets_root / model_name
|
||||
# .safetensorsファイルを検索
|
||||
safetensors_files = model_path.glob("*.safetensors")
|
||||
|
||||
|
||||
def get_model(model_file: Path):
|
||||
return TTSModel(
|
||||
model_path=str(model_file),
|
||||
config_path=str(model_file.parent / "config.json"),
|
||||
style_vec_path=str(model_file.parent / "style_vectors.npy"),
|
||||
model_path=model_file,
|
||||
config_path=model_file.parent / "config.json",
|
||||
style_vec_path=model_file.parent / "style_vectors.npy",
|
||||
device=device,
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from style_bert_vits2.utils.strenum import StrEnum
|
||||
|
||||
|
||||
# Style-Bert-VITS2 のバージョン
|
||||
VERSION = "2.4.1"
|
||||
VERSION = "2.5.0"
|
||||
|
||||
# Style-Bert-VITS2 のベースディレクトリ
|
||||
BASE_DIR = Path(__file__).parent.parent
|
||||
|
||||
@@ -8,12 +8,14 @@ from numpy.typing import NDArray
|
||||
from pyannote.audio import Inference, Model
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import config
|
||||
from config import get_config
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.models.hyper_parameters import HyperParameters
|
||||
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
|
||||
|
||||
|
||||
config = get_config()
|
||||
|
||||
model = Model.from_pretrained("pyannote/wespeaker-voxceleb-resnet34-LM")
|
||||
inference = Inference(model, window="whole")
|
||||
device = torch.device(config.style_gen_config.device)
|
||||
|
||||
@@ -16,7 +16,7 @@ from tqdm import tqdm
|
||||
|
||||
# logging.getLogger("numba").setLevel(logging.WARNING)
|
||||
import default_style
|
||||
from config import config
|
||||
from config import get_config
|
||||
from data_utils import (
|
||||
DistributedBucketSampler,
|
||||
TextAudioSpeakerCollate,
|
||||
@@ -48,7 +48,7 @@ torch.backends.cuda.enable_mem_efficient_sdp(
|
||||
) # Not available if torch version is lower than 2.0
|
||||
torch.backends.cuda.enable_math_sdp(True)
|
||||
|
||||
|
||||
config = get_config()
|
||||
global_step = 0
|
||||
|
||||
api = HfApi()
|
||||
|
||||
@@ -16,7 +16,7 @@ from tqdm import tqdm
|
||||
|
||||
# logging.getLogger("numba").setLevel(logging.WARNING)
|
||||
import default_style
|
||||
from config import config
|
||||
from config import get_config
|
||||
from data_utils import (
|
||||
DistributedBucketSampler,
|
||||
TextAudioSpeakerCollate,
|
||||
@@ -48,6 +48,8 @@ torch.backends.cuda.enable_flash_sdp(True)
|
||||
torch.backends.cuda.enable_mem_efficient_sdp(
|
||||
True
|
||||
) # Not available if torch version is lower than 2.0
|
||||
|
||||
config = get_config()
|
||||
global_step = 0
|
||||
|
||||
api = HfApi()
|
||||
|
||||
@@ -8,6 +8,7 @@ import yaml
|
||||
from torch.utils.data import Dataset
|
||||
from tqdm import tqdm
|
||||
|
||||
from config import get_path_config
|
||||
from style_bert_vits2.constants import Languages
|
||||
from style_bert_vits2.logging import logger
|
||||
from style_bert_vits2.utils.stdout_wrapper import SAFE_STDOUT
|
||||
@@ -124,9 +125,8 @@ if __name__ == "__main__":
|
||||
parser.add_argument("--no_repeat_ngram_size", type=int, default=10)
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(os.path.join("configs", "paths.yml"), "r", encoding="utf-8") as f:
|
||||
path_config: dict[str, str] = yaml.safe_load(f.read())
|
||||
dataset_root = Path(path_config["dataset_root"])
|
||||
path_config = get_path_config()
|
||||
dataset_root = path_config.dataset_root
|
||||
|
||||
model_name = str(args.model_name)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user