diff --git a/src/block.py b/src/block.py new file mode 100644 index 0000000..ef9b389 --- /dev/null +++ b/src/block.py @@ -0,0 +1,333 @@ +import torch +from typing import List, Union, Optional, Dict, Any, Callable +from diffusers.models.attention_processor import Attention, F +from .lora_controller import enable_lora + + +def attn_forward( + attn: Attention, + hidden_states: torch.FloatTensor, + encoder_hidden_states: torch.FloatTensor = None, + condition_latents: torch.FloatTensor = None, + attention_mask: Optional[torch.FloatTensor] = None, + image_rotary_emb: Optional[torch.Tensor] = None, + cond_rotary_emb: Optional[torch.Tensor] = None, + model_config: Optional[Dict[str, Any]] = {}, +) -> torch.FloatTensor: + batch_size, _, _ = ( + hidden_states.shape + if encoder_hidden_states is None + else encoder_hidden_states.shape + ) + + with enable_lora( + (attn.to_q, attn.to_k, attn.to_v), model_config.get("latent_lora", False) + ): + # `sample` projections. + query = attn.to_q(hidden_states) + key = attn.to_k(hidden_states) + value = attn.to_v(hidden_states) + + inner_dim = key.shape[-1] + head_dim = inner_dim // attn.heads + + query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) + key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) + value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) + + if attn.norm_q is not None: + query = attn.norm_q(query) + if attn.norm_k is not None: + key = attn.norm_k(key) + + # the attention in FluxSingleTransformerBlock does not use `encoder_hidden_states` + if encoder_hidden_states is not None: + # `context` projections. + encoder_hidden_states_query_proj = attn.add_q_proj(encoder_hidden_states) + encoder_hidden_states_key_proj = attn.add_k_proj(encoder_hidden_states) + encoder_hidden_states_value_proj = attn.add_v_proj(encoder_hidden_states) + + encoder_hidden_states_query_proj = encoder_hidden_states_query_proj.view( + batch_size, -1, attn.heads, head_dim + ).transpose(1, 2) + encoder_hidden_states_key_proj = encoder_hidden_states_key_proj.view( + batch_size, -1, attn.heads, head_dim + ).transpose(1, 2) + encoder_hidden_states_value_proj = encoder_hidden_states_value_proj.view( + batch_size, -1, attn.heads, head_dim + ).transpose(1, 2) + + if attn.norm_added_q is not None: + encoder_hidden_states_query_proj = attn.norm_added_q( + encoder_hidden_states_query_proj + ) + if attn.norm_added_k is not None: + encoder_hidden_states_key_proj = attn.norm_added_k( + encoder_hidden_states_key_proj + ) + + # attention + query = torch.cat([encoder_hidden_states_query_proj, query], dim=2) + key = torch.cat([encoder_hidden_states_key_proj, key], dim=2) + value = torch.cat([encoder_hidden_states_value_proj, value], dim=2) + + if image_rotary_emb is not None: + from diffusers.models.embeddings import apply_rotary_emb + + query = apply_rotary_emb(query, image_rotary_emb) + key = apply_rotary_emb(key, image_rotary_emb) + + if condition_latents is not None: + cond_query = attn.to_q(condition_latents) + cond_key = attn.to_k(condition_latents) + cond_value = attn.to_v(condition_latents) + + cond_query = cond_query.view(batch_size, -1, attn.heads, head_dim).transpose( + 1, 2 + ) + cond_key = cond_key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) + cond_value = cond_value.view(batch_size, -1, attn.heads, head_dim).transpose( + 1, 2 + ) + if attn.norm_q is not None: + cond_query = attn.norm_q(cond_query) + if attn.norm_k is not None: + cond_key = attn.norm_k(cond_key) + + if cond_rotary_emb is not None: + cond_query = apply_rotary_emb(cond_query, cond_rotary_emb) + cond_key = apply_rotary_emb(cond_key, cond_rotary_emb) + + if condition_latents is not None: + query = torch.cat([query, cond_query], dim=2) + key = torch.cat([key, cond_key], dim=2) + value = torch.cat([value, cond_value], dim=2) + + if not model_config.get("union_cond_attn", True): + # If we don't want to use the union condition attention, we need to mask the attention + # between the hidden states and the condition latents + attention_mask = torch.ones( + query.shape[2], key.shape[2], device=query.device, dtype=torch.bool + ) + condition_n = cond_query.shape[2] + attention_mask[-condition_n:, :-condition_n] = False + attention_mask[:-condition_n, -condition_n:] = False + if hasattr(attn, "c_factor"): + attention_mask = torch.zeros( + query.shape[2], key.shape[2], device=query.device, dtype=query.dtype + ) + condition_n = cond_query.shape[2] + bias = torch.log(attn.c_factor[0]) + attention_mask[-condition_n:, :-condition_n] = bias + attention_mask[:-condition_n, -condition_n:] = bias + hidden_states = F.scaled_dot_product_attention( + query, key, value, dropout_p=0.0, is_causal=False, attn_mask=attention_mask + ) + hidden_states = hidden_states.transpose(1, 2).reshape( + batch_size, -1, attn.heads * head_dim + ) + hidden_states = hidden_states.to(query.dtype) + + if encoder_hidden_states is not None: + if condition_latents is not None: + encoder_hidden_states, hidden_states, condition_latents = ( + hidden_states[:, : encoder_hidden_states.shape[1]], + hidden_states[ + :, encoder_hidden_states.shape[1] : -condition_latents.shape[1] + ], + hidden_states[:, -condition_latents.shape[1] :], + ) + else: + encoder_hidden_states, hidden_states = ( + hidden_states[:, : encoder_hidden_states.shape[1]], + hidden_states[:, encoder_hidden_states.shape[1] :], + ) + + with enable_lora((attn.to_out[0],), model_config.get("latent_lora", False)): + # linear proj + hidden_states = attn.to_out[0](hidden_states) + # dropout + hidden_states = attn.to_out[1](hidden_states) + encoder_hidden_states = attn.to_add_out(encoder_hidden_states) + + if condition_latents is not None: + condition_latents = attn.to_out[0](condition_latents) + condition_latents = attn.to_out[1](condition_latents) + + return ( + (hidden_states, encoder_hidden_states, condition_latents) + if condition_latents is not None + else (hidden_states, encoder_hidden_states) + ) + elif condition_latents is not None: + # if there are condition_latents, we need to separate the hidden_states and the condition_latents + hidden_states, condition_latents = ( + hidden_states[:, : -condition_latents.shape[1]], + hidden_states[:, -condition_latents.shape[1] :], + ) + return hidden_states, condition_latents + else: + return hidden_states + + +def block_forward( + self, + hidden_states: torch.FloatTensor, + encoder_hidden_states: torch.FloatTensor, + condition_latents: torch.FloatTensor, + temb: torch.FloatTensor, + cond_temb: torch.FloatTensor, + cond_rotary_emb=None, + image_rotary_emb=None, + model_config: Optional[Dict[str, Any]] = {}, +): + use_cond = condition_latents is not None + with enable_lora((self.norm1.linear,), model_config.get("latent_lora", False)): + norm_hidden_states, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.norm1( + hidden_states, emb=temb + ) + + norm_encoder_hidden_states, c_gate_msa, c_shift_mlp, c_scale_mlp, c_gate_mlp = ( + self.norm1_context(encoder_hidden_states, emb=temb) + ) + + if use_cond: + ( + norm_condition_latents, + cond_gate_msa, + cond_shift_mlp, + cond_scale_mlp, + cond_gate_mlp, + ) = self.norm1(condition_latents, emb=cond_temb) + + # Attention. + result = attn_forward( + self.attn, + model_config=model_config, + hidden_states=norm_hidden_states, + encoder_hidden_states=norm_encoder_hidden_states, + condition_latents=norm_condition_latents if use_cond else None, + image_rotary_emb=image_rotary_emb, + cond_rotary_emb=cond_rotary_emb if use_cond else None, + ) + attn_output, context_attn_output = result[:2] + cond_attn_output = result[2] if use_cond else None + + # Process attention outputs for the `hidden_states`. + # 1. hidden_states + attn_output = gate_msa.unsqueeze(1) * attn_output + hidden_states = hidden_states + attn_output + # 2. encoder_hidden_states + context_attn_output = c_gate_msa.unsqueeze(1) * context_attn_output + encoder_hidden_states = encoder_hidden_states + context_attn_output + # 3. condition_latents + if use_cond: + cond_attn_output = cond_gate_msa.unsqueeze(1) * cond_attn_output + condition_latents = condition_latents + cond_attn_output + if model_config.get("add_cond_attn", False): + hidden_states += cond_attn_output + + # LayerNorm + MLP. + # 1. hidden_states + norm_hidden_states = self.norm2(hidden_states) + norm_hidden_states = ( + norm_hidden_states * (1 + scale_mlp[:, None]) + shift_mlp[:, None] + ) + # 2. encoder_hidden_states + norm_encoder_hidden_states = self.norm2_context(encoder_hidden_states) + norm_encoder_hidden_states = ( + norm_encoder_hidden_states * (1 + c_scale_mlp[:, None]) + c_shift_mlp[:, None] + ) + # 3. condition_latents + if use_cond: + norm_condition_latents = self.norm2(condition_latents) + norm_condition_latents = ( + norm_condition_latents * (1 + cond_scale_mlp[:, None]) + + cond_shift_mlp[:, None] + ) + + # Feed-forward. + with enable_lora((self.ff.net[2],), model_config.get("latent_lora", False)): + # 1. hidden_states + ff_output = self.ff(norm_hidden_states) + ff_output = gate_mlp.unsqueeze(1) * ff_output + # 2. encoder_hidden_states + context_ff_output = self.ff_context(norm_encoder_hidden_states) + context_ff_output = c_gate_mlp.unsqueeze(1) * context_ff_output + # 3. condition_latents + if use_cond: + cond_ff_output = self.ff(norm_condition_latents) + cond_ff_output = cond_gate_mlp.unsqueeze(1) * cond_ff_output + + # Process feed-forward outputs. + hidden_states = hidden_states + ff_output + encoder_hidden_states = encoder_hidden_states + context_ff_output + if use_cond: + condition_latents = condition_latents + cond_ff_output + + # Clip to avoid overflow. + if encoder_hidden_states.dtype == torch.float16: + encoder_hidden_states = encoder_hidden_states.clip(-65504, 65504) + + return encoder_hidden_states, hidden_states, condition_latents if use_cond else None + + +def single_block_forward( + self, + hidden_states: torch.FloatTensor, + temb: torch.FloatTensor, + image_rotary_emb=None, + condition_latents: torch.FloatTensor = None, + cond_temb: torch.FloatTensor = None, + cond_rotary_emb=None, + model_config: Optional[Dict[str, Any]] = {}, +): + + using_cond = condition_latents is not None + residual = hidden_states + with enable_lora( + ( + self.norm.linear, + self.proj_mlp, + ), + model_config.get("latent_lora", False), + ): + norm_hidden_states, gate = self.norm(hidden_states, emb=temb) + mlp_hidden_states = self.act_mlp(self.proj_mlp(norm_hidden_states)) + if using_cond: + residual_cond = condition_latents + norm_condition_latents, cond_gate = self.norm(condition_latents, emb=cond_temb) + mlp_cond_hidden_states = self.act_mlp(self.proj_mlp(norm_condition_latents)) + + attn_output = attn_forward( + self.attn, + model_config=model_config, + hidden_states=norm_hidden_states, + image_rotary_emb=image_rotary_emb, + **( + { + "condition_latents": norm_condition_latents, + "cond_rotary_emb": cond_rotary_emb if using_cond else None, + } + if using_cond + else {} + ), + ) + if using_cond: + attn_output, cond_attn_output = attn_output + + with enable_lora((self.proj_out,), model_config.get("latent_lora", False)): + hidden_states = torch.cat([attn_output, mlp_hidden_states], dim=2) + gate = gate.unsqueeze(1) + hidden_states = gate * self.proj_out(hidden_states) + hidden_states = residual + hidden_states + if using_cond: + condition_latents = torch.cat([cond_attn_output, mlp_cond_hidden_states], dim=2) + cond_gate = cond_gate.unsqueeze(1) + condition_latents = cond_gate * self.proj_out(condition_latents) + condition_latents = residual_cond + condition_latents + + if hidden_states.dtype == torch.float16: + hidden_states = hidden_states.clip(-65504, 65504) + + return hidden_states if not using_cond else (hidden_states, condition_latents) diff --git a/src/condition.py b/src/condition.py new file mode 100644 index 0000000..3cad84c --- /dev/null +++ b/src/condition.py @@ -0,0 +1,128 @@ +import torch +from typing import Optional, Union, List, Tuple +from diffusers.pipelines import FluxPipeline +from PIL import Image, ImageFilter +import numpy as np +import cv2 + +condition_dict = { + "depth": 0, + "canny": 1, + "subject": 4, + "coloring": 6, + "deblurring": 7, + "fill": 9, +} + + +class Condition(object): + def __init__( + self, + condition_type: str, + raw_img: Union[Image.Image, torch.Tensor] = None, + condition: Union[Image.Image, torch.Tensor] = None, + mask=None, + ) -> None: + self.condition_type = condition_type + assert raw_img is not None or condition is not None + if raw_img is not None: + self.condition = self.get_condition(condition_type, raw_img) + else: + self.condition = condition + # TODO: Add mask support + assert mask is None, "Mask not supported yet" + + def get_condition( + self, condition_type: str, raw_img: Union[Image.Image, torch.Tensor] + ) -> Union[Image.Image, torch.Tensor]: + """ + Returns the condition image. + """ + if condition_type == "depth": + from transformers import pipeline + import folder_paths + import os + + depth_pipe = pipeline( + task="depth-estimation", + # model="LiheYoung/depth-anything-small-hf", + model=os.path.join(folder_paths.models_dir, 'flux', 'OminiControl', 'depth-anything-small-hf'), + device="cuda", + ) + source_image = raw_img.convert("RGB") + condition_img = depth_pipe(source_image)["depth"].convert("RGB") + return condition_img + elif condition_type == "canny": + img = np.array(raw_img) + edges = cv2.Canny(img, 100, 200) + edges = Image.fromarray(edges).convert("RGB") + return edges + elif condition_type == "subject": + return raw_img + elif condition_type == "coloring": + return raw_img.convert("L").convert("RGB") + elif condition_type == "deblurring": + condition_image = ( + raw_img.convert("RGB") + .filter(ImageFilter.GaussianBlur(10)) + .convert("RGB") + ) + return condition_image + elif condition_type == "fill": + return raw_img.convert("RGB") + return self.condition + + @property + def type_id(self) -> int: + """ + Returns the type id of the condition. + """ + return condition_dict[self.condition_type] + + @classmethod + def get_type_id(cls, condition_type: str) -> int: + """ + Returns the type id of the condition. + """ + return condition_dict[condition_type] + + def _encode_image(self, pipe: FluxPipeline, cond_img: Image.Image) -> torch.Tensor: + """ + Encodes an image condition into tokens using the pipeline. + """ + cond_img = pipe.image_processor.preprocess(cond_img) + # cond_img = cond_img.to(pipe.device).to(pipe.dtype) + cond_img = cond_img.to('cuda').to(pipe.dtype) + cond_img = pipe.vae.encode(cond_img).latent_dist.sample() + cond_img = ( + cond_img - pipe.vae.config.shift_factor + ) * pipe.vae.config.scaling_factor + cond_tokens = pipe._pack_latents(cond_img, *cond_img.shape) + cond_ids = pipe._prepare_latent_image_ids( + cond_img.shape[0], + cond_img.shape[2], + cond_img.shape[3], + pipe.device, + pipe.dtype, + ) + return cond_tokens, cond_ids + + def encode(self, pipe: FluxPipeline) -> Tuple[torch.Tensor, torch.Tensor, int]: + """ + Encodes the condition into tokens, ids and type_id. + """ + if self.condition_type in [ + "depth", + "canny", + "subject", + "coloring", + "deblurring", + "fill", + ]: + tokens, ids = self._encode_image(pipe, self.condition) + else: + raise NotImplementedError( + f"Condition type {self.condition_type} not implemented" + ) + type_id = torch.ones_like(ids[:, :1]) * self.type_id + return tokens, ids, type_id diff --git a/src/generate.py b/src/generate.py new file mode 100644 index 0000000..a823420 --- /dev/null +++ b/src/generate.py @@ -0,0 +1,300 @@ +import torch +import yaml, os +from diffusers.pipelines import FluxPipeline +from typing import List, Union, Optional, Dict, Any, Callable +from .transformer import tranformer_forward +from .condition import Condition + +from diffusers.pipelines.flux.pipeline_flux import ( + FluxPipelineOutput, + calculate_shift, + retrieve_timesteps, + np, +) + + +def prepare_params( + prompt: Union[str, List[str]] = None, + prompt_2: Optional[Union[str, List[str]]] = None, + height: Optional[int] = 512, + width: Optional[int] = 512, + num_inference_steps: int = 28, + timesteps: List[int] = None, + guidance_scale: float = 3.5, + num_images_per_prompt: Optional[int] = 1, + generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, + latents: Optional[torch.FloatTensor] = None, + prompt_embeds: Optional[torch.FloatTensor] = None, + pooled_prompt_embeds: Optional[torch.FloatTensor] = None, + output_type: Optional[str] = "pil", + return_dict: bool = True, + joint_attention_kwargs: Optional[Dict[str, Any]] = None, + callback_on_step_end: Optional[Callable[[int, int, Dict], None]] = None, + callback_on_step_end_tensor_inputs: List[str] = ["latents"], + max_sequence_length: int = 512, + **kwargs: dict, +): + return ( + prompt, + prompt_2, + height, + width, + num_inference_steps, + timesteps, + guidance_scale, + num_images_per_prompt, + generator, + latents, + prompt_embeds, + pooled_prompt_embeds, + output_type, + return_dict, + joint_attention_kwargs, + callback_on_step_end, + callback_on_step_end_tensor_inputs, + max_sequence_length, + ) + + +def seed_everything(seed: int = 42): + torch.backends.cudnn.deterministic = True + torch.manual_seed(seed) + np.random.seed(seed) + + +@torch.no_grad() +def generate( + pipeline: FluxPipeline, + conditions: List[Condition] = None, + model_config: Optional[Dict[str, Any]] = {}, + condition_scale: float = 1.0, + **params: dict, +): + + # print(params) + # return + # model_config = model_config or get_config(config_path).get("model", {}) + if condition_scale != 1: + for name, module in pipeline.transformer.named_modules(): + if not name.endswith(".attn"): + continue + module.c_factor = torch.ones(1, 1) * condition_scale + + self = pipeline + ( + prompt, + prompt_2, + height, + width, + num_inference_steps, + timesteps, + guidance_scale, + num_images_per_prompt, + generator, + latents, + prompt_embeds, + pooled_prompt_embeds, + output_type, + return_dict, + joint_attention_kwargs, + callback_on_step_end, + callback_on_step_end_tensor_inputs, + max_sequence_length, + ) = prepare_params(**params) + + height = height or self.default_sample_size * self.vae_scale_factor + width = width or self.default_sample_size * self.vae_scale_factor + + # 1. Check inputs. Raise error if not correct + self.check_inputs( + prompt, + prompt_2, + height, + width, + prompt_embeds=prompt_embeds, + pooled_prompt_embeds=pooled_prompt_embeds, + callback_on_step_end_tensor_inputs=callback_on_step_end_tensor_inputs, + max_sequence_length=max_sequence_length, + ) + + self._guidance_scale = guidance_scale + self._joint_attention_kwargs = joint_attention_kwargs + self._interrupt = False + + # 2. Define call parameters + if prompt is not None and isinstance(prompt, str): + batch_size = 1 + elif prompt is not None and isinstance(prompt, list): + batch_size = len(prompt) + else: + batch_size = prompt_embeds.shape[0] + + device = self._execution_device + # print('execution device --->', device) + # device = 'cpu' + + lora_scale = ( + self.joint_attention_kwargs.get("scale", None) + if self.joint_attention_kwargs is not None + else None + ) + ( + prompt_embeds, + pooled_prompt_embeds, + text_ids, + ) = self.encode_prompt( + prompt=prompt, + prompt_2=prompt_2, + prompt_embeds=prompt_embeds, + pooled_prompt_embeds=pooled_prompt_embeds, + device=device, + num_images_per_prompt=num_images_per_prompt, + max_sequence_length=max_sequence_length, + lora_scale=lora_scale, + ) + + # print('-----> real prompt embeds:') + # print(prompt_embeds[0]) + # print(pooled_prompt_embeds[0]) + # print(text_ids) + + # 4. Prepare latent variables + num_channels_latents = self.transformer.config.in_channels // 4 + latents, latent_image_ids = self.prepare_latents( + batch_size * num_images_per_prompt, + num_channels_latents, + height, + width, + prompt_embeds.dtype, + device, + generator, + latents, + ) + + # 4.1. Prepare conditions + condition_latents, condition_ids, condition_type_ids = ([] for _ in range(3)) + use_condition = conditions is not None or [] + if use_condition: + assert len(conditions) <= 1, "Only one condition is supported for now." + pipeline.set_adapters(conditions[0].condition_type) + for condition in conditions: + # tokens, ids, type_id = condition.encode(self) + tokens, ids, type_id = params['encoded_condition'] + tokens.to(torch.bfloat16) + ids.to(torch.bfloat16) + type_id.to(torch.bfloat16) + condition_latents.append(tokens) # [batch_size, token_n, token_dim] + condition_ids.append(ids) # [token_n, id_dim(3)] + condition_type_ids.append(type_id) # [token_n, 1] + condition_latents = torch.cat(condition_latents, dim=1) + condition_ids = torch.cat(condition_ids, dim=0) + if condition.condition_type == "subject": + condition_ids[:, 2] += width // 16 + condition_type_ids = torch.cat(condition_type_ids, dim=0) + + # 5. Prepare timesteps + sigmas = np.linspace(1.0, 1 / num_inference_steps, num_inference_steps) + image_seq_len = latents.shape[1] + mu = calculate_shift( + image_seq_len, + self.scheduler.config.base_image_seq_len, + self.scheduler.config.max_image_seq_len, + self.scheduler.config.base_shift, + self.scheduler.config.max_shift, + ) + timesteps, num_inference_steps = retrieve_timesteps( + self.scheduler, + num_inference_steps, + device, + timesteps, + sigmas, + mu=mu, + ) + num_warmup_steps = max( + len(timesteps) - num_inference_steps * self.scheduler.order, 0 + ) + self._num_timesteps = len(timesteps) + + # 6. Denoising loop + with self.progress_bar(total=num_inference_steps) as progress_bar: + for i, t in enumerate(timesteps): + if self.interrupt: + continue + + # broadcast to batch dimension in a way that's compatible with ONNX/Core ML + timestep = t.expand(latents.shape[0]).to(latents.dtype) + + # handle guidance + if self.transformer.config.guidance_embeds: + guidance = torch.tensor([guidance_scale], device=device) + guidance = guidance.expand(latents.shape[0]) + else: + guidance = None + noise_pred = tranformer_forward( + self.transformer, + model_config=model_config, + # Inputs of the condition (new feature) + condition_latents=condition_latents if use_condition else None, + condition_ids=condition_ids if use_condition else None, + condition_type_ids=condition_type_ids if use_condition else None, + # Inputs to the original transformer + hidden_states=latents, + # YiYi notes: divide it by 1000 for now because we scale it by 1000 in the transforme rmodel (we should not keep it but I want to keep the inputs same for the model for testing) + timestep=timestep / 1000, + guidance=guidance, + pooled_projections=pooled_prompt_embeds, + encoder_hidden_states=prompt_embeds, + txt_ids=text_ids, + img_ids=latent_image_ids, + joint_attention_kwargs=self.joint_attention_kwargs, + return_dict=False, + )[0] + + # compute the previous noisy sample x_t -> x_t-1 + latents_dtype = latents.dtype + latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0] + + if latents.dtype != latents_dtype: + if torch.backends.mps.is_available(): + # some platforms (eg. apple mps) misbehave due to a pytorch bug: https://github.com/pytorch/pytorch/pull/99272 + latents = latents.to(latents_dtype) + + if callback_on_step_end is not None: + callback_kwargs = {} + for k in callback_on_step_end_tensor_inputs: + callback_kwargs[k] = locals()[k] + callback_outputs = callback_on_step_end(self, i, t, callback_kwargs) + + latents = callback_outputs.pop("latents", latents) + prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds) + + # call the callback, if provided + if i == len(timesteps) - 1 or ( + (i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0 + ): + progress_bar.update() + + if output_type == "latent": + image = latents + + else: + latents = self._unpack_latents(latents, height, width, self.vae_scale_factor) + latents = ( + latents / self.vae.config.scaling_factor + ) + self.vae.config.shift_factor + image = self.vae.decode(latents, return_dict=False)[0] + image = self.image_processor.postprocess(image, output_type=output_type) + + # Offload all models + self.maybe_free_model_hooks() + + if condition_scale != 1: + for name, module in pipeline.transformer.named_modules(): + if not name.endswith(".attn"): + continue + del module.c_factor + + if not return_dict: + return (image,) + + return FluxPipelineOutput(images=image) diff --git a/src/lora_controller.py b/src/lora_controller.py new file mode 100644 index 0000000..21b23ea --- /dev/null +++ b/src/lora_controller.py @@ -0,0 +1,75 @@ +from peft.tuners.tuners_utils import BaseTunerLayer +from typing import List, Any, Optional, Type + + +class enable_lora: + def __init__(self, lora_modules: List[BaseTunerLayer], activated: bool) -> None: + self.activated: bool = activated + if activated: + return + self.lora_modules: List[BaseTunerLayer] = [ + each for each in lora_modules if isinstance(each, BaseTunerLayer) + ] + self.scales = [ + { + active_adapter: lora_module.scaling[active_adapter] + for active_adapter in lora_module.active_adapters + } + for lora_module in self.lora_modules + ] + + def __enter__(self) -> None: + if self.activated: + return + + for lora_module in self.lora_modules: + if not isinstance(lora_module, BaseTunerLayer): + continue + lora_module.scale_layer(0) + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[Any], + ) -> None: + if self.activated: + return + for i, lora_module in enumerate(self.lora_modules): + if not isinstance(lora_module, BaseTunerLayer): + continue + for active_adapter in lora_module.active_adapters: + lora_module.scaling[active_adapter] = self.scales[i][active_adapter] + + +class set_lora_scale: + def __init__(self, lora_modules: List[BaseTunerLayer], scale: float) -> None: + self.lora_modules: List[BaseTunerLayer] = [ + each for each in lora_modules if isinstance(each, BaseTunerLayer) + ] + self.scales = [ + { + active_adapter: lora_module.scaling[active_adapter] + for active_adapter in lora_module.active_adapters + } + for lora_module in self.lora_modules + ] + self.scale = scale + + def __enter__(self) -> None: + for lora_module in self.lora_modules: + if not isinstance(lora_module, BaseTunerLayer): + continue + lora_module.scale_layer(self.scale) + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[Any], + ) -> None: + for i, lora_module in enumerate(self.lora_modules): + if not isinstance(lora_module, BaseTunerLayer): + continue + for active_adapter in lora_module.active_adapters: + lora_module.scaling[active_adapter] = self.scales[i][active_adapter] diff --git a/src/transformer.py b/src/transformer.py new file mode 100644 index 0000000..ad8021b --- /dev/null +++ b/src/transformer.py @@ -0,0 +1,270 @@ +import torch +from diffusers.pipelines import FluxPipeline +from typing import List, Union, Optional, Dict, Any, Callable +from .block import block_forward, single_block_forward +from .lora_controller import enable_lora +from diffusers.models.transformers.transformer_flux import ( + FluxTransformer2DModel, + Transformer2DModelOutput, + USE_PEFT_BACKEND, + is_torch_version, + scale_lora_layers, + unscale_lora_layers, + logger, +) +import numpy as np + + +def prepare_params( + hidden_states: torch.Tensor, + encoder_hidden_states: torch.Tensor = None, + pooled_projections: torch.Tensor = None, + timestep: torch.LongTensor = None, + img_ids: torch.Tensor = None, + txt_ids: torch.Tensor = None, + guidance: torch.Tensor = None, + joint_attention_kwargs: Optional[Dict[str, Any]] = None, + controlnet_block_samples=None, + controlnet_single_block_samples=None, + return_dict: bool = True, + **kwargs: dict, +): + return ( + hidden_states, + encoder_hidden_states, + pooled_projections, + timestep, + img_ids, + txt_ids, + guidance, + joint_attention_kwargs, + controlnet_block_samples, + controlnet_single_block_samples, + return_dict, + ) + + +def tranformer_forward( + transformer: FluxTransformer2DModel, + condition_latents: torch.Tensor, + condition_ids: torch.Tensor, + condition_type_ids: torch.Tensor, + model_config: Optional[Dict[str, Any]] = {}, + return_conditional_latents: bool = False, + c_t=0, + **params: dict, +): + self = transformer + use_condition = condition_latents is not None + use_condition_in_single_blocks = model_config.get( + "use_condition_in_single_blocks", True + ) + # if return_conditional_latents is True, use_condition and use_condition_in_single_blocks must be True + assert not return_conditional_latents or ( + use_condition and use_condition_in_single_blocks + ), "`return_conditional_latents` is True, `use_condition` and `use_condition_in_single_blocks` must be True" + + ( + hidden_states, + encoder_hidden_states, + pooled_projections, + timestep, + img_ids, + txt_ids, + guidance, + joint_attention_kwargs, + controlnet_block_samples, + controlnet_single_block_samples, + return_dict, + ) = prepare_params(**params) + + if joint_attention_kwargs is not None: + joint_attention_kwargs = joint_attention_kwargs.copy() + lora_scale = joint_attention_kwargs.pop("scale", 1.0) + else: + lora_scale = 1.0 + + if USE_PEFT_BACKEND: + # weight the lora layers by setting `lora_scale` for each PEFT layer + scale_lora_layers(self, lora_scale) + else: + if ( + joint_attention_kwargs is not None + and joint_attention_kwargs.get("scale", None) is not None + ): + logger.warning( + "Passing `scale` via `joint_attention_kwargs` when not using the PEFT backend is ineffective." + ) + with enable_lora((self.x_embedder,), model_config.get("latent_lora", False)): + hidden_states = self.x_embedder(hidden_states) + condition_latents = self.x_embedder(condition_latents) if use_condition else None + + timestep = timestep.to(hidden_states.dtype) * 1000 + if guidance is not None: + guidance = guidance.to(hidden_states.dtype) * 1000 + else: + guidance = None + temb = ( + self.time_text_embed(timestep, pooled_projections) + if guidance is None + else self.time_text_embed(timestep, guidance, pooled_projections) + ) + cond_temb = ( + self.time_text_embed(torch.ones_like(timestep) * c_t * 1000, pooled_projections) + if guidance is None + else self.time_text_embed( + torch.ones_like(timestep) * c_t * 1000, guidance, pooled_projections + ) + ) + if hasattr(self, "cond_type_embed") and condition_type_ids is not None: + cond_type_proj = self.time_text_embed.time_proj(condition_type_ids[0]) + cond_type_emb = self.cond_type_embed(cond_type_proj.to(dtype=cond_temb.dtype)) + cond_temb = cond_temb + cond_type_emb + encoder_hidden_states = self.context_embedder(encoder_hidden_states) + + if txt_ids.ndim == 3: + logger.warning( + "Passing `txt_ids` 3d torch.Tensor is deprecated." + "Please remove the batch dimension and pass it as a 2d torch Tensor" + ) + txt_ids = txt_ids[0] + if img_ids.ndim == 3: + logger.warning( + "Passing `img_ids` 3d torch.Tensor is deprecated." + "Please remove the batch dimension and pass it as a 2d torch Tensor" + ) + img_ids = img_ids[0] + + ids = torch.cat((txt_ids, img_ids), dim=0) + image_rotary_emb = self.pos_embed(ids) + if use_condition: + cond_ids = condition_ids + cond_rotary_emb = self.pos_embed(cond_ids) + + # hidden_states = torch.cat([hidden_states, condition_latents], dim=1) + + for index_block, block in enumerate(self.transformer_blocks): + if self.training and self.gradient_checkpointing: + + def create_custom_forward(module, return_dict=None): + def custom_forward(*inputs): + if return_dict is not None: + return module(*inputs, return_dict=return_dict) + else: + return module(*inputs) + + return custom_forward + + ckpt_kwargs: Dict[str, Any] = ( + {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {} + ) + encoder_hidden_states, hidden_states = torch.utils.checkpoint.checkpoint( + create_custom_forward(block), + hidden_states, + encoder_hidden_states, + temb, + image_rotary_emb, + **ckpt_kwargs, + ) + + else: + encoder_hidden_states, hidden_states, condition_latents = block_forward( + block, + model_config=model_config, + hidden_states=hidden_states, + encoder_hidden_states=encoder_hidden_states, + condition_latents=condition_latents if use_condition else None, + temb=temb, + cond_temb=cond_temb if use_condition else None, + cond_rotary_emb=cond_rotary_emb if use_condition else None, + image_rotary_emb=image_rotary_emb, + ) + + # controlnet residual + if controlnet_block_samples is not None: + interval_control = len(self.transformer_blocks) / len( + controlnet_block_samples + ) + interval_control = int(np.ceil(interval_control)) + hidden_states = ( + hidden_states + + controlnet_block_samples[index_block // interval_control] + ) + hidden_states = torch.cat([encoder_hidden_states, hidden_states], dim=1) + + for index_block, block in enumerate(self.single_transformer_blocks): + if self.training and self.gradient_checkpointing: + + def create_custom_forward(module, return_dict=None): + def custom_forward(*inputs): + if return_dict is not None: + return module(*inputs, return_dict=return_dict) + else: + return module(*inputs) + + return custom_forward + + ckpt_kwargs: Dict[str, Any] = ( + {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {} + ) + hidden_states = torch.utils.checkpoint.checkpoint( + create_custom_forward(block), + hidden_states, + temb, + image_rotary_emb, + **ckpt_kwargs, + ) + + else: + result = single_block_forward( + block, + model_config=model_config, + hidden_states=hidden_states, + temb=temb, + image_rotary_emb=image_rotary_emb, + **( + { + "condition_latents": condition_latents, + "cond_temb": cond_temb, + "cond_rotary_emb": cond_rotary_emb, + } + if use_condition_in_single_blocks and use_condition + else {} + ), + ) + if use_condition_in_single_blocks and use_condition: + hidden_states, condition_latents = result + else: + hidden_states = result + + # controlnet residual + if controlnet_single_block_samples is not None: + interval_control = len(self.single_transformer_blocks) / len( + controlnet_single_block_samples + ) + interval_control = int(np.ceil(interval_control)) + hidden_states[:, encoder_hidden_states.shape[1] :, ...] = ( + hidden_states[:, encoder_hidden_states.shape[1] :, ...] + + controlnet_single_block_samples[index_block // interval_control] + ) + + hidden_states = hidden_states[:, encoder_hidden_states.shape[1] :, ...] + + hidden_states = self.norm_out(hidden_states, temb) + output = self.proj_out(hidden_states) + if return_conditional_latents: + condition_latents = ( + self.norm_out(condition_latents, cond_temb) if use_condition else None + ) + condition_output = self.proj_out(condition_latents) if use_condition else None + + if USE_PEFT_BACKEND: + # remove `lora_scale` from each PEFT layer + unscale_lora_layers(self, lora_scale) + + if not return_dict: + return ( + (output,) if not return_conditional_latents else (output, condition_output) + ) + + return Transformer2DModelOutput(sample=output)