sd_models.py 8.1 KB
Newer Older
1
import collections
2 3 4 5 6 7 8 9
import os.path
import sys
from collections import namedtuple
import torch
from omegaconf import OmegaConf

from ldm.util import instantiate_from_config

10
from modules import shared, modelloader, devices
11 12 13
from modules.paths import models_path

model_dir = "Stable-diffusion"
14
model_path = os.path.abspath(os.path.join(models_path, model_dir))
15

16
CheckpointInfo = namedtuple("CheckpointInfo", ['filename', 'title', 'hash', 'model_name', 'config'])
17
checkpoints_list = {}
18
checkpoints_loaded = collections.OrderedDict()
19 20 21 22 23 24 25 26 27 28 29

try:
    # this silences the annoying "Some weights of the model checkpoint were not used when initializing..." message at start.

    from transformers import logging

    logging.set_verbosity_error()
except Exception:
    pass


30
def setup_model():
31 32
    if not os.path.exists(model_path):
        os.makedirs(model_path)
33

34 35 36
    list_models()


37 38 39 40
def checkpoint_tiles():
    return sorted([x.title for x in checkpoints_list.values()])


41 42
def list_models():
    checkpoints_list.clear()
43
    model_list = modelloader.load_models(model_path=model_path, command_path=shared.cmd_opts.ckpt_dir, ext_filter=[".ckpt"])
44

45
    def modeltitle(path, shorthash):
46 47
        abspath = os.path.abspath(path)

48 49
        if shared.cmd_opts.ckpt_dir is not None and abspath.startswith(shared.cmd_opts.ckpt_dir):
            name = abspath.replace(shared.cmd_opts.ckpt_dir, '')
50 51
        elif abspath.startswith(model_path):
            name = abspath.replace(model_path, '')
52 53 54 55 56 57
        else:
            name = os.path.basename(path)

        if name.startswith("\\") or name.startswith("/"):
            name = name[1:]

58 59
        shortname = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0]

60
        return f'{name} [{shorthash}]', shortname
61 62 63 64

    cmd_ckpt = shared.cmd_opts.ckpt
    if os.path.exists(cmd_ckpt):
        h = model_hash(cmd_ckpt)
65
        title, short_model_name = modeltitle(cmd_ckpt, h)
66
        checkpoints_list[title] = CheckpointInfo(cmd_ckpt, title, h, short_model_name, shared.cmd_opts.config)
67
        shared.opts.data['sd_model_checkpoint'] = title
68
    elif cmd_ckpt is not None and cmd_ckpt != shared.default_sd_model_file:
69 70 71
        print(f"Checkpoint in --ckpt argument not found (Possible it was moved to {model_path}: {cmd_ckpt}", file=sys.stderr)
    for filename in model_list:
        h = model_hash(filename)
72
        title, short_model_name = modeltitle(filename, h)
73 74 75 76 77 78 79

        basename, _ = os.path.splitext(filename)
        config = basename + ".yaml"
        if not os.path.exists(config):
            config = shared.cmd_opts.config

        checkpoints_list[title] = CheckpointInfo(filename, title, h, short_model_name, config)
80

81

D
DepFA 已提交
82
def get_closet_checkpoint_match(searchString):
D
DepFA 已提交
83
    applicable = sorted([info for info in checkpoints_list.values() if searchString in info.title], key = lambda x:len(x.title))
84
    if len(applicable) > 0:
D
DepFA 已提交
85 86
        return applicable[0]
    return None
87

88

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
def model_hash(filename):
    try:
        with open(filename, "rb") as file:
            import hashlib
            m = hashlib.sha256()

            file.seek(0x100000)
            m.update(file.read(0x10000))
            return m.hexdigest()[0:8]
    except FileNotFoundError:
        return 'NOFILE'


def select_checkpoint():
    model_checkpoint = shared.opts.sd_model_checkpoint
    checkpoint_info = checkpoints_list.get(model_checkpoint, None)
    if checkpoint_info is not None:
        return checkpoint_info

    if len(checkpoints_list) == 0:
109
        print(f"No checkpoints found. When searching for checkpoints, looked at:", file=sys.stderr)
110 111 112 113 114
        if shared.cmd_opts.ckpt is not None:
            print(f" - file {os.path.abspath(shared.cmd_opts.ckpt)}", file=sys.stderr)
        print(f" - directory {model_path}", file=sys.stderr)
        if shared.cmd_opts.ckpt_dir is not None:
            print(f" - directory {os.path.abspath(shared.cmd_opts.ckpt_dir)}", file=sys.stderr)
115 116
        print(f"Can't run without a checkpoint. Find and place a .ckpt file into any of those locations. The program will exit.", file=sys.stderr)
        exit(1)
