Skip to content

Commit a4647e1

Browse files
committed
FBCache and comfyUI
1 parent a41d686 commit a4647e1

10 files changed

Lines changed: 348 additions & 216 deletions

File tree

examples/flux.1-dev-IP-adapter.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from diffusers.utils import load_image
44

55
from nunchaku import NunchakuFluxTransformer2dModel
6+
from nunchaku.caching.diffusers_adapters import apply_cache_on_pipe
67
from nunchaku.models.IP_adapter.diffusers_adapters import apply_IPA_on_pipe
78
from nunchaku.utils import get_precision
89

@@ -18,9 +19,16 @@
1819
weight_name="ip_adapter.safetensors",
1920
image_encoder_pretrained_model_name_or_path="openai/clip-vit-large-patch14",
2021
)
22+
apply_cache_on_pipe(
23+
pipeline,
24+
use_double_fb_cache=True,
25+
residual_diff_threshold_multi=0.09,
26+
residual_diff_threshold_single=0.12,
27+
)
2128

2229
apply_IPA_on_pipe(pipeline, ip_adapter_scale=1.0, repo_id="XLabs-AI/flux-ip-adapter-v2")
2330

31+
2432
IP_image = load_image("https://github.com/ToTheBeginning/PuLID/blob/main/example_inputs/liuyifei.png?raw=true")
2533

