Implementation:AUTOMATIC1111 Stable diffusion webui Run modelmerger
| Knowledge Sources | |
|---|---|
| Domains | Model Merging, Checkpoint Merging, Memory Management |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
Concrete tool for executing the full checkpoint merging pipeline including model loading, two-pass weight interpolation, and output generation provided by stable-diffusion-webui.
Description
The run_modelmerger function is the main entry point for the checkpoint merging workflow. It orchestrates the entire merge pipeline:
- Validates input parameters and resolves model names to
CheckpointInfoobjects via the globalcheckpoints_list. - Selects the interpolation method from the
theta_funcsdispatch dictionary. - Pass 1 (conditional): For "Add difference" mode, loads models B and C, computes B - C per key using
get_difference, then frees model C. - Pass 2: Loads model A and iterates over its state dict, applying the interpolation function (
weighted_sumoradd_difference) for each key present in both A and B. Handles shape mismatches for inpainting and instruct-pix2pix models. - Applies FP16 conversion per-tensor via
to_halfduring the merge loop. - Optionally bakes in an external VAE by overwriting
first_stage_model.*keys. - Optionally discards weight keys matching a regex pattern.
- Constructs the output filename (auto-generated or custom) and saves in the specified format.
- Optionally embeds metadata including a machine-readable merge recipe.
- Refreshes the model registry via
sd_models.list_models()and computes the shorthash of the new checkpoint.
The function uses shared.state for job management and progress reporting, and returns a list of Gradio UI updates plus a status message.
Usage
This function is called from the Gradio UI's "Merge" button handler. It can also be invoked programmatically through the WebUI's API. It should be called as a background task (via id_task) since merging large models can take several minutes.
Code Reference
Source Location
- Repository: stable-diffusion-webui
- File:
modules/extras.py - Lines: L88-330
Signature
def run_modelmerger(
id_task,
primary_model_name,
secondary_model_name,
tertiary_model_name,
interp_method,
multiplier,
save_as_half,
custom_name,
checkpoint_format,
config_source,
bake_in_vae,
discard_weights,
save_metadata,
add_merge_recipe,
copy_metadata_fields,
metadata_json
):
...
Import
from modules.extras import run_modelmerger
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| id_task | str | Yes | Task identifier for progress tracking |
| primary_model_name | str | Yes | Title/key of model A in checkpoints_list
|
| secondary_model_name | str | Yes | Title/key of model B (required for Weighted sum and Add difference) |
| tertiary_model_name | str | Yes | Title/key of model C (required only for Add difference) |
| interp_method | str | Yes | One of: "Weighted sum", "Add difference", "No interpolation"
|
| multiplier | float | Yes | Interpolation alpha value, typically in [0, 1] |
| save_as_half | bool | Yes | Whether to convert float32 weights to float16 |
| custom_name | str | Yes | Custom output filename (empty string for auto-generated name) |
| checkpoint_format | str | Yes | Output format: "safetensors" or "ckpt"
|
| config_source | int | Yes | Config file source: 0=A/B/C, 1=B, 2=C, 3=None |
| bake_in_vae | str | Yes | VAE name to bake in (empty or name from sd_vae.vae_dict)
|
| discard_weights | str | Yes | Regex pattern for keys to discard (empty to keep all) |
| save_metadata | bool | Yes | Whether to embed metadata in the output file |
| add_merge_recipe | bool | Yes | Whether to include merge recipe in metadata |
| copy_metadata_fields | bool | Yes | Whether to copy metadata from source models |
| metadata_json | str | Yes | Additional JSON metadata string to embed |
Outputs
| Name | Type | Description |
|---|---|---|
| return | list | A list containing 4 gr.Dropdown.update objects (refreshed model dropdowns) followed by a status message string
|
Execution Flow
1. shared.state.begin(job="model-merge")
2. Resolve model names -> CheckpointInfo objects
3. Select (filename_generator, theta_func1, theta_func2) from theta_funcs[interp_method]
4. IF theta_func1 (Add difference mode):
a. Load model B state dict (theta_1)
b. Load model C state dict (theta_2)
c. For each key in theta_1:
- Skip keys in checkpoint_dict_skip_on_merge
- If "model" in key and key in theta_2:
theta_1[key] = get_difference(theta_1[key], theta_2[key])
- Else if "model" in key:
theta_1[key] = zeros_like(theta_1[key])
d. Delete theta_2
5. Load model A state dict (theta_0)
6. For each key in theta_0:
a. Skip keys in checkpoint_dict_skip_on_merge
b. If theta_1 exists and "model" in key and key in theta_1:
- Handle shape mismatches (inpainting/instruct-pix2pix)
- theta_0[key] = theta_func2(theta_0[key], theta_1[key], multiplier)
- theta_0[key] = to_half(theta_0[key], save_as_half)
7. Delete theta_1
8. IF bake_in_vae: load VAE and overwrite first_stage_model.* keys
9. IF save_as_half and no theta_func2: convert remaining tensors
10. IF discard_weights: remove matching keys
11. Generate output filename and path
12. Save as safetensors or ckpt with optional metadata
13. sd_models.list_models() to refresh registry
14. Calculate shorthash of new model
15. Copy config file if applicable
16. shared.state.end()
17. Return [dropdown_updates..., status_message]
Error Handling
The function uses an internal fail(message) helper that:
- Sets
shared.state.textinfoto the error message - Calls
shared.state.end()to clean up the job - Returns a list of
gr.update()placeholders plus the error message
Specific error conditions:
- Missing primary model:
"Failed: Merging requires a primary model." - Missing secondary model for interpolation methods that require it
- Missing tertiary model for "Add difference" method
- Shape mismatch where A has fewer channels than B raises
RuntimeError
Usage Examples
Basic Usage
from modules.extras import run_modelmerger
# Weighted sum merge at 30% model B
result = run_modelmerger(
id_task="merge-001",
primary_model_name="v1-5-pruned-emaonly.safetensors [6ce0161689]",
secondary_model_name="dreamshaper_8.safetensors [abcd1234ef]",
tertiary_model_name="",
interp_method="Weighted sum",
multiplier=0.3,
save_as_half=True,
custom_name="my_merged_model",
checkpoint_format="safetensors",
config_source=0,
bake_in_vae="",
discard_weights="",
save_metadata=True,
add_merge_recipe=True,
copy_metadata_fields=True,
metadata_json="{}"
)
# result[-1] == "Checkpoint saved to /models/Stable-diffusion/my_merged_model.safetensors"
Add Difference Merge
from modules.extras import run_modelmerger
# Transfer specialization from B over base C to model A
result = run_modelmerger(
id_task="merge-002",
primary_model_name="v1-5-pruned-emaonly.safetensors [6ce0161689]",
secondary_model_name="specialized_model.safetensors [1234abcdef]",
tertiary_model_name="base_model.safetensors [fedcba4321]",
interp_method="Add difference",
multiplier=1.0,
save_as_half=True,
custom_name="",
checkpoint_format="safetensors",
config_source=0,
bake_in_vae="vae-ft-mse-840000-ema-pruned",
discard_weights="",
save_metadata=True,
add_merge_recipe=True,
copy_metadata_fields=False,
metadata_json="{}"
)