117 118 119 120 121 122 123 124

    checkpoint_info = next(iter(checkpoints_list.values()))
    if model_checkpoint is not None:
        print(f"Checkpoint {model_checkpoint} not found; loading fallback {checkpoint_info.title}", file=sys.stderr)

    return checkpoint_info


125 126 127 128 129 130 131
def get_state_dict_from_checkpoint(pl_sd):
    if "state_dict" in pl_sd:
        return pl_sd["state_dict"]

    return pl_sd


132 133 134 135
def load_model_weights(model, checkpoint_info):
    checkpoint_file = checkpoint_info.filename
    sd_model_hash = checkpoint_info.hash

136 137
    if checkpoint_info not in checkpoints_loaded:
        print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}")
138

139
        pl_sd = torch.load(checkpoint_file, map_location=shared.weight_load_location)
140 141
        if "global_step" in pl_sd:
            print(f"Global Step: {pl_sd['global_step']}")
142

143 144
        sd = get_state_dict_from_checkpoint(pl_sd)
        model.load_state_dict(sd, strict=False)
145

146 147
        if shared.cmd_opts.opt_channelslast:
            model.to(memory_format=torch.channels_last)
148

149 150
        if not shared.cmd_opts.no_half:
            model.half()
151

152 153
        devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16
        devices.dtype_vae = torch.float32 if shared.cmd_opts.no_half or shared.cmd_opts.no_half_vae else torch.float16
154

155
        vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt"
156

157 158
        if not os.path.exists(vae_file) and shared.cmd_opts.vae_path is not None:
            vae_file = shared.cmd_opts.vae_path
159

160 161
        if os.path.exists(vae_file):
            print(f"Loading VAE weights from: {vae_file}")
162
            vae_ckpt = torch.load(vae_file, map_location=shared.weight_load_location)
163 164
            vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"}
            model.first_stage_model.load_state_dict(vae_dict)
A
AUTOMATIC 已提交
165

166
        model.first_stage_model.to(devices.dtype_vae)
A
AUTOMATIC 已提交
167

168 169 170 171 172 173 174
        checkpoints_loaded[checkpoint_info] = model.state_dict().copy()
        while len(checkpoints_loaded) > shared.opts.sd_checkpoint_cache:
            checkpoints_loaded.popitem(last=False)  # LRU
    else:
        print(f"Loading weights [{sd_model_hash}] from cache")
        checkpoints_loaded.move_to_end(checkpoint_info)
        model.load_state_dict(checkpoints_loaded[checkpoint_info])
A
AUTOMATIC 已提交
175

176
    model.sd_model_hash = sd_model_hash
A
Aidan Holland 已提交
177
    model.sd_model_checkpoint = checkpoint_file
178
    model.sd_checkpoint_info = checkpoint_info
179 180 181 182 183 184


def load_model():
    from modules import lowvram, sd_hijack
    checkpoint_info = select_checkpoint()

185
    if checkpoint_info.config != shared.cmd_opts.config:
186
        print(f"Loading config from: {checkpoint_info.config}")
187 188

    sd_config = OmegaConf.load(checkpoint_info.config)
189
    sd_model = instantiate_from_config(sd_config.model)
190
    load_model_weights(sd_model, checkpoint_info)
191 192 193 194 195 196 197 198 199 200 201 202 203 204

    if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
        lowvram.setup_for_low_vram(sd_model, shared.cmd_opts.medvram)
    else:
        sd_model.to(shared.device)

    sd_hijack.model_hijack.hijack(sd_model)

    sd_model.eval()

    print(f"Model loaded.")
    return sd_model


205
def reload_model_weights(sd_model, info=None):
206
    from modules import lowvram, devices, sd_hijack
207
    checkpoint_info = info or select_checkpoint()
208

A
Aidan Holland 已提交
209
    if sd_model.sd_model_checkpoint == checkpoint_info.filename:
210 211
        return

212
    if sd_model.sd_checkpoint_info.config != checkpoint_info.config:
213
        checkpoints_loaded.clear()
214 215
        shared.sd_model = load_model()
        return shared.sd_model
216

217 218 219 220 221
    if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
        lowvram.send_everything_to_cpu()
    else:
        sd_model.to(devices.cpu)

222 223
    sd_hijack.model_hijack.undo_hijack(sd_model)

224
    load_model_weights(sd_model, checkpoint_info)
225

226 227
    sd_hijack.model_hijack.hijack(sd_model)

228 229 230 231 232
    if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram:
        sd_model.to(devices.device)

    print(f"Weights loaded.")
    return sd_model