2634
image = pipeline(

nunchaku/caching/diffusers_adapters/flux.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@ def apply_cache_on_transformer(
1313
use_double_fb_cache: bool = False,
1414
residual_diff_threshold: float = 0.12,
1515
residual_diff_threshold_multi: float | None = None,
16-
residual_diff_threshold_single: float = 0.1,
16+
residual_diff_threshold_single: float | None = None,
1717
):
18+
if not hasattr(transformer, "_original_forward"):
19+
transformer._original_forward = transformer.forward
20+
if not hasattr(transformer, "_original_blocks"):
21+
transformer._original_blocks = transformer.transformer_blocks
22+
1823
if residual_diff_threshold_multi is None:
1924
residual_diff_threshold_multi = residual_diff_threshold
2025

@@ -49,6 +54,9 @@ def new_forward(self, *args, **kwargs):
4954

5055
transformer.forward = new_forward.__get__(transformer)
5156
transformer._is_cached = True
57+
transformer.use_double_fb_cache = use_double_fb_cache
58+
transformer.residual_diff_threshold_multi = residual_diff_threshold_multi
59+
transformer.residual_diff_threshold_single = residual_diff_threshold_single
5260

5361
return transformer
5462

nunchaku/caching/utils.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def forward(
260260
can_use_cache, _ = get_can_use_cache(
261261
first_hidden_states_residual,
262262
threshold=self.residual_diff_threshold,
263-
parallelized=self.transformer is not None and getattr(self.transformer, "_is_parallelized", False),
263+
parallelized=False,
264264
)
265265

266266
torch._dynamo.graph_break()
@@ -329,7 +329,7 @@ def __init__(
329329
verbose: bool = False,
330330
):
331331
super().__init__()
332-
self.transformer = transformer
332+
# self.transformer = transformer
333333
self.transformer_blocks = transformer.transformer_blocks
334334
self.single_transformer_blocks = transformer.single_transformer_blocks
335335

@@ -486,7 +486,7 @@ def forward(
486486
hidden_states=hidden_states,
487487
encoder_hidden_states=encoder_hidden_states,
488488
threshold=self.residual_diff_threshold_multi,
489-
parallelized=(self.transformer is not None and getattr(self.transformer, "_is_parallelized", False)),
489+
parallelized=False,
490490
mode="multi",
491491
verbose=self.verbose,
492492
call_remaining_fn=call_remaining_fn,
@@ -515,7 +515,7 @@ def forward(
515515
hidden_states=cat_hidden_states,
516516
encoder_hidden_states=None,
517517
threshold=self.residual_diff_threshold_single,
518-
parallelized=(self.transformer is not None and getattr(self.transformer, "_is_parallelized", False)),
518+
parallelized=False,
519519
mode="single",
520520
verbose=self.verbose,
521521
call_remaining_fn=call_remaining_fn_single,
@@ -591,8 +591,9 @@ def call_remaining_multi_transformer_blocks(
591591
controlnet_single_block_samples=None,
592592
skip_first_layer=False,
593593
txt_tokens=None,
594+
start_idx=1,
594595
):
595-
start_idx = 1
596+
start_idx = start_idx
596597
original_hidden_states = hidden_states.clone()
597598
original_encoder_hidden_states = encoder_hidden_states.clone()
598599

@@ -627,8 +628,9 @@ def call_remaining_single_transformer_blocks(
627628
controlnet_single_block_samples=None,
628629
skip_first_layer=False,
629630
txt_tokens=None,
631+
start_idx=1,
630632
):
631-
start_idx = 1
633+
start_idx = start_idx
632634
original_hidden_states = hidden_states.clone()
633635

634636
for idx in range(start_idx, num_single_transformer_blocks):

nunchaku/csrc/flux.h

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,6 @@ class QuantizedFluxModel : public ModuleWrapper<FluxModel> { // : public torch::
220220
torch::Tensor temb,
221221
torch::Tensor rotary_emb_img,
222222
torch::Tensor rotary_emb_context,
223-
torch::Tensor k_img,
224-
torch::Tensor v_img,
225223
std::optional<torch::Tensor> controlnet_block_samples = std::nullopt,
226224
std::optional<torch::Tensor> controlnet_single_block_samples = std::nullopt) {
227225
CUDADeviceContext ctx(deviceId);
@@ -233,8 +231,6 @@ class QuantizedFluxModel : public ModuleWrapper<FluxModel> { // : public torch::
233231
temb = temb.contiguous();
234232
rotary_emb_img = rotary_emb_img.contiguous();
235233
rotary_emb_context = rotary_emb_context.contiguous();
236-
k_img = k_img.contiguous();
237-
v_img = v_img.contiguous();
238234

239235
auto &&[hidden_states_, encoder_hidden_states_, ip_query_] = net->forward_ip_adapter(
240236
idx,
@@ -243,22 +239,13 @@ class QuantizedFluxModel : public ModuleWrapper<FluxModel> { // : public torch::
243239
from_torch(temb),
244240
from_torch(rotary_emb_img),
245241
from_torch(rotary_emb_context),
246-
from_torch(k_img),
247-
from_torch(v_img),
248242
controlnet_block_samples.has_value() ? from_torch(controlnet_block_samples.value().contiguous()) : Tensor{},
249243
controlnet_single_block_samples.has_value()
250244
? from_torch(controlnet_single_block_samples.value().contiguous())
251245
: Tensor{});
252-
/*
253-
auto ip_attn_output_contig =
254-
ip_attn_output_.is_contiguous()
255-
? ip_attn_output_
256-
: ip_attn_output_.copy(ip_attn_output_.device());
257-
*/
258246

259-
hidden_states = to_torch(hidden_states_);
260-
encoder_hidden_states = to_torch(encoder_hidden_states_);
261-
// torch::Tensor ip_attn_output = to_torch(ip_attn_output_contig);
247+
hidden_states = to_torch(hidden_states_);
248+
encoder_hidden_states = to_torch(encoder_hidden_states_);
262249
torch::Tensor ip_query = to_torch(ip_query_);
263250
Tensor::synchronizeDevice();
264251

nunchaku/csrc/pybind.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
5757
py::arg("temb"),
5858
py::arg("rotary_emb_img"),
5959
py::arg("rotary_emb_context"),
60-
py::arg("k_img"),
61-
py::arg("v_img"),
6260
py::arg("controlnet_block_samples") = py::none(),
6361
py::arg("controlnet_single_block_samples") = py::none())
6462
.def("forward_single_layer", &QuantizedFluxModel::forward_single_layer)

nunchaku/models/IP_adapter/diffusers_adapters/flux.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import functools
2+
import unittest
3+
14
from diffusers import DiffusionPipeline, FluxTransformer2DModel
25
from torch import nn
36

7+
from nunchaku.caching.utils import cache_context, create_cache_context
8+
from nunchaku.models.IP_adapter.utils import undo_all_mods_on_transformer
9+
410
from ...IP_adapter import utils
511

612

713
def apply_IPA_on_transformer(transformer: FluxTransformer2DModel, *, ip_adapter_scale: float = 1.0, repo_id: str):
8-
914
IPA_transformer_blocks = nn.ModuleList(
1015
[
1116
utils.IPA_TransformerBlocks(
@@ -16,19 +21,52 @@ def apply_IPA_on_transformer(transformer: FluxTransformer2DModel, *, ip_adapter_
1621
)
1722
]
1823
)
24+
if getattr(transformer, "_is_cached", False):
25+
IPA_transformer_blocks[0].update_residual_diff_threshold(
26+
use_double_fb_cache=transformer.use_double_fb_cache,
27+
residual_diff_threshold_multi=transformer.residual_diff_threshold_multi,
28+
residual_diff_threshold_single=transformer.residual_diff_threshold_single,
29+
)
30+
undo_all_mods_on_transformer(transformer)
31+
if not hasattr(transformer, "_original_forward"):
32+
transformer._original_forward = transformer.forward
33+
if not hasattr(transformer, "_original_blocks"):
34+
transformer._original_blocks = transformer.transformer_blocks
35+
1936
dummy_single_transformer_blocks = nn.ModuleList()
2037

2138
IPA_transformer_blocks[0].load_ip_adapter_weights_per_layer(repo_id=repo_id)
2239

2340
transformer.transformer_blocks = IPA_transformer_blocks
2441
transformer.single_transformer_blocks = dummy_single_transformer_blocks
42+
original_forward = transformer.forward
2543

44+
@functools.wraps(original_forward)
45+
def new_forward(self, *args, **kwargs):
46+
with (
47+
unittest.mock.patch.object(self, "transformer_blocks", IPA_transformer_blocks),
48+
unittest.mock.patch.object(self, "single_transformer_blocks", dummy_single_transformer_blocks),
49+
):
50+
return original_forward(*args, **kwargs)
51+
52+
transformer.forward = new_forward.__get__(transformer)
2653
transformer._is_IPA = True
2754

2855
return transformer
2956

3057

3158
def apply_IPA_on_pipe(pipe: DiffusionPipeline, *, shallow_patch: bool = False, **kwargs):
59+
if getattr(pipe, "_is_cached", False):
60+
original_call = pipe.__class__.__call__
61+
62+
@functools.wraps(original_call)
63+
def new_call(self, *args, **kwargs):
64+
with cache_context(create_cache_context()):
65+
return original_call(self, *args, **kwargs)
66+
67+
pipe.__class__.__call__ = new_call
68+
pipe.__class__._is_cached = True
69+
3270
if not shallow_patch:
3371
apply_IPA_on_transformer(pipe.transformer, **kwargs)
3472

0 commit comments

Comments
 (0)