Skip to content

Commit 3eabbd0

Browse files
Bluear7878lmxyy
andauthored
fix: txt2_img pipe and controlnet pipe share components (#452)
* fix:txt2_img pipe and controlnet pipe share components * add the test script * comfyUI bug fix * garbage collection * wrap the test --------- Co-authored-by: Muyang Li <lmxyy1999@foxmail.com>
1 parent e419dc2 commit 3eabbd0

3 files changed

Lines changed: 128 additions & 6 deletions

File tree

nunchaku/caching/diffusers_adapters/flux.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,20 @@ def apply_cache_on_transformer(
4141

4242
@functools.wraps(original_forward)
4343
def new_forward(self, *args, **kwargs):
44-
with (
45-
unittest.mock.patch.object(self, "transformer_blocks", cached_transformer_blocks),
46-
unittest.mock.patch.object(self, "single_transformer_blocks", dummy_single_transformer_blocks),
47-
):
44+
cache_context = utils.get_current_cache_context()
45+
if cache_context is not None:
46+
with (
47+
unittest.mock.patch.object(self, "transformer_blocks", cached_transformer_blocks),
48+
unittest.mock.patch.object(self, "single_transformer_blocks", dummy_single_transformer_blocks),
49+
):
50+
transformer._is_cached = True
51+
transformer.cached_transformer_blocks = cached_transformer_blocks
52+
transformer.single_transformer_blocks = dummy_single_transformer_blocks
53+
return original_forward(*args, **kwargs)
54+
else:
4855
return original_forward(*args, **kwargs)
4956

5057
transformer.forward = new_forward.__get__(transformer)
51-
transformer._is_cached = True
5258

5359
return transformer
5460

nunchaku/caching/diffusers_adapters/sana.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ def apply_cache_on_transformer(transformer: SanaTransformer2DModel, *, residual_
2323

2424
@functools.wraps(original_forward)
2525
def new_forward(self, *args, **kwargs):
26-
with unittest.mock.patch.object(self, "transformer_blocks", cached_transformer_blocks):
26+
cache_context = utils.get_current_cache_context()
27+
if cache_context is not None:
28+
with unittest.mock.patch.object(self, "transformer_blocks", cached_transformer_blocks):
29+
return original_forward(*args, **kwargs)
30+
else:
2731
return original_forward(*args, **kwargs)
2832

2933
transformer.forward = new_forward.__get__(transformer)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import gc
2+
3+
import torch
4+
from diffusers import (
5+
AutoencoderKL,
6+
FlowMatchEulerDiscreteScheduler,
7+
FluxControlNetModel,
8+
FluxControlNetPipeline,
9+
FluxPipeline,
10+
)
11+
from diffusers.models import FluxMultiControlNetModel
12+
from diffusers.utils import load_image
13+
from transformers import CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
14+
15+
from nunchaku import NunchakuT5EncoderModel
16+
from nunchaku.caching.diffusers_adapters import apply_cache_on_pipe
17+
from nunchaku.models.transformers.transformer_flux import NunchakuFluxTransformer2dModel
18+
from nunchaku.utils import get_precision
19+
20+
21+
def test_flux_txt2img_cache_controlnet():
22+
bfl_repo = "black-forest-labs/FLUX.1-dev"
23+
dtype = torch.bfloat16 # or torch.float16, or torch.float32
24+
device = "cuda" # or "cpu" if you want to run on CPU
25+
26+
scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(bfl_repo, subfolder="scheduler", torch_dtype=dtype)
27+
text_encoder = CLIPTextModel.from_pretrained(bfl_repo, subfolder="text_encoder", torch_dtype=dtype)
28+
text_encoder_2 = T5EncoderModel.from_pretrained(bfl_repo, subfolder="text_encoder_2", torch_dtype=dtype)
29+
tokenizer = CLIPTokenizer.from_pretrained(
30+
bfl_repo, subfolder="tokenizer", torch_dtype=dtype, clean_up_tokenization_spaces=True
31+
)
32+
tokenizer_2 = T5TokenizerFast.from_pretrained(
33+
bfl_repo, subfolder="tokenizer_2", torch_dtype=dtype, clean_up_tokenization_spaces=True
34+
)
35+
vae = AutoencoderKL.from_pretrained(bfl_repo, subfolder="vae", torch_dtype=dtype)
36+
precision = get_precision()
37+
transformer = NunchakuFluxTransformer2dModel.from_pretrained(
38+
f"mit-han-lab/nunchaku-flux.1-dev/svdq-{precision}_r32-flux.1-dev.safetensors",
39+
# offload=True
40+
)
41+
transformer.set_attention_impl("nunchaku-fp16")
42+
43+
# qencoder
44+
text_encoder_2 = NunchakuT5EncoderModel.from_pretrained("mit-han-lab/nunchaku-t5/awq-int4-flux.1-t5xxl.safetensors")
45+
controlnet_union = FluxControlNetModel.from_pretrained(
46+
"Shakker-Labs/FLUX.1-dev-ControlNet-Union-Pro-2.0", torch_dtype=torch.bfloat16
47+
)
48+
controlnet = FluxMultiControlNetModel(
49+
[controlnet_union]
50+
) # we always recommend loading via FluxMultiControlNetModel
51+
52+
params = {
53+
"scheduler": scheduler,
54+
"vae": vae,
55+
"tokenizer": tokenizer,
56+
"tokenizer_2": tokenizer_2,
57+
"text_encoder": text_encoder,
58+
"text_encoder_2": text_encoder_2,
59+
"transformer": transformer,
60+
}
61+
# pipe
62+
pipe = FluxPipeline(**params).to(device, dtype=dtype)
63+
pipe_cn = FluxControlNetPipeline(**params, controlnet=controlnet).to(device, dtype)
64+
65+
# offload
66+
pipe.enable_sequential_cpu_offload(device=device)
67+
pipe_cn.enable_sequential_cpu_offload(device=device)
68+
69+
# cache
70+
apply_cache_on_pipe(
71+
pipe_cn,
72+
use_double_fb_cache=True,
73+
residual_diff_threshold_multi=0.09,
74+
residual_diff_threshold_single=0.12,
75+
)
76+
77+
params = {
78+
"prompt": "A bohemian-style female travel blogger with sun-kissed skin and messy beach waves.",
79+
"height": 1152,
80+
"width": 768,
81+
"num_inference_steps": 30,
82+
"guidance_scale": 3.5,
83+
}
84+
85+
# pipe
86+
txt2img_res = pipe(
87+
**params,
88+
).images[0]
89+
txt2img_res.save("flux.1-dev-txt2img.jpg")
90+
91+
gc.collect()
92+
torch.cuda.empty_cache()
93+
94+
# cache
95+
apply_cache_on_pipe(
96+
pipe_cn,
97+
use_double_fb_cache=True,
98+
residual_diff_threshold_multi=0.09,
99+
residual_diff_threshold_single=0.12,
100+
)
101+
102+
# pipe_cn
103+
control_iamge = load_image(
104+
"https://huggingface.co/Shakker-Labs/FLUX.1-dev-ControlNet-Union-Pro/resolve/main/assets/openpose.jpg"
105+
)
106+
params["control_image"] = [control_iamge]
107+
params["controlnet_conditioning_scale"] = [0.9]
108+
params["control_guidance_end"] = [0.65]
109+
cn_res = pipe_cn(
110+
**params,
111+
).images[0]
112+
cn_res.save("flux.1-dev-cn-txt2img.jpg")

0 commit comments

Comments
 (0)