diff --git a/CHANGELOG.md b/CHANGELOG.md index 941d5238b..753add9f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Update for 2025-10-23 +- **Models** + - [Tencent HunyuanImage 2.1](https://huggingface.co/tencent/HunyuanImage-2.1) in *full*, *distilled* and *refiner* variants + HunyuanImage-2.1 is a large (51GB) T2I model capable of natively generating 2K images and uses Qwen2.5 + T5 text-encoders and 32x VAE - **Features** - **offline mode**: enable in *settings -> hugginface* enables fully offline mode where previously downloaded models can be used as-is diff --git a/html/reference.json b/html/reference.json index b401cb544..1fb653172 100644 --- a/html/reference.json +++ b/html/reference.json @@ -1,52 +1,4 @@ { - "Tempest-by-Vlad XL": { - "path": "tempestByVlad_baseV01.safetensors@https://civitai.com/api/download/models/1301775", - "preview": "tempestByVlad_baseV01.jpg", - "desc": "Flexible SDXL model with custom encoder and finetuned for larger landscape resolutions with high details and high contrast.", - "tags": "community", - "size": 6.94, - "date": "2025 January", - "extras": "" - }, - "Tempest-by-Vlad XL Hyper": { - "path": "tempestByVlad_hyperV01.safetensors@https://civitai.com/api/download/models/1343512", - "preview": "tempestByVlad_hyperV01.jpg", - "desc": "Custom distilled variant with goal to get as-normal-as-possible model that works with low steps and guidance-free", - "tags": "community", - "size": 6.94, - "date": "2025 January", - "extras": "" - }, - - "Juggernaut XL XI": { - "path": "juggernautXL_juggXIByRundiffusion.safetensors@https://civitai.com/api/download/models/782002", - "preview": "juggernautXL_juggXIByRundiffusion.jpg", - "desc": "Showcase finetuned model based on Stable diffusion XL", - "date": "2024 August", - "size": 6.94, - "tags": "community", - "extras": "sampler: DEIS, steps: 20, cfg_scale: 6.0" - }, - "Juggernaut XL XI Lightning": { - "path": "juggernautXL_juggXILightningByRD.safetensors@https://civitai.com/api/download/models/920957", - "preview": "juggernautXL_juggXILightningByRD.jpg", - "desc": "Showcase finetuned model based on Stable diffusion XL", - "date": "2024 August", - "size": 6.94, - "tags": "community", - "extras": "sampler: DPM SDE, steps: 6, cfg_scale: 2.0" - }, - "Juggernaut SD Reborn": { - "original": true, - "path": "juggernaut_reborn.safetensors@https://civitai.com/api/download/models/274039", - "preview": "juggernaut_reborn.jpg", - "desc": "Showcase finetuned model based on Stable diffusion 1.5", - "date": "2023 December", - "size": 2.28, - "tags": "community", - "extras": "width: 512, height: 512, sampler: DEIS, steps: 20, cfg_scale: 6.0" - }, - "RunwayML StableDiffusion 1.5": { "original": true, "path": "v1-5-pruned-fp16-emaonly.safetensors@https://huggingface.co/Aptronym/SDNext/resolve/main/Reference/v1-5-pruned-fp16-emaonly.safetensors?download=true", @@ -647,6 +599,34 @@ "date": "2024 April" }, + "Tencent HunyuanImage 2.1": { + "path": "hunyuanvideo-community/HunyuanImage-2.1-Diffusers", + "desc": "HunyuanImage-2.1, a highly efficient text-to-image model that is capable of generating 2K (2048 × 2048) resolution images.", + "preview": "hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg", + "extras": "", + "skip": true, + "size": 0, + "date": "2025 August" + }, + "Tencent HunyuanImage 2.1 Distilled": { + "path": "hunyuanvideo-community/HunyuanImage-2.1-Distilled-Diffusers", + "desc": "HunyuanImage-2.1, a highly efficient text-to-image model that is capable of generating 2K (2048 × 2048) resolution images.", + "preview": "hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg", + "extras": "", + "tags": "distilled", + "skip": true, + "size": 0, + "date": "2025 August" + }, + "Tencent HunyuanImage 2.1 Refiner": { + "path": "hunyuanvideo-community/HunyuanImage-2.1-Refiner-Diffusers", + "desc": "HunyuanImage-2.1, a highly efficient text-to-image model that is capable of generating 2K (2048 × 2048) resolution images.", + "preview": "hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg", + "extras": "", + "skip": true, + "size": 0, + "date": "2025 August" + }, "Tencent HunyuanDiT 1.2": { "path": "Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers", "desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.", @@ -946,6 +926,52 @@ "extras": "sampler: Default", "size": 15.48, "date": "2023 April" - } + }, + "Tempest-by-Vlad XL": { + "path": "tempestByVlad_baseV01.safetensors@https://civitai.com/api/download/models/1301775", + "preview": "tempestByVlad_baseV01.jpg", + "desc": "Flexible SDXL model with custom encoder and finetuned for larger landscape resolutions with high details and high contrast.", + "tags": "community", + "size": 6.94, + "date": "2025 January", + "extras": "" + }, + "Tempest-by-Vlad XL Hyper": { + "path": "tempestByVlad_hyperV01.safetensors@https://civitai.com/api/download/models/1343512", + "preview": "tempestByVlad_hyperV01.jpg", + "desc": "Custom distilled variant with goal to get as-normal-as-possible model that works with low steps and guidance-free", + "tags": "community", + "size": 6.94, + "date": "2025 January", + "extras": "" + }, + "Juggernaut XL XI": { + "path": "juggernautXL_juggXIByRundiffusion.safetensors@https://civitai.com/api/download/models/782002", + "preview": "juggernautXL_juggXIByRundiffusion.jpg", + "desc": "Showcase finetuned model based on Stable diffusion XL", + "date": "2024 August", + "size": 6.94, + "tags": "community", + "extras": "sampler: DEIS, steps: 20, cfg_scale: 6.0" + }, + "Juggernaut XL XI Lightning": { + "path": "juggernautXL_juggXILightningByRD.safetensors@https://civitai.com/api/download/models/920957", + "preview": "juggernautXL_juggXILightningByRD.jpg", + "desc": "Showcase finetuned model based on Stable diffusion XL", + "date": "2024 August", + "size": 6.94, + "tags": "community", + "extras": "sampler: DPM SDE, steps: 6, cfg_scale: 2.0" + }, + "Juggernaut SD Reborn": { + "original": true, + "path": "juggernaut_reborn.safetensors@https://civitai.com/api/download/models/274039", + "preview": "juggernaut_reborn.jpg", + "desc": "Showcase finetuned model based on Stable diffusion 1.5", + "date": "2023 December", + "size": 2.28, + "tags": "community", + "extras": "width: 512, height: 512, sampler: DEIS, steps: 20, cfg_scale: 6.0" + } } diff --git a/installer.py b/installer.py index d668cb86d..d930851a5 100644 --- a/installer.py +++ b/installer.py @@ -611,7 +611,7 @@ def check_diffusers(): if args.skip_git: install('diffusers') return - sha = 'b3e56e71fb7c73601851bb83e7583f113f563d26' # diffusers commit hash + sha = '7536f647e4144c7acaf9e140893ff7edb85bf9a3' # diffusers commit hash # if args.use_rocm or args.use_zluda or args.use_directml: # sha = '043ab2520f6a19fce78e6e060a68dbc947edb9f9' # lock diffusers versions for now pkg = pkg_resources.working_set.by_key.get('diffusers', None) diff --git a/models/Reference/Tiwaz--CenKreChro.jpg b/models/Reference/Tiwaz--CenKreChro.jpg new file mode 100644 index 000000000..f657dc131 Binary files /dev/null and b/models/Reference/Tiwaz--CenKreChro.jpg differ diff --git a/models/Reference/hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg b/models/Reference/hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg new file mode 100644 index 000000000..4e7f34c88 Binary files /dev/null and b/models/Reference/hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg differ diff --git a/models/Reference/noobaiXLNAIXL_epsilonPred11Version.jpg b/models/Reference/noobaiXLNAIXL_epsilonPred11Version.jpg new file mode 100644 index 000000000..cbb7cc1fa Binary files /dev/null and b/models/Reference/noobaiXLNAIXL_epsilonPred11Version.jpg differ diff --git a/models/Reference/noobaiXLNAIXL_vPred10Version.jpg b/models/Reference/noobaiXLNAIXL_vPred10Version.jpg new file mode 100644 index 000000000..17dd2c8d4 Binary files /dev/null and b/models/Reference/noobaiXLNAIXL_vPred10Version.jpg differ diff --git a/models/Reference/ponyRealism_V23.jpg b/models/Reference/ponyRealism_V23.jpg new file mode 100644 index 000000000..c92446fd6 Binary files /dev/null and b/models/Reference/ponyRealism_V23.jpg differ diff --git a/models/Reference/waiANIPONYXL_v140.jpg b/models/Reference/waiANIPONYXL_v140.jpg new file mode 100644 index 000000000..7888d1eeb Binary files /dev/null and b/models/Reference/waiANIPONYXL_v140.jpg differ diff --git a/models/Reference/waiIllustriousSDXL_v150.jpg b/models/Reference/waiIllustriousSDXL_v150.jpg new file mode 100644 index 000000000..4d697cf70 Binary files /dev/null and b/models/Reference/waiIllustriousSDXL_v150.jpg differ diff --git a/modules/loader.py b/modules/loader.py index a224c05c7..d540fbac9 100644 --- a/modules/loader.py +++ b/modules/loader.py @@ -129,6 +129,8 @@ import tqdm as tqdm_lib # pylint: disable=C0411 from tqdm.rich import tqdm # pylint: disable=W0611,C0411 try: + logging.getLogger("diffusers.guiders").setLevel(logging.ERROR) + logging.getLogger("diffusers.loaders.single_file").setLevel(logging.ERROR) import diffusers.utils.import_utils # pylint: disable=W0611,C0411 diffusers.utils.import_utils._k_diffusion_available = True # pylint: disable=protected-access # monkey-patch since we use k-diffusion from git diffusers.utils.import_utils._k_diffusion_version = '0.0.12' # pylint: disable=protected-access @@ -136,7 +138,6 @@ try: import diffusers # pylint: disable=W0611,C0411 import diffusers.loaders.single_file # pylint: disable=W0611,C0411 diffusers.loaders.single_file.logging.tqdm = partial(tqdm, unit='C') - logging.getLogger("diffusers.loaders.single_file").setLevel(logging.ERROR) timer.startup.record("diffusers") except Exception as e: errors.log.error(f'Loader: diffusers=={diffusers.__version__ if "diffusers" in sys.modules else None} {e}') diff --git a/modules/lora/lora_overrides.py b/modules/lora/lora_overrides.py index 5889e1dec..b47e58862 100644 --- a/modules/lora/lora_overrides.py +++ b/modules/lora/lora_overrides.py @@ -31,6 +31,7 @@ force_models_diffusers = [ # forced always 'h1', 'kandinsky', 'hunyuandit', + 'hunyuanimage', 'auraflow', 'lumina2', 'qwen', diff --git a/modules/modeldata.py b/modules/modeldata.py index 881a5fba0..c7224d06a 100644 --- a/modules/modeldata.py +++ b/modules/modeldata.py @@ -80,6 +80,8 @@ def get_model_type(pipe): model_type = 'wanai' elif 'HDM-xut' in name: model_type = 'hdm' + elif 'HunyuanImage' in name: + model_type = 'hunyuanimage' else: model_type = name return model_type diff --git a/modules/modular.py b/modules/modular.py index 5f3bfefc2..ac744f6d0 100644 --- a/modules/modular.py +++ b/modules/modular.py @@ -26,6 +26,11 @@ def is_compatible(diffusion_pipeline: diffusers.DiffusionPipeline) -> bool: return compatible +def is_guider(diffusion_pipeline: diffusers.DiffusionPipeline) -> bool: + guider = getattr(diffusion_pipeline, 'guider', None) + return guider is not None + + def convert_to_modular(diffusion_pipeline: diffusers.DiffusionPipeline) -> diffusers.ModularPipeline: modular_pipe = None try: diff --git a/modules/modular_guiders.py b/modules/modular_guiders.py index 556ad52b4..8ddc8e572 100644 --- a/modules/modular_guiders.py +++ b/modules/modular_guiders.py @@ -32,16 +32,24 @@ def set_guider(p: processing.StableDiffusionProcessing): if guidance_name == 'Default': if hasattr(shared.sd_model, 'default_guider'): guider_info = shared.sd_model.default_guider + guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) shared.sd_model.update_components(guider=guider_info) - else: + elif hasattr(shared.sd_model, 'get_component_spec'): guider_info = shared.sd_model.get_component_spec("guider") + guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) shared.sd_model.default_guider = guider_info - guider_cls = guider_info.type_hint + elif hasattr(shared.sd_model, 'guider') and hasattr(shared.sd_model.guider, 'config'): + guider_info = shared.sd_model.guider + guider_cls = type(shared.sd_model.guider) + # shared.sd_model.default_guider = guider_info + else: + guider_info = None + guider_cls = None if guider_info is not None and guider_cls is not None and guider_info.config is not None: guider_args = {k: v for k, v in guider_info.config.items() if not k.startswith('_') and v is not None} else: guider_args = {} - shared.log.info(f'Guider: name={guidance_name} cls={guider_cls.__name__} args={guider_args}') + shared.log.info(f'Guider: name={guidance_name} cls={guider_cls.__name__ if guider_cls is not None else None} args={guider_args}') return if guidance_name == 'None': shared.sd_model.update_components(guider=None) # breaks the pipeline diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 277b5e1c5..dffeaf780 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -102,8 +102,9 @@ def process_pre(p: processing.StableDiffusionProcessing): modular_pipe = modular.convert_to_modular(shared.sd_model) if modular_pipe is not None: shared.sd_model = modular_pipe - from modules import modular_guiders - modular_guiders.set_guider(p) + if modular.is_guider(shared.sd_model): + from modules import modular_guiders + modular_guiders.set_guider(p) timer.process.record('pre') diff --git a/modules/sd_models.py b/modules/sd_models.py index c619c8ca2..6696c7d23 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -46,6 +46,7 @@ pipe_switch_task_exclude = [ 'StableDiffusionReferencePipeline', 'StableDiffusionXLInstantIDPipeline', 'XOmniPipeline', + 'HunyuanImagePipeline', ] i2i_pipes = [ 'LEditsPPPipelineStableDiffusion', 'LEditsPPPipelineStableDiffusionXL', diff --git a/modules/sd_offload.py b/modules/sd_offload.py index 59aea6fd0..b40fe8815 100644 --- a/modules/sd_offload.py +++ b/modules/sd_offload.py @@ -14,7 +14,7 @@ from modules.timer import process as process_timer debug = os.environ.get('SD_MOVE_DEBUG', None) is not None verbose = os.environ.get('SD_MOVE_VERBOSE', None) is not None debug_move = log.trace if debug else lambda *args, **kwargs: None -offload_warn = ['sc', 'sd3', 'f1', 'h1', 'hunyuandit', 'auraflow', 'omnigen', 'omnigen2', 'cogview4', 'cosmos', 'chroma', 'x-omni'] +offload_warn = ['sc', 'sd3', 'f1', 'h1', 'hunyuandit', 'auraflow', 'omnigen', 'omnigen2', 'cogview4', 'cosmos', 'chroma', 'x-omni', 'hunyuanimage'] offload_post = ['h1'] offload_hook_instance = None balanced_offload_exclude = ['CogView4Pipeline', 'MeissonicPipeline'] diff --git a/modules/shared_items.py b/modules/shared_items.py index f09df5769..f01ee6e33 100644 --- a/modules/shared_items.py +++ b/modules/shared_items.py @@ -45,6 +45,7 @@ pipelines = { 'Cosmos': getattr(diffusers, 'Cosmos2TextToImagePipeline', None), 'WanAI': getattr(diffusers, 'WanPipeline', None), 'Qwen': getattr(diffusers, 'QwenImagePipeline', None), + 'HunyuanImage': getattr(diffusers, 'HunyuanImagePipeline', None), # dynamically imported and redefined later 'Meissonic': getattr(diffusers, 'DiffusionPipeline', None), @@ -55,7 +56,6 @@ pipelines = { 'FLite': getattr(diffusers, 'DiffusionPipeline', None), 'Bria': getattr(diffusers, 'DiffusionPipeline', None), 'hdm': getattr(diffusers, 'DiffusionPipeline', None), - 'HunyuanImage': getattr(diffusers, 'DiffusionPipeline', None), 'X-Omni': getattr(diffusers, 'DiffusionPipeline', None), } diff --git a/pipelines/generic.py b/pipelines/generic.py index f14f88ab8..e78ac7b8b 100644 --- a/pipelines/generic.py +++ b/pipelines/generic.py @@ -141,6 +141,20 @@ def load_text_encoder(repo_id, cls_name, load_config={}, subfolder="text_encoder **load_args, **quant_args, ) + elif cls_name == transformers.Qwen2_5_VLForConditionalGeneration and allow_shared: + if shared.opts.te_shared_t5: + repo_id = 'hunyuanvideo-community/HunyuanImage-2.1-Diffusers' + subfolder = 'text_encoder' + shared.log.debug(f'Load model: text_encoder="{repo_id}" cls={cls_name.__name__} quant="{quant_type}" shared={shared.opts.te_shared_t5}') + if dtype is not None: + load_args['torch_dtype'] = dtype + text_encoder = cls_name.from_pretrained( + repo_id, + cache_dir=shared.opts.hfcache_dir, + subfolder=subfolder, + **load_args, + **quant_args, + ) # load from repo if text_encoder is None: diff --git a/pipelines/model_hyimage.py b/pipelines/model_hyimage.py index 0d731a6c9..b91cff00c 100644 --- a/pipelines/model_hyimage.py +++ b/pipelines/model_hyimage.py @@ -1,44 +1,37 @@ -from modules import shared, sd_models, devices, model_quant, errors # pylint: disable=unused-import +import transformers +import diffusers +from modules import shared, sd_models, devices, model_quant, sd_hijack_te, sd_hijack_vae +from pipelines import generic def load_hyimage(checkpoint_info, diffusers_load_config={}): # pylint: disable=unused-argument repo_id = sd_models.path_to_repo(checkpoint_info) sd_models.hf_auth_check(checkpoint_info) - shared.log.error(f'Load model: type=NextStep model="{checkpoint_info.name}" repo="{repo_id}" not supported') - - """ load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config) - shared.log.debug(f'Load model: type=HunyuanImage repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') + shared.log.debug(f'Load model: type=HunyuanImage21 repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') - sys.path.append(os.path.dirname(__file__)) - from pipelines.hyimage.diffusion.pipelines.hunyuanimage_pipeline import HunyuanImagePipeline, HunyuanImagePipelineConfig - from pipelines.hyimage.common.config import instantiate - - use_distilled = 'distilled' in repo_id.lower() - config = HunyuanImagePipelineConfig.create_default(version='v2.1', use_distilled=use_distilled) - config.torch_dtype = devices.dtype - config.device = devices.device - config.enable_dit_offloading = False - config.enable_reprompt_model_offloading = False - config.enable_refiner_offloading = False - - pipe = HunyuanImagePipeline(config=config) - - snapshot_folder = snapshot_download(repo_id, cache_dir=shared.opts.hfcache_dir, allow_patterns='vae/vae_2_1/*') - pipe.config.vae_config.load_from = os.path.join(snapshot_folder, 'vae/vae_2_1') - pipe.vae = instantiate(pipe.config.vae_config.model, vae_path=pipe.config.vae_config.load_from) - - pipe._load_dit() # pylint: disable=protected-access - pipe._load_byt5() # pylint: disable=protected-access - pipe._load_text_encoder() # pylint: disable=protected-access - pipe._load_reprompt_model() # pylint: disable=protected-access + transformer = generic.load_transformer(repo_id, cls_name=diffusers.HunyuanImageTransformer2DModel, load_config=diffusers_load_config, subfolder="transformer") + text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.Qwen2_5_VLForConditionalGeneration, load_config=diffusers_load_config, subfolder="text_encoder") + text_encoder_2 = generic.load_text_encoder(repo_id, cls_name=transformers.T5EncoderModel, load_config=diffusers_load_config, subfolder="text_encoder_2", allow_shared=False) + pipe = diffusers.HunyuanImagePipeline.from_pretrained( + repo_id, + transformer=transformer, + text_encoder=text_encoder, + text_encoder_2=text_encoder_2, + cache_dir=shared.opts.diffusers_dir, + **load_args, + ) pipe.task_args = { - 'use_reprompt': False, - 'use_refiner': False, + 'output_type': 'np', } + del transformer + del text_encoder + del text_encoder_2 + sd_hijack_te.init_hijack(pipe) + sd_hijack_vae.init_hijack(pipe) + devices.torch_gc(force=True, reason='load') - """ - return None + return pipe