|
1 | | -import json |
2 | | -import os |
3 | | -import yaml |
4 | | - |
5 | | -import folder_paths |
6 | | -from comfy.ldm.util import instantiate_from_config |
7 | | -from comfy.sd import ModelPatcher, load_model_weights, CLIP, VAE |
8 | | -import os.path as osp |
9 | 1 | import re |
10 | 2 | import torch |
11 | | -from safetensors.torch import load_file, save_file |
12 | 3 |
|
13 | 4 | # conversion code from https://github.com/huggingface/diffusers/blob/main/scripts/convert_diffusers_to_original_stable_diffusion.py |
14 | 5 |
|
@@ -262,101 +253,3 @@ def convert_text_enc_state_dict(text_enc_dict): |
262 | 253 | return text_enc_dict |
263 | 254 |
|
264 | 255 |
|
265 | | -def load_diffusers(model_path, fp16=True, output_vae=True, output_clip=True, embedding_directory=None): |
266 | | - diffusers_unet_conf = json.load(open(osp.join(model_path, "unet/config.json"))) |
267 | | - diffusers_scheduler_conf = json.load(open(osp.join(model_path, "scheduler/scheduler_config.json"))) |
268 | | - |
269 | | - # magic |
270 | | - v2 = diffusers_unet_conf["sample_size"] == 96 |
271 | | - if 'prediction_type' in diffusers_scheduler_conf: |
272 | | - v_pred = diffusers_scheduler_conf['prediction_type'] == 'v_prediction' |
273 | | - |
274 | | - if v2: |
275 | | - if v_pred: |
276 | | - config_path = folder_paths.get_full_path("configs", 'v2-inference-v.yaml') |
277 | | - else: |
278 | | - config_path = folder_paths.get_full_path("configs", 'v2-inference.yaml') |
279 | | - else: |
280 | | - config_path = folder_paths.get_full_path("configs", 'v1-inference.yaml') |
281 | | - |
282 | | - with open(config_path, 'r') as stream: |
283 | | - config = yaml.safe_load(stream) |
284 | | - |
285 | | - model_config_params = config['model']['params'] |
286 | | - clip_config = model_config_params['cond_stage_config'] |
287 | | - scale_factor = model_config_params['scale_factor'] |
288 | | - vae_config = model_config_params['first_stage_config'] |
289 | | - vae_config['scale_factor'] = scale_factor |
290 | | - model_config_params["unet_config"]["params"]["use_fp16"] = fp16 |
291 | | - |
292 | | - unet_path = osp.join(model_path, "unet", "diffusion_pytorch_model.safetensors") |
293 | | - vae_path = osp.join(model_path, "vae", "diffusion_pytorch_model.safetensors") |
294 | | - text_enc_path = osp.join(model_path, "text_encoder", "model.safetensors") |
295 | | - |
296 | | - # Load models from safetensors if it exists, if it doesn't pytorch |
297 | | - if osp.exists(unet_path): |
298 | | - unet_state_dict = load_file(unet_path, device="cpu") |
299 | | - else: |
300 | | - unet_path = osp.join(model_path, "unet", "diffusion_pytorch_model.bin") |
301 | | - unet_state_dict = torch.load(unet_path, map_location="cpu") |
302 | | - |
303 | | - if osp.exists(vae_path): |
304 | | - vae_state_dict = load_file(vae_path, device="cpu") |
305 | | - else: |
306 | | - vae_path = osp.join(model_path, "vae", "diffusion_pytorch_model.bin") |
307 | | - vae_state_dict = torch.load(vae_path, map_location="cpu") |
308 | | - |
309 | | - if osp.exists(text_enc_path): |
310 | | - text_enc_dict = load_file(text_enc_path, device="cpu") |
311 | | - else: |
312 | | - text_enc_path = osp.join(model_path, "text_encoder", "pytorch_model.bin") |
313 | | - text_enc_dict = torch.load(text_enc_path, map_location="cpu") |
314 | | - |
315 | | - # Convert the UNet model |
316 | | - unet_state_dict = convert_unet_state_dict(unet_state_dict) |
317 | | - unet_state_dict = {"model.diffusion_model." + k: v for k, v in unet_state_dict.items()} |
318 | | - |
319 | | - # Convert the VAE model |
320 | | - vae_state_dict = convert_vae_state_dict(vae_state_dict) |
321 | | - vae_state_dict = {"first_stage_model." + k: v for k, v in vae_state_dict.items()} |
322 | | - |
323 | | - # Easiest way to identify v2.0 model seems to be that the text encoder (OpenCLIP) is deeper |
324 | | - is_v20_model = "text_model.encoder.layers.22.layer_norm2.bias" in text_enc_dict |
325 | | - |
326 | | - if is_v20_model: |
327 | | - # Need to add the tag 'transformer' in advance so we can knock it out from the final layer-norm |
328 | | - text_enc_dict = {"transformer." + k: v for k, v in text_enc_dict.items()} |
329 | | - text_enc_dict = convert_text_enc_state_dict_v20(text_enc_dict) |
330 | | - text_enc_dict = {"cond_stage_model.model." + k: v for k, v in text_enc_dict.items()} |
331 | | - else: |
332 | | - text_enc_dict = convert_text_enc_state_dict(text_enc_dict) |
333 | | - text_enc_dict = {"cond_stage_model.transformer." + k: v for k, v in text_enc_dict.items()} |
334 | | - |
335 | | - # Put together new checkpoint |
336 | | - sd = {**unet_state_dict, **vae_state_dict, **text_enc_dict} |
337 | | - |
338 | | - clip = None |
339 | | - vae = None |
340 | | - |
341 | | - class WeightsLoader(torch.nn.Module): |
342 | | - pass |
343 | | - |
344 | | - w = WeightsLoader() |
345 | | - load_state_dict_to = [] |
346 | | - if output_vae: |
347 | | - vae = VAE(scale_factor=scale_factor, config=vae_config) |
348 | | - w.first_stage_model = vae.first_stage_model |
349 | | - load_state_dict_to = [w] |
350 | | - |
351 | | - if output_clip: |
352 | | - clip = CLIP(config=clip_config, embedding_directory=embedding_directory) |
353 | | - w.cond_stage_model = clip.cond_stage_model |
354 | | - load_state_dict_to = [w] |
355 | | - |
356 | | - model = instantiate_from_config(config["model"]) |
357 | | - model = load_model_weights(model, sd, verbose=False, load_state_dict_to=load_state_dict_to) |
358 | | - |
359 | | - if fp16: |
360 | | - model = model.half() |
361 | | - |
362 | | - return ModelPatcher(model), clip, vae |
0 commit comments