Guest User

Untitled

a guest
Jun 26th, 2026
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.34 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. """
  3. Krea2 fal LoRA → ComfyUI conversion script
  4. ==========================================
  5. Converts LoRA files trained with Krea2 (fal.ai format) to ComfyUI-compatible
  6. safetensors by remapping key prefixes.
  7.  
  8. The fal/PEFT format wraps all weights under:
  9. base_model.model.<layer>
  10.  
  11. ComfyUI expects them directly under the model prefix, e.g.:
  12. diffusion_model.<layer>
  13.  
  14. Usage
  15. -----
  16. python convert_krea2_lora_to_comfy.py input.safetensors [output.safetensors]
  17.  
  18. If no output path is given, the script writes <input>_comfy.safetensors
  19. next to the input file.
  20. """
  21.  
  22. import sys
  23. import os
  24. import argparse
  25. from pathlib import Path
  26.  
  27. try:
  28. from safetensors.torch import load_file, save_file
  29. except ImportError:
  30. print("ERROR: safetensors is not installed. Run: pip install safetensors torch")
  31. sys.exit(1)
  32.  
  33.  
  34. # ---------------------------------------------------------------------------
  35. # Key-mapping rules
  36. # ---------------------------------------------------------------------------
  37. # Krea2 uses a non-Flux architecture. Keys seen in the warning log follow the
  38. # pattern:
  39. #
  40. # base_model.model.blocks.<N>.attn.{gate,wk,wo,wq,wv}.lora_{A,B}.weight
  41. # base_model.model.blocks.<N>.mlp.{down,gate,up}.lora_{A,B}.weight
  42. # base_model.model.first.lora_{A,B}.weight
  43. # base_model.model.last.linear.lora_{A,B}.weight
  44. # base_model.model.tmlp.{0,2}.lora_{A,B}.weight
  45. # base_model.model.tproj.1.lora_{A,B}.weight
  46. # base_model.model.txtfusion.layerwise_blocks.<N>.*
  47. # base_model.model.txtfusion.refiner_blocks.<N>.*
  48. # base_model.model.txtfusion.projector.lora_{A,B}.weight
  49. # base_model.model.txtmlp.{1,3}.lora_{A,B}.weight
  50. #
  51. # ComfyUI looks for the model weights under diffusion_model.*
  52. # (same convention used by Flux / SD3 / etc.).
  53. #
  54. # Strategy: strip the "base_model.model." prefix and replace with
  55. # "diffusion_model."
  56. # ---------------------------------------------------------------------------
  57.  
  58. SOURCE_PREFIX = "base_model.model."
  59. TARGET_PREFIX = "diffusion_model."
  60.  
  61.  
  62. def remap_key(key: str) -> str:
  63. """Return the ComfyUI-compatible key for a given fal LoRA key."""
  64. if key.startswith(SOURCE_PREFIX):
  65. return TARGET_PREFIX + key[len(SOURCE_PREFIX):]
  66. # Already in another format or global key – pass through unchanged
  67. return key
  68.  
  69.  
  70. def convert(input_path: Path, output_path: Path) -> None:
  71. print(f"Loading : {input_path}")
  72. state_dict = load_file(str(input_path))
  73.  
  74. original_keys = list(state_dict.keys())
  75. print(f"Keys found: {len(original_keys)}")
  76.  
  77. converted: dict = {}
  78. remapped = 0
  79. unchanged = 0
  80.  
  81. for key, tensor in state_dict.items():
  82. new_key = remap_key(key)
  83. if new_key != key:
  84. remapped += 1
  85. else:
  86. unchanged += 1
  87. converted[new_key] = tensor
  88.  
  89. print(f"Remapped : {remapped} keys ({SOURCE_PREFIX!r} → {TARGET_PREFIX!r})")
  90. if unchanged:
  91. print(f"Unchanged : {unchanged} keys (no matching prefix)")
  92.  
  93. # Show a few sample mappings so the user can sanity-check
  94. sample_keys = [k for k in original_keys if k.startswith(SOURCE_PREFIX)][:5]
  95. if sample_keys:
  96. print("\nSample key mappings:")
  97. for k in sample_keys:
  98. print(f" {k}")
  99. print(f" → {remap_key(k)}")
  100.  
  101. print(f"\nSaving to : {output_path}")
  102. save_file(converted, str(output_path))
  103. print("Done ✓")
  104.  
  105.  
  106. def main() -> None:
  107. parser = argparse.ArgumentParser(
  108. description="Convert Krea2 fal LoRA to ComfyUI format"
  109. )
  110. parser.add_argument("input", help="Path to the input .safetensors file")
  111. parser.add_argument(
  112. "output",
  113. nargs="?",
  114. default=None,
  115. help="Path for the output .safetensors file (default: <input>_comfy.safetensors)",
  116. )
  117. args = parser.parse_args()
  118.  
  119. input_path = Path(args.input)
  120. if not input_path.exists():
  121. print(f"ERROR: Input file not found: {input_path}")
  122. sys.exit(1)
  123. if input_path.suffix.lower() != ".safetensors":
  124. print("WARNING: Input file does not have a .safetensors extension.")
  125.  
  126. if args.output:
  127. output_path = Path(args.output)
  128. else:
  129. output_path = input_path.with_name(input_path.stem + "_comfy.safetensors")
  130.  
  131. convert(input_path, output_path)
  132.  
  133.  
  134. if __name__ == "__main__":
  135. main()
  136.  
Advertisement
Add Comment
Please, Sign In to add comment