Repository navigation
v2.5.3 - Partial adoption of PR #52 merge plan
| EN | 中文 |
Summary
v2.5.3 brings LoRA performance and correctness improvements from PR #52 (author Sniper199999), plus follow-up fixes that complete those ideas.
Technical background: md/PR52_MERGE_PLAN.md
Changes
1. Bypass-path LoRA corruption fix (_has_ever_had_loras)
Files: wrappers/qwenimage.py (and related wrapper paths)
ComfyUI bypass can route through a wrapper that previously had LoRAs cleared (loras=[]) while still sharing the same transformer instance as the real LoRA-managing wrapper. The old dirty check could call reset_lora_v2 on that shared transformer and wipe the active LoRA stack. After bypass was turned off again, the manager wrapper often skipped recompose because _applied_loras still matched the desired list — LoRA appeared to vanish intermittently.
Fix: monotonic _has_ever_had_loras. Only wrappers that have ever managed LoRA may reset / recompose the shared transformer. Bypass shells that never owned LoRA no longer mutate the shared model.
2. Remove model from IS_CHANGED
Files: nodes/lora/qwenimage.py, qwenimage_v2.py, qwenimage_v3.py
ComfyUI’s cache calls IS_CHANGED without MODEL inputs. A model parameter caused TypeError → ComfyUI’s NaN “always dirty” sentinel → LoRA re-compose on every queue run even when nothing changed (large cost for 500MB–2GB LoRAs). Hashing str(model) had the same problem (object repr changes every run).
Fix: drop model from the signature; hash only LoRA-relevant controls (lora_name, strength, cpu_offload, save_precompiled_lora, etc.).
3. Disk-persistent LoRA precompiled cache
Files: new nunchaku_code/lora_cache.py; wired from nunchaku_code/lora_qwen.py and LoRA nodes
When the same LoRA file is reused, classify + fuse no longer need to re-run from scratch every generation:
- Cache directory under ComfyUI models (
SVDQLora/) - Collision-safe paths (parent-dir hash)
- Atomic writes (
tmp+os.replace) - mtime sidecar invalidation when the source LoRA file changes
- B tensors stored unscaled so the strength slider remains correct at apply time
Optional UI: save_precompiled_lora widget (see item 6).
Also restored _cached_first_lora_state_dict in compose_loras_v2 so that when the precompiled cache is off (default), the first LoRA is not read from disk twice.
4. GPU pack / unpack for nunchaku LoRA apply
File: nunchaku_code/lora_qwen.py
pack_lowrank_weight / unpack_lowrank_weight / cat for nunchaku proj_down/proj_up now prefer the Comfy compute device (CUDA) instead of bouncing through CPU paging for every module. Same idea applied on the reset path.
5. set_lora_strength_v2 base_rank guard
File: nunchaku_code/lora_qwen.py
AWQ modulation slots (img_mod.1 / txt_mod.1) have no base_rank. Accessing info["base_rank"] raised KeyError. Slots without base_rank are skipped safely.
6. Dynamic UI support for save_precompiled_lora
Files: js/z_qwen_lora_dynamic.js, js/z_qwen_lora_dynamic_v3.js
Cache / restore / height accounting for the save_precompiled_lora widget so it does not disappear or mis-size after redraw/onConfigure.
Practical effects
- More stable LoRA when toggling bypass on LoRA nodes
- Faster repeated generations when LoRA inputs are unchanged (
IS_CHANGEDno longer always dirty) - Optional precompiled LoRA cache for large LoRAs (2nd+ generation savings)
- Lower CPU↔GPU thrash during nunchaku pack/unpack
Credits
- PR author: Sniper199999 — PR #52
- Merge plan: PR52_MERGE_PLAN.md
Upgrade notes
- Update / reload this custom node to v2.5.3 (ComfyUI Manager reads
__init__.py__version__). - Fully restart ComfyUI after update.
- Existing workflows keep working. New optional widget:
save_precompiled_loraon supported dynamic LoRA nodes when you want disk cache writes. - If you previously saw intermittent LoRA loss after bypass toggles, re-test with this build.