Upload extensions_built_in/diffusion_models/hidream/hidream_e1_model.py with huggingface_hub
Browse files
extensions_built_in/diffusion_models/hidream/hidream_e1_model.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .hidream_model import HidreamModel
|
| 2 |
+
from .src.pipelines.hidream_image.pipeline_hidream_image_editing import (
|
| 3 |
+
HiDreamImageEditingPipeline,
|
| 4 |
+
)
|
| 5 |
+
from .src.schedulers.fm_solvers_unipc import FlowUniPCMultistepScheduler
|
| 6 |
+
from toolkit.accelerator import unwrap_model
|
| 7 |
+
import torch
|
| 8 |
+
from toolkit.prompt_utils import PromptEmbeds
|
| 9 |
+
from toolkit.config_modules import GenerateImageConfig
|
| 10 |
+
from diffusers.models import HiDreamImageTransformer2DModel
|
| 11 |
+
|
| 12 |
+
import torch.nn.functional as F
|
| 13 |
+
from PIL import Image
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
if TYPE_CHECKING:
|
| 17 |
+
from toolkit.data_transfer_object.data_loader import DataLoaderBatchDTO
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class HidreamE1Model(HidreamModel):
|
| 21 |
+
arch = "hidream_e1"
|
| 22 |
+
hidream_transformer_class = HiDreamImageTransformer2DModel
|
| 23 |
+
hidream_pipeline_class = HiDreamImageEditingPipeline
|
| 24 |
+
|
| 25 |
+
def get_generation_pipeline(self):
|
| 26 |
+
scheduler = FlowUniPCMultistepScheduler(
|
| 27 |
+
num_train_timesteps=1000, shift=3.0, use_dynamic_shifting=False
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
pipeline: HiDreamImageEditingPipeline = HiDreamImageEditingPipeline(
|
| 31 |
+
scheduler=scheduler,
|
| 32 |
+
vae=self.vae,
|
| 33 |
+
text_encoder=self.text_encoder[0],
|
| 34 |
+
tokenizer=self.tokenizer[0],
|
| 35 |
+
text_encoder_2=self.text_encoder[1],
|
| 36 |
+
tokenizer_2=self.tokenizer[1],
|
| 37 |
+
text_encoder_3=self.text_encoder[2],
|
| 38 |
+
tokenizer_3=self.tokenizer[2],
|
| 39 |
+
text_encoder_4=self.text_encoder[3],
|
| 40 |
+
tokenizer_4=self.tokenizer[3],
|
| 41 |
+
transformer=unwrap_model(self.model),
|
| 42 |
+
aggressive_unloading=self.low_vram,
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
pipeline = pipeline.to(self.device_torch)
|
| 46 |
+
|
| 47 |
+
return pipeline
|
| 48 |
+
|
| 49 |
+
def generate_single_image(
|
| 50 |
+
self,
|
| 51 |
+
pipeline: HiDreamImageEditingPipeline,
|
| 52 |
+
gen_config: GenerateImageConfig,
|
| 53 |
+
conditional_embeds: PromptEmbeds,
|
| 54 |
+
unconditional_embeds: PromptEmbeds,
|
| 55 |
+
generator: torch.Generator,
|
| 56 |
+
extra: dict,
|
| 57 |
+
):
|
| 58 |
+
if gen_config.ctrl_img is None:
|
| 59 |
+
raise ValueError(
|
| 60 |
+
"Control image is required for Flux Kontext model generation."
|
| 61 |
+
)
|
| 62 |
+
else:
|
| 63 |
+
control_img = Image.open(gen_config.ctrl_img)
|
| 64 |
+
control_img = control_img.convert("RGB")
|
| 65 |
+
# resize to width and height
|
| 66 |
+
if control_img.size != (gen_config.width, gen_config.height):
|
| 67 |
+
control_img = control_img.resize(
|
| 68 |
+
(gen_config.width, gen_config.height), Image.BILINEAR
|
| 69 |
+
)
|
| 70 |
+
img = pipeline(
|
| 71 |
+
prompt_embeds_t5=conditional_embeds.text_embeds[0],
|
| 72 |
+
prompt_embeds_llama3=conditional_embeds.text_embeds[1],
|
| 73 |
+
pooled_prompt_embeds=conditional_embeds.pooled_embeds,
|
| 74 |
+
negative_prompt_embeds_t5=unconditional_embeds.text_embeds[0],
|
| 75 |
+
negative_prompt_embeds_llama3=unconditional_embeds.text_embeds[1],
|
| 76 |
+
negative_pooled_prompt_embeds=unconditional_embeds.pooled_embeds,
|
| 77 |
+
height=gen_config.height,
|
| 78 |
+
width=gen_config.width,
|
| 79 |
+
num_inference_steps=gen_config.num_inference_steps,
|
| 80 |
+
guidance_scale=gen_config.guidance_scale,
|
| 81 |
+
latents=gen_config.latents,
|
| 82 |
+
generator=generator,
|
| 83 |
+
image=control_img,
|
| 84 |
+
**extra,
|
| 85 |
+
).images[0]
|
| 86 |
+
return img
|
| 87 |
+
|
| 88 |
+
def get_prompt_embeds(self, prompt: str) -> PromptEmbeds:
|
| 89 |
+
self.text_encoder_to(self.device_torch, dtype=self.torch_dtype)
|
| 90 |
+
max_sequence_length = 128
|
| 91 |
+
(
|
| 92 |
+
prompt_embeds_t5,
|
| 93 |
+
negative_prompt_embeds_t5,
|
| 94 |
+
prompt_embeds_llama3,
|
| 95 |
+
negative_prompt_embeds_llama3,
|
| 96 |
+
pooled_prompt_embeds,
|
| 97 |
+
negative_pooled_prompt_embeds,
|
| 98 |
+
) = self.pipeline.encode_prompt(
|
| 99 |
+
prompt=prompt,
|
| 100 |
+
prompt_2=prompt,
|
| 101 |
+
prompt_3=prompt,
|
| 102 |
+
prompt_4=prompt,
|
| 103 |
+
device=self.device_torch,
|
| 104 |
+
dtype=self.torch_dtype,
|
| 105 |
+
num_images_per_prompt=1,
|
| 106 |
+
max_sequence_length=max_sequence_length,
|
| 107 |
+
do_classifier_free_guidance=False,
|
| 108 |
+
)
|
| 109 |
+
prompt_embeds = [prompt_embeds_t5, prompt_embeds_llama3]
|
| 110 |
+
pe = PromptEmbeds([prompt_embeds, pooled_prompt_embeds])
|
| 111 |
+
return pe
|
| 112 |
+
|
| 113 |
+
def condition_noisy_latents(
|
| 114 |
+
self, latents: torch.Tensor, batch: "DataLoaderBatchDTO"
|
| 115 |
+
):
|
| 116 |
+
with torch.no_grad():
|
| 117 |
+
control_tensor = batch.control_tensor
|
| 118 |
+
if control_tensor is not None:
|
| 119 |
+
self.vae.to(self.device_torch)
|
| 120 |
+
# we are not packed here, so we just need to pass them so we can pack them later
|
| 121 |
+
control_tensor = control_tensor * 2 - 1
|
| 122 |
+
control_tensor = control_tensor.to(
|
| 123 |
+
self.vae_device_torch, dtype=self.torch_dtype
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
# if it is not the size of batch.tensor, (bs,ch,h,w) then we need to resize it
|
| 127 |
+
if batch.tensor is not None:
|
| 128 |
+
target_h, target_w = batch.tensor.shape[2], batch.tensor.shape[3]
|
| 129 |
+
else:
|
| 130 |
+
# When caching latents, batch.tensor is None. We get the size from the file_items instead.
|
| 131 |
+
target_h = batch.file_items[0].crop_height
|
| 132 |
+
target_w = batch.file_items[0].crop_width
|
| 133 |
+
|
| 134 |
+
if (
|
| 135 |
+
control_tensor.shape[2] != target_h
|
| 136 |
+
or control_tensor.shape[3] != target_w
|
| 137 |
+
):
|
| 138 |
+
control_tensor = F.interpolate(
|
| 139 |
+
control_tensor, size=(target_h, target_w), mode="bilinear"
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
control_latent = self.encode_images(control_tensor).to(
|
| 143 |
+
latents.device, latents.dtype
|
| 144 |
+
)
|
| 145 |
+
latents = torch.cat((latents, control_latent), dim=1)
|
| 146 |
+
|
| 147 |
+
return latents.detach()
|
| 148 |
+
|
| 149 |
+
def get_noise_prediction(
|
| 150 |
+
self,
|
| 151 |
+
latent_model_input: torch.Tensor,
|
| 152 |
+
timestep: torch.Tensor, # 0 to 1000 scale
|
| 153 |
+
text_embeddings: PromptEmbeds,
|
| 154 |
+
**kwargs,
|
| 155 |
+
):
|
| 156 |
+
with torch.no_grad():
|
| 157 |
+
# make sure config is set
|
| 158 |
+
self.model.config.force_inference_output = True
|
| 159 |
+
has_control = False
|
| 160 |
+
lat_size = latent_model_input.shape[-1]
|
| 161 |
+
if latent_model_input.shape[1] == 32:
|
| 162 |
+
# chunk it and stack it on batch dimension
|
| 163 |
+
# dont update batch size for img_its
|
| 164 |
+
lat, control = torch.chunk(latent_model_input, 2, dim=1)
|
| 165 |
+
latent_model_input = torch.cat([lat, control], dim=-1)
|
| 166 |
+
has_control = True
|
| 167 |
+
|
| 168 |
+
dtype = self.model.dtype
|
| 169 |
+
device = self.device_torch
|
| 170 |
+
|
| 171 |
+
text_embeds = text_embeddings.text_embeds
|
| 172 |
+
# run the to for the list
|
| 173 |
+
text_embeds = [te.to(device, dtype=dtype) for te in text_embeds]
|
| 174 |
+
|
| 175 |
+
noise_pred = self.transformer(
|
| 176 |
+
hidden_states=latent_model_input,
|
| 177 |
+
timesteps=timestep,
|
| 178 |
+
encoder_hidden_states_t5=text_embeds[0],
|
| 179 |
+
encoder_hidden_states_llama3=text_embeds[1],
|
| 180 |
+
pooled_embeds=text_embeddings.pooled_embeds.to(device, dtype=dtype),
|
| 181 |
+
return_dict=False,
|
| 182 |
+
)[0]
|
| 183 |
+
|
| 184 |
+
if has_control:
|
| 185 |
+
noise_pred = -1.0 * noise_pred[..., :lat_size]
|
| 186 |
+
else:
|
| 187 |
+
noise_pred = -1.0 * noise_pred
|
| 188 |
+
|
| 189 |
+
return noise_pred
|