# !/usr/bin/env python # -*- coding: UTF-8 -*- import logging import os import re import random import torch import gc from omegaconf import OmegaConf from PIL import Image import numpy as np import cv2 from diffusers import ( DDIMScheduler, KDPM2AncestralDiscreteScheduler, LMSDiscreteScheduler, DPMSolverMultistepScheduler, DPMSolverSinglestepScheduler, EulerDiscreteScheduler, HeunDiscreteScheduler, KDPM2DiscreteScheduler, EulerAncestralDiscreteScheduler, UniPCMultistepScheduler, DDPMScheduler, LCMScheduler) from .msdiffusion.models.projection import Resampler from .msdiffusion.models.modelWrapper import MSAdapter as MSAdapterWarpper from .utils.style_template import styles from .utils.load_models_utils import get_lora_dict from .PuLID.pulid.utils import resize_numpy_image_long from transformers import AutoModel, AutoTokenizer from comfy.utils import common_upscale,ProgressBar import folder_paths from comfy.clip_vision import load as clip_load from .utils.gradio_utils import process_original_text,character_to_dict import json cur_path = os.path.dirname(os.path.abspath(__file__)) photomaker_dir=os.path.join(folder_paths.models_dir, "photomaker") base_pt = os.path.join(photomaker_dir,"pt") device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" lora_get = get_lora_dict() lora_lightning_list = lora_get["lightning_xl_lora"] SAMPLER_NAMES = ["euler", "euler_cfg_pp", "euler_ancestral", "euler_ancestral_cfg_pp", "heun", "heunpp2","dpm_2", "dpm_2_ancestral", "lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_2s_ancestral_cfg_pp", "dpmpp_sde", "dpmpp_sde_gpu", "dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm", "ipndm", "ipndm_v", "deis","ddim", "uni_pc", "uni_pc_bh2"] SCHEDULER_NAMES = ["normal", "karras", "exponential", "sgm_uniform", "simple", "ddim_uniform", "beta"] def gc_cleanup(): gc.collect() torch.cuda.empty_cache() def get_scheduler(name,scheduler_): scheduler = False if name == "euler" or name =="euler_cfg_pp": scheduler = EulerDiscreteScheduler() elif name == "euler_ancestral" or name =="euler_ancestral_cfg_pp": scheduler = EulerAncestralDiscreteScheduler() elif name == "ddim": scheduler = DDIMScheduler() elif name == "ddpm": scheduler = DDPMScheduler() elif name == "dpmpp_2m": scheduler = DPMSolverMultistepScheduler() elif name == "dpmpp_2m" and scheduler_=="karras": scheduler = DPMSolverMultistepScheduler(use_karras_sigmas=True) elif name == "dpmpp_2m_sde": scheduler = DPMSolverMultistepScheduler(algorithm_type="sde-dpmsolver++") elif name == "dpmpp_2m" and scheduler_=="karras": scheduler = DPMSolverMultistepScheduler(use_karras_sigmas=True, algorithm_type="sde-dpmsolver++") elif name == "dpmpp_sde" or name == "dpmpp_sde_gpu": scheduler = DPMSolverSinglestepScheduler() elif (name == "dpmpp_sde" or name == "dpmpp_sde_gpu") and scheduler_=="karras": scheduler = DPMSolverSinglestepScheduler(use_karras_sigmas=True) elif name == "dpm_2": scheduler = KDPM2DiscreteScheduler() elif name == "dpm_2" and scheduler_=="karras": scheduler = KDPM2DiscreteScheduler(use_karras_sigmas=True) elif name == "dpm_2_ancestral": scheduler = KDPM2AncestralDiscreteScheduler() elif name == "dpm_2_ancestral" and scheduler_=="karras": scheduler = KDPM2AncestralDiscreteScheduler(use_karras_sigmas=True) elif name == "heun": scheduler = HeunDiscreteScheduler() elif name == "lcm": scheduler = LCMScheduler() elif name == "lms": scheduler = LMSDiscreteScheduler() elif name == "lms" and scheduler_=="karras": scheduler = LMSDiscreteScheduler(use_karras_sigmas=True) elif name == "uni_pc": scheduler = UniPCMultistepScheduler() else: scheduler = EulerDiscreteScheduler() return scheduler def get_extra_function(extra_function,extra_param,photomake_ckpt_path,image,infer_mode): auraface=False use_photov2=False cached=False inject=False onnx_provider="gpu" img2img_mode = True if isinstance(image, torch.Tensor) else False trigger_words_dual="best" dual_lora_scale=1.0 dreamo_mode="ip" if extra_function: extra_function = extra_function.strip().lower() if "auraface" in extra_function: auraface=True if extra_param: extra_param = extra_param.strip().lower() if "cache" in extra_param: cached=True if "inject" in extra_param: inject=True if "cpu" in extra_param: onnx_provider="cpu" if "id" in extra_param: dreamo_mode="id" elif "style" in extra_param: dreamo_mode="style" if "[" in extra_param: trigger_words_param=extra_param.split("[")[1].split("]")[0] trigger_words_dual=trigger_words_param.split(",")[0] dual_lora_scale=float(trigger_words_param.split(",")[1]) if isinstance(photomake_ckpt_path, str) and img2img_mode: use_photov2 = True if "v2" in photomake_ckpt_path else False return auraface,use_photov2,img2img_mode,cached,inject,onnx_provider,dreamo_mode,trigger_words_dual,dual_lora_scale def extract_content_from_brackets(text): # 正则表达式匹配多对方括号内的内容 return re.findall(r'\[(.*?)\]', text) def phi2narry(img): img = torch.from_numpy(np.array(img).astype(np.float32) / 255.0).unsqueeze(0) return img def tensor_to_image(tensor): image_np = tensor.squeeze().mul(255).clamp(0, 255).byte().numpy() image = Image.fromarray(image_np, mode='RGB') return image def tensortopil_list(tensor_in): d1, _, _, _ = tensor_in.size() if d1 == 1: img_list = [tensor_to_image(tensor_in)] else: tensor_list = torch.chunk(tensor_in, chunks=d1) img_list=[tensor_to_image(i) for i in tensor_list] return img_list def tensortopil_list_upscale(tensor_in,width,height): d1, _, _, _ = tensor_in.size() if d1 == 1: img_list = [nomarl_upscale(tensor_in,width,height)] else: tensor_list = torch.chunk(tensor_in, chunks=d1) img_list=[nomarl_upscale(i,width,height) for i in tensor_list] return img_list def tensortolist(tensor_in,width,height): d1, _, _, _ = tensor_in.size() if d1 == 1: tensor_list = [nomarl_tensor_upscale(tensor_in,width,height)] else: tensor_list_ = torch.chunk(tensor_in, chunks=d1) tensor_list=[nomarl_tensor_upscale(i,width,height) for i in tensor_list_] return tensor_list def nomarl_tensor_upscale(tensor, width, height): samples = tensor.movedim(-1, 1) samples = common_upscale(samples, width, height, "nearest-exact", "center") samples = samples.movedim(1, -1) return samples def nomarl_upscale(img, width, height): samples = img.movedim(-1, 1) img = common_upscale(samples, width, height, "nearest-exact", "center") samples = img.movedim(1, -1) img = tensor_to_image(samples) return img def nomarl_upscale_tensor(img, width, height): samples = img.movedim(-1, 1) img = common_upscale(samples, width, height, "nearest-exact", "center") samples = img.movedim(1, -1) return samples def center_crop(img): width, height = img.size square = min(width, height) left = (width - square) / 2 top = (height - square) / 2 right = (width + square) / 2 bottom = (height + square) / 2 return img.crop((left, top, right, bottom)) def center_crop_s(img, new_width, new_height): width, height = img.size left = (width - new_width) / 2 top = (height - new_height) / 2 right = (width + new_width) / 2 bottom = (height + new_height) / 2 return img.crop((left, top, right, bottom)) def contains_brackets(s): return '[' in s or ']' in s def has_parentheses(s): return bool(re.search(r'\(.*?\)', s)) def extract_content_from_brackets_(text): # 正则表达式匹配多对圆括号内的内容 return re.findall(r'\((.*?)\)', text) def narry_list(list_in): for i in range(len(list_in)): value = list_in[i] modified_value = phi2narry(value) list_in[i] = modified_value return list_in def remove_punctuation_from_strings(lst): pattern = r"[\W]+$" # 匹配字符串末尾的所有非单词字符 return [re.sub(pattern, '', s) for s in lst] def phi_list(list_in): for i in range(len(list_in)): value = list_in[i] list_in[i] = value return list_in def narry_list_pil(list_in): for i in range(len(list_in)): value = list_in[i] modified_value = tensor_to_image(value) list_in[i] = modified_value return list_in def setup_seed(seed): torch.manual_seed(seed) if device == "cuda": torch.cuda.manual_seed_all(seed) np.random.seed(seed) random.seed(seed) torch.backends.cudnn.deterministic = True def apply_style_positive(style_name: str, positive: str): p, n = styles.get(style_name, styles[style_name]) #print(p, "test0", n) return p.replace("{prompt}", positive),n def apply_style(style_name: str, positives: list, negative: str = ""): p, n = styles.get(style_name, styles[style_name]) #print(p,"test1",n) return [ p.replace("{prompt}", positive) for positive in positives ], n + " " + negative def face_bbox_to_square(bbox): ## l, t, r, b to square l, t, r, b l,t,r,b = bbox cent_x = (l + r) / 2 cent_y = (t + b) / 2 w, h = r - l, b - t r = max(w, h) / 2 l0 = cent_x - r r0 = cent_x + r t0 = cent_y - r b0 = cent_y + r return [l0, t0, r0, b0] def insight_face_loader(infer_mode,use_photov2,auraface,onnx_provider="cpu",mask_repo="briaai/RMBG-1.4"): insightface_root_path= folder_paths.base_path if infer_mode=="story" and use_photov2: from .utils.insightface_package import FaceAnalysis2 if auraface: from huggingface_hub import snapshot_download snapshot_download( "fal/AuraFace-v1", local_dir="models/auraface", ) app_face = FaceAnalysis2(name="auraface", providers=["CUDAExecutionProvider", "CPUExecutionProvider"], root=insightface_root_path, allowed_modules=['detection', 'recognition']) else: app_face = FaceAnalysis2(providers=['CUDAExecutionProvider'], allowed_modules=['detection', 'recognition']) app_face.prepare(ctx_id=0, det_size=(640, 640)) pipeline_mask = None app_face_ = None elif infer_mode=="kolor_face" : from .kolors.models.sample_ipadapter_faceid_plus import FaceInfoGenerator from huggingface_hub import snapshot_download snapshot_download( 'DIAMONIK7777/antelopev2', local_dir='models/antelopev2', ) app_face = FaceInfoGenerator(root_dir=insightface_root_path) pipeline_mask = None app_face_ = None elif infer_mode=="story_maker": from insightface.app import FaceAnalysis from transformers import pipeline pipeline_mask = pipeline("image-segmentation", model=mask_repo, trust_remote_code=True) app_face = FaceAnalysis(name='buffalo_l', root=insightface_root_path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider']) app_face.prepare(ctx_id=0, det_size=(640, 640)) app_face_ = None elif infer_mode=="story_and_maker": from insightface.app import FaceAnalysis from transformers import pipeline pipeline_mask = pipeline("image-segmentation", model=mask_repo, trust_remote_code=True) if use_photov2: from .utils.insightface_package import FaceAnalysis2 if auraface: from huggingface_hub import snapshot_download snapshot_download( "fal/AuraFace-v1", local_dir="models/auraface", ) app_face = FaceAnalysis2(name="auraface", providers=["CUDAExecutionProvider", "CPUExecutionProvider"], root=insightface_root_path, allowed_modules=['detection', 'recognition']) else: app_face = FaceAnalysis2(providers=['CUDAExecutionProvider'], allowed_modules=['detection', 'recognition']) app_face.prepare(ctx_id=0, det_size=(640, 640)) app_face_ = FaceAnalysis(name='buffalo_l', root=insightface_root_path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider']) app_face_.prepare(ctx_id=0, det_size=(640, 640)) else: app_face = FaceAnalysis(name='buffalo_l', root=insightface_root_path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider']) app_face.prepare(ctx_id=0, det_size=(640, 640)) app_face_ = None elif infer_mode=="flux_pulid": import insightface from facexlib.parsing import init_parsing_model from facexlib.utils.face_restoration_helper import FaceRestoreHelper from insightface.app import FaceAnalysis from huggingface_hub import snapshot_download # antelopev2 snapshot_download('DIAMONIK7777/antelopev2', local_dir='models/antelopev2') providers = ['CPUExecutionProvider'] if onnx_provider == 'cpu' else ['CUDAExecutionProvider', 'CPUExecutionProvider'] app_face = FaceAnalysis(name='antelopev2', root=insightface_root_path, providers=providers) app_face.prepare(ctx_id=0, det_size=(640, 640)) # face_helper face_helper = FaceRestoreHelper( upscale_factor=1, face_size=512, crop_ratio=(1, 1), det_model='retinaface_resnet50', save_ext='png', device=device,) face_helper.face_parse = None face_helper.face_parse = init_parsing_model(model_name='bisenet', device=device) app_face_ = face_helper handler_ante = insightface.model_zoo.get_model('models/antelopev2/glintr100.onnx',providers=providers) handler_ante.prepare(ctx_id=0) pipeline_mask = handler_ante elif infer_mode=="infiniteyou": from facexlib.recognition import init_recognition_model from insightface.app import FaceAnalysis # Load face encoder app_face = FaceAnalysis(name='antelopev2', root=insightface_root_path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider']) app_face.prepare(ctx_id=0, det_size=(640, 640)) app_face_ = init_recognition_model('arcface', device='cuda') pipeline_mask = None else: app_face = None pipeline_mask = None app_face_ = None return app_face,pipeline_mask,app_face_ def get_float(str_in): list_str=str_in.split(",") float_box=[float(x) for x in list_str] return float_box def adjust_indices(original_indices, deleted_indices): """根据删除的索引列表调整原索引""" # 处理删除列表为空的特殊情况 if not deleted_indices: return original_indices.copy() # 直接返回原索引,无需调整 deleted_sorted = sorted(deleted_indices) adjusted = [] for idx in original_indices: # 计算偏移量:有多少个删除索引 < 当前索引 offset = sum(1 for d in deleted_sorted if d < idx) new_idx = idx - offset # 如果原索引未被删除,则保留 if idx not in deleted_sorted: adjusted.append(new_idx) else: adjusted.append(-1) # 标记为无效 return adjusted def get_insight_dict(app_face,app_face_,pipeline_mask,infer_mode,use_photov2,image_list, character_list_,condition_image,width, height,model=None,image_proj_model=None): input_id_emb_s_dict = {} input_id_img_s_dict = {} input_id_emb_un_dict = {} for ind, img in enumerate(image_list): # 最大只有2个ID if infer_mode == "story" and use_photov2: from .utils.insightface_package import analyze_faces img_ = np.array(img) img_ = cv2.cvtColor(img_, cv2.COLOR_RGB2BGR) faces = analyze_faces(app_face, img_, ) id_embed_list = torch.from_numpy((faces[0]['embedding'])) crop_image = img_ uncond_id_embeddings = None elif infer_mode == "kolor_face": device = ( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) face_info = app_face.get_faceinfo_one_img(img) face_bbox_square = face_bbox_to_square(face_info["bbox"]) crop_image = img.crop(face_bbox_square) crop_image = crop_image.resize((336, 336)) face_embeds = torch.from_numpy(np.array([face_info["embedding"]])) id_embed_list = face_embeds.to(device, dtype=torch.float16) uncond_id_embeddings = None elif infer_mode=="story_maker": crop_image = pipeline_mask(img, return_mask=True).convert('RGB') # outputs a pillow mask # timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") # crop_image.copy().save(os.path.join(folder_paths.get_output_directory(),f"{timestamp}_mask.png")) face_info = app_face.get(cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)) id_embed_list = sorted(face_info,key=lambda x: (x['bbox'][2] - x['bbox'][0]) * (x['bbox'][3] - x['bbox'][1]))[-1] # only use the maximum face uncond_id_embeddings = img elif infer_mode=="story_and_maker": if use_photov2: from .utils.insightface_package import analyze_faces img = np.array(img) img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) faces = analyze_faces(app_face, img, ) id_embed_list = torch.from_numpy((faces[0]['embedding'])) crop_image = pipeline_mask(img, return_mask=True).convert( 'RGB') # outputs a pillow mask face_info = app_face_.get(cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)) uncond_id_embeddings = sorted(face_info,key=lambda x: (x['bbox'][2] - x['bbox'][0]) * (x['bbox'][3] - x['bbox'][1]))[-1] # only use the maximum face #photomake_mode = "v2" # make+v2模式下,emb存v2的向量,corp 和 unemb 存make的向量 else: # V1不需要调用emb crop_image = pipeline_mask(img, return_mask=True).convert( 'RGB') # outputs a pillow mask face_info = app_face.get(cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)) id_embed_list = sorted(face_info,key=lambda x: (x['bbox'][2] - x['bbox'][0]) * (x['bbox'][3] - x['bbox'][1]))[-1] # only use the maximum face uncond_id_embeddings = img elif infer_mode=="flux_pulid": id_image = resize_numpy_image_long(img, 1024) use_true_cfg = abs(1.0 - 1.0) > 1e-2 id_embed_list, uncond_id_embeddings=model.pulid_model.get_id_embedding_( id_image,app_face_,app_face,pipeline_mask,cal_uncond=use_true_cfg) #id_embed_list, uncond_id_embeddings = pipe.pulid_model.get_id_embedding(id_image,cal_uncond=use_true_cfg) crop_image = img elif infer_mode=="infiniteyou": def _detect_face(app_face, id_image_cv2): face_info = app_face.get(id_image_cv2) if face_info: return face_info else: print("No face detected in the input ID image") return [] from .pipelines.pipeline_infu_flux import extract_arcface_bgr_embedding,resize_and_pad_image,draw_kps # Extract ID embeddings print('Preparing ID embeddings') id_image_cv2 = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) face_info = _detect_face(app_face,id_image_cv2) if len(face_info) == 0: raise ValueError('No face detected in the input ID image') face_info = sorted(face_info, key=lambda x:(x['bbox'][2]-x['bbox'][0])*(x['bbox'][3]-x['bbox'][1]))[-1] # only use the maximum face landmark = face_info['kps'] id_embed = extract_arcface_bgr_embedding(id_image_cv2, landmark, app_face_) id_embed = id_embed.clone().unsqueeze(0).float().cuda() id_embed = id_embed.reshape([1, -1, 512]) id_embed = id_embed.to(device='cuda', dtype=torch.bfloat16) with torch.no_grad(): id_embed = image_proj_model(id_embed) bs_embed, seq_len, _ = id_embed.shape id_embed = id_embed.repeat(1, 1, 1) id_embed = id_embed.view(bs_embed * 1, seq_len, -1) id_embed = id_embed.to(device='cuda', dtype=torch.bfloat16) # Load control image print('Preparing the control image') if isinstance(condition_image, torch.Tensor): e1, _, _, _ = condition_image.size() if e1 == 1: cn_image_load = [nomarl_upscale(condition_image, width, height)] else: img_list = list(torch.chunk(condition_image, chunks=e1)) cn_image_load = [nomarl_upscale(img, width, height) for img in img_list] # control_image = control_image.convert("RGB") # control_image = resize_and_pad_image(control_image, (width, height)) control_image=[] #如果是单人多张控制图,可能导致失序,所以统一改成列表,并在采样的时候依次调用 for img in cn_image_load: face_info = _detect_face(app_face,cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)) if len(face_info) == 0: print('No face detected in the control image,use empty image,无法识别到面部,加载全黑图片替代.') #卡通人物很难识别,所以避免反复加载, 直接用黑图 face_cn=Image.fromarray(np.zeros([height, width, 3]).astype(np.uint8)) else: face_info = sorted(face_info, key=lambda x:(x['bbox'][2]-x['bbox'][0])*(x['bbox'][3]-x['bbox'][1]))[-1] # only use the maximum face face_cn = draw_kps(img, face_info['kps']) control_image.append(face_cn) else: out_img = np.zeros([height, width, 3]) control_image = Image.fromarray(out_img.astype(np.uint8)) id_embed_list=id_embed crop_image = control_image # inf use crop to control img uncond_id_embeddings = None else: id_embed_list = None uncond_id_embeddings = None crop_image = None input_id_img_s_dict[character_list_[ind]] = [crop_image] input_id_emb_s_dict[character_list_[ind]] = [id_embed_list] input_id_emb_un_dict[character_list_[ind]] = [uncond_id_embeddings] app_face = None app_face_= None pipeline_mask =None gc_cleanup() if isinstance(condition_image, torch.Tensor) and infer_mode=="story_maker": e1, _, _, _ = condition_image.size() if e1 == 1: cn_image_load = [nomarl_upscale(condition_image, width, height)] else: img_list = list(torch.chunk(condition_image, chunks=e1)) cn_image_load = [nomarl_upscale(img, width, height) for img in img_list] input_id_cloth_dict = {} if len(cn_image_load)>2: cn_image_load_role=cn_image_load[0:2] else: cn_image_load_role=cn_image_load for ind, img in enumerate(cn_image_load_role): input_id_cloth_dict[character_list_[ind]] = [img] if len(cn_image_load)>2: #处理多张control img my_list=cn_image_load[2:] for ind,img in enumerate(my_list): input_id_cloth_dict[f"dual{ind}"] = [img] else: input_id_cloth_dict = {} return input_id_emb_s_dict,input_id_img_s_dict,input_id_emb_un_dict,input_id_cloth_dict def load_model_tag(repo,device,select_method): if "flor" in select_method.lower():#"thwri/CogFlorence-2-Large-Freeze" #pip install flash_attn from transformers import AutoModelForCausalLM, AutoProcessor, AutoConfig model = AutoModelForCausalLM.from_pretrained(repo, trust_remote_code=True).to( device) processor = AutoProcessor.from_pretrained(repo, trust_remote_code=True) else: model = AutoModel.from_pretrained(repo, trust_remote_code=True) processor = AutoTokenizer.from_pretrained(repo, trust_remote_code=True)#tokenizer model.eval() return model,processor class StoryLiteTag: def __init__(self, device,temperature,select_method,repo="pzc163/MiniCPMv2_6-prompt-generator",): self.device = device self.repo = repo self.select_method=select_method self.model, self.processor=load_model_tag(self.repo, self.device,self.select_method) self.temperature=temperature def run_tag(self,image): if "flor" in self.select_method.lower(): inputs = self.processor(text="" , images=image, return_tensors="pt").to(device) generated_ids = self.model.generate( input_ids=inputs["input_ids"], pixel_values=inputs["pixel_values"], max_new_tokens=1024, num_beams=3, do_sample=True ) generated_text = self.processor.batch_decode(generated_ids, skip_special_tokens=False)[0] parsed_answer = self.processor.post_process_generation(generated_text, task="" , image_size=(image.width, image.height)) res=parsed_answer[""] else: question = 'Provide a detailed description of the details and content contained in the image, and generate a short prompt that can be used for image generation tasks in Stable Diffusion,remind you only need respons prompt itself and no other information.' msgs = [{'role': 'user', 'content': [image, question]}] res = self.model.chat( image=None, msgs=msgs, tokenizer=self.processor,# tokenizer temperature=self.temperature ) res=res.split(":",1)[1].strip('"') s=res.strip() res=re.sub(r'^\n+|\n+$', '', s) res.strip("'") logging.info(f"{res}") return res def images_generator(img_list: list, ): # get img size sizes = {} for image_ in img_list: if isinstance(image_, Image.Image): count = sizes.get(image_.size, 0) sizes[image_.size] = count + 1 elif isinstance(image_, np.ndarray): count = sizes.get(image_.shape[:2][::-1], 0) sizes[image_.shape[:2][::-1]] = count + 1 else: raise "unsupport image list,must be pil or cv2!!!" size = max(sizes.items(), key=lambda x: x[1])[0] yield size[0], size[1] # any to tensor def load_image(img_in): if isinstance(img_in, Image.Image): img_in = img_in.convert("RGB") i = np.array(img_in, dtype=np.float32) i = torch.from_numpy(i).div_(255) if i.shape[0] != size[1] or i.shape[1] != size[0]: i = torch.from_numpy(i).movedim(-1, 0).unsqueeze(0) i = common_upscale(i, size[0], size[1], "lanczos", "center") i = i.squeeze(0).movedim(0, -1).numpy() return i elif isinstance(img_in, np.ndarray): i = cv2.cvtColor(img_in, cv2.COLOR_BGR2RGB).astype(np.float32) i = torch.from_numpy(i).div_(255) print(i.shape) return i else: raise "unsupport image list,must be pil,cv2 or tensor!!!" total_images = len(img_list) processed_images = 0 pbar = ProgressBar(total_images) images = map(load_image, img_list) try: prev_image = next(images) while True: next_image = next(images) yield prev_image processed_images += 1 pbar.update_absolute(processed_images, total_images) prev_image = next_image except StopIteration: pass if prev_image is not None: yield prev_image def load_images_list(img_list: list, ): gen = images_generator(img_list) (width, height) = next(gen) images = torch.from_numpy(np.fromiter(gen, np.dtype((np.float32, (height, width, 3))))) if len(images) == 0: raise FileNotFoundError(f"No images could be loaded .") return images def fitter_cf_model_type(model): VALUE_=model.model.model_type.value if VALUE_ == 8: cf_model_type = "FLUX" elif VALUE_ == 4: cf_model_type = "CASCADE" elif VALUE_ == 6: cf_model_type = "FLOW" elif VALUE_ == 5: cf_model_type = "EDM" elif VALUE_ == 1: cf_model_type = "EPS" elif VALUE_ == 2: cf_model_type = "V_PREDICTION" elif VALUE_ == 3: cf_model_type = "V_PREDICTION_EDM" elif VALUE_ == 7: cf_model_type = "PREDICTION_CONTINUOUS" else: raise "unsupport checkpoints" return cf_model_type def pre_text2infer(role_text,scene_text,lora_trigger_words,use_lora,tag_list): ''' Args: role_index_dict: {'[Taylor]': [0, 1], '[Lecun]': [2, 3]} invert_role_index_dict{0: ['[Taylor]'], 1: ['[Taylor]'], 2: ['[Lecun]'], 3: ['[Lecun]']} ref_role_index_dict {'[Taylor]': [0, 1], '[Lecun]': [2, 3]} ref_role_totals[0, 1, 2, 3] role_list ['[Taylor]', '[Lecun]'] role_dict {'[Taylor]': ' a woman img, wearing a white T-shirt, blue loose hair.', '[Lecun]': ' a man img,wearing a suit,black hair.'} nc_txt_list [' a panda'] nc_indexs[4] positions_index_dual[] positions_index_char_1 0 2 positions_index_char_2 [] prompts_dual[] #['[A] play whith [B] in the garden'] index_char_1_list [0, 1] index_char_2_list[2, 3] Returns: character_index_dict:{'[Taylor]': [0, 3], '[sam]': [1, 2]},if 1 role {'[Taylor]': [0, 1, 2]} ''' add_trigger_words = " " + lora_trigger_words + " style " # pre role_text role_dict, role_list = character_to_dict(role_text, use_lora, add_trigger_words) id_len=len(role_dict) #pre scene_text scene_text_origin = [i.strip() for i in scene_text.splitlines()] scene_text_origin = [i for i in scene_text_origin if '[' in i] # 删除空行 prompt_sence = [i for i in scene_text_origin if not len(extract_content_from_brackets(i)) >= 2] # 剔除双角色的场景词 positions_index_dual = [index for index, prompt in enumerate(scene_text_origin) if len(extract_content_from_brackets(prompt)) >= 2] #获取双角色出现的位置 prompts_dual = [prompt for prompt in scene_text_origin if len(extract_content_from_brackets(prompt)) >= 2] # 改成单句中双方括号方法,利于MS组句,[A]... [B]...[C] #print(id_len,role_list) if id_len == 2: index_char_1_list=[index for index, prompt in enumerate(scene_text_origin) if role_list[0] in prompt] positions_index_char_1 = index_char_1_list[0] # 获取角色出现的索引列表,并获取首次出现的位置 index_char_2_list=[index for index, prompt in enumerate(scene_text_origin) if role_list[1] in prompt] positions_index_char_2 = index_char_2_list[0] # 获取角色出现的索引列表,并获取首次出现的位置 # print(positions_index_char_1, positions_index_char_2) #0,2 else: index_char_1_list=[index for index, prompt in enumerate(scene_text_origin) if role_list[0] in prompt] index_char_2_list=[] positions_index_char_1=[] positions_index_char_2=[] if index_char_1_list and index_char_2_list: #dual 情况下,该列表有误,须排除重复元素 common_ = set(index_char_1_list) & set(index_char_2_list) if common_: index_char_1_list=[x for x in index_char_1_list if x not in common_] index_char_2_list = [x for x in index_char_2_list if x not in common_] clipped_prompts = prompt_sence[:] # copy nc_indexs = [] for ind, prompt in enumerate(clipped_prompts): #获取NC的index if "[NC]" in prompt: nc_indexs.append(ind) if ind < id_len: raise f"The first [role] row need be a id prompts, cannot use [NC]!" prompts = [ i if "[NC]" not in i else i.replace("[NC]", "") for i in clipped_prompts] #去除# prompts = [prompt.rpartition("#")[0] if "#" in prompt else prompt for prompt in prompts] # character_dict:{'[Taylor]': ' a woman img, wearing a white T-shirt, blue loose hair.'},character_list:['[Taylor]'] 1role #character_dict:{'[Taylor]': ' a woman img, wearing a white T-shirt, blue loose hair.', '[Lecun]': ' a man img,wearing a suit,black hair.'},character_list:['[Taylor]', '[Lecun]'] 2 role #获取字典,实际用词等 role_index_dict, invert_role_index_dict, replace_prompts, ref_role_index_dict, ref_role_totals= process_original_text(role_dict, prompts) if tag_list: #tag方法 if len(tag_list) < len(replace_prompts): raise "The number of input condition images is less than the number of scene prompts!" replace_prompts = [prompt + " " + tag_list[i] for i, prompt in enumerate(replace_prompts)] if nc_indexs: for x in nc_indexs: # 获取NC列表 nc_txt_list = [item for i, item in enumerate(replace_prompts) if i == x] for x in nc_indexs: # 去除NC列表 replace_prompts = [item for i, item in enumerate(replace_prompts) if i != x] else: nc_txt_list = [] replace_prompts=[i for i in replace_prompts] return replace_prompts,role_index_dict,invert_role_index_dict,ref_role_index_dict,ref_role_totals,role_list,role_dict,nc_txt_list,nc_indexs,positions_index_char_1,positions_index_char_2,positions_index_dual,prompts_dual,index_char_1_list,index_char_2_list def convert_cf2diffuser(model): from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_ldm_unet_checkpoint from diffusers import UNet2DConditionModel config_file = os.path.join(cur_path,"local_repo/unet/config.json") cf_state_dict = model.diffusion_model.state_dict() unet_state_dict = model.model_config.process_unet_state_dict_for_saving(cf_state_dict) unet_config = UNet2DConditionModel.load_config(config_file) Unet = UNet2DConditionModel.from_config(unet_config).to(device, torch.float16) cf_state_dict = convert_ldm_unet_checkpoint(unet_state_dict, Unet.config) Unet.load_state_dict(cf_state_dict, strict=False) del cf_state_dict,unet_state_dict gc.collect() torch.cuda.empty_cache() return Unet def cf_clip(txt_list, clip, infer_mode,role_list,input_split=True): if infer_mode == "classic": input_split= False if len(role_list)==1: input_split= False if input_split: role_emb_dict={} for role,role_text_list in zip(role_list,txt_list): pos_cond_list=[] for j in role_text_list: tokens_p = clip.tokenize(j) output_p = clip.encode_from_tokens(tokens_p, return_dict=True) # {"pooled_output":tensor} cond_p = output_p.pop("cond") if cond_p.shape[1] / 77 > 1 and infer_mode != "classic": # logging.warning("prompt'tokens length is abvoe 77,split it") cond_p = torch.chunk(cond_p, cond_p.shape[1] // 77, dim=1)[0] positive = [cond_p, output_p] pos_cond_list.append(positive) role_emb_dict[role]=pos_cond_list return role_emb_dict pos_cond_list = [] for i in txt_list[0]: tokens_p = clip.tokenize(i) output_p = clip.encode_from_tokens(tokens_p, return_dict=True) # {"pooled_output":tensor} cond_p = output_p.pop("cond") if cond_p.shape[1] / 77 > 1 and infer_mode != "classic": # logging.warning("prompt'tokens length is abvoe 77,split it") cond_p = torch.chunk(cond_p, cond_p.shape[1] // 77, dim=1)[0] if infer_mode == "classic": positive = [[cond_p, output_p]] else: positive = [cond_p, output_p] # logging.info(f"sampler text is {i}") pos_cond_list.append(positive) return pos_cond_list def get_eot_idx_cf(tokenizer, prompt): words = prompt.split() start = 1 for w in words: start += len(tokenizer.encode(w)) - 2 return start def get_phrase_idx_cf(tokenizer, phrase, prompt, get_last_word=False, num=0): def is_equal_words(pr_words, ph_words): if len(pr_words) != len(ph_words): return False for pr_word, ph_word in zip(pr_words, ph_words): if "-"+ph_word not in pr_word and ph_word != re.sub(r'[.!?,:]$', '', pr_word): return False return True phrase_words = phrase.split() if len(phrase_words) == 0: return [0, 0], None if get_last_word: phrase_words = phrase_words[-1:] # prompt_words = re.findall(r'\b[\w\'-]+\b', prompt) prompt_words = prompt.split() start = 1 end = 0 res_words = phrase_words for i in range(len(prompt_words)): if is_equal_words(prompt_words[i:i+len(phrase_words)], phrase_words): if num != 0: # skip this one num -= 1 continue end = start res_words = prompt_words[i:i+len(phrase_words)] res_words = [re.sub(r'[.!?,:]$', '', w) for w in res_words] prompt_words[i+len(phrase_words)-1] = res_words[-1] # remove the last punctuation for j in range(i, i+len(phrase_words)): end += len(tokenizer.encode(prompt_words[j])) - 2 break else: start += len(tokenizer.encode(prompt_words[i])) - 2 if end == 0: return [0, 0], None return [start, end], res_words def get_phrases_idx_cf(tokenizer, phrases, prompt): res = [] phrase_cnt = {} for phrase in phrases: if phrase in phrase_cnt: cur_cnt = phrase_cnt[phrase] phrase_cnt[phrase] += 1 else: cur_cnt = 0 phrase_cnt[phrase] = 1 res.append(get_phrase_idx_cf(tokenizer, phrase, prompt, num=cur_cnt)[0]) return res def replicate_data_by_indices(data_list, index_list1, index_list2): # 确定新列表的长度 max_index = max(max(index_list1), max(index_list2)) if (index_list1 and index_list2) else 0 new_list = [None] * (max_index + 1) # 根据索引填充数据 for idx in index_list1: new_list[idx] = data_list[0] for idx in index_list2: new_list[idx] = data_list[1] return new_list def get_ms_phrase_emb(boxes, device, weight_dtype, drop_grounding_tokens, bsz, phrase_idxes, num_samples, eot_idxes,phrases,clip,tokenizer): cross_attention_kwargs = None grounding_kwargs = None if boxes is not None: boxes = torch.tensor(boxes).to(device, weight_dtype) #torch.Size([1, 2, 4]) if phrases is not None: drop_grounding_tokens = drop_grounding_tokens if drop_grounding_tokens is not None else [0] * bsz batch_boxes = boxes.view(bsz * boxes.shape[1], -1).to(device) phrase_input_ids=[] for phrase in phrases: phrase_input_id = tokenizer(phrase, max_length=tokenizer.model_max_length, padding="max_length", truncation=True, return_tensors="pt").input_ids int_list = phrase_input_id.tolist()[0] clean_input_ids_1=[(i,1.0) for i in int_list] clean_input_ids_2=[(i,1.0) for i in int_list if i==int_list[0] or i==49407 ] clean_input_ids_2=clean_input_ids_2[:77] if len(clean_input_ids_2) >=77 else clean_input_ids_2 + [(0,1.0)]*(77 - len(clean_input_ids_2)) phrase_input_ids.append([clean_input_ids_1,clean_input_ids_2]) phrase_embeds_list = [] for i in phrase_input_ids: _, pooled_prompt_embed_= clip.cond_stage_model.clip_l.encode_token_weights(i) pooled_prompt_embed_= pooled_prompt_embed_.to(device,dtype=weight_dtype) phrase_embeds_list.append(pooled_prompt_embed_) #phrase_input_id = clip.tokenize(phrase, return_word_ids=False)["l"] #output_=clip.cond_stage_model.clip_l.encode_token_weights(phrase_input_id)[1] phrase_embeds=torch.cat(phrase_embeds_list,dim=0) #print(phrase_embeds.shape,phrase_embeds.is_cuda,batch_boxes.shape,batch_boxes.is_cuda)#torch.Size([2, 768]) torch.Size([2 4]) grounding_kwargs = {"boxes": batch_boxes, "phrase_embeds": phrase_embeds,"drop_grounding_tokens": drop_grounding_tokens} else: grounding_kwargs = None boxes = torch.repeat_interleave(boxes, repeats=num_samples, dim=0) uncond_boxes = torch.zeros_like(boxes) boxes = torch.cat([uncond_boxes, boxes], dim=0) cross_attention_kwargs = {"boxes": boxes} if phrase_idxes is not None: # phrase_idxes = torch.tensor(phrase_idxes).to(device, torch.int) # eot_idxes = torch.tensor(eot_idxes).to(device, torch.int) phrase_idxes = torch.tensor(phrase_idxes).to(device, weight_dtype) eot_idxes = torch.tensor(eot_idxes).to(device, weight_dtype) phrase_idxes = torch.repeat_interleave(phrase_idxes, repeats=num_samples, dim=0) eot_idxes = torch.repeat_interleave(eot_idxes, repeats=num_samples, dim=0) uncond_phrase_idxes = torch.zeros_like(phrase_idxes) uncond_eot_idxes = torch.zeros_like(eot_idxes) phrase_idxes = torch.cat([uncond_phrase_idxes, phrase_idxes], dim=0) eot_idxes = torch.cat([uncond_eot_idxes, eot_idxes], dim=0) if cross_attention_kwargs is None: cross_attention_kwargs = {"phrase_idxes": phrase_idxes, "eot_idxes": eot_idxes} else: cross_attention_kwargs["phrase_idxes"] = phrase_idxes cross_attention_kwargs["eot_idxes"] = eot_idxes return cross_attention_kwargs,grounding_kwargs def Infer_MSdiffusion(model, photomake_or_ipadapter_path,image_embeds, prompt_embeds_, negative_prompt_embeds_,grounding_kwargs,cross_attention_kwargs, bsz,mask_threshold,height,width,steps,seed,cfg,pooled_prompt_embeds,negative_pooled_prompt_embeds,): image_proj_model = Resampler( dim=1280, depth=4, dim_head=64, heads=20, num_queries=16, embedding_dim=1664, output_dim=model.unet.config.cross_attention_dim, ff_mult=4, latent_init_mode="grounding", phrase_embeddings_dim=768, ).to(device, dtype=torch.float16) PIPE = MSAdapterWarpper(model, image_proj_model, ckpt_path=photomake_or_ipadapter_path, device=device, num_tokens=16) samples=PIPE.generate(model, image_embeds, prompt_embeds_, negative_prompt_embeds_,grounding_kwargs,cross_attention_kwargs, bsz,height,width,steps,seed,cfg,pooled_prompt_embeds,negative_pooled_prompt_embeds,scale=1.0, num_samples=bsz, weight_dtype=torch.float16, subject_scales=None, mask_threshold=mask_threshold, start_step=5) return samples def convert_clip2diffuser(clip): from transformers import ( CLIPTextModel,CLIPTextModelWithProjection, CLIPTextConfig, ) from contextlib import nullcontext try: from accelerate import init_empty_weights from accelerate.utils import set_module_tensor_to_device is_accelerate_available = True except: pass import comfy.model_management as mm offload_device=mm.unet_offload_device() text_encoder_config=CLIPTextConfig.from_pretrained(os.path.join(cur_path, 'local_repo/text_encoder'), local_files_only=True) ctx = init_empty_weights if is_accelerate_available else nullcontext with ctx(): text_encoder = CLIPTextModel(text_encoder_config) text_encoder_sd = clip.get_sd() text_encoder_2_sd = clip.get_sd() from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_open_clip_checkpoint,convert_ldm_clip_checkpoint text_encoder = convert_ldm_clip_checkpoint(text_encoder_sd, text_encoder=text_encoder) text_encoder=None text_encoder_2 = convert_open_clip_checkpoint(text_encoder_2_sd,config_name=os.path.join(cur_path, 'local_repo/text_encoder_2')) return text_encoder,text_encoder_2 def convert_cfvae2diffuser(VAE,use_flux=False): from diffusers import AutoencoderKL from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_ldm_vae_checkpoint if use_flux: vae_config = os.path.join(cur_path, "config/FLUX.1-dev/vae/config.json") else: vae_config = os.path.join(cur_path, "local_repo/vae/config.json") vae_state_dict=VAE.get_sd() ae_config = AutoencoderKL.load_config(vae_config) if not use_flux: AE = AutoencoderKL.from_config(ae_config).to(device, torch.float16) cf_state_dict = convert_ldm_vae_checkpoint(vae_state_dict, AE.config) AE.load_state_dict(cf_state_dict, strict=False) del cf_state_dict,vae_state_dict else: AE = AutoencoderKL.from_config(ae_config).to(device, torch.bfloat16) AE.load_state_dict(vae_state_dict, strict=False) del vae_state_dict torch.cuda.empty_cache() return AE def Loader_storydiffusion(cf_model,photomake_ckpt_path,VAE,UNET=None): sdxl_repo = os.path.join(cur_path, "local_repo") vae_config=OmegaConf.load(os.path.join(cur_path,"local_repo/vae/config.json")) from .utils.pipeline_wrapper import StableDiffusionXLPipelineWrapper from .utils.pipeline_img import PhotoMakerStableDiffusionXLPipeline as PhotoMakerStableDiffusionXLPipelineWrapper from .utils.pipeline_v2_warrper import PhotoMakerStableDiffusionXLPipeline as PhotoMakerStableDiffusionXLPipelineV2 if cf_model is not None: Unet=convert_cf2diffuser(cf_model.model) if photomake_ckpt_path is not None: # guess img2img if VAE is None: raise "need link a SDXL vae when use img2img!" vae = convert_cfvae2diffuser(VAE) if "v1" in photomake_ckpt_path: model = PhotoMakerStableDiffusionXLPipelineWrapper.from_pretrained(sdxl_repo, unet=Unet, vae=vae,text_encoder=None,text_encoder_2=None, torch_dtype=torch.float16, use_safetensors=True) model.load_photomaker_adapter( photomake_ckpt_path, subfolder="", weight_name="photomaker-v1.bin", trigger_word="img" # define the trigger word ) else: model = PhotoMakerStableDiffusionXLPipelineV2.from_pretrained(sdxl_repo, unet=Unet, vae=vae,text_encoder=None,text_encoder_2=None, torch_dtype=torch.float16, use_safetensors=True) model.load_photomaker_adapter( photomake_ckpt_path, subfolder="", weight_name="photomaker-v2.bin", trigger_word="img", pm_version='v2', ) else: model = StableDiffusionXLPipelineWrapper.from_pretrained(sdxl_repo, unet=Unet, vae_config=vae_config, torch_dtype=torch.float16, use_safetensors=True) elif UNET is not None: model = StableDiffusionXLPipelineWrapper.from_pretrained(sdxl_repo, unet=UNET.unet, vae_config=vae_config, torch_dtype=torch.float16, use_safetensors=True) else: raise "need link a comfyUI checkpoint model!" model.to(device) return model def Loader_story_maker(cf_model,ipadapter_ckpt_path,VAE,low_vram,lora_scale,controlnet=None,UNET=None): sdxl_repo = os.path.join(cur_path, "local_repo") #vae_config = OmegaConf.load(vae_config) if cf_model is not None: Unet = convert_cf2diffuser(cf_model.model) AE=convert_cfvae2diffuser(VAE) from .StoryMaker.pipeline_sdxl_storymaker_wrapper import StableDiffusionXLStoryMakerPipeline as StableDiffusionXLStoryMakerPipeline_wapper model = StableDiffusionXLStoryMakerPipeline_wapper.from_pretrained(sdxl_repo, vae=AE,unet=Unet,text_encoder=None,text_encoder_2=None, torch_dtype=torch.float16, use_safetensors=True) elif UNET is not None: AE=convert_cfvae2diffuser(VAE) from .StoryMaker.pipeline_sdxl_storymaker_wrapper import StableDiffusionXLStoryMakerPipeline as StableDiffusionXLStoryMakerPipeline_wapper model = StableDiffusionXLStoryMakerPipeline_wapper.from_pretrained(sdxl_repo, vae=AE,unet=UNET.unet,text_encoder=None,text_encoder_2=None, torch_dtype=torch.float16, use_safetensors=True) else: raise "need link a comfyUI checkpoint model!" if device != "mps": if not low_vram: model.cuda() model.load_storymaker_adapter(ipadapter_ckpt_path, scale=0.8, lora_scale=lora_scale, controlnet=controlnet) #model.scheduler = UniPCMultistepScheduler.from_config(model.scheduler.config) return model def Loader_Flux_Pulid(model,cf_model, ipadapter_ckpt_path,quantized_mode,aggressive_offload,offload,if_repo,clip_vision_path): logging.info("start flux-pulid processing...") from .PuLID.app_flux import FluxGenerator pipe = FluxGenerator(model, "cuda:0", offload,aggressive_offload, pretrained_model=ipadapter_ckpt_path, quantized_mode=quantized_mode, if_repo=if_repo,clip_vision_path=clip_vision_path) return pipe def Loader_InfiniteYou(extra_info,VAE,quantize_mode): logging.info("start InfiniteYou mode processing...") from .pipelines.pipeline_infu_flux import InfUFluxPipeline from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig,FluxTransformer2DModel from transformers import BitsAndBytesConfig as TransformersBitsAndBytesConfig,T5EncoderModel from .pipelines.resampler import Resampler # quantize T5 # quant_config = TransformersBitsAndBytesConfig( # load_in_4bit=True, # bnb_4bit_quant_type="nf4", # ) # text_encoder_2_4bit = T5EncoderModel.from_pretrained( # repo_id, # subfolder="text_encoder_2", # quantization_config=quant_config, # torch_dtype=torch.bfloat16, # ) # init nf4 repo_list=[i for i in [extra_info.get("repo1_path") , extra_info.get("repo2_path")] if i is not None] assert repo_list is not [] ,"repo_list is None" find_infusenet=[i for i in repo_list if "sim_stage1" in i or "aes_stage2" in i] assert len(find_infusenet)>=1 ,"no infusenet" repo_id=os.path.join(cur_path, "config/FLUX.1-dev") use_svdq=False if extra_info.get("svdq_repo") is not None: print("use svdq quantization") from nunchaku import NunchakuFluxTransformer2dModel use_svdq=True transformer = NunchakuFluxTransformer2dModel.from_pretrained(extra_info.get("svdq_repo"),offload=True) try: transformer.set_attention_impl("nunchaku-fp16") except: pass vae=convert_cfvae2diffuser(VAE,use_flux=True) elif extra_info.get("gguf_path") is not None: print("use gguf quantization") from diffusers import GGUFQuantizationConfig transformer = FluxTransformer2DModel.from_single_file( extra_info.get("gguf_path"), config=os.path.join(repo_id, "transformer"), quantization_config=GGUFQuantizationConfig(compute_dtype=torch.bfloat16), torch_dtype=torch.bfloat16, ) vae=convert_cfvae2diffuser(VAE,use_flux=True) elif extra_info.get("unet_path") is not None: if quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_single_file(extra_info.get("unet_path"), config=os.path.join(repo_id,"transformer/config.json"), torch_dtype=torch.bfloat16) else: from safetensors.torch import load_file t_state_dict=load_file(extra_info.get("unet_path")) unet_config = FluxTransformer2DModel.load_config(os.path.join(repo_id,"transformer/config.json")) transformer = FluxTransformer2DModel.from_config(unet_config).to(torch.bfloat16) transformer.load_state_dict(t_state_dict, strict=False) del t_state_dict gc_cleanup() else: vae = None find_flux=[i for i in repo_list if "flux" in i ] if not find_flux: raise "need fill flux repo in EasyFunction_Lite repo1 or repo2!" print("use nf4 quantization") if quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_pretrained( find_flux[0], subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig(load_in_8bit=True,), torch_dtype=torch.bfloat16, ) elif quantize_mode=="nf4": #nf4 transformer = FluxTransformer2DModel.from_pretrained( find_flux[0], subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ), torch_dtype=torch.bfloat16,) else: transformer = FluxTransformer2DModel.from_pretrained( find_flux[0], subfolder="transformer", torch_dtype=torch.bfloat16, ) infusenet_path = os.path.join(find_infusenet[0], 'InfuseNetModel') pipe = InfUFluxPipeline( repo_id,infusenet_path, text_encoder_2=None, text_encoder=None, transformer=transformer, vae=vae, use_svdq=use_svdq, ) # Load image proj model num_tokens = 8 # image_proj_num_tokens image_emb_dim = 512 image_proj_model = Resampler( dim=1280, depth=4, dim_head=64, heads=20, num_queries=num_tokens, embedding_dim=image_emb_dim, output_dim=4096, ff_mult=4, ) image_proj_model_path = os.path.join(find_infusenet[0], 'image_proj_model.bin') ipm_state_dict = torch.load(image_proj_model_path, map_location="cpu",weights_only=False) image_proj_model.load_state_dict(ipm_state_dict['image_proj']) del ipm_state_dict torch.cuda.empty_cache() image_proj_model.to('cuda', torch.bfloat16) image_proj_model.eval() pipe.pipe.enable_model_cpu_offload() return pipe,image_proj_model def load_pipeline_consistory(cf_model,VAE): from .consistory.consistory_unet_sdxl import ConsistorySDXLUNet2DConditionModel from .consistory.consistory_pipeline_wapper import ConsistoryExtendAttnSDXLPipeline as ConsistoryExtendAttnSDXLPipeline_wapper float_type = torch.float16 device = torch.device(f'cuda:0') if torch.cuda.is_available() else torch.device('cpu') if cf_model is not None: config_file = os.path.join(cur_path,"local_repo/unet/config.json") sdxl_repo = os.path.join(cur_path, "local_repo") from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_ldm_unet_checkpoint cf_state_dict = cf_model.model.diffusion_model.state_dict() unet_state_dict = cf_model.model.model_config.process_unet_state_dict_for_saving(cf_state_dict) unet_config = ConsistorySDXLUNet2DConditionModel.load_config(config_file) Unet = ConsistorySDXLUNet2DConditionModel.from_config(unet_config).to(torch.float16) cf_state_dict = convert_ldm_unet_checkpoint(unet_state_dict, Unet.config) Unet.load_state_dict(cf_state_dict, strict=False) del cf_state_dict,unet_state_dict gc_cleanup() AE=convert_cfvae2diffuser(VAE) story_pipeline=ConsistoryExtendAttnSDXLPipeline_wapper.from_pretrained(sdxl_repo,unet=Unet,vae=AE,text_encoder=None,text_encoder_2=None, torch_dtype=float_type, ) story_pipeline.to(device) else: raise "need link a sdxl checkpoints" story_pipeline.enable_freeu(s1=0.6, s2=0.4, b1=1.1, b2=1.2) return story_pipeline def Loader_KOLOR(repo_id,clip_vision_path,face_ckpt,): from .kolors.models.modeling_chatglm import ChatGLMModel from .kolors.models.tokenization_chatglm import ChatGLMTokenizer from transformers import CLIPVisionModelWithProjection,CLIPImageProcessor from diffusers import EulerDiscreteScheduler, UNet2DConditionModel, AutoencoderKL logging.info("loader kolor processing...") # text_encoder = ChatGLMModel.from_pretrained( # f'{repo_id}/text_encoder', torch_dtype=torch.float16).half() vae = AutoencoderKL.from_pretrained(f"{repo_id}/vae", revision=None).half() #tokenizer = ChatGLMTokenizer.from_pretrained(f'{repo_id}/text_encoder') scheduler = EulerDiscreteScheduler.from_pretrained(f"{repo_id}/scheduler") from .kolors.pipelines.pipeline_stable_diffusion_xl_chatglm_256_ipadapter_FaceID import \ StableDiffusionXLPipeline as StableDiffusionXLPipelineFaceID unet = UNet2DConditionModel.from_pretrained(f'{repo_id}/unet', revision=None).half() if clip_vision_path: clip_image_encoder = clip_vision_path clip_image_processor = CLIPImageProcessor(size=224, crop_size=224) use_singel_clip = True else: clip_image_encoder = CLIPVisionModelWithProjection.from_pretrained( f'{repo_id}/clip-vit-large-patch14-336', ignore_mismatched_sizes=True) clip_image_encoder.to("cuda") clip_image_processor = CLIPImageProcessor(size=336, crop_size=336) use_singel_clip = False pipe = StableDiffusionXLPipelineFaceID( vae=vae, text_encoder=None, tokenizer=None, unet=unet, scheduler=scheduler, face_clip_encoder=clip_image_encoder, face_clip_processor=clip_image_processor, force_zeros_for_empty_prompt=False, use_single_clip=use_singel_clip, ) pipe = pipe.to("cuda") pipe.load_ip_adapter_faceid_plus(face_ckpt, device="cuda") pipe.set_face_fidelity_scale(0.8) return pipe def GLM_clip(cur_path,chatglm3_path): #https://github.com/kijai/ComfyUI-KwaiKolorsWrapper/blob/main/nodes.py @kijai from .kolors.models.modeling_chatglm import ChatGLMModel, ChatGLMConfig from contextlib import nullcontext from comfy.utils import ProgressBar, load_torch_file try: from accelerate import init_empty_weights from accelerate.utils import set_module_tensor_to_device is_accelerate_available = True except: pass import comfy.model_management as mm import json offload_device=mm.unet_offload_device() text_encoder_config = os.path.join(cur_path, 'config/glm/text_encoder_config.json') with open(text_encoder_config, 'r') as file: config = json.load(file) text_encoder_config = ChatGLMConfig(**config) with (init_empty_weights() if is_accelerate_available else nullcontext()): text_encoder = ChatGLMModel(text_encoder_config) if '4bit' in chatglm3_path: text_encoder.quantize(4) elif '8bit' in chatglm3_path: text_encoder.quantize(8) text_encoder_sd = load_torch_file(chatglm3_path) if is_accelerate_available: for key in text_encoder_sd: set_module_tensor_to_device(text_encoder, key, device=offload_device, value=text_encoder_sd[key]) else: text_encoder.load_state_dict() return text_encoder def glm_single_encode(chatglm3_model, prompt_list,role_list, negative_prompt_, num_images_per_prompt,nc_mode=False): #https://github.com/kijai/ComfyUI-KwaiKolorsWrapper/blob/main/nodes.py @kijai import comfy.model_management as mm device = mm.get_torch_device() offload_device = mm.unet_offload_device() mm.unload_all_models() mm.soft_empty_cache() # Function to randomly select an option from the brackets # def choose_random_option(match): # options = match.group(1).split('|') # return random.choice(options) # # Randomly choose between options in brackets for prompt and negative_prompt # prompt = re.sub(r'\{([^{}]*)\}', choose_random_option, prompt) # negative_prompt = re.sub(r'\{([^{}]*)\}', choose_random_option, negative_prompt) # if "|" in prompt: # prompt = prompt.split("|") # negative_prompt = [negative_prompt] * len(prompt) # Replicate negative_prompt to match length of prompt list do_classifier_free_guidance = True #print(prompt) if nc_mode: only_role_emb,only_role_emb_ne = [],[] for prompt,negative_prompt in zip(prompt_list,[negative_prompt_]*len(prompt_list)): if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) # Define tokenizers and text encoders tokenizer = chatglm3_model['tokenizer'] text_encoder = chatglm3_model['text_encoder'] text_encoder.to(device) text_inputs = tokenizer( prompt, padding="max_length", max_length=256, truncation=True, return_tensors="pt", ).to(device) output = text_encoder( input_ids=text_inputs['input_ids'] , attention_mask=text_inputs['attention_mask'], position_ids=text_inputs['position_ids'], output_hidden_states=True) prompt_embeds = output.hidden_states[-2].permute(1, 0, 2).clone() # [batch_size, 77, 4096] text_proj = output.hidden_states[-1][-1, :, :].clone() # [batch_size, 4096] bs_embed, seq_len, _ = prompt_embeds.shape prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1) prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1) if do_classifier_free_guidance: uncond_tokens = [] if negative_prompt is None: uncond_tokens = [""] * batch_size elif prompt is not None and type(prompt) is not type(negative_prompt): raise TypeError( f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !=" f" {type(prompt)}." ) elif isinstance(negative_prompt, str): uncond_tokens = [negative_prompt] elif batch_size != len(negative_prompt): raise ValueError( f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:" f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches" " the batch size of `prompt`." ) else: uncond_tokens = negative_prompt max_length = prompt_embeds.shape[1] uncond_input = tokenizer( uncond_tokens, padding="max_length", max_length=max_length, truncation=True, return_tensors="pt", ).to(device) output = text_encoder( input_ids=uncond_input['input_ids'] , attention_mask=uncond_input['attention_mask'], position_ids=uncond_input['position_ids'], output_hidden_states=True) negative_prompt_embeds = output.hidden_states[-2].permute(1, 0, 2).clone() # [batch_size, 77, 4096] negative_text_proj = output.hidden_states[-1][-1, :, :].clone() # [batch_size, 4096] if do_classifier_free_guidance: # duplicate unconditional embeddings for each generation per prompt, using mps friendly method seq_len = negative_prompt_embeds.shape[1] negative_prompt_embeds = negative_prompt_embeds.to(dtype=text_encoder.dtype, device=device) negative_prompt_embeds = negative_prompt_embeds.repeat(1, num_images_per_prompt, 1) negative_prompt_embeds = negative_prompt_embeds.view( batch_size * num_images_per_prompt, seq_len, -1 ) bs_embed = text_proj.shape[0] text_proj = text_proj.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) negative_text_proj = negative_text_proj.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) math_emb=[prompt_embeds,text_proj] only_role_emb.append(math_emb) math_emb_n=[negative_prompt_embeds,negative_text_proj] only_role_emb_ne.append(math_emb_n) text_encoder.to(offload_device) mm.soft_empty_cache() gc.collect() return only_role_emb,only_role_emb_ne else: role_emb_dict={} for key,prompts in zip(role_list,prompt_list): only_role_emb,only_role_emb_ne = [],[] for prompt,negative_prompt in zip(prompts,[negative_prompt_]*len(prompts)): if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) # Define tokenizers and text encoders tokenizer = chatglm3_model['tokenizer'] text_encoder = chatglm3_model['text_encoder'] text_encoder.to(device) text_inputs = tokenizer( prompt, padding="max_length", max_length=256, truncation=True, return_tensors="pt", ).to(device) output = text_encoder( input_ids=text_inputs['input_ids'] , attention_mask=text_inputs['attention_mask'], position_ids=text_inputs['position_ids'], output_hidden_states=True) prompt_embeds = output.hidden_states[-2].permute(1, 0, 2).clone() # [batch_size, 77, 4096] text_proj = output.hidden_states[-1][-1, :, :].clone() # [batch_size, 4096] bs_embed, seq_len, _ = prompt_embeds.shape prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1) prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1) if do_classifier_free_guidance: uncond_tokens = [] if negative_prompt is None: uncond_tokens = [""] * batch_size elif prompt is not None and type(prompt) is not type(negative_prompt): raise TypeError( f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !=" f" {type(prompt)}." ) elif isinstance(negative_prompt, str): uncond_tokens = [negative_prompt] elif batch_size != len(negative_prompt): raise ValueError( f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:" f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches" " the batch size of `prompt`." ) else: uncond_tokens = negative_prompt max_length = prompt_embeds.shape[1] uncond_input = tokenizer( uncond_tokens, padding="max_length", max_length=max_length, truncation=True, return_tensors="pt", ).to(device) output = text_encoder( input_ids=uncond_input['input_ids'] , attention_mask=uncond_input['attention_mask'], position_ids=uncond_input['position_ids'], output_hidden_states=True) negative_prompt_embeds = output.hidden_states[-2].permute(1, 0, 2).clone() # [batch_size, 77, 4096] negative_text_proj = output.hidden_states[-1][-1, :, :].clone() # [batch_size, 4096] if do_classifier_free_guidance: # duplicate unconditional embeddings for each generation per prompt, using mps friendly method seq_len = negative_prompt_embeds.shape[1] negative_prompt_embeds = negative_prompt_embeds.to(dtype=text_encoder.dtype, device=device) negative_prompt_embeds = negative_prompt_embeds.repeat(1, num_images_per_prompt, 1) negative_prompt_embeds = negative_prompt_embeds.view( batch_size * num_images_per_prompt, seq_len, -1 ) bs_embed = text_proj.shape[0] text_proj = text_proj.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) negative_text_proj = negative_text_proj.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) math_emb=[prompt_embeds,text_proj] only_role_emb.append(math_emb) math_emb_n=[negative_prompt_embeds,negative_text_proj] only_role_emb_ne.append(math_emb_n) role_emb_dict[key]=only_role_emb text_encoder.to(offload_device) mm.soft_empty_cache() gc.collect() return role_emb_dict,only_role_emb_ne def encode_prompt_with_trigger_word(clip,model_, prompt: str, prompt_2 = None, num_id_images= 1, device = None, prompt_embeds = None, pooled_prompt_embeds= None, class_tokens_mask = None, nc_flag: bool = False, trigger_word="img", unet_dtype=torch.float16 ): device = device tokenizer_2=model_.tokenizer_2 tokenizer=model_.tokenizer #text_encoders=clip.encode_from_tokens if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) else: batch_size = prompt_embeds.shape[0] # Find the token id of the trigger word image_token_id = tokenizer_2.convert_tokens_to_ids(trigger_word) # Define tokenizers and text encoders tokenizers = [tokenizer, tokenizer_2] if tokenizer is not None else [tokenizer_2] # text_encoders = ( # [self.text_encoder, self.text_encoder_2] if self.text_encoder is not None else [self.text_encoder_2] # ) if prompt_embeds is None: prompt_2 = prompt_2 or prompt prompt_embeds_list = [] prompts = [prompt, prompt_2] for prompt, tokenizer,text_en in zip(prompts, tokenizers,[clip.cond_stage_model.clip_l.encode_token_weights,clip.cond_stage_model.clip_g.encode_token_weights]): input_ids = tokenizer.encode(prompt) # TODO: batch encode clean_index = 0 clean_input_ids = [] class_token_index = [] # Find out the corresponding class word token based on the newly added trigger word token for i, token_id in enumerate(input_ids): if token_id == image_token_id: class_token_index.append(clean_index - 1) else: clean_input_ids.append(token_id) clean_index += 1 if nc_flag: return None, None, None if len(class_token_index) > 1: raise ValueError( f"PhotoMaker currently does not support multiple trigger words in a single prompt.\ Trigger word: {trigger_word}, Prompt: {prompt}." ) elif len(class_token_index) == 0 and not nc_flag: raise ValueError( f"PhotoMaker currently does not support multiple trigger words in a single prompt.\ Trigger word: {trigger_word}, Prompt: {prompt}." ) class_token_index = class_token_index[0] # Expand the class word token and corresponding mask class_token = clean_input_ids[class_token_index] clean_input_ids = clean_input_ids[:class_token_index] + [class_token] * num_id_images + \ clean_input_ids[class_token_index+1:] # Truncation or padding max_len = tokenizer.model_max_length if len(clean_input_ids) > max_len: clean_input_ids = clean_input_ids[:max_len] else: clean_input_ids = clean_input_ids + [tokenizer.pad_token_id] * ( max_len - len(clean_input_ids) ) class_tokens_mask = [True if class_token_index <= i < class_token_index+num_id_images else False \ for i in range(len(clean_input_ids))] #print(clean_input_ids) #print(max_len) clean_input_ids=clean_input_ids[:77] if len(clean_input_ids) > 77 else clean_input_ids + [0]*(77 - len(clean_input_ids)) clean_input_ids_1=[(i,1.0) for i in clean_input_ids] clean_input_ids_2=[(i,1.0) for i in clean_input_ids if i==clean_input_ids[0] or i==49407 ] clean_input_ids_2=clean_input_ids_2[:77] if len(clean_input_ids_2) > 77 else clean_input_ids_2 + [(0,1.0)]*(77 - len(clean_input_ids_2)) clean_input_ids_list=[clean_input_ids_1,clean_input_ids_2] #print(clean_input_ids) #clean_input_ids_ = torch.tensor(clean_input_ids, dtype=torch.long).unsqueeze(0) class_tokens_mask = torch.tensor(class_tokens_mask, dtype=torch.bool).unsqueeze(0) prompt_embeds, pooled_prompt_embeds = text_en(clean_input_ids_list) # print(prompt_embeds.shape,pooled_prompt_embeds.shape)torch.Size([1, 154, 768]) torch.Size([1, 768]) torch.Size([1, 154, 1280]) torch.Size([1, 1280]) prompt_embeds_list.append((prompt_embeds,pooled_prompt_embeds)) #prompt_embeds = torch.concat(prompt_embeds_list, dim=-1) #prompt_embeds=prompt_embeds_list[1] pooled_prompt_embeds=prompt_embeds_list[1][1] # cut_to = min(prompt_embeds_list[0][0].shape[1], prompt_embeds_list[1][0].shape[1]) # print(cut_to) cut_to=77 prompt_embeds= torch.cat([prompt_embeds_list[0][0][:,:cut_to], prompt_embeds_list[1][0][:,:cut_to]], dim=-1) prompt_embeds = prompt_embeds.to(device=device,dtype=unet_dtype, ) class_tokens_mask = class_tokens_mask.to(device=device) # TODO: ignoring two-prompt case return prompt_embeds, pooled_prompt_embeds, class_tokens_mask def cf_clip_single(clip,prompt, prompt_2, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt, negative_prompt_2, prompt_embeds, negative_prompt_embeds, pooled_prompt_embeds, negative_pooled_prompt_embeds,): tokens_p = clip.tokenize(prompt) output_p = clip.encode_from_tokens(tokens_p, return_dict=True) # {"pooled_output":tensor} cond_p = output_p.pop("cond") if cond_p.shape[1] / 77 > 1 : logging.warning("prompt'tokens length is abvoe 77,split it") cond_p = torch.chunk(cond_p, cond_p.shape[1] // 77, dim=1)[0] pool_p=output_p.pop("pooled_output") tokens_n = clip.tokenize(negative_prompt) output_n = clip.encode_from_tokens(tokens_n, return_dict=True) # {"pooled_output":tensor} cond_n = output_n.pop("cond") if cond_n.shape[1] / 77 > 1 : logging.warning("prompt'tokens length is abvoe 77,split it") cond_n = torch.chunk(cond_n, cond_n.shape[1] // 77, dim=1)[0] pool_n = output_n.pop("pooled_output") return cond_p,cond_n,pool_p,pool_n # TODO: replace the pooled_prompt_embeds with text only prompt def photomaker_clip(clip,model_,prompt_list,negative_prompt,input_id_images,trigger_word="img",num_images_per_prompt=1,nc_flag=False,prompt_2=None,prompt_embeds=None,pooled_prompt_embeds=None,class_tokens_mask=None,prompt_embeds_text_only=None,negative_pooled_prompt_embeds=None): id_encoder=model_.id_encoder id_image_processor=model_.id_image_processor tokenizer=model_.tokenizer_2 batch_size=len(prompt_list) num_id_images = len(input_id_images) #双角色时,须确保输入的图片是列表,且跟prompt对应上 prompt_arr = prompt_list negative_prompt_embeds_arr = [] prompt_embeds_text_only_arr = [] prompt_embeds_arr = [] latents_arr = [] add_time_ids_arr = [] negative_pooled_prompt_embeds_arr = [] pooled_prompt_embeds_text_only_arr = [] pooled_prompt_embeds_arr = [] for prompt in prompt_arr: ( prompt_embeds, pooled_prompt_embeds, class_tokens_mask, ) = encode_prompt_with_trigger_word(clip,model_, prompt=prompt, prompt_2=prompt_2, device=device, num_id_images=num_id_images, prompt_embeds=prompt_embeds, pooled_prompt_embeds=pooled_prompt_embeds, class_tokens_mask=class_tokens_mask, nc_flag = nc_flag, ) # 4. Encode input prompt without the trigger word for delayed conditioning # encode, remove trigger word token, then decode tokens_text_only = tokenizer.encode(prompt, add_special_tokens=False) trigger_word_token = tokenizer.convert_tokens_to_ids(trigger_word) if not nc_flag: tokens_text_only.remove(trigger_word_token) prompt_text_only = tokenizer.decode(tokens_text_only, add_special_tokens=False) #print(prompt_text_only) ( prompt_embeds_text_only, negative_prompt_embeds, pooled_prompt_embeds_text_only, # TODO: replace the pooled_prompt_embeds with text only prompt negative_pooled_prompt_embeds, ) = cf_clip_single(clip, prompt=prompt_text_only, prompt_2=prompt_2, device=device, num_images_per_prompt=num_images_per_prompt, do_classifier_free_guidance=True, negative_prompt=negative_prompt, negative_prompt_2=None, prompt_embeds=prompt_embeds_text_only, negative_prompt_embeds=None, pooled_prompt_embeds=None, negative_pooled_prompt_embeds=negative_pooled_prompt_embeds, ) # 5. Prepare the input ID images dtype = next(id_encoder.parameters()).dtype if not isinstance(input_id_images[0], torch.Tensor): id_pixel_values = id_image_processor(input_id_images, return_tensors="pt").pixel_values id_pixel_values = id_pixel_values.unsqueeze(0).to(device=device, dtype=dtype) # TODO: multiple prompts # duplicate text embeddings for each generation per prompt, using mps friendly method if not nc_flag: # 6. Get the update text embedding with the stacked ID embedding prompt_embeds = id_encoder(id_pixel_values, prompt_embeds, class_tokens_mask) bs_embed, seq_len, _ = prompt_embeds.shape prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1) prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1) pooled_prompt_embeds = pooled_prompt_embeds.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) pooled_prompt_embeds_arr.append(pooled_prompt_embeds) pooled_prompt_embeds = None negative_prompt_embeds_arr.append(negative_prompt_embeds) negative_prompt_embeds = None negative_pooled_prompt_embeds_arr.append(negative_pooled_prompt_embeds) negative_pooled_prompt_embeds = None prompt_embeds_text_only_arr.append(prompt_embeds_text_only) prompt_embeds_text_only = None prompt_embeds_arr.append(prompt_embeds) prompt_embeds = None pooled_prompt_embeds_text_only_arr.append(pooled_prompt_embeds_text_only) pooled_prompt_embeds_text_only = None emb_dict={"negative_prompt_embeds_arr":negative_prompt_embeds_arr, "negative_prompt_embeds":negative_prompt_embeds, "negative_pooled_prompt_embeds_arr":negative_pooled_prompt_embeds_arr, "negative_pooled_prompt_embeds":negative_pooled_prompt_embeds, "prompt_embeds_text_only_arr":prompt_embeds_text_only_arr, "prompt_embeds_text_only":prompt_embeds_text_only, "prompt_embeds_arr":prompt_embeds_arr, "prompt_embeds":prompt_embeds, "pooled_prompt_embeds":pooled_prompt_embeds, "pooled_prompt_embeds_text_only_arr":pooled_prompt_embeds_text_only_arr, "pooled_prompt_embeds_text_only":pooled_prompt_embeds_text_only, "pooled_prompt_embeds_arr":pooled_prompt_embeds_arr, "batch_size":batch_size, } return emb_dict from typing import Any, Callable, Dict, List, Optional, Tuple, Union def encode_prompt_with_trigger_word_v2(clip,model_, prompt: str, prompt_2 = None, num_id_images= 1, device = None, prompt_embeds = None, negative_prompt = None, negative_prompt_2 = None, negative_prompt_embeds= None, pooled_prompt_embeds= None, negative_pooled_prompt_embeds= None, num_images_per_prompt=1, class_tokens_mask = None, nc_flag: bool = False, trigger_word="img", unet_dtype=torch.float16, clip_skip=None, lora_scale=None, do_classifier_free_guidance=True, force_zeros_for_empty_prompts=False, num_tokens=2, ): device = device tokenizer_2=model_.tokenizer_2 tokenizer=model_.tokenizer #text_encoders=clip.encode_from_tokens if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) else: batch_size = prompt_embeds.shape[0] # Find the token id of the trigger word image_token_id = tokenizer_2.convert_tokens_to_ids(trigger_word) # Define tokenizers and text encoders tokenizers = [tokenizer, tokenizer_2] if tokenizer is not None else [tokenizer_2] # text_encoders = ( # [self.text_encoder, self.text_encoder_2] if self.text_encoder is not None else [self.text_encoder_2] # ) if prompt_embeds is None: prompt_2 = prompt_2 or prompt prompt_embeds_list = [] prompts = [prompt, prompt_2] for prompt, tokenizer,text_en in zip(prompts, tokenizers,[clip.cond_stage_model.clip_l.encode_token_weights,clip.cond_stage_model.clip_g.encode_token_weights]): # if isinstance(self, TextualInversionLoaderMixin): # prompt = self.maybe_convert_prompt(prompt, tokenizer) input_ids = tokenizer.encode(prompt) # TODO: batch encode clean_index = 0 clean_input_ids = [] class_token_index = [] # Find out the corresponding class word token based on the newly added trigger word token for i, token_id in enumerate(input_ids): if token_id == image_token_id: class_token_index.append(clean_index - 1) else: clean_input_ids.append(token_id) clean_index += 1 if nc_flag: return None, None, None,None, None if len(class_token_index) > 1: raise ValueError( f"PhotoMaker currently does not support multiple trigger words in a single prompt.\ Trigger word: {trigger_word}, Prompt: {prompt}." ) elif len(class_token_index) == 0 and not nc_flag: raise ValueError( f"PhotoMaker currently does not support multiple trigger words in a single prompt.\ Trigger word: {trigger_word}, Prompt: {prompt}." ) class_token_index = class_token_index[0] # Expand the class word token and corresponding mask class_token = clean_input_ids[class_token_index] clean_input_ids = clean_input_ids[:class_token_index] + [class_token] * num_id_images * num_tokens + clean_input_ids[class_token_index + 1:] # Truncation or padding max_len = tokenizer.model_max_length if len(clean_input_ids) > max_len: clean_input_ids = clean_input_ids[:max_len] else: clean_input_ids = clean_input_ids + [tokenizer.pad_token_id] * ( max_len - len(clean_input_ids) ) #class_tokens_mask = [True if class_token_index <= i < class_token_index+num_id_images else False for i in range(len(clean_input_ids))] class_tokens_mask = [True if class_token_index <= i < class_token_index + (num_id_images * num_tokens) else False for i in range(len(clean_input_ids))] #print(clean_input_ids) #print(max_len) clean_input_ids=clean_input_ids[:77] if len(clean_input_ids) > 77 else clean_input_ids + [0]*(77 - len(clean_input_ids)) clean_input_ids_1=[(i,1.0) for i in clean_input_ids] clean_input_ids_2=[(i,1.0) for i in clean_input_ids if i==clean_input_ids[0] or i==49407 ] clean_input_ids_2=clean_input_ids_2[:77] if len(clean_input_ids_2) > 77 else clean_input_ids_2 + [(0,1.0)]*(77 - len(clean_input_ids_2)) clean_input_ids_list=[clean_input_ids_1,clean_input_ids_2] #print(clean_input_ids) #clean_input_ids_ = torch.tensor(clean_input_ids, dtype=torch.long).unsqueeze(0) class_tokens_mask = torch.tensor(class_tokens_mask, dtype=torch.bool).unsqueeze(0) prompt_embeds, pooled_prompt_embeds = text_en(clean_input_ids_list) # print(prompt_embeds.shape,pooled_prompt_embeds.shape)torch.Size([1, 154, 768]) torch.Size([1, 768]) torch.Size([1, 154, 1280]) torch.Size([1, 1280]) prompt_embeds_list.append((prompt_embeds,pooled_prompt_embeds)) #prompt_embeds = torch.concat(prompt_embeds_list, dim=-1) #prompt_embeds=prompt_embeds_list[1] pooled_prompt_embeds=prompt_embeds_list[1][1] # cut_to = min(prompt_embeds_list[0][0].shape[1], prompt_embeds_list[1][0].shape[1]) # print(cut_to) cut_to=77 prompt_embeds= torch.cat([prompt_embeds_list[0][0][:,:cut_to], prompt_embeds_list[1][0][:,:cut_to]], dim=-1) prompt_embeds = prompt_embeds.to(device=device,dtype=unet_dtype, ) class_tokens_mask = class_tokens_mask.to(device=device) # TODO: ignoring two-prompt case # get unconditional embeddings for classifier free guidance zero_out_negative_prompt = negative_prompt is None and force_zeros_for_empty_prompts if do_classifier_free_guidance and negative_prompt_embeds is None and zero_out_negative_prompt: negative_prompt_embeds = torch.zeros_like(prompt_embeds) negative_pooled_prompt_embeds = torch.zeros_like(pooled_prompt_embeds) elif do_classifier_free_guidance and negative_prompt_embeds is None: negative_prompt = negative_prompt or "" negative_prompt_2 = negative_prompt_2 or negative_prompt # normalize str to list #negative_prompt = batch_size * [negative_prompt] if isinstance(negative_prompt, str) else negative_prompt negative_prompt = str(negative_prompt) if isinstance(negative_prompt, list) else negative_prompt negative_prompt_2 = ( batch_size * [negative_prompt_2] if isinstance(negative_prompt_2, str) else negative_prompt_2 ) uncond_tokens: List[str] if prompt is not None and type(prompt) is not type(negative_prompt): raise TypeError( f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !=" f" {type(prompt)}." ) # elif batch_size != len(negative_prompt): # raise ValueError( # f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:" # f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches" # " the batch size of `prompt`." # ) else: uncond_tokens = [negative_prompt, negative_prompt_2] # ng 没用上 negative_prompt_embeds_list = [] for negative_prompt, tokenizer, text_encoder in zip(uncond_tokens, tokenizers, [clip.cond_stage_model.clip_l.encode_token_weights,clip.cond_stage_model.clip_g.encode_token_weights]): # if isinstance(self, TextualInversionLoaderMixin): # negative_prompt = self.maybe_convert_prompt(negative_prompt, tokenizer) max_length = prompt_embeds.shape[1] uncond_input=tokenizer.encode(negative_prompt) # uncond_input = tokenizer( # negative_prompt, # padding="max_length", # max_length=max_length, # truncation=True, # return_tensors="pt", # ) # negative_prompt_embeds = text_encoder( # uncond_input.input_ids.to(device), # output_hidden_states=True, # ) clean_input_ids_n=uncond_input[:77] if len(uncond_input) > 77 else uncond_input + [0]*(77 - len(uncond_input)) clean_input_ids_1_=[(i,1.0) for i in clean_input_ids_n] clean_input_ids_2_=[(i,1.0) for i in clean_input_ids_n if i==clean_input_ids_n[0] or i==49407 ] clean_input_ids_2_=clean_input_ids_2_[:77] if len(clean_input_ids_2_) > 77 else clean_input_ids_2_ + [(0,1.0)]*(77 - len(clean_input_ids_2_)) clean_input_ids_list_n=[clean_input_ids_1_,clean_input_ids_2_] prompt_embeds_n, pooled_prompt_embeds_n = text_en(clean_input_ids_list_n) negative_prompt_embeds_list.append((prompt_embeds_n,pooled_prompt_embeds_n)) # We are only ALWAYS interested in the pooled output of the final text encoder # negative_pooled_prompt_embeds = negative_prompt_embeds[0] # negative_prompt_embeds = negative_prompt_embeds.hidden_states[-2] # negative_prompt_embeds_list.append(negative_prompt_embeds) negative_pooled_prompt_embeds=negative_prompt_embeds_list[1][1] #negative_prompt_embeds = torch.concat(negative_prompt_embeds_list, dim=-1) cut_to=77 negative_prompt_embeds= torch.cat([negative_prompt_embeds_list[0][0][:,:cut_to], negative_prompt_embeds_list[1][0][:,:cut_to]], dim=-1) negative_prompt_embeds = negative_prompt_embeds.to(device=device,dtype=unet_dtype, ) bs_embed, seq_len, _ = prompt_embeds.shape if do_classifier_free_guidance: # duplicate unconditional embeddings for each generation per prompt, using mps friendly method seq_len = negative_prompt_embeds.shape[1] negative_prompt_embeds = negative_prompt_embeds.to(dtype=unet_dtype, device=device) negative_prompt_embeds = negative_prompt_embeds.repeat(1, num_images_per_prompt, 1) negative_prompt_embeds = negative_prompt_embeds.view(batch_size * num_images_per_prompt, seq_len, -1) pooled_prompt_embeds = pooled_prompt_embeds.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) if do_classifier_free_guidance: negative_pooled_prompt_embeds = negative_pooled_prompt_embeds.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) return prompt_embeds, negative_prompt_embeds,pooled_prompt_embeds, negative_pooled_prompt_embeds, class_tokens_mask def photomaker_clip_v2(clip,model_,prompt_list,negative_prompt,input_id_images,id_embeds,trigger_word="img",num_images_per_prompt=1,nc_flag=False,prompt_2=None,prompt_embeds=None,pooled_prompt_embeds=None,class_tokens_mask=None,prompt_embeds_text_only=None,negative_pooled_prompt_embeds=None): id_encoder=model_.id_encoder id_image_processor=model_.id_image_processor tokenizer=model_.tokenizer_2 batch_size=len(prompt_list) num_id_images = len(input_id_images) #双角色时,须确保输入的图片是列表,且跟prompt对应上 prompt_arr = prompt_list negative_prompt_embeds_arr = [] prompt_embeds_text_only_arr = [] prompt_embeds_arr = [] latents_arr = [] add_time_ids_arr = [] negative_pooled_prompt_embeds_arr = [] pooled_prompt_embeds_text_only_arr = [] pooled_prompt_embeds_arr = [] for prompt in prompt_arr: ( prompt_embeds, _, pooled_prompt_embeds, _, class_tokens_mask ) = encode_prompt_with_trigger_word_v2(clip,model_, prompt=prompt, prompt_2=prompt_2, device=device, num_id_images=num_id_images, class_tokens_mask=class_tokens_mask, num_images_per_prompt=num_images_per_prompt, do_classifier_free_guidance=True, negative_prompt=negative_prompt, negative_prompt_2=None, prompt_embeds=None, negative_prompt_embeds=None, pooled_prompt_embeds=None, negative_pooled_prompt_embeds=None, nc_flag=nc_flag, ) # 4. Encode input prompt without the trigger word for delayed conditioning # encode, remove trigger word token, then decode tokens_text_only = tokenizer.encode(prompt, add_special_tokens=False) trigger_word_token = tokenizer.convert_tokens_to_ids(trigger_word) if not nc_flag: tokens_text_only.remove(trigger_word_token) prompt_text_only = tokenizer.decode(tokens_text_only, add_special_tokens=False) #print(prompt_text_only) ( prompt_embeds_text_only, negative_prompt_embeds, pooled_prompt_embeds_text_only, # TODO: replace the pooled_prompt_embeds with text only prompt negative_pooled_prompt_embeds, ) = cf_clip_single(clip, prompt=prompt_text_only, prompt_2=prompt_2, device=device, num_images_per_prompt=num_images_per_prompt, do_classifier_free_guidance=True, negative_prompt=negative_prompt, negative_prompt_2=None, prompt_embeds=prompt_embeds_text_only, negative_prompt_embeds=None, pooled_prompt_embeds=None, negative_pooled_prompt_embeds=negative_pooled_prompt_embeds, ) # 5. Prepare the input ID images dtype = next(id_encoder.parameters()).dtype if not isinstance(input_id_images[0], torch.Tensor): id_pixel_values = id_image_processor(input_id_images, return_tensors="pt").pixel_values id_pixel_values = id_pixel_values.unsqueeze(0).to(device=device, dtype=dtype) # TODO: multiple prompts # duplicate text embeddings for each generation per prompt, using mps friendly method if not nc_flag: if id_embeds is not None: id_embeds = id_embeds.unsqueeze(0).to(device=device, dtype=dtype) prompt_embeds = id_encoder(id_pixel_values, prompt_embeds, class_tokens_mask, id_embeds) #torch.Size([1, 1, 3, 224, 224]) torch.Size([1, 77, 2048]) torch.Size([1, 77]) torch.Size([1, 512]) else: prompt_embeds = id_encoder(id_pixel_values, prompt_embeds, class_tokens_mask) # 6. Get the update text embedding with the stacked ID embedding bs_embed, seq_len, _ = prompt_embeds.shape prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1) prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1) pooled_prompt_embeds = pooled_prompt_embeds.repeat(1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1 ) pooled_prompt_embeds_arr.append(pooled_prompt_embeds) pooled_prompt_embeds = None negative_prompt_embeds_arr.append(negative_prompt_embeds) negative_prompt_embeds = None negative_pooled_prompt_embeds_arr.append(negative_pooled_prompt_embeds) negative_pooled_prompt_embeds = None prompt_embeds_text_only_arr.append(prompt_embeds_text_only) prompt_embeds_text_only = None prompt_embeds_arr.append(prompt_embeds) prompt_embeds = None pooled_prompt_embeds_text_only_arr.append(pooled_prompt_embeds_text_only) pooled_prompt_embeds_text_only = None emb_dict={"negative_prompt_embeds_arr":negative_prompt_embeds_arr, "negative_prompt_embeds":negative_prompt_embeds, "negative_pooled_prompt_embeds_arr":negative_pooled_prompt_embeds_arr, "negative_pooled_prompt_embeds":negative_pooled_prompt_embeds, "prompt_embeds_text_only_arr":prompt_embeds_text_only_arr, "prompt_embeds_text_only":prompt_embeds_text_only, "prompt_embeds_arr":prompt_embeds_arr, "prompt_embeds":prompt_embeds, "pooled_prompt_embeds":pooled_prompt_embeds, "pooled_prompt_embeds_text_only_arr":pooled_prompt_embeds_text_only_arr, "pooled_prompt_embeds_text_only":pooled_prompt_embeds_text_only, "pooled_prompt_embeds_arr":pooled_prompt_embeds_arr, "batch_size":batch_size, } return emb_dict def Loader_UNO(extra_info,offload,quantize_mode,save_quantezed,lora_rank): from .UNO.uno.flux.pipeline import UNOPipeline from accelerate import Accelerator accelerator = Accelerator() device= accelerator.device if extra_info is not None: model_path = extra_info["unet_path"] lora_list=[i for i in [extra_info.get("lora1_path"),extra_info.get("lora2_path")] if i is not None] if lora_list: lora_ckpt_path=lora_list[0] if "dit_lora" not in lora_ckpt_path.lower(): raise ValueError("lora_ckpt_path must be a dit_lora checkpoint") only_lora=True else: only_lora=False use_fp8=True if quantize_mode=="fp8" else False if "schnell" in model_path: model_type="flux-schnell" else: model_type="flux-dev" if "schnell" in model_path: model_type="flux-schnell" else: model_type="flux-dev" if only_lora : from .UNO.uno.flux.util import load_flow_model_only_lora model_ = load_flow_model_only_lora( model_type,model_path,lora_ckpt_path,use_fp8, device="cpu" if offload else device,save_quantezed=save_quantezed, lora_rank=lora_rank) else: from .UNO.uno.flux.util import load_flow_model model_ = load_flow_model(model_type,model_path,use_fp8, device="cpu" if offload else device,save_quantezed=save_quantezed) model = UNOPipeline( model_, device, offload, use_fp8, ) else: raise ValueError("must use EasyFunction_Lite node") return model def load_pipeline_realcustom(cf_model,realcustom_checkpoint): from .RealCustom.models.unet_2d_condition_custom import UNet2DConditionModel as UNet2DConditionModelDiffusers if "shallow" in realcustom_checkpoint.lower(): unet_config_path=os.path.join(cur_path, "RealCustom/configs/realcustom_sigdino_highres_shallow.json") else: unet_config_path=os.path.join(cur_path, "RealCustom/configs/realcustom_sigdino_highres.json") with open(unet_config_path, 'r') as f: unet_config = json.load(f) # Settings for image encoder vision_model_config = unet_config.pop("vision_model_config", None) vision_model_config_ar = vision_model_config.pop("vision_model_config", None) unet_type = unet_config.pop("type", None) unet_model = UNet2DConditionModelDiffusers(**unet_config) unet_model.eval() #cf_state_dict=torch.load(unet_checkpoint,weights_only=False, map_location="cpu") cf_state_dict = cf_model.model.diffusion_model.state_dict() unet_state_dict = cf_model.model.model_config.process_unet_state_dict_for_saving(cf_state_dict) from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_ldm_unet_checkpoint cf_state_dict = convert_ldm_unet_checkpoint(unet_state_dict, unet_model.config) unet_model.load_state_dict(cf_state_dict, strict=False) realcustom_DICT=torch.load(realcustom_checkpoint,weights_only=False, map_location="cpu") unet_model.load_state_dict(realcustom_DICT, strict=False) unet_model = torch.compile(unet_model, disable=True)# CHECK THIS del cf_state_dict,realcustom_DICT gc.collect() torch.cuda.empty_cache() print("loading unet base model finished.") return unet_model,vision_model_config_ar,unet_type def load_clip_clipvsion(clip_paths,token_paths,dino_path,siglip_path,vision_model_config): from .RealCustom.models.text import TextModel from transformers import CLIPTextModel,CLIPTextConfig from .RealCustom.utils import instantiate_from_config # text_encoder=CLIPTextModel.from_pretrained(clip_paths[0], local_files_only=True) # text_encoder_2=CLIPTextModel.from_pretrained(clip_paths[1], local_files_only=True) from safetensors.torch import load_file text_encoder_config=CLIPTextConfig.from_pretrained(token_paths[0], local_files_only=True) text_encoder = CLIPTextModel(text_encoder_config) text_encoder_sd_1 = load_file(clip_paths[0]) text_encoder.load_state_dict(text_encoder_sd_1, strict=False) text_encoder_config_2=CLIPTextConfig.from_pretrained(token_paths[1], local_files_only=True) text_encoder_2 = CLIPTextModel(text_encoder_config_2) text_encoder_sd_2 = load_file(clip_paths[1]) text_encoder_2.load_state_dict(text_encoder_sd_2, strict=False) del text_encoder_sd_2,text_encoder_sd_1 gc.collect() text_model = TextModel([text_encoder,text_encoder_2],token_paths,["penultimate_nonorm"]) text_model.eval() siglip_path = os.path.normpath(siglip_path).replace("\\", "/") dino_path = os.path.normpath(dino_path).replace("\\", "/") vision_model_config["params"]["siglip_path"] = siglip_path vision_model_config["params"]["dino_path"] = dino_path vision_model = instantiate_from_config(vision_model_config) vision_model = vision_model.eval().to(device) print("loading image model and text_model finished.") return text_model,vision_model def realcustom_clip_emb(text_model,vision_model,vae_config,vae_downsample_factor,positive_prompt,negative_prompt,positive_image,target_phrase,width,height,device,samples_per_prompt,guidance_weight=7.5): from .RealCustom.inference.inference_utils import find_phrase_positions_in_text import torchvision with torch.no_grad(): image_metadata_validate = torch.tensor( data=[ width, # original_height height, # original_width 0, # coordinate top 0, # coordinate left width, # target_height height, # target_width ], device=device, dtype=torch.float32 ).view(1, -1).repeat(samples_per_prompt, 1) if guidance_weight != 1: text_negative_output = text_model(negative_prompt) # Compute target phrases target_token = torch.zeros(1, 77).to(device) positions = find_phrase_positions_in_text(positive_prompt, target_phrase) for position in positions: prompt_before = positive_prompt[:position] # NOTE We do not need -1 here because the SDXL text encoder does not encode the trailing space. prompt_include = positive_prompt[:position+len(target_phrase)] #print("prompt before: ", prompt_before, ", prompt_include: ", prompt_include) prompt_before_length = text_model.get_vaild_token_length(prompt_before) + 1 prompt_include_length = text_model.get_vaild_token_length(prompt_include) + 1 # print("prompt_before_length: ", prompt_before_length, ", prompt_include_length: ", prompt_include_length) target_token[:, prompt_before_length:prompt_include_length] = 1 # Text used for progress bar pbar_text = positive_prompt[:40] # Compute text embeddings text_positive_output = text_model(positive_prompt) text_positive_embeddings = text_positive_output.embeddings.repeat_interleave(samples_per_prompt, dim=0) text_positive_pooled = text_positive_output.pooled[-1].repeat_interleave(samples_per_prompt, dim=0) if guidance_weight != 1: text_negative_embeddings = text_negative_output.embeddings.repeat_interleave(samples_per_prompt, dim=0) text_negative_pooled = text_negative_output.pooled[-1].repeat_interleave(samples_per_prompt, dim=0) # Compute image embeddings # positive_image = Image.open(positive_promt_image_path).convert("RGB") positive_image = torchvision.transforms.ToTensor()(positive_image) positive_image = positive_image.unsqueeze(0).repeat_interleave(samples_per_prompt, dim=0) positive_image = torch.nn.functional.interpolate( positive_image, size=(768, 768), mode="bilinear", align_corners=False ) negative_image = torch.zeros_like(positive_image) #print("positive_image:",positive_image.size(), negative_image.size()) #torch.Size([1, 3, 768, 768]) torch.Size([1, 3, 768, 768]) positive_image = positive_image.to(device) negative_image = negative_image.to(device) positive_image_dict = {"image_ref": positive_image} positive_image_output = vision_model(positive_image_dict, device=device) #positive_image_output = daul_encoder(vision_model,positive_image_dict) negative_image_dict = {"image_ref": negative_image} negative_image_output = vision_model(negative_image_dict, device=device) #negative_image_output=daul_encoder(vision_model,negative_image_dict) # Initialize latent with input latent + noise (i2i) / pure noise (t2i) # latent = torch.randn( # size=[ # samples_per_prompt, # vae_config["latent_channels"], # height // vae_downsample_factor, # width // vae_downsample_factor # ], # device=device, # generator=torch.Generator(device).manual_seed(seed)) target_h = (height // vae_downsample_factor) // 2 target_w = (width // vae_downsample_factor) // 2 emb_dict={ "text_positive_embeddings":text_positive_embeddings.to(device), "text_positive_pooled":text_positive_pooled.to(device), "image_metadata_validate":image_metadata_validate.to(device), "positive_image_output":positive_image_output, "text_negative_embeddings":text_negative_embeddings.to(device), "text_negative_pooled":text_negative_pooled.to(device), "negative_image_output":negative_image_output, } latent_dict={ "vae_config":vae_config, "vae_downsample_factor":vae_downsample_factor, "target_h":target_h, "target_w":target_w, "pbar_text":pbar_text, "guidance_weight":guidance_weight, "target_token":target_token, } return emb_dict,latent_dict def realcustom_infer(unet_model,sample_steps,mask_reused_step,emb_dict,latent_dict,mask_scope,mask_strategy,guidance_weight,height,width,seed, device,schedule_type="squared_linear",schedule_shift_snr=1.0,scheduler_type="ddim",unet_prediction="epsilon"): from .RealCustom.schedulers.ddim import DDIMScheduler from .RealCustom.schedulers.dpm_s import DPMSolverSingleStepScheduler from .RealCustom.schedulers.utils import get_betas from .RealCustom.inference.mask_generation import mask_generation from .RealCustom.inference.inference_utils import classifier_free_guidance_image_prompt_cascade from torchvision.transforms.functional import to_pil_image from tqdm import tqdm # Initialize ddim scheduler ddim_train_steps = 1000 ddim_betas = get_betas(name=schedule_type, num_steps=ddim_train_steps, shift_snr=schedule_shift_snr, terminal_pure_noise=False) scheduler_class = DPMSolverSingleStepScheduler if scheduler_type == 'dpm' else DDIMScheduler scheduler = scheduler_class(betas=ddim_betas, num_train_timesteps=ddim_train_steps, num_inference_timesteps=sample_steps, device=device) infer_timesteps = scheduler.timesteps #print(infer_timesteps) # Real Reverse diffusion process. text2image_crossmap_2d_all_timesteps_list = [] current_step = 0 pbar_text = latent_dict.get("pbar_text") #guidance_weight = latent_dict.get("guidance_weight") unet_model.to(device) latent=latent_dict.get("latent") latent = torch.randn( size=[ 1, latent_dict.get("vae_config")["latent_channels"], height // latent_dict.get("vae_downsample_factor"), width // latent_dict.get("vae_downsample_factor") ], device=device, generator=torch.Generator(device).manual_seed(seed)) with torch.no_grad(): for timestep in tqdm(iterable=infer_timesteps, desc=f"[{pbar_text}]", dynamic_ncols=True): if current_step < mask_reused_step: pred_cond, pred_cond_dict = unet_model( sample=latent, timestep=timestep, encoder_hidden_states=emb_dict.get("text_positive_embeddings"), encoder_attention_mask=None, added_cond_kwargs=dict( text_embeds=emb_dict.get("text_positive_pooled"), time_ids=emb_dict.get("image_metadata_validate") ), vision_input_dict=None, vision_guided_mask=None, return_as_origin=False, return_text2image_mask=True, ) crossmap_2d_avg = mask_generation( crossmap_2d_list=pred_cond_dict.get("text2image_crossmap_2d",[]), selfmap_2d_list=pred_cond_dict.get("self_attention_map", []), target_token=latent_dict.get("target_token"), mask_scope=mask_scope, mask_target_h=latent_dict.get("target_h"), mask_target_w=latent_dict.get("target_w"), mask_mode=mask_strategy, ) else: # using previous step's mask crossmap_2d_avg = text2image_crossmap_2d_all_timesteps_list[-1].squeeze(1) if crossmap_2d_avg.dim() == 5: # Means that each layer uses a separate mask weight. text2image_crossmap_2d_all_timesteps_list.append(crossmap_2d_avg.mean(dim=2).unsqueeze(1)) else: text2image_crossmap_2d_all_timesteps_list.append(crossmap_2d_avg.unsqueeze(1)) pred_cond, pred_cond_dict = unet_model( sample=latent, timestep=timestep, encoder_hidden_states=emb_dict.get("text_positive_embeddings"), encoder_attention_mask=None, added_cond_kwargs=dict( text_embeds=emb_dict.get("text_positive_pooled"), time_ids=emb_dict.get("image_metadata_validate") ), vision_input_dict=emb_dict.get("positive_image_output"), vision_guided_mask=crossmap_2d_avg, return_as_origin=False, return_text2image_mask=True, multiple_reference_image=False ) crossmap_2d_avg_neg = crossmap_2d_avg.mean(dim=1, keepdim=True) pred_negative, pred_negative_dict = unet_model( sample=latent, timestep=timestep, encoder_hidden_states=emb_dict.get("text_negative_embeddings"), encoder_attention_mask=None, added_cond_kwargs=dict( text_embeds=emb_dict.get("text_negative_pooled"), time_ids=emb_dict.get("image_metadata_validate") ), vision_input_dict=emb_dict.get("negative_image_output"), vision_guided_mask=crossmap_2d_avg, return_as_origin=False, return_text2image_mask=True, multiple_reference_image=False ) pred = classifier_free_guidance_image_prompt_cascade( pred_t_cond=None, pred_ti_cond=pred_cond, pred_uncond=pred_negative, guidance_weight_t=guidance_weight, guidance_weight_i=guidance_weight, guidance_stdev_rescale_factor=0, cfg_rescale_mode="naive_global_direct" ) step = scheduler.step( model_output=pred, model_output_type=unet_prediction, timestep=timestep, sample=latent, ) latent = step.prev_sample current_step += 1 sample=step.pred_original_sample/0.13025 return sample def load_realcustom_vae(vae,device): from .RealCustom.models.vae import AutoencoderKL from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_ldm_vae_checkpoint vae_config_path = os.path.join(cur_path, "local_repo/vae/config.json") # Initialize vae model with open(vae_config_path, 'r') as vae_config_file: vae_config = json.load(vae_config_file) vae_downsample_factor = 2 ** (len(vae_config["block_out_channels"]) - 1) # 2 ** 3 = 8 vae_model = AutoencoderKL(**vae_config) vae_model.eval().to(device) vae_state_dict=vae.get_sd() #AE = AutoencoderKL.from_config(ae_config).to(device, torch.float16) cf_state_dict = convert_ldm_vae_checkpoint(vae_state_dict, vae_model.config) vae_model.load_state_dict(cf_state_dict, strict=False) del cf_state_dict,vae_state_dict #vae_decoder = torch.compile(lambda x: vae_model.decode(x / vae_model.scaling_factor).sample.clip(-1, 1), disable=True) vae_encoder = torch.compile(lambda x: vae_model.encode(x).latent_dist.mode().mul_(vae_model.scaling_factor), disable=True) print("loading vae finished.") return vae_encoder,vae_downsample_factor,vae_config def load_pipeline_instant_character(extra_info,ip_adapter_path,VAE,quantize_mode): from .InstantCharacter.pipeline_wrapper import InstantCharacterFluxPipeline from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig,FluxTransformer2DModel if extra_info.get("svdq_repo") is not None: print("use svdq") from nunchaku import NunchakuFluxTransformer2dModel transformer = NunchakuFluxTransformer2dModel.from_pretrained(extra_info.get("svdq_repo"),offload=True) try: transformer.set_attention_impl("nunchaku-fp16") except: pass vae=convert_cfvae2diffuser(VAE,use_flux=True) pipe = InstantCharacterFluxPipeline.from_pretrained(os.path.join(cur_path,"config/FLUX.1-dev"),vae=vae,transformer=transformer,text_encoder=None,text_encoder_2=None, torch_dtype=torch.bfloat16) elif extra_info.get("gguf_path") is not None: print("use gguf quantization") from diffusers import GGUFQuantizationConfig transformer = FluxTransformer2DModel.from_single_file( extra_info.get("gguf_path") , config=os.path.join(cur_path, "config/FLUX.1-dev/transformer"), quantization_config=GGUFQuantizationConfig(compute_dtype=torch.bfloat16), torch_dtype=torch.bfloat16, ) vae=convert_cfvae2diffuser(VAE,use_flux=True) pipe = InstantCharacterFluxPipeline.from_pretrained(os.path.join(cur_path,"config/FLUX.1-dev"),vae=vae,transformer=transformer,text_encoder=None,text_encoder_2=None, torch_dtype=torch.bfloat16) elif extra_info.get("unet_path"): if quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_single_file(extra_info.get("unet_path"), config=os.path.join(cur_path,"config/FLUX.1-dev/transformer/config.json"), torch_dtype=torch.bfloat16) else: from safetensors.torch import load_file t_state_dict=load_file(extra_info.get("unet_path")) unet_config = FluxTransformer2DModel.load_config(os.path.join(cur_path,"config/FLUX.1-dev/transformer/config.json")) transformer = FluxTransformer2DModel.from_config(unet_config).to(torch.bfloat16) transformer.load_state_dict(t_state_dict, strict=False) del t_state_dict gc_cleanup() vae=convert_cfvae2diffuser(VAE,use_flux=True) pipe = InstantCharacterFluxPipeline.from_pretrained(os.path.join(cur_path,"config/FLUX.1-dev"),transformer=transformer,vae=vae,text_encoder=None,text_encoder_2=None, torch_dtype=torch.bfloat16) else: print(f"use {quantize_mode} quantization") find_flux=[i for i in [extra_info.get("repo1_path") , extra_info.get("repo2_path")] if "flux" in i ] if not find_flux: raise ValueError("can not find flux repo") if quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_pretrained( find_flux[0], subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig(load_in_8bit=True,), torch_dtype=torch.bfloat16, ) elif quantize_mode=="nf4": #nf4 transformer = FluxTransformer2DModel.from_pretrained( find_flux[0], subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ), torch_dtype=torch.bfloat16,) else: transformer = FluxTransformer2DModel.from_pretrained( find_flux[0], subfolder="transformer", torch_dtype=torch.bfloat16, ) pipe = InstantCharacterFluxPipeline.from_pretrained(find_flux[0],transformer=transformer,text_encoder=None,text_encoder_2=None, torch_dtype=torch.bfloat16) # if not cf_model.get("use_svdq"): # pipe.enable_model_cpu_offload() pipe.to(device) pipe.init_adapter( subject_ipadapter_cfg=dict(subject_ip_adapter_path=ip_adapter_path, nb_token=1024), ) return pipe def cf_flux_prompt_clip(cf_clip,prompt): tokens = cf_clip.tokenize(prompt) tokens["t5xxl"] = cf_clip.tokenize(prompt)["t5xxl"] prompt_embeds = cf_clip.encode_from_tokens(tokens, return_pooled=True, return_dict=True).pop("cond") tokens["l"] = cf_clip.tokenize(prompt)["l"] pooled_prompt_embeds = cf_clip.encode_from_tokens(tokens, return_dict=True).pop("pooled_output") prompt_embeds=prompt_embeds.to(device,torch.bfloat16) pooled_prompt_embeds=pooled_prompt_embeds.to(device,torch.bfloat16) text_ids = torch.zeros(prompt_embeds.shape[1], 3).to(device=device, dtype=torch.bfloat16) return prompt_embeds,pooled_prompt_embeds,text_ids def load_dual_clip(image_encoder_path,image_encoder_2_path,device,dtype): from transformers import SiglipVisionModel, SiglipImageProcessor, AutoModel, AutoImageProcessor # image encoder print(f"=> loading image_encoder_1: {image_encoder_path}") image_encoder = SiglipVisionModel.from_pretrained(image_encoder_path) image_processor = SiglipImageProcessor.from_pretrained(image_encoder_path) image_encoder.eval() image_encoder.to(device, dtype=dtype) # image encoder 2 print(f"=> loading image_encoder_2: {image_encoder_2_path}") image_encoder_2 = AutoModel.from_pretrained(image_encoder_2_path) image_processor_2 = AutoImageProcessor.from_pretrained(image_encoder_2_path) image_encoder_2.eval() image_encoder_2.to(device, dtype=dtype) image_processor_2.crop_size = dict(height=384, width=384) image_processor_2.size = dict(shortest_edge=384) return image_encoder,image_processor,image_encoder_2,image_processor_2 @torch.inference_mode() def instant_character_id_clip(subject_image,siglip_image_encoder,siglip_image_processor,dino_image_encoder_2,dino_image_processor_2,device,dtype): from einops import rearrange def encode_siglip_image_emb(siglip_image, device, dtype): siglip_image = siglip_image.to(device, dtype=dtype) res = siglip_image_encoder(siglip_image, output_hidden_states=True) siglip_image_embeds = res.last_hidden_state siglip_image_shallow_embeds = torch.cat([res.hidden_states[i] for i in [7, 13, 26]], dim=1) return siglip_image_embeds, siglip_image_shallow_embeds def encode_dinov2_image_emb(dinov2_image, device, dtype): dinov2_image = dinov2_image.to(device, dtype=dtype) res = dino_image_encoder_2(dinov2_image, output_hidden_states=True) dinov2_image_embeds = res.last_hidden_state[:, 1:] dinov2_image_shallow_embeds = torch.cat([res.hidden_states[i][:, 1:] for i in [9, 19, 29]], dim=1) return dinov2_image_embeds, dinov2_image_shallow_embeds def encode_image_emb(siglip_image, device, dtype): object_image_pil = siglip_image object_image_pil_low_res = [object_image_pil.resize((384, 384))] object_image_pil_high_res = object_image_pil.resize((768, 768)) object_image_pil_high_res = [ object_image_pil_high_res.crop((0, 0, 384, 384)), object_image_pil_high_res.crop((384, 0, 768, 384)), object_image_pil_high_res.crop((0, 384, 384, 768)), object_image_pil_high_res.crop((384, 384, 768, 768)), ] nb_split_image = len(object_image_pil_high_res) siglip_image_embeds = encode_siglip_image_emb( siglip_image_processor(images=object_image_pil_low_res, return_tensors="pt").pixel_values, device, dtype ) dinov2_image_embeds = encode_dinov2_image_emb( dino_image_processor_2(images=object_image_pil_low_res, return_tensors="pt").pixel_values, device, dtype ) image_embeds_low_res_deep = torch.cat([siglip_image_embeds[0], dinov2_image_embeds[0]], dim=2) image_embeds_low_res_shallow = torch.cat([siglip_image_embeds[1], dinov2_image_embeds[1]], dim=2) siglip_image_high_res = siglip_image_processor(images=object_image_pil_high_res, return_tensors="pt").pixel_values siglip_image_high_res = siglip_image_high_res[None] siglip_image_high_res = rearrange(siglip_image_high_res, 'b n c h w -> (b n) c h w') siglip_image_high_res_embeds = encode_siglip_image_emb(siglip_image_high_res, device, dtype) siglip_image_high_res_deep = rearrange(siglip_image_high_res_embeds[0], '(b n) l c -> b (n l) c', n=nb_split_image) dinov2_image_high_res = dino_image_processor_2(images=object_image_pil_high_res, return_tensors="pt").pixel_values dinov2_image_high_res = dinov2_image_high_res[None] dinov2_image_high_res = rearrange(dinov2_image_high_res, 'b n c h w -> (b n) c h w') dinov2_image_high_res_embeds = encode_dinov2_image_emb(dinov2_image_high_res, device, dtype) dinov2_image_high_res_deep = rearrange(dinov2_image_high_res_embeds[0], '(b n) l c -> b (n l) c', n=nb_split_image) image_embeds_high_res_deep = torch.cat([siglip_image_high_res_deep, dinov2_image_high_res_deep], dim=2) image_embeds_dict = dict( image_embeds_low_res_shallow=image_embeds_low_res_shallow.to(device), image_embeds_low_res_deep=image_embeds_low_res_deep.to(device), image_embeds_high_res_deep=image_embeds_high_res_deep.to(device), ) return image_embeds_dict subject_image = subject_image.resize((max(subject_image.size), max(subject_image.size))) subject_image_embeds_dict = encode_image_emb(subject_image, device, dtype) return subject_image_embeds_dict def Loader_Dreamo(extra_info,VAE,quantize_mode,dreamo_lora_path,cfg_distill_path,Turbo_path,device,dreamo_version): from .DreamO.dreamo.dreamo_pipeline import DreamOPipeline from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig,FluxTransformer2DModel #vae=convert_cfvae2diffuser(VAE,use_flux=True) repo_list=[i for i in [extra_info.get("repo1_path"),extra_info.get("repo2_path")] if i is not None] if repo_list: flux_repo=[i for i in repo_list if "flux" in i.lower()] else: raise "you must fill a flux repo" if extra_info.get("gguf_path") is not None: #get error print("use gguf quantization") from diffusers import GGUFQuantizationConfig transformer = FluxTransformer2DModel.from_single_file( extra_info.get("gguf_path"), config=os.path.join(cur_path, "config/FLUX.1-dev/transformer"), quantization_config=GGUFQuantizationConfig(compute_dtype=torch.bfloat16), torch_dtype=torch.bfloat16, ) dreamo_pipeline = DreamOPipeline.from_pretrained(flux_repo, transformer=transformer,torch_dtype=torch.bfloat16) dreamo_pipeline.load_dreamo_model(device,dreamo_lora_path,cfg_distill_path,Turbo_path, use_turbo=True,dreamo_version=dreamo_version) elif extra_info.get("svdq_repo") is not None:#get error print("use svdq") from nunchaku import NunchakuFluxTransformer2dModel transformer = NunchakuFluxTransformer2dModel.from_pretrained(extra_info.get("svdq_repo"),offload=True) try: transformer.set_attention_impl("nunchaku-fp16") except: pass dreamo_pipeline = DreamOPipeline.from_pretrained(flux_repo, transformer=transformer,torch_dtype=torch.bfloat16) dreamo_pipeline.load_dreamo_model(device,dreamo_lora_path,cfg_distill_path,Turbo_path, use_turbo=True,use_svdq=True,dreamo_version=dreamo_version) elif extra_info.get("unet_path") is not None: print("use single unet") if quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_single_file(extra_info.get("unet_path"), config=os.path.join(cur_path,"config/FLUX.1-dev/transformer/config.json"), torch_dtype=torch.bfloat16) else: from safetensors.torch import load_file t_state_dict=load_file(extra_info.get("unet_path")) unet_config = FluxTransformer2DModel.load_config(os.path.join(cur_path,"config/FLUX.1-dev/transformer/config.json")) transformer = FluxTransformer2DModel.from_config(unet_config).to(torch.bfloat16) transformer.load_state_dict(t_state_dict, strict=False) del t_state_dict gc_cleanup() dreamo_pipeline = DreamOPipeline.from_pretrained(flux_repo, transformer=transformer,torch_dtype=torch.bfloat16) dreamo_pipeline.load_dreamo_model(device,dreamo_lora_path,cfg_distill_path,Turbo_path, use_turbo=True,dreamo_version=dreamo_version) else: print(f"use {quantize_mode} quantization") if quantize_mode=="fp8": # transformer = FluxTransformer2DModel.from_pretrained( # cf_model.get("extra_repo"), # subfolder="transformer", # quantization_config=DiffusersBitsAndBytesConfig(load_in_8bit=True,), # torch_dtype=torch.bfloat16, # ) dreamo_pipeline = DreamOPipeline.from_pretrained(flux_repo, torch_dtype=torch.bfloat16) dreamo_pipeline.load_dreamo_model(device,dreamo_lora_path,cfg_distill_path,Turbo_path, use_turbo=True,dreamo_version=dreamo_version) from optimum.quanto import freeze, qint8, quantize quantize(dreamo_pipeline.transformer, qint8) freeze(dreamo_pipeline.transformer) quantize(dreamo_pipeline.text_encoder_2, qint8) freeze(dreamo_pipeline.text_encoder_2) else: if quantize_mode=="nf4": #nf4 transformer = FluxTransformer2DModel.from_pretrained( flux_repo, subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ), torch_dtype=torch.bfloat16,) else: transformer = FluxTransformer2DModel.from_pretrained( flux_repo, subfolder="transformer", torch_dtype=torch.bfloat16, ) dreamo_pipeline = DreamOPipeline.from_pretrained(flux_repo, transformer=transformer,torch_dtype=torch.bfloat16) dreamo_pipeline.load_dreamo_model(device,dreamo_lora_path,cfg_distill_path,Turbo_path, use_turbo=True,dreamo_version=dreamo_version) dreamo_pipeline.enable_model_cpu_offload() return dreamo_pipeline @torch.no_grad() def get_align_face(img,face_helper): from .DreamO.dreamo.utils import img2tensor,tensor2img from torchvision.transforms.functional import normalize # the face preprocessing code is same as PuLID face_helper.clean_all() image_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) face_helper.read_image(image_bgr) face_helper.get_face_landmarks_5(only_center_face=True) face_helper.align_warp_face() if len(face_helper.cropped_faces) == 0: return None align_face = face_helper.cropped_faces[0] input = img2tensor(align_face, bgr2rgb=True).unsqueeze(0) / 255.0 input = input.to(torch.device("cuda")) parsing_out = face_helper.face_parse(normalize(input, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]))[0] parsing_out = parsing_out.argmax(dim=1, keepdim=True) bg_label = [0, 16, 18, 7, 8, 9, 14, 15] bg = sum(parsing_out == i for i in bg_label).bool() white_image = torch.ones_like(input) # only keep the face features face_features_image = torch.where(bg, white_image, input) face_features_image = tensor2img(face_features_image, rgb2bgr=False) return face_features_image def Dreamo_image_encoder(BEN2_path,ref_image1,ref_image2,ref_task1,ref_task2,ref_res): from .DreamO.dreamo.utils import img2tensor, resize_numpy_image_area ref_conds = [] #debug_images = [] ref_images = [ref_image1, ref_image2] ref_tasks = [ref_task1, ref_task2] for idx, (ref_image, ref_task) in enumerate(zip(ref_images, ref_tasks)): if ref_image is not None: if ref_task == "id": from facexlib.utils.face_restoration_helper import FaceRestoreHelper face_helper = FaceRestoreHelper( upscale_factor=1, face_size=512, crop_ratio=(1, 1), det_model='retinaface_resnet50', save_ext='png', device=device, ) ref_image = resize_numpy_image_long(ref_image, 1024) ref_image = get_align_face(ref_image,face_helper) elif ref_task != "style": # ip from .DreamO.tools import BEN2 bg_rm_model = BEN2.BEN_Base().to(device).eval() #TODO 反复加载 需要修复 #hf_hub_download(repo_id='PramaLLC/BEN2', filename='BEN2_Base.pth', local_dir='models') bg_rm_model.loadcheckpoints(BEN2_path) ref_image = bg_rm_model.inference(ref_image) #NEED TO CHECK bg_rm_model.to(torch.device('cpu')) if ref_task != "id": ref_image = resize_numpy_image_area(np.array(ref_image), ref_res * ref_res) #debug_images.append(ref_image) ref_image = img2tensor(ref_image, bgr2rgb=False).unsqueeze(0) / 255.0 ref_image = 2 * ref_image - 1.0 ref_conds.append( { 'img': ref_image, 'task': ref_task, 'idx': idx + 1, } ) return ref_conds def Loader_Flux_Diffuser(extra_info,omi_lora_path,VAE,quantize_mode): from .OmniConsistency.src_inference.pipeline import FluxPipeline as FluxPipeline_dif from .OmniConsistency.src_inference.pipeline_ import FluxPipeline as FluxPipeline_dif_original from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig,FluxTransformer2DModel from .OmniConsistency.src_inference.lora_helper import set_single_lora flux_dif_repo=os.path.join(cur_path,"config/FLUX.1-dev") if extra_info.get("gguf_path") is not None: vae=convert_cfvae2diffuser(VAE,use_flux=True) print("use gguf quantization") from diffusers import GGUFQuantizationConfig transformer = FluxTransformer2DModel.from_single_file( extra_info.get("gguf_path"), config=os.path.join(cur_path, "config/FLUX.1-dev/transformer"), quantization_config=GGUFQuantizationConfig(compute_dtype=torch.bfloat16), torch_dtype=torch.bfloat16, ) pipeline = FluxPipeline_dif.from_pretrained(flux_dif_repo, vae=vae,transformer=transformer,text_encoder=None,text_encoder_2=None,torch_dtype=torch.bfloat16) elif extra_info.get("svdq_repo") is not None: print("use svdq") vae=convert_cfvae2diffuser(VAE,use_flux=True) from nunchaku import NunchakuFluxTransformer2dModel transformer = NunchakuFluxTransformer2dModel.from_pretrained(extra_info.get("svdq_repo"),offload=True) try: transformer.set_attention_impl("nunchaku-fp16") except: pass pipeline = FluxPipeline_dif.from_pretrained(flux_dif_repo, vae=vae,transformer=transformer,text_encoder=None,text_encoder_2=None,torch_dtype=torch.bfloat16) elif extra_info.get("unet_path") is not None: print("use single unet") vae=convert_cfvae2diffuser(VAE,use_flux=True) if quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_single_file(extra_info.get("unet_path"), config=os.path.join(cur_path,"config/FLUX.1-dev/transformer/config.json"), torch_dtype=torch.bfloat16) else: from safetensors.torch import load_file t_state_dict=load_file(extra_info.get("unet_path")) unet_config = FluxTransformer2DModel.load_config(os.path.join(cur_path,"config/FLUX.1-dev/transformer/config.json")) transformer = FluxTransformer2DModel.from_config(unet_config).to(torch.bfloat16) transformer.load_state_dict(t_state_dict, strict=False) del t_state_dict gc_cleanup() pipeline = FluxPipeline_dif.from_pretrained(flux_dif_repo, vae=vae,transformer=transformer,text_encoder=None,text_encoder_2=None,torch_dtype=torch.bfloat16) else: print(f"use {quantize_mode} quantization") repo_list=[i for i in [extra_info.get("repo1_path"),extra_info.get("repo2_path")] if i is not None] if repo_list: flux_repo=[i for i in repo_list if "flux" in i.lower()] else: raise "you must fill a flux repo" if quantize_mode=="nf4": #nf4 transformer = FluxTransformer2DModel.from_pretrained( flux_repo[0], subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ), torch_dtype=torch.bfloat16,) elif quantize_mode=="fp8": transformer = FluxTransformer2DModel.from_pretrained( flux_repo[0], subfolder="transformer", quantization_config=DiffusersBitsAndBytesConfig(load_in_8bit=True,), torch_dtype=torch.bfloat16, ) else: transformer = FluxTransformer2DModel.from_pretrained( flux_repo[0], subfolder="transformer", torch_dtype=torch.bfloat16, ) pipeline = FluxPipeline_dif_original.from_pretrained(flux_repo[0],transformer=transformer,torch_dtype=torch.bfloat16) multi_lora=[] if extra_info.get("lora1_path") is not None: multi_lora.append(extra_info.get("lora1_path")) if extra_info.get("lora2_path") is not None: multi_lora.append(extra_info.get("lora2_path")) if multi_lora: if len(multi_lora)==1: set_single_lora(pipeline.transformer, omi_lora_path, lora_weights=[1], cond_size=512) pipeline.unload_lora_weights() pipeline.load_lora_weights(os.path.dirname(multi_lora[0]),weight_name=os.path.basename(multi_lora[0])) else: from .OmniConsistency.src_inference.lora_helper import set_multi_lora lora_weights = [1]*len(multi_lora) set_multi_lora(pipeline.transformer, multi_lora, lora_weights=[[lora_weights]], cond_size=512) pipeline.unload_lora_weights() else: raise "need chocie a lora model in EasyFunction_Lite!" pipeline.enable_model_cpu_offload() return pipeline def load_lora_for_unet_only(pipeline, lora_path, adapter_name="default", lora_scale=1.0): try: pipeline.load_lora_weights(lora_path, adapter_name=adapter_name) pipeline.set_adapters(adapter_name, adapter_weights=lora_scale) print(f"成功加载LoRA权重: {adapter_name} (scale: {lora_scale})") except Exception as e: print(f"加载LoRA权重失败: {e}") return pipeline