# How GPT-SoVITS WebUI Implements Model Weight Selection and Checkpoint Switching

> Discover how GPT-SoVITS WebUI dynamically selects and switches model weights and checkpoints. Learn about its efficient checkpoint scanning and loading process.

- Repository: [RVC-Boss/GPT-SoVITS](https://github.com/RVC-Boss/GPT-SoVITS)
- Tags: internals
- Published: 2026-03-07

---

**The GPT-SoVITS WebUI dynamically scans checkpoint directories, populates Gradio dropdown menus with discovered `.pth` and `.ckpt` files, and switches models via dedicated change handlers that resolve paths, detect versions, and load weights into global inference objects while yielding UI state updates.**

The RVC-Boss/GPT-SoVITS repository provides a Gradio-based WebUI for voice synthesis that requires seamless switching between GPT and SoVITS checkpoints. Understanding how the WebUI implements model weight selection and checkpoint switching reveals a tightly coupled system of filesystem scanning, UI state management, and runtime model instantiation.

## How Checkpoint Discovery Works

The foundation of model selection lies in [`config.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/config.py), which defines static maps for pre-trained models and the weight-root directories. The system maintains separate lists for SoVITS and GPT weights:

```python

# config.py – definitions of the weight roots

SoVITS_weight_root = ["SoVITS_weights", "SoVITS_weights_v2", ...]   # ← line 44‑49

GPT_weight_root    = ["GPT_weights", "GPT_weights_v2", ...]          # ← line 52‑58

```

The `get_weights_names()` function walks these directories to discover available checkpoints. It scans for files ending in `.pth` (SoVITS) or `.ckpt` (GPT), while also checking named entries in `name2sovits_path` and `name2gpt_path`:

```python
def get_weights_names():
    SoVITS_names = []
    for key in name2sovits_path:
        if os.path.exists(name2sovits_path[key]):
            SoVITS_names.append(key)                         # ← line 88‑90

    for path in SoVITS_weight_root:
        if not os.path.exists(path):
            continue
        for name in os.listdir(path):
            if name.endswith(".pth"):
                SoVITS_names.append(f"{path}/{name}")       # ← line 95‑97

    # … same logic for GPT (lines 99‑108) …

    SoVITS_names = sorted(SoVITS_names, key=custom_sort_key) # ← line 109‑110

    return SoVITS_names, GPT_names                         # ← line 113‑114

```

This discovery mechanism ensures that both repository-provided models and user-added checkpoints in custom `*_weights` folders appear in the UI automatically.

## Populating the Gradio Dropdown Menus

In [`webui.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/webui.py), the inference tab constructs the **GPT_dropdown** and **SoVITS_dropdown** components using the sorted lists returned by `config.get_weights_names()`:

```python

# webui.py – inference tab (excerpt)

GPT_dropdown = gr.Dropdown(
    label=i18n("GPT模型列表"),
    choices=sorted(GPT_names, key=custom_sort_key),   # ← line 1450‑1452

    value=gpt_path,
    interactive=True,
    scale=14,
)

SoVITS_dropdown = gr.Dropdown(
    label=i18n("SoVITS模型列表"),
    choices=sorted(SoVITS_names, key=custom_sort_key), # ← line 1452‑1455

    value=sovits_path,
    interactive=True,
    scale=14,
)

```

A **Refresh** button allows users to re-scan the filesystem at runtime without restarting the application:

```python
refresh_button = gr.Button(i18n("刷新模型路径"), variant="primary", scale=14)  # line 1459

refresh_button.click(fn=change_choices, inputs=[], outputs=[SoVITS_dropdown, GPT_dropdown])  # line 1460

```

The `change_choices()` function forwards the updated lists back to the dropdown components:

```python
def change_choices():
    SoVITS_names, GPT_names = get_weights_names()   # ← line 116‑117

    return {"choices": SoVITS_names, "__type__": "update"}, {"choices": GPT_names, "__type__": "update"}

```

## Switching Between Checkpoints

When a user selects a new checkpoint from either dropdown, Gradio invokes dedicated change handlers that perform the actual model loading and UI synchronization.

### Resolving Model Paths and Versions

Both `change_sovits_weights()` and `change_gpt_weights()` first resolve friendly display names (e.g., "v2底模！") into actual filesystem paths. The handlers check for special characters `！` or `!` in the selection to identify named entries:

```python
if "！" in sovits_path or "!" in sovits_path:
    sovits_path = name2sovits_path[sovits_path]                     # line 30‑31

```

For SoVITS checkpoints, the system must detect the model version to instantiate the correct class. The `get_sovits_version_from_path_fast()` function extracts version information (v1, v2, v3, v4) and LoRA flags directly from the filename:

```python
version, model_version, if_lora_v3 = get_sovits_version_from_path_fast(sovits_path)  # line 33‑34

```

### Loading SoVITS Checkpoints

The `change_sovits_weights()` function in [`GPT_SoVITS/inference_webui.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/GPT_SoVITS/inference_webui.py) implements the complete switching logic as a **generator**, yielding Gradio update dictionaries to refresh UI elements progressively without blocking the main thread:

```python
def change_sovits_weights(sovits_path, prompt_language=None, text_language=None):
    # ① Resolve named entries

    if "！" in sovits_path or "!" in sovits_path:
        sovits_path = name2sovits_path[sovits_path]                     # line 30‑31

    # ② Determine version, model‑type and LoRA flag from the filename

    version, model_version, if_lora_v3 = get_sovits_version_from_path_fast(sovits_path)  # line 33‑34

    # ③ Prepare UI state (language lists, visibility of sample‑steps, etc.) and **yield**

    #    a series of Gradio update dicts so the UI instantly reflects the new model.

    #    (lines 42‑78 – see the “yield (…)” block)

    # ④ Load the checkpoint (weights + config) and build the model instance

    dict_s2 = load_sovits_new(sovits_path)                 # line 81

    hps = DictToAttrRecursive(dict_s2["config"])           # line 82‑84

    #    – adjust version flags, instantiate the appropriate Synthesizer class

    #      (v1/v2 vs. v3/v4) (lines 92‑110)

    # ⑤ Move model to the selected device & precision

    if is_half:
        vq_model = vq_model.half().to(device)              # line 117‑119

    else:
        vq_model = vq_model.to(device)

```

Key implementation details include:

- **Path resolution** allows readable UI labels while loading the correct file from `name2sovits_path`
- **Version detection** determines whether to instantiate `SynthesizerTrn` (v1/v2) or `SynthesizerTrnV3` (v3/v4)
- **UI synchronization** yields update dictionaries that adjust language selectors and reveal version-specific controls like `sample_steps` for V3/V4 models
- **Device handling** moves the loaded `vq_model` to the configured GPU/CPU and applies `float16` precision when `is_half` is enabled

### Loading GPT Checkpoints

The GPT switching logic follows a similar pattern but with less UI complexity. The `change_gpt_weights()` function updates the global `gpt` inference object:

```python
def change_gpt_weights(gpt_path):
    global gpt
    # Resolve named entries (same as SoVITS)

    if "！" in gpt_path or "!" in gpt_path:
        gpt_path = name2gpt_path[gpt_path]               # line 376‑377 (in inference_webui.py)

    # Load the checkpoint (the implementation lives in process_ckpt)

    gpt = load_gpt_new(gpt_path)                         # line 381

    # Update UI (show loading indicator, enable inference button, etc.)

    return (
        {"__type__": "update", "value": i18n("模型加载中，请等待"), "interactive": False},
        {"__type__": "update", "value": True, "interactive": True},
    )

```

Once loaded, the global `gpt` variable ensures that subsequent calls to `get_tts_wav()` reference the currently selected checkpoint.

## Programmatic Model Switching

You can trigger checkpoint switches programmatically by importing the change handlers directly from [`GPT_SoVITS/inference_webui.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/GPT_SoVITS/inference_webui.py):

```python
from GPT_SoVITS.inference_webui import change_sovits_weights, change_gpt_weights

# Switch SoVITS checkpoint

list(change_sovits_weights("SoVITS_weights_v2/my_model.pth", prompt_language="中文", text_language="中文"))

# Switch GPT checkpoint

list(change_gpt_weights("GPT_weights_v2/my_gpt.ckpt"))

```

Each function returns a generator of Gradio update dictionaries; iterating over the generator forces the loading process to execute and apply UI updates.

## Key Source Files and Architecture

The checkpoint switching mechanism spans several critical files in the RVC-Boss/GPT-SoVITS repository:

- **[`config.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/config.py)** – Contains `get_weights_names()`, `SoVITS_weight_root`, and `GPT_weight_root` definitions for filesystem scanning
- **[`webui.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/webui.py)** – Constructs the `GPT_dropdown` and `SoVITS_dropdown` Gradio components and wires the refresh button to `change_choices()`
- **[`GPT_SoVITS/inference_webui.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/GPT_SoVITS/inference_webui.py)** – Implements `change_sovits_weights()` and `change_gpt_weights()` with version detection and model instantiation
- **[`GPT_SoVITS/inference_webui_fast.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/GPT_SoVITS/inference_webui_fast.py)** – Mirrors the switching logic for the low-latency inference path
- **[`process_ckpt.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/process_ckpt.py)** – Provides `load_sovits_new()` and `load_gpt_new()` for low-level checkpoint deserialization

## Summary

- **Filesystem discovery** via `config.get_weights_names()` scans `SoVITS_weight_root` and `GPT_weight_root` for `.pth` and `.ckpt` files, merging results with named path mappings
- **Dynamic UI population** uses `change_choices()` to refresh Gradio dropdowns without requiring application restarts
- **Path resolution** handles both direct file paths and friendly display names containing `！` or `!` characters through `name2sovits_path` and `name2gpt_path` lookups
- **Version-aware loading** detects model architecture (v1/v2 vs. v3/v4) from filenames and instantiates the appropriate `SynthesizerTrn` class
- **Generator-based updates** allow `change_sovits_weights()` to yield progressive UI state changes while loading large models into the global `vq_model` and `gpt` objects

## Frequently Asked Questions

### How does the WebUI detect new checkpoints added after startup?

The **Refresh** button in the inference tab triggers `change_choices()`, which re-executes `get_weights_names()` to scan the filesystem again. This updates both dropdown menus with any new `.pth` or `.ckpt` files placed in the weight directories since the last scan, eliminating the need to restart the Gradio server.

### What file extensions does GPT-SoVITS expect for model weights?

According to the source code in [`config.py`](https://github.com/RVC-Boss/GPT-SoVITS/blob/main/config.py), SoVITS checkpoints must use the **`.pth`** extension while GPT checkpoints use the **`.ckpt`** extension. The `get_weights_names()` function explicitly filters for these extensions when building the dropdown choices lists.

### Why does `change_sovits_weights()` use a generator pattern?

The function yields multiple Gradio update dictionaries (with `"__type__": "update"`) during execution rather than returning a single value. This allows the UI to display loading states, adjust language selectors, and toggle visibility of version-specific controls (like `sample_steps` for V3/V4) immediately, while the heavyweight model loading continues in the background without blocking the interface.

### How does the system handle different model versions (v1, v2, v3, v4)?

The `get_sovits_version_from_path_fast()` function parses the selected filename to extract version strings. Based on this detection, `change_sovits_weights()` instantiates the appropriate synthesizer class—`SynthesizerTrn` for v1/v2 models or `SynthesizerTrnV3` for v3/v4 models—and adjusts global configuration flags accordingly.