| |
|
|
| import torch, math |
| from PIL import Image |
| from typing import Union |
| from tqdm import tqdm |
| from einops import rearrange |
| import numpy as np |
|
|
| from diffsynth.diffusion import FlowMatchScheduler |
| from diffsynth.core import ModelConfig, gradient_checkpoint_forward |
| from diffsynth.diffusion.base_pipeline import BasePipeline, PipelineUnit, ControlNetInput |
|
|
| from diffsynth.models.qwen_image_text_encoder import QwenImageTextEncoder |
| from diffsynth.models.qwen_image_vae import QwenImageVAE |
| from diffsynth.models.qwen_image_controlnet import QwenImageBlockWiseControlNet |
|
|
| from src.PRoPE import PropeDotProductAttention |
| from src.MetaView_dit import MetaViewDiT |
|
|
| import torch.nn.functional as F |
|
|
| class MetaViewPipeline(BasePipeline): |
|
|
| def __init__(self, device="cuda", torch_dtype=torch.bfloat16): |
| super().__init__( |
| device=device, torch_dtype=torch_dtype, |
| height_division_factor=16, width_division_factor=16, |
| ) |
| from transformers import Qwen2Tokenizer, Qwen2VLProcessor |
| |
| self.scheduler = FlowMatchScheduler("Qwen-Image") |
| self.text_encoder: QwenImageTextEncoder = None |
| self.dit: MetaViewDiT = None |
| self.vae: QwenImageVAE = None |
| self.blockwise_controlnet: QwenImageBlockwiseMultiControlNet = None |
| self.tokenizer: Qwen2Tokenizer = None |
| self.processor: Qwen2VLProcessor = None |
| self.in_iteration_models = ("dit", "blockwise_controlnet") |
| self.units = [ |
| MetaViewUnit_ShapeChecker(), |
| MetaViewUnit_NoiseInitializer(), |
| MetaViewUnit_InputImageEmbedder(), |
| MetaViewUnit_EditImageEmbedder(), |
| MetaViewUnit_PromptEmbedder(), |
| ] |
| self.model_fn = model_fn_MetaView |
| |
| |
| @staticmethod |
| def from_pretrained( |
| torch_dtype: torch.dtype = torch.bfloat16, |
| device: Union[str, torch.device] = "cuda", |
| model_configs: list[ModelConfig] = [], |
| tokenizer_config: ModelConfig = ModelConfig(model_id="Qwen/Qwen-Image", origin_file_pattern="tokenizer/"), |
| processor_config: ModelConfig = None, |
| vram_limit: float = None, |
| ): |
| |
| pipe = MetaViewPipeline(device=device, torch_dtype=torch_dtype) |
| model_pool = pipe.download_and_load_models(model_configs, vram_limit) |
| |
| |
| pipe.text_encoder = model_pool.fetch_model("qwen_image_text_encoder") |
| pipe.dit = model_pool.fetch_model("metaview_dit") |
| pipe.vae = model_pool.fetch_model("qwen_image_vae") |
| pipe.blockwise_controlnet = QwenImageBlockwiseMultiControlNet(model_pool.fetch_model("qwen_image_blockwise_controlnet", index="all")) |
| if tokenizer_config is not None: |
| tokenizer_config.download_if_necessary() |
| from transformers import Qwen2Tokenizer |
| pipe.tokenizer = Qwen2Tokenizer.from_pretrained(tokenizer_config.path) |
| if processor_config is not None: |
| processor_config.download_if_necessary() |
| from transformers import Qwen2VLProcessor |
| pipe.processor = Qwen2VLProcessor.from_pretrained(processor_config.path) |
| |
| |
| pipe.vram_management_enabled = pipe.check_vram_management_state() |
| return pipe |
| |
| |
| @torch.no_grad() |
| def __call__( |
| self, |
| |
| prompt: str, |
| negative_prompt: str = "", |
| cfg_scale: float = 4.0, |
| |
| input_image: Image.Image = None, |
| denoising_strength: float = 1.0, |
| |
| inpaint_mask: Image.Image = None, |
| inpaint_blur_size: int = None, |
| inpaint_blur_sigma: float = None, |
| |
| height: int = 1328, |
| width: int = 1328, |
| |
| seed: int = None, |
| rand_device: str = "cpu", |
| |
| num_inference_steps: int = 30, |
| exponential_shift_mu: float = None, |
| |
| blockwise_controlnet_inputs: list[ControlNetInput] = None, |
| |
| eligen_entity_prompts: list[str] = None, |
| eligen_entity_masks: list[Image.Image] = None, |
| eligen_enable_on_negative: bool = False, |
| |
| edit_image: Image.Image = None, |
| edit_image_auto_resize: bool = True, |
| edit_rope_interpolation: bool = False, |
| |
| context_image: Image.Image = None, |
| |
| tiled: bool = False, |
| tile_size: int = 128, |
| tile_stride: int = 64, |
| |
| progress_bar_cmd = tqdm, |
| |
| viewmats = None, |
| Ks = None, |
| prope_dim_arrange = [16, 56, 56], |
| add_attn = True, |
| add_3D = False, |
| feat_3D = None, |
| depth = None, |
| merge_3D = False, |
| val = False, |
| batch_size = 1, |
| ): |
| |
| self.scheduler.set_timesteps(num_inference_steps, denoising_strength=denoising_strength, dynamic_shift_len=(height // 16) * (width // 16), exponential_shift_mu=exponential_shift_mu) |
| |
| |
| inputs_posi = { |
| "prompt": prompt, |
| } |
| inputs_nega = { |
| "negative_prompt": [negative_prompt], |
| } |
| inputs_shared = { |
| "cfg_scale": cfg_scale, |
| "input_image": input_image, "denoising_strength": denoising_strength, |
| "inpaint_mask": inpaint_mask, "inpaint_blur_size": inpaint_blur_size, "inpaint_blur_sigma": inpaint_blur_sigma, |
| "height": height, "width": width, |
| "seed": seed, "rand_device": rand_device, |
| "num_inference_steps": num_inference_steps, |
| "blockwise_controlnet_inputs": blockwise_controlnet_inputs, |
| "tiled": tiled, "tile_size": tile_size, "tile_stride": tile_stride, |
| "eligen_entity_prompts": eligen_entity_prompts, "eligen_entity_masks": eligen_entity_masks, "eligen_enable_on_negative": eligen_enable_on_negative, |
| "edit_image": edit_image, "edit_image_auto_resize": edit_image_auto_resize, "edit_rope_interpolation": edit_rope_interpolation, |
| "context_image": context_image, |
| |
| "viewmats": viewmats, |
| "Ks": Ks, |
| "prope_dim_arrange": prope_dim_arrange, |
| "add_attn": add_attn, |
| "add_3D": add_3D, |
| "feat_3D": feat_3D, |
| "depth": depth, |
| "merge_3D": merge_3D, |
| "val": val, |
| "batch_size": batch_size, |
| } |
| for unit in self.units: |
| inputs_shared, inputs_posi, inputs_nega = self.unit_runner(unit, self, inputs_shared, inputs_posi, inputs_nega) |
|
|
| |
| self.load_models_to_device(self.in_iteration_models) |
| models = {name: getattr(self, name) for name in self.in_iteration_models} |
| for progress_id, timestep in enumerate(progress_bar_cmd(self.scheduler.timesteps)): |
| timestep = timestep.unsqueeze(0).to(dtype=self.torch_dtype, device=self.device) |
| noise_pred = self.cfg_guided_model_fn( |
| self.model_fn, cfg_scale, |
| inputs_shared, inputs_posi, inputs_nega, |
| **models, timestep=timestep, progress_id=progress_id |
| ) |
| inputs_shared["latents"] = self.step(self.scheduler, progress_id=progress_id, noise_pred=noise_pred, **inputs_shared) |
| |
|
|
| |
| self.load_models_to_device(['vae']) |
| image = self.vae.decode(inputs_shared["latents"], device=self.device, tiled=tiled, tile_size=tile_size, tile_stride=tile_stride) |
| image = self.vae_output_to_image(image) |
| self.load_models_to_device([]) |
|
|
| return image |
|
|
|
|
| class QwenImageBlockwiseMultiControlNet(torch.nn.Module): |
| def __init__(self, models: list[QwenImageBlockWiseControlNet]): |
| super().__init__() |
| if not isinstance(models, list): |
| models = [models] |
| self.models = torch.nn.ModuleList(models) |
| for model in models: |
| if hasattr(model, "vram_management_enabled") and getattr(model, "vram_management_enabled"): |
| self.vram_management_enabled = True |
|
|
| def preprocess(self, controlnet_inputs: list[ControlNetInput], conditionings: list[torch.Tensor], **kwargs): |
| processed_conditionings = [] |
| for controlnet_input, conditioning in zip(controlnet_inputs, conditionings): |
| conditioning = rearrange(conditioning, "B C (H P) (W Q) -> B (H W) (C P Q)", P=2, Q=2) |
| model_output = self.models[controlnet_input.controlnet_id].process_controlnet_conditioning(conditioning) |
| processed_conditionings.append(model_output) |
| return processed_conditionings |
|
|
| def blockwise_forward(self, image, conditionings: list[torch.Tensor], controlnet_inputs: list[ControlNetInput], progress_id, num_inference_steps, block_id, **kwargs): |
| res = 0 |
| for controlnet_input, conditioning in zip(controlnet_inputs, conditionings): |
| progress = (num_inference_steps - 1 - progress_id) / max(num_inference_steps - 1, 1) |
| if progress > controlnet_input.start + (1e-4) or progress < controlnet_input.end - (1e-4): |
| continue |
| model_output = self.models[controlnet_input.controlnet_id].blockwise_forward(image, conditioning, block_id) |
| res = res + model_output * controlnet_input.scale |
| return res |
|
|
|
|
| class MetaViewUnit_ShapeChecker(PipelineUnit): |
| def __init__(self): |
| super().__init__( |
| input_params=("height", "width"), |
| output_params=("height", "width"), |
| ) |
|
|
| def process(self, pipe: MetaViewPipeline, height, width): |
| height, width = pipe.check_resize_height_width(height, width) |
| return {"height": height, "width": width} |
|
|
|
|
|
|
| class MetaViewUnit_NoiseInitializer(PipelineUnit): |
| def __init__(self): |
| super().__init__( |
| input_params=("height", "width", "seed", "rand_device", "batch_size"), |
| output_params=("noise",), |
| ) |
|
|
| def process(self, pipe: MetaViewPipeline, height, width, seed, rand_device, batch_size): |
| noise = pipe.generate_noise((batch_size, 16, height//8, width//8), seed=seed, rand_device=rand_device, rand_torch_dtype=pipe.torch_dtype) |
| return {"noise": noise} |
|
|
|
|
|
|
| class MetaViewUnit_InputImageEmbedder(PipelineUnit): |
| def __init__(self): |
| super().__init__( |
| input_params=("input_image", "noise", "tiled", "tile_size", "tile_stride"), |
| output_params=("latents", "input_latents"), |
| onload_model_names=("vae",) |
| ) |
|
|
| def process(self, pipe: MetaViewPipeline, input_image, noise, tiled, tile_size, tile_stride): |
| if input_image is None: |
| return {"latents": noise, "input_latents": None} |
| pipe.load_models_to_device(['vae']) |
|
|
| if isinstance(input_image, list): |
| input_latents = [] |
| for input_img in input_image: |
| img = pipe.preprocess_image(input_img).to(device=pipe.device, dtype=pipe.torch_dtype) |
| input_latent = pipe.vae.encode(img, tiled=tiled, tile_size=tile_size, tile_stride=tile_stride) |
| input_latents.append(input_latent) |
| input_latents = torch.cat(input_latents, dim=0) |
| else: |
| |
| image = pipe.preprocess_image(input_image).to(device=pipe.device, dtype=pipe.torch_dtype) |
| input_latents = pipe.vae.encode(image, tiled=tiled, tile_size=tile_size, tile_stride=tile_stride) |
|
|
| assert noise.shape[0] == input_latents.shape[0] |
|
|
| if pipe.scheduler.training: |
| return {"latents": noise, "input_latents": input_latents} |
| else: |
| latents = pipe.scheduler.add_noise(input_latents, noise, timestep=pipe.scheduler.timesteps[0]) |
| return {"latents": latents, "input_latents": input_latents} |
|
|
|
|
| class MetaViewUnit_EditImageEmbedder(PipelineUnit): |
| def __init__(self): |
| super().__init__( |
| input_params=("edit_image", "tiled", "tile_size", "tile_stride", "edit_image_auto_resize"), |
| output_params=("edit_latents", "edit_image"), |
| onload_model_names=("vae",) |
| ) |
|
|
|
|
| def calculate_dimensions(self, target_area, ratio): |
| import math |
| width = math.sqrt(target_area * ratio) |
| height = width / ratio |
| width = round(width / 32) * 32 |
| height = round(height / 32) * 32 |
| return width, height |
|
|
|
|
| def edit_image_auto_resize(self, edit_image): |
| calculated_width, calculated_height = self.calculate_dimensions(1024 * 1024, edit_image.size[0] / edit_image.size[1]) |
| return edit_image.resize((calculated_width, calculated_height)) |
|
|
|
|
| def process(self, pipe: MetaViewPipeline, edit_image, tiled, tile_size, tile_stride, edit_image_auto_resize=False): |
| if edit_image is None: |
| return {} |
| pipe.load_models_to_device(self.onload_model_names) |
| if isinstance(edit_image, Image.Image): |
| |
| resized_edit_image = edit_image |
| edit_image = pipe.preprocess_image(resized_edit_image).to(device=pipe.device, dtype=pipe.torch_dtype) |
| edit_latents = pipe.vae.encode(edit_image, tiled=tiled, tile_size=tile_size, tile_stride=tile_stride) |
| else: |
| resized_edit_image, edit_latents = [], [] |
| for image in edit_image: |
| |
| |
| resized_edit_image.append(image) |
| image = pipe.preprocess_image(image).to(device=pipe.device, dtype=pipe.torch_dtype) |
| latents = pipe.vae.encode(image, tiled=tiled, tile_size=tile_size, tile_stride=tile_stride) |
| edit_latents.append(latents) |
| edit_latents = torch.cat(edit_latents, dim=0) |
| return {"edit_latents": edit_latents, "edit_image": resized_edit_image} |
|
|
|
|
|
|
| class MetaViewUnit_PromptEmbedder(PipelineUnit): |
| def __init__(self): |
| super().__init__( |
| seperate_cfg=True, |
| input_params_posi={"prompt": "prompt"}, |
| input_params_nega={"prompt": "negative_prompt"}, |
| input_params=("edit_image",), |
| output_params=("prompt_emb", "prompt_emb_mask"), |
| onload_model_names=("text_encoder",) |
| ) |
| |
| def extract_masked_hidden(self, hidden_states: torch.Tensor, mask: torch.Tensor): |
| bool_mask = mask.bool() |
| valid_lengths = bool_mask.sum(dim=1) |
| selected = hidden_states[bool_mask] |
| split_result = torch.split(selected, valid_lengths.tolist(), dim=0) |
| return split_result |
| |
| def calculate_dimensions(self, target_area, ratio): |
| width = math.sqrt(target_area * ratio) |
| height = width / ratio |
| width = round(width / 32) * 32 |
| height = round(height / 32) * 32 |
| return width, height |
| |
| def resize_image(self, image, target_area=384*384): |
| width, height = self.calculate_dimensions(target_area, image.size[0] / image.size[1]) |
| return image.resize((width, height)) |
| |
| def encode_prompt(self, pipe: MetaViewPipeline, prompt): |
| template = "<|im_start|>system\nDescribe the image by detailing the color, shape, size, texture, quantity, text, spatial relationships of the objects and background:<|im_end|>\n<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n" |
| drop_idx = 34 |
| txt = [template.format(e) for e in prompt] |
| model_inputs = pipe.tokenizer(txt, max_length=4096+drop_idx, padding=True, truncation=True, return_tensors="pt").to(pipe.device) |
| if model_inputs.input_ids.shape[1] >= 1024: |
| print(f"Warning!!! QwenImage model was trained on prompts up to 512 tokens. Current prompt requires {model_inputs['input_ids'].shape[1] - drop_idx} tokens, which may lead to unpredictable behavior.") |
| hidden_states = pipe.text_encoder(input_ids=model_inputs.input_ids, attention_mask=model_inputs.attention_mask, output_hidden_states=True,)[-1] |
| split_hidden_states = self.extract_masked_hidden(hidden_states, model_inputs.attention_mask) |
| split_hidden_states = [e[drop_idx:] for e in split_hidden_states] |
| return split_hidden_states |
| |
| def encode_prompt_edit(self, pipe: MetaViewPipeline, prompt, edit_image): |
| template = "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n<|vision_start|><|image_pad|><|vision_end|>{}<|im_end|>\n<|im_start|>assistant\n" |
| drop_idx = 64 |
| txt = [template.format(e) for e in prompt] |
| |
| model_inputs = pipe.processor(text=txt, images=edit_image, padding=True, return_tensors="pt").to(pipe.device) |
| hidden_states = pipe.text_encoder(input_ids=model_inputs.input_ids, attention_mask=model_inputs.attention_mask, pixel_values=model_inputs.pixel_values, image_grid_thw=model_inputs.image_grid_thw, output_hidden_states=True,)[-1] |
| split_hidden_states = self.extract_masked_hidden(hidden_states, model_inputs.attention_mask) |
| split_hidden_states = [e[drop_idx:] for e in split_hidden_states] |
| return split_hidden_states |
| |
| def encode_prompt_edit_batch(self, pipe: MetaViewPipeline, prompt, edit_image): |
| |
| template = "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n<|vision_start|><|image_pad|><|vision_end|>{}<|im_end|>\n<|im_start|>assistant\n" |
| drop_idx = 64 |
| txt = [template.format(e) for e in prompt] |
| split_hidden_states_list = [] |
| for i in range(len(prompt)): |
| model_inputs = pipe.processor(text=[txt[i]], images=[edit_image[i]], padding=True, return_tensors="pt").to(pipe.device) |
| hidden_states = pipe.text_encoder(input_ids=model_inputs.input_ids, attention_mask=model_inputs.attention_mask, pixel_values=model_inputs.pixel_values, image_grid_thw=model_inputs.image_grid_thw, output_hidden_states=True,)[-1] |
| split_hidden_states = self.extract_masked_hidden(hidden_states, model_inputs.attention_mask) |
| |
| |
| split_hidden_states_list.append(split_hidden_states[0]) |
| |
| split_hidden_states = [e[drop_idx:] for e in split_hidden_states_list] |
|
|
| return split_hidden_states |
| |
| def encode_prompt_edit_multi(self, pipe: MetaViewPipeline, prompt, edit_image): |
| template = "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n" |
| drop_idx = 64 |
| img_prompt_template = "Picture {}: <|vision_start|><|image_pad|><|vision_end|>" |
| base_img_prompt = "".join([img_prompt_template.format(i + 1) for i in range(len(edit_image))]) |
| txt = [template.format(base_img_prompt + e) for e in prompt] |
| edit_image = [self.resize_image(image) for image in edit_image] |
| model_inputs = pipe.processor(text=txt, images=edit_image, padding=True, return_tensors="pt").to(pipe.device) |
| hidden_states = pipe.text_encoder(input_ids=model_inputs.input_ids, attention_mask=model_inputs.attention_mask, pixel_values=model_inputs.pixel_values, image_grid_thw=model_inputs.image_grid_thw, output_hidden_states=True,)[-1] |
| split_hidden_states = self.extract_masked_hidden(hidden_states, model_inputs.attention_mask) |
| split_hidden_states = [e[drop_idx:] for e in split_hidden_states] |
| return split_hidden_states |
|
|
| def process(self, pipe: MetaViewPipeline, prompt, edit_image=None) -> dict: |
| |
| pipe.load_models_to_device(self.onload_model_names) |
| if pipe.text_encoder is not None: |
| |
| if edit_image is None: |
| split_hidden_states = self.encode_prompt(pipe, prompt) |
| elif isinstance(edit_image, Image.Image): |
| split_hidden_states = self.encode_prompt_edit(pipe, prompt, edit_image) |
| elif isinstance(edit_image, list): |
| split_hidden_states = self.encode_prompt_edit_batch(pipe, prompt, edit_image) |
| |
| |
| attn_mask_list = [torch.ones(e.size(0), dtype=torch.long, device=e.device) for e in split_hidden_states] |
| max_seq_len = max([e.size(0) for e in split_hidden_states]) |
| prompt_embeds = torch.stack([torch.cat([u, u.new_zeros(max_seq_len - u.size(0), u.size(1))]) for u in split_hidden_states]) |
| encoder_attention_mask = torch.stack([torch.cat([u, u.new_zeros(max_seq_len - u.size(0))]) for u in attn_mask_list]) |
| prompt_embeds = prompt_embeds.to(dtype=pipe.torch_dtype, device=pipe.device) |
| return {"prompt_emb": prompt_embeds, "prompt_emb_mask": encoder_attention_mask} |
| else: |
| return {} |
|
|
|
|
|
|
| def model_fn_MetaView( |
| dit: MetaViewDiT = None, |
| blockwise_controlnet: QwenImageBlockwiseMultiControlNet = None, |
| latents=None, |
| timestep=None, |
| prompt_emb=None, |
| prompt_emb_mask=None, |
| height=None, |
| width=None, |
| blockwise_controlnet_conditioning=None, |
| blockwise_controlnet_inputs=None, |
| progress_id=0, |
| num_inference_steps=1, |
| entity_prompt_emb=None, |
| entity_prompt_emb_mask=None, |
| entity_masks=None, |
| edit_latents=None, |
| context_latents=None, |
| enable_fp8_attention=False, |
| use_gradient_checkpointing=False, |
| use_gradient_checkpointing_offload=False, |
| edit_rope_interpolation=False, |
| viewmats=None, |
| Ks=None, |
| feat_3D=None, |
| prope_dim_arrange=None, |
| add_attn=False, |
| add_3D=False, |
| depth=None, |
| merge_3D=False, |
| decode_3D=False, |
| val=False, |
| **kwargs |
| ): |
| img_shapes = [(1, latents.shape[2]//2, latents.shape[3]//2)] |
| txt_seq_lens = prompt_emb_mask.sum(dim=1).tolist() |
| timestep = timestep / 1000 |
| |
| image = rearrange(latents, "B C (H P) (W Q) -> B (H W) (C P Q)", H=height//16, W=width//16, P=2, Q=2) |
| image_seq_len = image.shape[1] |
|
|
|
|
| if edit_latents is not None: |
| e = edit_latents |
| img_shapes += [(1, e.shape[2]//2, e.shape[3]//2)] |
| edit_image = [rearrange(e, "B C (H P) (W Q) -> B (H W) (C P Q)", H=e.shape[2]//2, W=e.shape[3]//2, P=2, Q=2)] |
| image = torch.cat([image] + edit_image, dim=1) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| image = dit.img_in(image) |
| conditioning = dit.time_text_embed(timestep, image.dtype) |
|
|
| text = dit.txt_in(dit.txt_norm(prompt_emb)) |
| if edit_rope_interpolation: |
| image_rotary_emb = dit.pos_embed.forward_sampling(img_shapes, txt_seq_lens, device=latents.device) |
| else: |
| image_rotary_emb = dit.pos_embed(img_shapes, txt_seq_lens, device=latents.device) |
| |
| if viewmats is not None: |
| if depth is not None: |
| depth = F.interpolate(depth, size=(height // 16, width // 16), mode='bilinear', align_corners=False) |
| depth = depth.to(image.device) |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| dit.PRoPE = PropeDotProductAttention( |
| head_dim=128, |
| patches_x=width // 16, |
| patches_y=height // 16, |
| image_width=width, |
| image_height=height, |
| freq_base=10000, |
| dim_arrange=prope_dim_arrange, |
| ) |
| dit.PRoPE = dit.PRoPE.to(image.device) |
| dit.PRoPE._precompute_and_cache_apply_fns(viewmats.to(image.device), Ks.to(image.device), depth) |
|
|
| if feat_3D is not None: |
| dit.add_PRoPE = PropeDotProductAttention( |
| head_dim=128, |
| patches_x=width // 16, |
| patches_y=height // 16, |
| image_width=width, |
| image_height=height, |
| freq_base=10000, |
| dim_arrange=prope_dim_arrange, |
| ) |
| dit.add_PRoPE = dit.add_PRoPE.to(image.device) |
| if depth is not None: |
| dit.add_PRoPE._precompute_and_cache_apply_fns(viewmats[:, 1:2, :, :].to(image.device), Ks[:, 1:2, :, :].to(image.device), depth[:, 1:2, :, :]) |
| else: |
| dit.add_PRoPE._precompute_and_cache_apply_fns(viewmats[:, 1:2, :, :].to(image.device), Ks[:, 1:2, :, :].to(image.device)) |
| attention_mask = None |
|
|
| if feat_3D is not None: |
| h_3D, w_3D = feat_3D.shape[1], feat_3D.shape[2] |
| feat_3D = rearrange(feat_3D, 'b h w d -> b (h w) d') |
| |
| if merge_3D: |
| feat_3D = dit._3D_in(feat_3D) |
|
|
| for block_id, block in enumerate(dit.transformer_blocks): |
| if merge_3D: |
| text, image, feat_3D = gradient_checkpoint_forward( |
| block, |
| use_gradient_checkpointing, |
| use_gradient_checkpointing_offload, |
| image=image, |
| text=text, |
| temb=conditioning, |
| image_rotary_emb=image_rotary_emb, |
| attention_mask=attention_mask, |
| enable_fp8_attention=enable_fp8_attention, |
| prope=dit.PRoPE, |
| add_prope=dit.add_PRoPE, |
| add_attn=add_attn, |
| feat_3D=feat_3D, |
| block_id=block_id, |
| ) |
| else: |
| text, image = gradient_checkpoint_forward( |
| block, |
| use_gradient_checkpointing, |
| use_gradient_checkpointing_offload, |
| image=image, |
| text=text, |
| temb=conditioning, |
| image_rotary_emb=image_rotary_emb, |
| attention_mask=attention_mask, |
| enable_fp8_attention=enable_fp8_attention, |
| prope=dit.PRoPE, |
| add_prope=dit.add_PRoPE, |
| add_attn=add_attn, |
| feat_3D=feat_3D, |
| block_id=block_id, |
| ) |
|
|
| image = dit.norm_out(image, conditioning) |
| image = dit.proj_out(image) |
| image = image[:, :image_seq_len] |
|
|
| latents = rearrange(image, "B (H W) (C P Q) -> B C (H P) (W Q)", H=height//16, W=width//16, P=2, Q=2) |
|
|
| if val: |
| return latents |
|
|
| if decode_3D: |
| feat_3D = dit.norm_3D_out(feat_3D) |
| feat_3D = dit.proj_3D_out(feat_3D) |
| latents_3D = feat_3D.unsqueeze(0).unsqueeze(0) |
| latents_3D = list(torch.chunk(latents_3D, chunks=4, dim=-1)) |
| return latents, latents_3D |
|
|
| return latents, None |
|
|