nunchaku flux.1-pulid

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2025-09-21 12:33:54 -04:00
parent 2d14a6412d
commit 2ac299a5a4
5 changed files with 63 additions and 8 deletions
+3 -1
View File
@@ -1,6 +1,6 @@
# Change Log for SD.Next
## Update for 2025-09-20
## Update for 2025-09-21
- **Models**
- [WAN 2.2 14B VACE](https://huggingface.co/alibaba-pai/Wan2.2-VACE-Fun-A14B)
@@ -12,6 +12,8 @@
note that nunchaku optimized and prequantized unet is replacement for base unet, so its only applicable to base models, not any of finetunes
*how to use*: enable nunchaku in settings -> quantization and then load either sdxl-base or sdxl-base-turbo reference models
*note*: sdxl support for nunchaku is not in released version of `nunchaku==1.0.0`, so you need to build [nunchaku](https://nunchaku.tech/docs/nunchaku/installation/installation.html) from source
- [Nunchaku Flux.1 PulID](https://nunchaku.tech/docs/nunchaku/python_api/nunchaku.pipeline.pipeline_flux_pulid.html)
automatically enabled if loaded model is FLUX.1 with Nunchaku engine enabled and when PulID script is enabled
- **Offloading**
- improve offloading for pipelines with multiple stages such as *wan-2.2-14b*
- add timers to measure onload/offload times during generate
+6 -3
View File
@@ -1269,9 +1269,12 @@ def install_pydantic():
def install_insightface():
install('git+https://github.com/deepinsight/insightface@29b6cd65aa0e9ae3b6602de3c52e9d8949c8ee86#subdirectory=python-package', 'insightface') # insightface==0.7.3 with patches
# install('albumentations==1.4.3', ignore=True, quiet=True)
uninstall('albumentations')
install('albumentationsx')
if args.new:
uninstall('albumentations')
install('albumentationsx')
else:
uninstall('albumentationsx')
install('albumentations==1.4.3', ignore=True, quiet=True)
install_pydantic()
+1
View File
@@ -8,6 +8,7 @@ from modules.errors import log
sys.path.append(os.path.dirname(__file__))
try:
from pulid_sdxl import StableDiffusionXLPuLIDPipeline, StableDiffusionXLPuLIDPipelineImage, StableDiffusionXLPuLIDPipelineInpaint
from pulid_flux import apply_flux, unapply_flux
from pulid_utils import resize_numpy_image_long as resize
import attention_processor as attention
import pulid_sampling as sampling
+35
View File
@@ -0,0 +1,35 @@
from types import MethodType
import accelerate
from diffusers import FluxPipeline
from modules import shared, sd_models
def apply_flux(pipe: FluxPipeline):
if not hasattr(pipe, 'transformer') or not 'Nunchaku' in pipe.transformer.__class__.__name__:
shared.log.error('PuLID: flux support requires nunchaku')
return pipe
from nunchaku.pipeline.pipeline_flux_pulid import PuLIDFluxPipeline
if not isinstance(pipe, PuLIDFluxPipeline):
from nunchaku.models.pulid.pulid_forward import pulid_forward
sd_models.clear_caches(full=True)
accelerate.hooks.remove_hook_from_module(pipe.transformer, recurse=True)
pipe = sd_models.switch_pipe(PuLIDFluxPipeline, pipe)
pipe.transformer.orig_forward = pipe.transformer.forward
pipe.transformer.forward = MethodType(pulid_forward, pipe.transformer)
pipe = sd_models.apply_balanced_offload(pipe)
pipe.pulid_model = sd_models.apply_balanced_offload(pipe.pulid_model)
shared.log.info(f'PuLID: flux applied cls={pipe.__class__.__name__} pipe={pipe.pulid_model.__class__.__name__}')
return pipe
def unapply_flux(pipe: FluxPipeline):
from nunchaku.pipeline.pipeline_flux_pulid import PuLIDFluxPipeline
if isinstance(pipe, PuLIDFluxPipeline) and hasattr(pipe.transformer, 'orig_forward'):
sd_models.clear_caches(full=True)
accelerate.hooks.remove_hook_from_module(pipe.transformer, recurse=True)
pipe.transformer.forward = MethodType(pipe.transformer.orig_forward, pipe.transformer)
del pipe.transformer.orig_forward
pipe = sd_models.switch_pipe(FluxPipeline, pipe)
pipe = sd_models.apply_balanced_offload(pipe)
return pipe
+18 -4
View File
@@ -200,14 +200,12 @@ class Script(scripts_manager.Script):
errors.display(e, 'PuLID')
return None
elif shared.sd_model_type == 'f1':
# TODO nunchaku: pulid-f1
shared.log.error('PuLID: f1 not supported')
return None
shared.sd_model = self.pulid.apply_flux(shared.sd_model)
if shared.sd_model_type == 'sdxl':
processed = self.run_sdxl(p, images, strength, zero, sampler, ortho, restore, offload, version)
elif shared.sd_model_type == 'f1':
processed = None
processed = self.run_flux(p, images, strength)
else:
shared.log.error(f'PuLID: class={shared.sd_model.__class__.__name__} model={shared.sd_model_type} required={supported_model_list}')
processed = None
@@ -227,6 +225,12 @@ class Script(scripts_manager.Script):
shared.sd_model = shared.sd_model.pipe
devices.torch_gc(force=True, reason='pulid')
shared.log.debug(f'PuLID complete: class={shared.sd_model.__class__.__name__} preprocess={self.preprocess:.2f} pipe={"restore" if restore else "cache"}')
if shared.sd_model_type == "f1":
restore = getattr(p, 'pulid_restore', restore)
if restore:
shared.sd_model = self.pulid.unapply_flux(shared.sd_model)
devices.torch_gc(force=True, reason='pulid')
shared.log.debug(f'PuLID complete: class={shared.sd_model.__class__.__name__} pipe={"restore" if restore else "cache"}')
return processed
def run_sdxl(self, p: processing.StableDiffusionProcessing, images: list, strength: float, zero: int, sampler: str, ortho: str, restore: bool, offload: bool, version: str):
@@ -285,3 +289,13 @@ class Script(scripts_manager.Script):
# interim = [Image.fromarray(img) for img in shared.sd_model.debug_img_list]
# shared.log.debug(f'PuLID: time={t1-t0:.2f}')
return processed
def run_flux(self, p: processing.StableDiffusionProcessing, images: list, strength: float):
image = Image.fromarray(images[0]) # takes single pil image
p.task_args['id_image'] = image
p.task_args['id_weight'] = strength
shared.log.info(f'PuLID: class={shared.sd_model.__class__.__name__} strength={strength} image={image}')
p.extra_generation_params["PuLID"] = f'Strength={strength}'
processed: processing.Processed = processing.process_images(p) # runs processing using main loop
return processed