mirror of
https://github.com/RVC-Boss/GPT-SoVITS.git
synced 2026-07-22 10:03:23 +08:00
refactor(webui): 选模型名自动匹配权重(目标epoch 8/15), 移除自动匹配按钮
按产品逻辑重构模型切换流程: 1. 选中模型名(实验名) -> 自动设置 GPT/SoVITS 下拉默认值, 无需点按钮 2. GPT 目标 epoch=8, SoVITS 目标 epoch=15 (对应训练WebUI默认total_epoch) 3. 用户仍可通过下拉框手动更换 GPT/SoVITS 权重 实现: - 新增 _extract_epoch_from_weight: 从文件名提取epoch (GPT: -e10, SoVITS: _e12_s180) - 新增 _pick_weight_by_epoch: 从权重列表选epoch最接近目标的(平手取较小epoch) - 新增 auto_match_weights_for_model: 封装扫描+匹配, 返回 gr.Dropdown 更新 - on_model_name_change 合并自动匹配: outputs 从 [样本,预览] 扩展为 [样本,预览,GPT下拉,SoVITS下拉], 选中模型名即联动设置权重 - 移除「自动匹配权重」按钮组件及 click 绑定 (不再需要手动触发) - 删除 on_auto_select_weights (逻辑并入 on_model_name_change) 验证(真实proplus数据): 选「光头TTS新-20260611」-> GPT 自动选 e10(可选5/10/15../50, |10-8|最近), SoVITS 自动选 e16(可选4/8/12/16/20/24, |16-15|最近), 样本下拉40个含emotion标签。组件数64->63。
This commit is contained in:
parent
c0e7c75ab5
commit
2dfe91afbb
@ -1293,12 +1293,17 @@ def _read_emotion_map_for_webui(model_name: str) -> dict[str, str]:
|
||||
|
||||
|
||||
def on_model_name_change(model_name: str):
|
||||
"""模型名变化时,加载该模型的训练样本列表到下拉框与预览播放器。"""
|
||||
"""模型名变化时:加载训练样本列表 + 自动匹配最佳 GPT/SoVITS 权重。
|
||||
|
||||
返回: [样本下拉框, 样本预览, GPT下拉框, SoVITS下拉框]
|
||||
GPT/SoVITS 自动选中 epoch 最接近推荐值(8/15)的权重, 用户仍可手动改。
|
||||
"""
|
||||
model_name = _coerce_single(model_name)
|
||||
if not model_name:
|
||||
return gr.Dropdown(choices=[], value=""), gr.Audio(value=None)
|
||||
return gr.Dropdown(choices=[], value=""), gr.Audio(value=None), gr.Dropdown(), gr.Dropdown()
|
||||
from config import exp_root
|
||||
|
||||
# 1. 加载训练样本
|
||||
logs_dir = Path(exp_root) / model_name
|
||||
wav_dir = logs_dir / "5-wav32k"
|
||||
samples: list[tuple[str, str]] = []
|
||||
@ -1318,7 +1323,9 @@ def on_model_name_change(model_name: str):
|
||||
choices = [s[0] for s in samples]
|
||||
value = samples[0][0] if samples else ""
|
||||
audio = samples[0][1] if samples else None
|
||||
return gr.Dropdown(choices=choices, value=value), gr.Audio(value=audio)
|
||||
# 2. 自动匹配 GPT/SoVITS 权重(epoch 最接近 8/15)
|
||||
gpt_dd, sovits_dd = auto_match_weights_for_model(model_name)
|
||||
return gr.Dropdown(choices=choices, value=value), gr.Audio(value=audio), gpt_dd, sovits_dd
|
||||
|
||||
|
||||
def on_ref_sample_change(sample_label: str, model_name: str):
|
||||
@ -1381,21 +1388,59 @@ def _scan_model_weights_for_webui() -> dict[str, dict[str, list[str]]]:
|
||||
return grouped
|
||||
|
||||
|
||||
def on_auto_select_weights(model_name: str):
|
||||
"""根据模型名自动匹配并选择最佳 GPT/SoVITS 权重。
|
||||
def _extract_epoch_from_weight(weight_path: str, kind: str) -> int | None:
|
||||
"""从权重文件名提取 epoch 数字。
|
||||
|
||||
仅返回 Dropdown 的 value;真正的权重切换由已绑定的
|
||||
GPT_dropdown.change / SoVITS_dropdown.change 在 value 变化时自动触发。
|
||||
(change_sovits_weights 是生成器,手动消费会丢失对其它组件的更新,故不直接调用。)
|
||||
kind='gpt': '<exp>-e10.ckpt' -> 10
|
||||
kind='sovits': '<exp>_e12_s180.pth' -> 12
|
||||
"""
|
||||
name = Path(weight_path).name
|
||||
pattern = r"-e(\d+)" if kind == "gpt" else r"_e(\d+)_s\d+"
|
||||
m = re.search(pattern, name, flags=re.IGNORECASE)
|
||||
return int(m.group(1)) if m else None
|
||||
|
||||
|
||||
def _pick_weight_by_epoch(weights: list[str], target_epoch: int) -> str | None:
|
||||
"""从权重列表中选 epoch 最接近 target_epoch 的(平手取较小 epoch)。
|
||||
|
||||
匹配训练 WebUI 的推荐: GPT 目标 8 (total_epoch 默认 8), SoVITS 目标 15
|
||||
(total_epoch 默认 15)。无法提取 epoch 时退化为列表第一个。
|
||||
"""
|
||||
if not weights:
|
||||
return None
|
||||
best = None
|
||||
best_diff = None
|
||||
for w in weights:
|
||||
# kind 由文件扩展名推断
|
||||
kind = "gpt" if w.endswith(".ckpt") else "sovits"
|
||||
ep = _extract_epoch_from_weight(w, kind)
|
||||
if ep is None:
|
||||
continue
|
||||
diff = abs(ep - target_epoch)
|
||||
if best_diff is None or diff < best_diff or (diff == best_diff and ep < (best_ep or 0)):
|
||||
best = w
|
||||
best_diff = diff
|
||||
best_ep = ep
|
||||
return best or weights[0]
|
||||
|
||||
|
||||
# GPT/SoVITS 自动匹配权重的目标 epoch(对应训练 WebUI 的默认 total_epoch)
|
||||
_GPT_TARGET_EPOCH = 8
|
||||
_SOVITS_TARGET_EPOCH = 15
|
||||
|
||||
|
||||
def auto_match_weights_for_model(model_name: str):
|
||||
"""选中模型名时自动匹配最佳 GPT/SoVITS 权重(按目标 epoch 最近匹配)。
|
||||
|
||||
返回 (gpt_dropdown_update, sovits_dropdown_update);真正的权重切换由已绑定的
|
||||
GPT_dropdown.change / SoVITS_dropdown.change 在 value 变化时自动触发。
|
||||
"""
|
||||
model_name = _coerce_single(model_name)
|
||||
if not model_name:
|
||||
return gr.Dropdown(), gr.Dropdown()
|
||||
weights = _scan_model_weights_for_webui()
|
||||
model_weights = weights.get(model_name, {"gpt": [], "sovits": []})
|
||||
# 选择最高 epoch 的权重(按字符串排序后取末尾)
|
||||
gpt_best = sorted(model_weights["gpt"])[-1] if model_weights["gpt"] else None
|
||||
sovits_best = sorted(model_weights["sovits"])[-1] if model_weights["sovits"] else None
|
||||
gpt_best = _pick_weight_by_epoch(model_weights["gpt"], _GPT_TARGET_EPOCH)
|
||||
sovits_best = _pick_weight_by_epoch(model_weights["sovits"], _SOVITS_TARGET_EPOCH)
|
||||
return gr.Dropdown(value=gpt_best), gr.Dropdown(value=sovits_best)
|
||||
|
||||
|
||||
@ -1424,8 +1469,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI", analytics_enabled=False, js=js, css=css
|
||||
interactive=True,
|
||||
scale=14,
|
||||
)
|
||||
refresh_button = gr.Button(i18n("刷新模型路径"), variant="primary", scale=7)
|
||||
auto_select_weights_btn = gr.Button(i18n("自动匹配权重"), variant="secondary", scale=7)
|
||||
refresh_button = gr.Button(i18n("刷新模型路径"), variant="primary", scale=14)
|
||||
refresh_button.click(fn=change_choices, inputs=[], outputs=[SoVITS_dropdown, GPT_dropdown])
|
||||
# ===== 新增:训练角色选择区域(独立 Group,按操作流程纵向排列) =====
|
||||
with gr.Group():
|
||||
@ -1650,7 +1694,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI", analytics_enabled=False, js=js, css=css
|
||||
model_name_dropdown.change(
|
||||
fn=on_model_name_change,
|
||||
inputs=[model_name_dropdown],
|
||||
outputs=[ref_sample_dropdown, ref_sample_player],
|
||||
outputs=[ref_sample_dropdown, ref_sample_player, GPT_dropdown, SoVITS_dropdown],
|
||||
)
|
||||
ref_sample_dropdown.change(
|
||||
fn=on_ref_sample_change,
|
||||
@ -1662,11 +1706,6 @@ with gr.Blocks(title="GPT-SoVITS WebUI", analytics_enabled=False, js=js, css=css
|
||||
inputs=[ref_sample_dropdown, model_name_dropdown],
|
||||
outputs=[inp_ref, prompt_text, ref_sample_dropdown, ref_emotion_text],
|
||||
)
|
||||
auto_select_weights_btn.click(
|
||||
fn=on_auto_select_weights,
|
||||
inputs=[model_name_dropdown],
|
||||
outputs=[GPT_dropdown, SoVITS_dropdown],
|
||||
)
|
||||
# 页面加载时自动扫描模型列表
|
||||
app.load(fn=refresh_model_dropdown, inputs=[], outputs=[model_name_dropdown])
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user