| import re |
| from typing import Optional, OrderedDict, Tuple, TypeAlias, Union |
| import torch |
| from loguru import logger |
| from safetensors.torch import load_file |
| from tqdm import tqdm |
| from torch import nn |
|
|
| try: |
| from cublas_ops import CublasLinear |
| except Exception as e: |
| CublasLinear = type(None) |
| from float8_quantize import F8Linear |
| from modules.flux_model import Flux |
|
|
| path_regex = re.compile(r"/|\\") |
|
|
| StateDict: TypeAlias = OrderedDict[str, torch.Tensor] |
|
|
|
|
| class LoraWeights: |
| def __init__( |
| self, |
| weights: StateDict, |
| path: str, |
| name: str = None, |
| scale: float = 1.0, |
| ) -> None: |
| self.path = path |
| self.weights = weights |
| self.name = name if name else path_regex.split(path)[-1] |
| self.scale = scale |
|
|
|
|
| def swap_scale_shift(weight): |
| scale, shift = weight.chunk(2, dim=0) |
| new_weight = torch.cat([shift, scale], dim=0) |
| return new_weight |
|
|
|
|
| def check_if_lora_exists(state_dict, lora_name): |
| subkey = lora_name.split(".lora_A")[0].split(".lora_B")[0].split(".weight")[0] |
| for key in state_dict.keys(): |
| if subkey in key: |
| return subkey |
| return False |
|
|
|
|
| def convert_if_lora_exists(new_state_dict, state_dict, lora_name, flux_layer_name): |
| if (original_stubkey := check_if_lora_exists(state_dict, lora_name)) != False: |
| weights_to_pop = [k for k in state_dict.keys() if original_stubkey in k] |
| for key in weights_to_pop: |
| key_replacement = key.replace( |
| original_stubkey, flux_layer_name.replace(".weight", "") |
| ) |
| new_state_dict[key_replacement] = state_dict.pop(key) |
| return new_state_dict, state_dict |
| else: |
| return new_state_dict, state_dict |
|
|
|
|
| def convert_diffusers_to_flux_transformer_checkpoint( |
| diffusers_state_dict, |
| num_layers, |
| num_single_layers, |
| has_guidance=True, |
| prefix="", |
| ): |
| original_state_dict = {} |
|
|
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}time_text_embed.timestep_embedder.linear_1.weight", |
| "time_in.in_layer.weight", |
| ) |
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}time_text_embed.text_embedder.linear_1.weight", |
| "vector_in.in_layer.weight", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}time_text_embed.text_embedder.linear_2.weight", |
| "vector_in.out_layer.weight", |
| ) |
|
|
| if has_guidance: |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}time_text_embed.guidance_embedder.linear_1.weight", |
| "guidance_in.in_layer.weight", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}time_text_embed.guidance_embedder.linear_2.weight", |
| "guidance_in.out_layer.weight", |
| ) |
|
|
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}context_embedder.weight", |
| "txt_in.weight", |
| ) |
|
|
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}x_embedder.weight", |
| "img_in.weight", |
| ) |
| |
| for i in range(num_layers): |
| block_prefix = f"transformer_blocks.{i}." |
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}norm1.linear.weight", |
| f"double_blocks.{i}.img_mod.lin.weight", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}norm1_context.linear.weight", |
| f"double_blocks.{i}.txt_mod.lin.weight", |
| ) |
|
|
| |
| temp_dict = {} |
|
|
| expected_shape_qkv_a = None |
| expected_shape_qkv_b = None |
| expected_shape_add_qkv_a = None |
| expected_shape_add_qkv_b = None |
| dtype = None |
| device = None |
|
|
| for component in [ |
| "to_q", |
| "to_k", |
| "to_v", |
| "add_q_proj", |
| "add_k_proj", |
| "add_v_proj", |
| ]: |
|
|
| sample_component_A_key = ( |
| f"{prefix}{block_prefix}attn.{component}.lora_A.weight" |
| ) |
| sample_component_B_key = ( |
| f"{prefix}{block_prefix}attn.{component}.lora_B.weight" |
| ) |
| if ( |
| sample_component_A_key in diffusers_state_dict |
| and sample_component_B_key in diffusers_state_dict |
| ): |
| sample_component_A = diffusers_state_dict.pop(sample_component_A_key) |
| sample_component_B = diffusers_state_dict.pop(sample_component_B_key) |
| temp_dict[f"{component}"] = [sample_component_A, sample_component_B] |
| if expected_shape_qkv_a is None and not component.startswith("add_"): |
| expected_shape_qkv_a = sample_component_A.shape |
| expected_shape_qkv_b = sample_component_B.shape |
| dtype = sample_component_A.dtype |
| device = sample_component_A.device |
| if expected_shape_add_qkv_a is None and component.startswith("add_"): |
| expected_shape_add_qkv_a = sample_component_A.shape |
| expected_shape_add_qkv_b = sample_component_B.shape |
| dtype = sample_component_A.dtype |
| device = sample_component_A.device |
| else: |
| logger.info( |
| f"Skipping layer {i} since no LoRA weight is available for {sample_component_A_key}" |
| ) |
| temp_dict[f"{component}"] = [None, None] |
|
|
| if device is not None: |
| if expected_shape_qkv_a is not None: |
|
|
| if (sq := temp_dict["to_q"])[0] is not None: |
| sample_q_A, sample_q_B = sq |
| else: |
| sample_q_A, sample_q_B = [ |
| torch.zeros(expected_shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(expected_shape_qkv_b, dtype=dtype, device=device), |
| ] |
| if (sq := temp_dict["to_k"])[0] is not None: |
| sample_k_A, sample_k_B = sq |
| else: |
| sample_k_A, sample_k_B = [ |
| torch.zeros(expected_shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(expected_shape_qkv_b, dtype=dtype, device=device), |
| ] |
| if (sq := temp_dict["to_v"])[0] is not None: |
| sample_v_A, sample_v_B = sq |
| else: |
| sample_v_A, sample_v_B = [ |
| torch.zeros(expected_shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(expected_shape_qkv_b, dtype=dtype, device=device), |
| ] |
| original_state_dict[f"double_blocks.{i}.img_attn.qkv.lora_A.weight"] = ( |
| torch.cat([sample_q_A, sample_k_A, sample_v_A], dim=0) |
| ) |
| original_state_dict[f"double_blocks.{i}.img_attn.qkv.lora_B.weight"] = ( |
| torch.cat([sample_q_B, sample_k_B, sample_v_B], dim=0) |
| ) |
| if expected_shape_add_qkv_a is not None: |
|
|
| if (sq := temp_dict["add_q_proj"])[0] is not None: |
| context_q_A, context_q_B = sq |
| else: |
| context_q_A, context_q_B = [ |
| torch.zeros( |
| expected_shape_add_qkv_a, dtype=dtype, device=device |
| ), |
| torch.zeros( |
| expected_shape_add_qkv_b, dtype=dtype, device=device |
| ), |
| ] |
| if (sq := temp_dict["add_k_proj"])[0] is not None: |
| context_k_A, context_k_B = sq |
| else: |
| context_k_A, context_k_B = [ |
| torch.zeros( |
| expected_shape_add_qkv_a, dtype=dtype, device=device |
| ), |
| torch.zeros( |
| expected_shape_add_qkv_b, dtype=dtype, device=device |
| ), |
| ] |
| if (sq := temp_dict["add_v_proj"])[0] is not None: |
| context_v_A, context_v_B = sq |
| else: |
| context_v_A, context_v_B = [ |
| torch.zeros( |
| expected_shape_add_qkv_a, dtype=dtype, device=device |
| ), |
| torch.zeros( |
| expected_shape_add_qkv_b, dtype=dtype, device=device |
| ), |
| ] |
|
|
| original_state_dict[f"double_blocks.{i}.txt_attn.qkv.lora_A.weight"] = ( |
| torch.cat([context_q_A, context_k_A, context_v_A], dim=0) |
| ) |
| original_state_dict[f"double_blocks.{i}.txt_attn.qkv.lora_B.weight"] = ( |
| torch.cat([context_q_B, context_k_B, context_v_B], dim=0) |
| ) |
|
|
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}attn.norm_q.weight", |
| f"double_blocks.{i}.img_attn.norm.query_norm.scale", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}attn.norm_k.weight", |
| f"double_blocks.{i}.img_attn.norm.key_norm.scale", |
| ) |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}attn.norm_added_q.weight", |
| f"double_blocks.{i}.txt_attn.norm.query_norm.scale", |
| ) |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}attn.norm_added_k.weight", |
| f"double_blocks.{i}.txt_attn.norm.key_norm.scale", |
| ) |
|
|
| |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}ff.net.0.proj.weight", |
| f"double_blocks.{i}.img_mlp.0.weight", |
| ) |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}ff.net.2.weight", |
| f"double_blocks.{i}.img_mlp.2.weight", |
| ) |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}ff_context.net.0.proj.weight", |
| f"double_blocks.{i}.txt_mlp.0.weight", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}ff_context.net.2.weight", |
| f"double_blocks.{i}.txt_mlp.2.weight", |
| ) |
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}attn.to_out.0.weight", |
| f"double_blocks.{i}.img_attn.proj.weight", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}attn.to_add_out.weight", |
| f"double_blocks.{i}.txt_attn.proj.weight", |
| ) |
|
|
| |
| for i in range(num_single_layers): |
| block_prefix = f"single_transformer_blocks.{i}." |
| |
| key_norm = f"{prefix}{block_prefix}norm.linear.weight" |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| key_norm, |
| f"single_blocks.{i}.modulation.lin.weight", |
| ) |
|
|
| has_q, has_k, has_v, has_mlp = False, False, False, False |
| shape_qkv_a = None |
| shape_qkv_b = None |
| |
| q_A = diffusers_state_dict.pop(f"{prefix}{block_prefix}attn.to_q.lora_A.weight") |
| q_B = diffusers_state_dict.pop(f"{prefix}{block_prefix}attn.to_q.lora_B.weight") |
| if q_A is not None and q_B is not None: |
| has_q = True |
| shape_qkv_a = q_A.shape |
| shape_qkv_b = q_B.shape |
| k_A = diffusers_state_dict.pop(f"{prefix}{block_prefix}attn.to_k.lora_A.weight") |
| k_B = diffusers_state_dict.pop(f"{prefix}{block_prefix}attn.to_k.lora_B.weight") |
| if k_A is not None and k_B is not None: |
| has_k = True |
| shape_qkv_a = k_A.shape |
| shape_qkv_b = k_B.shape |
| v_A = diffusers_state_dict.pop(f"{prefix}{block_prefix}attn.to_v.lora_A.weight") |
| v_B = diffusers_state_dict.pop(f"{prefix}{block_prefix}attn.to_v.lora_B.weight") |
| if v_A is not None and v_B is not None: |
| has_v = True |
| shape_qkv_a = v_A.shape |
| shape_qkv_b = v_B.shape |
| mlp_A = diffusers_state_dict.pop( |
| f"{prefix}{block_prefix}proj_mlp.lora_A.weight" |
| ) |
| mlp_B = diffusers_state_dict.pop( |
| f"{prefix}{block_prefix}proj_mlp.lora_B.weight" |
| ) |
| if mlp_A is not None and mlp_B is not None: |
| has_mlp = True |
| shape_qkv_a = mlp_A.shape |
| shape_qkv_b = mlp_B.shape |
| if any([has_q, has_k, has_v, has_mlp]): |
| if not has_q: |
| q_A, q_B = [ |
| torch.zeros(shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(shape_qkv_b, dtype=dtype, device=device), |
| ] |
| if not has_k: |
| k_A, k_B = [ |
| torch.zeros(shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(shape_qkv_b, dtype=dtype, device=device), |
| ] |
| if not has_v: |
| v_A, v_B = [ |
| torch.zeros(shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(shape_qkv_b, dtype=dtype, device=device), |
| ] |
| if not has_mlp: |
| mlp_A, mlp_B = [ |
| torch.zeros(shape_qkv_a, dtype=dtype, device=device), |
| torch.zeros(shape_qkv_b, dtype=dtype, device=device), |
| ] |
| original_state_dict[f"single_blocks.{i}.linear1.lora_A.weight"] = torch.cat( |
| [q_A, k_A, v_A, mlp_A], dim=0 |
| ) |
| original_state_dict[f"single_blocks.{i}.linear1.lora_B.weight"] = torch.cat( |
| [q_B, k_B, v_B, mlp_B], dim=0 |
| ) |
|
|
| |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}{block_prefix}proj_out.weight", |
| f"single_blocks.{i}.linear2.weight", |
| ) |
|
|
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}proj_out.weight", |
| "final_layer.linear.weight", |
| ) |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}proj_out.bias", |
| "final_layer.linear.bias", |
| ) |
| original_state_dict, diffusers_state_dict = convert_if_lora_exists( |
| original_state_dict, |
| diffusers_state_dict, |
| f"{prefix}norm_out.linear.weight", |
| "final_layer.adaLN_modulation.1.weight", |
| ) |
| if len(list(diffusers_state_dict.keys())) > 0: |
| logger.warning("Unexpected keys:", diffusers_state_dict.keys()) |
|
|
| return original_state_dict |
|
|
|
|
| def convert_from_original_flux_checkpoint(original_state_dict: StateDict) -> StateDict: |
| """ |
| Convert the state dict from the original Flux checkpoint format to the new format. |
| |
| Args: |
| original_state_dict (Dict[str, torch.Tensor]): The original Flux checkpoint state dict. |
| |
| Returns: |
| Dict[str, torch.Tensor]: The converted state dict in the new format. |
| """ |
| sd = { |
| k.replace("lora_unet_", "") |
| .replace("double_blocks_", "double_blocks.") |
| .replace("single_blocks_", "single_blocks.") |
| .replace("_img_attn_", ".img_attn.") |
| .replace("_txt_attn_", ".txt_attn.") |
| .replace("_img_mod_", ".img_mod.") |
| .replace("_txt_mod_", ".txt_mod.") |
| .replace("_img_mlp_", ".img_mlp.") |
| .replace("_txt_mlp_", ".txt_mlp.") |
| .replace("_linear1", ".linear1") |
| .replace("_linear2", ".linear2") |
| .replace("_modulation_", ".modulation.") |
| .replace("lora_up", "lora_B") |
| .replace("lora_down", "lora_A"): v |
| for k, v in original_state_dict.items() |
| if "lora" in k |
| } |
| return sd |
|
|
|
|
| def get_module_for_key( |
| key: str, model: Flux |
| ) -> F8Linear | torch.nn.Linear | CublasLinear: |
| parts = key.split(".") |
| module = model |
| for part in parts: |
| module = getattr(module, part) |
| return module |
|
|
|
|
| def get_lora_for_key( |
| key: str, lora_weights: dict |
| ) -> Optional[Tuple[torch.Tensor, torch.Tensor, Optional[float]]]: |
| """ |
| Get LoRA weights for a specific key. |
| |
| Args: |
| key (str): The key to look up in the LoRA weights. |
| lora_weights (dict): Dictionary containing LoRA weights. |
| |
| Returns: |
| Optional[Tuple[torch.Tensor, torch.Tensor, Optional[float]]]: A tuple containing lora_A, lora_B, and alpha if found, None otherwise. |
| """ |
| prefix = key.split(".lora")[0] |
| lora_A = lora_weights.get(f"{prefix}.lora_A.weight") |
| lora_B = lora_weights.get(f"{prefix}.lora_B.weight") |
| alpha = lora_weights.get(f"{prefix}.alpha") |
|
|
| if lora_A is None or lora_B is None: |
| return None |
| return lora_A, lora_B, alpha |
|
|
|
|
| def get_module_for_key( |
| key: str, model: Flux |
| ) -> F8Linear | torch.nn.Linear | CublasLinear: |
| parts = key.split(".") |
| module = model |
| for part in parts: |
| module = getattr(module, part) |
| return module |
|
|
|
|
| def calculate_lora_weight( |
| lora_weights: Tuple[torch.Tensor, torch.Tensor, Union[torch.Tensor, float]], |
| rank: Optional[int] = None, |
| lora_scale: float = 1.0, |
| device: Optional[Union[torch.device, int, str]] = None, |
| ): |
| lora_A, lora_B, alpha = lora_weights |
| if device is None: |
| device = lora_A.device |
|
|
| uneven_rank = lora_B.shape[1] != lora_A.shape[0] |
| rank_diff = lora_A.shape[0] / lora_B.shape[1] |
|
|
| if rank is None: |
| rank = lora_B.shape[1] |
| if alpha is None: |
| alpha = rank |
|
|
| dtype = torch.float32 |
| w_up = lora_A.to(dtype=dtype, device=device) |
| w_down = lora_B.to(dtype=dtype, device=device) |
|
|
| if alpha != rank: |
| w_up = w_up * alpha / rank |
| if uneven_rank: |
| |
| |
| fused_lora = torch.zeros( |
| (lora_B.shape[0], lora_A.shape[1]), device=device, dtype=dtype |
| ) |
| w_up = w_up.chunk(int(rank_diff), dim=0) |
| for w_up_chunk in w_up: |
| fused_lora = fused_lora + (lora_scale * torch.mm(w_down, w_up_chunk)) |
| else: |
| fused_lora = lora_scale * torch.mm(w_down, w_up) |
| return fused_lora |
|
|
|
|
| @torch.inference_mode() |
| def unfuse_lora_weight_from_module( |
| fused_weight: torch.Tensor, |
| lora_weights: dict, |
| rank: Optional[int] = None, |
| lora_scale: float = 1.0, |
| ): |
| w_dtype = fused_weight.dtype |
| dtype = torch.float32 |
| device = fused_weight.device |
|
|
| fused_weight = fused_weight.to(dtype=dtype, device=device) |
| fused_lora = calculate_lora_weight(lora_weights, rank, lora_scale, device=device) |
| module_weight = fused_weight - fused_lora |
| return module_weight.to(dtype=w_dtype, device=device) |
|
|
|
|
| @torch.inference_mode() |
| def apply_lora_weight_to_module( |
| module_weight: torch.Tensor, |
| lora_weights: dict, |
| rank: int = None, |
| lora_scale: float = 1.0, |
| ): |
| w_dtype = module_weight.dtype |
| dtype = torch.float32 |
| device = module_weight.device |
|
|
| fused_lora = calculate_lora_weight(lora_weights, rank, lora_scale, device=device) |
| fused_weight = module_weight.to(dtype=dtype) + fused_lora |
| return fused_weight.to(dtype=w_dtype, device=device) |
|
|
|
|
| def resolve_lora_state_dict(lora_weights, has_guidance: bool = True): |
| check_if_starts_with_transformer = [ |
| k for k in lora_weights.keys() if k.startswith("transformer.") |
| ] |
| if len(check_if_starts_with_transformer) > 0: |
| lora_weights = convert_diffusers_to_flux_transformer_checkpoint( |
| lora_weights, 19, 38, has_guidance=has_guidance, prefix="transformer." |
| ) |
| else: |
| lora_weights = convert_from_original_flux_checkpoint(lora_weights) |
| logger.info("LoRA weights loaded") |
| logger.debug("Extracting keys") |
| keys_without_ab = list( |
| set( |
| [ |
| key.replace(".lora_A.weight", "") |
| .replace(".lora_B.weight", "") |
| .replace(".lora_A", "") |
| .replace(".lora_B", "") |
| .replace(".alpha", "") |
| for key in lora_weights.keys() |
| ] |
| ) |
| ) |
| logger.debug("Keys extracted") |
| return keys_without_ab, lora_weights |
|
|
|
|
| def get_lora_weights(lora_path: str | StateDict): |
| if isinstance(lora_path, (dict, LoraWeights)): |
| return lora_path, True |
| else: |
| return load_file(lora_path, "cpu"), False |
|
|
|
|
| def extract_weight_from_linear(linear: Union[nn.Linear, CublasLinear, F8Linear]): |
| dtype = linear.weight.dtype |
| weight_is_f8 = False |
| if isinstance(linear, F8Linear): |
| weight_is_f8 = True |
| weight = ( |
| linear.float8_data.clone() |
| .detach() |
| .float() |
| .mul(linear.scale_reciprocal) |
| .to(linear.weight.device) |
| ) |
| elif isinstance(linear, torch.nn.Linear): |
| weight = linear.weight.clone().detach().float() |
| elif isinstance(linear, CublasLinear) and CublasLinear != type(None): |
| weight = linear.weight.clone().detach().float() |
| return weight, weight_is_f8, dtype |
|
|
|
|
| @torch.inference_mode() |
| def apply_lora_to_model( |
| model: Flux, |
| lora_path: str | StateDict, |
| lora_scale: float = 1.0, |
| return_lora_resolved: bool = False, |
| ) -> Flux: |
| has_guidance = model.params.guidance_embed |
| logger.info(f"Loading LoRA weights for {lora_path}") |
| lora_weights, already_loaded = get_lora_weights(lora_path) |
|
|
| if not already_loaded: |
| keys_without_ab, lora_weights = resolve_lora_state_dict( |
| lora_weights, has_guidance |
| ) |
| elif isinstance(lora_weights, LoraWeights): |
| b_ = lora_weights |
| lora_weights = b_.weights |
| keys_without_ab = list( |
| set( |
| [ |
| key.replace(".lora_A.weight", "") |
| .replace(".lora_B.weight", "") |
| .replace(".lora_A", "") |
| .replace(".lora_B", "") |
| .replace(".alpha", "") |
| for key in lora_weights.keys() |
| ] |
| ) |
| ) |
| else: |
| lora_weights = lora_weights |
| keys_without_ab = list( |
| set( |
| [ |
| key.replace(".lora_A.weight", "") |
| .replace(".lora_B.weight", "") |
| .replace(".lora_A", "") |
| .replace(".lora_B", "") |
| .replace(".alpha", "") |
| for key in lora_weights.keys() |
| ] |
| ) |
| ) |
| for key in tqdm(keys_without_ab, desc="Applying LoRA", total=len(keys_without_ab)): |
| module = get_module_for_key(key, model) |
| weight, is_f8, dtype = extract_weight_from_linear(module) |
| lora_sd = get_lora_for_key(key, lora_weights) |
| if lora_sd is None: |
| |
| continue |
| weight = apply_lora_weight_to_module(weight, lora_sd, lora_scale=lora_scale) |
| if is_f8: |
| module.set_weight_tensor(weight.type(dtype)) |
| else: |
| module.weight.data = weight.type(dtype) |
| logger.success("Lora applied") |
| if return_lora_resolved: |
| return model, lora_weights |
| return model |
|
|
|
|
| def remove_lora_from_module( |
| model: Flux, |
| lora_path: str | StateDict, |
| lora_scale: float = 1.0, |
| ): |
| has_guidance = model.params.guidance_embed |
| logger.info(f"Loading LoRA weights for {lora_path}") |
| lora_weights, already_loaded = get_lora_weights(lora_path) |
|
|
| if not already_loaded: |
| keys_without_ab, lora_weights = resolve_lora_state_dict( |
| lora_weights, has_guidance |
| ) |
| elif isinstance(lora_weights, LoraWeights): |
| b_ = lora_weights |
| lora_weights = b_.weights |
| keys_without_ab = list( |
| set( |
| [ |
| key.replace(".lora_A.weight", "") |
| .replace(".lora_B.weight", "") |
| .replace(".lora_A", "") |
| .replace(".lora_B", "") |
| .replace(".alpha", "") |
| for key in lora_weights.keys() |
| ] |
| ) |
| ) |
| lora_scale = b_.scale |
| else: |
| lora_weights = lora_weights |
| keys_without_ab = list( |
| set( |
| [ |
| key.replace(".lora_A.weight", "") |
| .replace(".lora_B.weight", "") |
| .replace(".lora_A", "") |
| .replace(".lora_B", "") |
| .replace(".alpha", "") |
| for key in lora_weights.keys() |
| ] |
| ) |
| ) |
|
|
| for key in tqdm(keys_without_ab, desc="Unfusing LoRA", total=len(keys_without_ab)): |
| module = get_module_for_key(key, model) |
| weight, is_f8, dtype = extract_weight_from_linear(module) |
| lora_sd = get_lora_for_key(key, lora_weights) |
| if lora_sd is None: |
| |
| continue |
| weight = unfuse_lora_weight_from_module(weight, lora_sd, lora_scale=lora_scale) |
| if is_f8: |
| module.set_weight_tensor(weight.type(dtype)) |
| else: |
| module.weight.data = weight.type(dtype) |
| logger.success("Lora unfused") |
| return model |
|
|