Repository navigation
Description
Describe the bug
QwenImage21Pipeline crashes on the second denoising step when a TaylorSeer cache is enabled on the transformer and the KV cache is left at its default (use_kv_cache=True).
With the KV cache, the first transformer call (kv_cache_mode="extract", prefill) returns the whole joint sequence (prefix + target tokens), while the following calls (kv_cache_mode="cached") return target tokens only. The pipeline handles this by slicing noise_pred[:, -latents.size(1):], but the TaylorSeer hook on proj_out sees both shapes and fails when it takes the divided difference between step 0 and step 1:
RuntimeError: The size of tensor a (1024) must match the size of tensor b (1038) at non-singleton dimension 1
(512×512 → 1024 target tokens; 1038 = 14 text tokens + 1024. At 832×1216 it is 3952 vs 4075.)
Passing use_kv_cache=False avoids the crash, but for image-conditioned edits that means the reference-image tokens are recomputed every step, so most of the speed-up is lost (numbers below).
The mismatch comes from the sequence length, not from the device, so I expect the same on CUDA — but I have only tested on Apple Silicon (MPS). I have also only tried TaylorSeerCacheConfig; other cache hooks may or may not be affected.
Reproduction
import torch
from diffusers import QwenImage21Pipeline, TaylorSeerCacheConfig
device = "cuda" if torch.cuda.is_available() else "mps"
pipe = QwenImage21Pipeline.from_pretrained("Qwen/Qwen-Image-2.1", torch_dtype=torch.bfloat16).to(device)
pipe.transformer.enable_cache(
TaylorSeerCacheConfig(cache_interval=3, disable_cache_before_step=3, max_order=1, use_lite_mode=True)
)
image = pipe(
prompt="a cat sitting on a wall",
width=512,
height=512,
num_inference_steps=8,
true_cfg_scale=1.0,
generator=torch.Generator("cpu").manual_seed(0),
).images[0] # use_kv_cache defaults to True -> crashes at step 2Workaround that worked for me (not proposing this as the fix, just sharing what made it run): reset the Taylor factors when the feature shape changes, so the prefill step is simply not used for the finite difference.
import diffusers.hooks.taylorseer_cache as ts
_orig_update = ts.TaylorSeerState.update
def _update(self, outputs):
if not self.is_inactive and self.last_update_step is not None:
for i, feat in enumerate(outputs):
prev = self.taylor_factors.get(i, {}).get(0)
if prev is not None and prev.shape != feat.shape:
self.taylor_factors = {}
self.last_update_step = None
break
return _orig_update(self, outputs)
ts.TaylorSeerState.update = _updateWith this patch the run completes, and the output is pixel-identical to the use_kv_cache=False + TaylorSeer output (mean abs diff 0.0 on both cases below).
Timings on an M1 Max 64GB (MPS, bf16, 832×1216, 40 steps, seed 42, true_cfg_scale=1.0, 15 full transformer passes out of 40 with the config above; "generation" = pipe(...) call only, single run each):
| case | no cache, KV cache on (baseline) | TaylorSeer lite, use_kv_cache=False |
TaylorSeer lite + KV cache (patched) |
|---|---|---|---|
| text-to-image | 614.7 s | 224.6 s (2.74x) | 218.8 s (2.81x) |
| edit with 1 reference image | 721.2 s | 484.4 s (1.49x) | 277.6 s (2.60x) |
For the edit case, disabling the KV cache raises a full step from ~17.4 s to ~31.6 s, which is why keeping the KV cache matters.
A cleaner fix may be on the model side (e.g. only passing target tokens through norm_out/proj_out in the prefill step, since the pipeline discards the prefix part anyway), but I'll leave that to you.
Logs
File ".../diffusers/hooks/hooks.py", line 217, in new_forward
output = function_reference.forward(*args, **kwargs)
File ".../diffusers/hooks/taylorseer_cache.py", line 240, in new_forward
state.update(wrapped_outputs)
File ".../diffusers/hooks/taylorseer_cache.py", line 154, in update
new_factors[j + 1] = (new_factors[j] - prev.to(features.dtype)) / delta_step
~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
RuntimeError: The size of tensor a (1024) must match the size of tensor b (1038) at non-singleton dimension 1System Info
- 🤗 Diffusers version: 0.41.0.dev0 (installed from commit 80c7ed2;
pipeline_qwenimage21.py,transformer_qwenimage21.pyandhooks/taylorseer_cache.pyhave no newer commits onmainas of 2026-09-21) - Platform: macOS-27.0-arm64-arm-64bit
- Running on Google Colab?: No
- Python version: 3.12.12
- PyTorch version (GPU?): 2.14.0 (False)
- Huggingface_hub version: 1.32.0
- Transformers version: 5.17.0
- Accelerate version: 1.15.0
- PEFT version: not installed
- Safetensors version: 0.8.0
- xFormers version: not installed
- Accelerator: Apple M1 Max (64GB unified memory)
- Using GPU in script?: Yes (MPS)
- Using distributed or parallel set-up in script?: No
Activity
sayakpaul commentedon Sep 21, 2026
Thanks for reporting the issue. Would you be willing to open a PR and we can take it from there?