Skip to content

Commit 5de6d7c

Browse files
authored
fix: enable correct batch processing in teacache (#601)
* fix teacache_batch * lint
1 parent 3bcc2d4 commit 5de6d7c

3 files changed

Lines changed: 46 additions & 118 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import time
2+
3+
import torch
4+
from diffusers.pipelines.flux.pipeline_flux import FluxPipeline
5+
6+
from nunchaku import NunchakuFluxTransformer2dModel
7+
from nunchaku.caching.teacache import TeaCache
8+
from nunchaku.utils import get_precision
9+
10+
precision = get_precision() # auto-detect your precision is 'int4' or 'fp4' based on your GPU
11+
transformer = NunchakuFluxTransformer2dModel.from_pretrained(
12+
f"nunchaku-tech/nunchaku-flux.1-dev/svdq-{precision}_r32-flux.1-dev.safetensors"
13+
)
14+
pipeline = FluxPipeline.from_pretrained(
15+
"black-forest-labs/FLUX.1-dev", transformer=transformer, torch_dtype=torch.bfloat16
16+
).to("cuda")
17+
start_time = time.time()
18+
19+
prompts = [
20+
"A cheerful woman in a pastel dress, holding a basket of colorful Easter eggs with a sign that says 'Happy Easter'",
21+
"A young peace activist with a gentle smile, holding a handmade sign that says 'Peace'",
22+
"A friendly chef wearing a tall white hat, holding a wooden spoon with a sign that says 'Let's Cook!",
23+
]
24+
25+
with TeaCache(model=transformer, num_steps=50, rel_l1_thresh=0.3, enabled=True):
26+
image = pipeline(
27+
prompts,
28+
num_inference_steps=50,
29+
guidance_scale=3.5,
30+
height=1024,
31+
width=1024,
32+
generator=torch.Generator(device="cuda").manual_seed(0),
33+
).images
34+
35+
end_time = time.time()
36+
print(f"Time taken: {(end_time - start_time)} seconds")
37+
image[0].save(f"flux.1-dev-{precision}1-tc.png")
38+
image[1].save(f"flux.1-dev-{precision}2-tc.png")
39+
image[2].save(f"flux.1-dev-{precision}3-tc.png")

nunchaku/caching/teacache.py

Lines changed: 5 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,8 @@ def teacache_forward(
161161
encoder_hidden_states = self.context_embedder(encoder_hidden_states)
162162

163163
if txt_ids.ndim == 3:
164-
logger.warning(
165-
"Passing `txt_ids` 3d torch.Tensor is deprecated."
166-
"Please remove the batch dimension and pass it as a 2d torch Tensor"
167-
)
168164
txt_ids = txt_ids[0]
169165
if img_ids.ndim == 3:
170-
logger.warning(
171-
"Passing `img_ids` 3d torch.Tensor is deprecated."
172-
"Please remove the batch dimension and pass it as a 2d torch Tensor"
173-
)
174166
img_ids = img_ids[0]
175167

176168
ids = torch.cat((txt_ids, img_ids), dim=0)
@@ -250,60 +242,10 @@ def custom_forward(*inputs): # type: ignore
250242
temb=temb,
251243
image_rotary_emb=image_rotary_emb,
252244
joint_attention_kwargs=joint_attention_kwargs,
245+
controlnet_block_samples=controlnet_block_samples,
246+
controlnet_single_block_samples=controlnet_single_block_samples,
253247
)
254248

255-
# controlnet residual
256-
if controlnet_block_samples is not None:
257-
interval_control = len(self.transformer_blocks) / len(controlnet_block_samples)
258-
interval_control = int(np.ceil(interval_control))
259-
# For Xlabs ControlNet.
260-
if controlnet_blocks_repeat:
261-
hidden_states = (
262-
hidden_states + controlnet_block_samples[index_block % len(controlnet_block_samples)]
263-
)
264-
else:
265-
hidden_states = hidden_states + controlnet_block_samples[index_block // interval_control]
266-
hidden_states = torch.cat([encoder_hidden_states, hidden_states], dim=1)
267-
268-
for index_block, block in enumerate(self.single_transformer_blocks):
269-
if torch.is_grad_enabled() and self.gradient_checkpointing:
270-
271-
def create_custom_forward(module, return_dict=None): # type: ignore
272-
def custom_forward(*inputs): # type: ignore
273-
if return_dict is not None:
274-
return module(*inputs, return_dict=return_dict)
275-
else:
276-
return module(*inputs)
277-
278-
return custom_forward
279-
280-
ckpt_kwargs = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {}
281-
hidden_states = torch.utils.checkpoint.checkpoint(
282-
create_custom_forward(block),
283-
hidden_states,
284-
temb,
285-
image_rotary_emb,
286-
**ckpt_kwargs,
287-
)
288-
289-
else:
290-
hidden_states = block(
291-
hidden_states=hidden_states,
292-
temb=temb,
293-
image_rotary_emb=image_rotary_emb,
294-
joint_attention_kwargs=joint_attention_kwargs,
295-
)
296-
297-
# controlnet residual
298-
if controlnet_single_block_samples is not None:
299-
interval_control = len(self.single_transformer_blocks) / len(controlnet_single_block_samples)
300-
interval_control = int(np.ceil(interval_control))
301-
hidden_states[:, encoder_hidden_states.shape[1] :, ...] = (
302-
hidden_states[:, encoder_hidden_states.shape[1] :, ...]
303-
+ controlnet_single_block_samples[index_block // interval_control]
304-
)
305-
306-
hidden_states = hidden_states[:, encoder_hidden_states.shape[1] :, ...]
307249
self.previous_residual = hidden_states - ori_hidden_states
308250
else:
309251
for index_block, block in enumerate(self.transformer_blocks):
@@ -335,61 +277,10 @@ def custom_forward(*inputs): # type: ignore
335277
temb=temb,
336278
image_rotary_emb=image_rotary_emb,
337279
joint_attention_kwargs=joint_attention_kwargs,
280+
controlnet_block_samples=controlnet_block_samples,
281+
controlnet_single_block_samples=controlnet_single_block_samples,
338282
)
339283

340-
# controlnet residual
341-
if controlnet_block_samples is not None:
342-
interval_control = len(self.transformer_blocks) / len(controlnet_block_samples)
343-
interval_control = int(np.ceil(interval_control))
344-
# For Xlabs ControlNet.
345-
if controlnet_blocks_repeat:
346-
hidden_states = (
347-
hidden_states + controlnet_block_samples[index_block % len(controlnet_block_samples)]
348-
)
349-
else:
350-
hidden_states = hidden_states + controlnet_block_samples[index_block // interval_control]
351-
hidden_states = torch.cat([encoder_hidden_states, hidden_states], dim=1)
352-
353-
for index_block, block in enumerate(self.single_transformer_blocks):
354-
if torch.is_grad_enabled() and self.gradient_checkpointing:
355-
356-
def create_custom_forward(module, return_dict=None): # type: ignore
357-
def custom_forward(*inputs): # type: ignore
358-
if return_dict is not None:
359-
return module(*inputs, return_dict=return_dict)
360-
else:
361-
return module(*inputs)
362-
363-
return custom_forward
364-
365-
ckpt_kwargs = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {}
366-
hidden_states = torch.utils.checkpoint.checkpoint(
367-
create_custom_forward(block),
368-
hidden_states,
369-
temb,
370-
image_rotary_emb,
371-
**ckpt_kwargs,
372-
)
373-
374-
else:
375-
hidden_states = block(
376-
hidden_states=hidden_states,
377-
temb=temb,
378-
image_rotary_emb=image_rotary_emb,
379-
joint_attention_kwargs=joint_attention_kwargs,
380-
)
381-
382-
# controlnet residual
383-
if controlnet_single_block_samples is not None:
384-
interval_control = len(self.single_transformer_blocks) / len(controlnet_single_block_samples)
385-
interval_control = int(np.ceil(interval_control))
386-
hidden_states[:, encoder_hidden_states.shape[1] :, ...] = (
387-
hidden_states[:, encoder_hidden_states.shape[1] :, ...]
388-
+ controlnet_single_block_samples[index_block // interval_control]
389-
)
390-
391-
hidden_states = hidden_states[:, encoder_hidden_states.shape[1] :, ...]
392-
393284
hidden_states = self.norm_out(hidden_states, temb)
394285
output: torch.FloatTensor = self.proj_out(hidden_states)
395286

@@ -398,7 +289,7 @@ def custom_forward(*inputs): # type: ignore
398289
unscale_lora_layers(self, lora_scale)
399290

400291
if not return_dict:
401-
return output
292+
return (output,)
402293

403294
return Transformer2DModelOutput(sample=output)
404295

nunchaku/caching/utils.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ def forward(
821821
-----
822822
If batch size > 2 or residual_diff_threshold <= 0, caching is disabled for now.
823823
"""
824-
batch_size = hidden_states.shape[0]
824+
# batch_size = hidden_states.shape[0]
825825
txt_tokens = encoder_hidden_states.shape[1]
826826
img_tokens = hidden_states.shape[1]
827827

@@ -860,9 +860,7 @@ def forward(
860860
rotary_emb_img = self.pack_rotemb(pad_tensor(rotary_emb_img, 256, 1))
861861
rotary_emb_single = self.pack_rotemb(pad_tensor(rotary_emb_single, 256, 1))
862862

863-
if (self.residual_diff_threshold_multi < 0.0) or (batch_size > 1):
864-
if batch_size > 1 and self.verbose:
865-
print("Batch size > 1 currently not supported")
863+
if self.residual_diff_threshold_multi < 0.0:
866864

867865
hidden_states = self.m.forward(
868866
hidden_states,

0 commit comments

Comments
 (0)