Skip to content

Add scripts/merge_lora.py: bake Wan LoRAs into fp16 before quantization (4-step distill on int4) - #48

Open
kayadibi1 wants to merge 1 commit into
Blaizzy:mainfrom
kayadibi1:feat/wan-merge-lora
Open

Add scripts/merge_lora.py: bake Wan LoRAs into fp16 before quantization (4-step distill on int4)#48
kayadibi1 wants to merge 1 commit into
Blaizzy:mainfrom
kayadibi1:feat/wan-merge-lora

Conversation

@kayadibi1

@kayadibi1 kayadibi1 commented Aug 2, 2026

Copy link
Copy Markdown

Motivation

Running Wan 2.2 I2V with the lightx2v 4-step distill LoRAs is the difference between 32.5 min and 8.9 min per 81-frame render on Apple Silicon (measured, config-matched: 768x512, same seed/steps/LoRAs — ComfyUI Q8 GGUF on PyTorch MPS 1947.7 s vs MLX int4 534 s, M5 Pro 48 GB). But applying LoRA at runtime on a quantized model dequantizes the int4 layers back to fp16, undoing quantization entirely — on a 48 GB machine this blew swap past 21 GB before the first denoising step. The clean path is: merge the LoRA into the fp16 base once, then quantize the merged weights. There's currently no tool for that step.

What this adds

scripts/merge_lora.py — self-contained (numpy + stdlib), streaming:

merge_lora.py base.safetensors lora.safetensors out.safetensors
  • Streaming: the base header is reused verbatim (shapes/dtypes unchanged); tensors are read, patched and written one at a time, with each up @ down delta computed at write time and freed. Peak RSS measured: 5 GB. Materializing all rank-256 deltas up front would need 57 GB fp32.
  • Handles all three entry kinds in the lightx2v files: lora_down/lora_up (with alpha/rank scaling), diff (norms), diff_b (biases).
  • Full key-rename table for the converter's PyTorch-Sequential flattening (ffn.0/2 → ffn.fc1/fc2, text/time_embedding.0/.2 → _0/_1, time_projection.1 → time_projection, patch_embedding → patch_embedding_proj). This matters: a partial table "succeeds" while silently dropping deltas — an early version of this script dropped all 160 FFN deltas (the model's largest matrices) that way. Unmatched deltas are therefore counted and reported (unused_deltas=N), never silent.

Validation

  • Header-level dry run: 1053/1053 delta targets resolve with exact shape matches on both Wan 2.2 I2V A14B noise experts (rank-256 lightx2v fp16 LoRAs).
  • End-to-end: merged fp16 → convert --quantize-only --bits 4 --group-size 64 → 81-frame I2V renders verified (frame 0 reproduces the input image, identity preserved through motion, no runtime LoRA path executes).

Happy to move/rename the script or add a doc entry if you'd like it somewhere else.

🤖 Generated with Claude Code

…antization

Applying LoRA at runtime on a quantized model dequantizes the int4
layers back to fp16, undoing quantization entirely (>21 GB swap on a
48 GB machine before the first step). Merging the LoRA into the fp16
base once, then quantizing the merged weights, keeps int4 inference
self-contained — with the lightx2v 4-step distill LoRAs this is the
difference between 32.5 min and 8.9 min (config-matched) per 81-frame Wan 2.2 I2V render
on Apple Silicon.

Streaming design: base header reused verbatim, tensors patched one at
a time, each up@down delta computed at write time and freed (peak RSS
5 GB measured; materializing all rank-256 deltas up front would need
57 GB fp32). Covers lora_down/lora_up (alpha/rank scaling), diff and
diff_b entries, with the full PyTorch-Sequential -> converter rename
table (ffn.0/2 -> ffn.fc1/fc2, text/time_embedding.0/.2 -> _0/_1,
time_projection.1 -> time_projection, patch_embedding ->
patch_embedding_proj). Unmatched deltas are counted and reported
rather than silently dropped.

Validated: 1053/1053 deltas resolve with exact shapes on both Wan 2.2
I2V A14B noise experts; merged -> int4 (--bits 4 --group-size 64)
renders verified end to end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kayadibi1
kayadibi1 force-pushed the feat/wan-merge-lora branch from a12ee07 to db03341 Compare August 2, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant