ColabWan / models /hidream /hidream_main.py
1ripon1's picture
Upload folder using huggingface_hub
7344bef verified
Raw
History Blame Contribute Delete
14.3 kB
import os
import json
import types
import torch
from mmgp import offload
from shared.utils import files_locator as fl
from shared.utils.utils import convert_image_to_tensor, convert_tensor_to_image
from transformers import AutoTokenizer, PreTrainedTokenizerBase, Qwen2VLImageProcessorFast, Qwen2VLProcessor
from transformers.processing_utils import ProcessorMixin
from .pipeline import DEFAULT_TIMESTEPS, NOISE_SCALE, generate_image, resample_timesteps
from .qwen3_vl_configuration import register_qwen3_vl_config
from .qwen3_vl_transformers import Qwen3VLForConditionalGeneration
HIDREAM_QUANTO_BF16_EXCLUDE = [
"model.language_model.layers.*.mlp.down_proj.weight",
"model.language_model.layers.*.self_attn.o_proj.weight",
]
class HiDreamQwen3VLProcessor(Qwen2VLProcessor):
attributes = ["image_processor", "tokenizer"]
def __init__(self, image_processor=None, tokenizer=None, chat_template=None, **kwargs):
self.image_token = "<|image_pad|>" if not hasattr(tokenizer, "image_token") else tokenizer.image_token
self.video_token = "<|video_pad|>" if not hasattr(tokenizer, "video_token") else tokenizer.video_token
self.image_token_id = tokenizer.image_token_id if getattr(tokenizer, "image_token_id", None) else tokenizer.convert_tokens_to_ids(self.image_token)
self.video_token_id = tokenizer.video_token_id if getattr(tokenizer, "video_token_id", None) else tokenizer.convert_tokens_to_ids(self.video_token)
ProcessorMixin.__init__(self, image_processor, tokenizer, chat_template=chat_template)
def add_special_tokens(tokenizer):
tokenizer.boi_token = "<|boi_token|>"
tokenizer.bor_token = "<|bor_token|>"
tokenizer.eor_token = "<|eor_token|>"
tokenizer.bot_token = "<|bot_token|>"
tokenizer.tms_token = "<|tms_token|>"
def get_tokenizer(processor):
if isinstance(processor, PreTrainedTokenizerBase):
return processor
return processor.tokenizer
def load_processor(processor_path):
tokenizer = AutoTokenizer.from_pretrained(processor_path, trust_remote_code=True)
image_processor = Qwen2VLImageProcessorFast.from_pretrained(processor_path)
chat_template = getattr(tokenizer, "chat_template", None)
chat_template_path = os.path.join(processor_path, "chat_template.json")
if chat_template is None and os.path.isfile(chat_template_path):
with open(chat_template_path, "r", encoding="utf-8") as reader:
chat_template = json.load(reader).get("chat_template")
return HiDreamQwen3VLProcessor(image_processor=image_processor, tokenizer=tokenizer, chat_template=chat_template)
def _as_pil(image):
return convert_tensor_to_image(image) if torch.is_tensor(image) else image
def _quantized_transformer_filename(model_filename, dtype):
model_filename = os.path.basename(model_filename)
if dtype == torch.bfloat16:
model_filename = model_filename.replace("fp16", "bf16").replace("FP16", "bf16")
elif dtype == torch.float16:
model_filename = model_filename.replace("bf16", "fp16").replace("BF16", "fp16")
for rep in ["mfp16", "fp16", "mbf16", "bf16"]:
if "_" + rep in model_filename:
return model_filename.replace("_" + rep, "_quanto_" + rep + "_int8")
pos = model_filename.rfind(".")
return model_filename[:pos] + "_quanto_int8" + model_filename[pos:] if pos >= 0 else model_filename + "_quanto_int8"
def save_quantized_transformer(model, model_filename, dtype, config_file):
if "quanto" in model_filename:
return None
quantized_filename = _quantized_transformer_filename(model_filename, dtype)
existing_path = fl.locate_file(quantized_filename, error_if_none=False)
if existing_path is not None:
print(f"There isn't any model to quantize as quantized model '{quantized_filename}' already exists")
return existing_path
quantized_path = fl.get_download_location(quantized_filename)
os.makedirs(os.path.dirname(quantized_path), exist_ok=True)
offload.save_model(model, quantized_path, do_quantize=True, config_file_path=config_file, quantize_exclude=HIDREAM_QUANTO_BF16_EXCLUDE)
print(f"New quantized file '{quantized_filename}' had been created.")
return quantized_path
def _attach_lora_preprocessor(transformer):
def preprocess_loras(self, model_type, sd):
if not sd:
return sd
qwen3_model_prefixes = (
"visual.",
"language_model.",
"t_embedder1.",
"t_embedder2.",
"x_embedder.",
"final_layer2.",
)
wrapper_prefixes = ("diffusion_model.", "transformer.")
new_sd = {}
for key, value in sd.items():
for wrapper_prefix in wrapper_prefixes:
if key.startswith(wrapper_prefix):
inner_key = key[len(wrapper_prefix):]
if inner_key.startswith(qwen3_model_prefixes):
key = wrapper_prefix + "model." + inner_key
break
else:
if key.startswith(qwen3_model_prefixes):
key = "model." + key
new_sd[key] = value
return new_sd
transformer.preprocess_loras = types.MethodType(preprocess_loras, transformer)
class model_factory:
def __init__(
self,
checkpoint_dir,
model_filename=None,
model_type=None,
model_def=None,
base_model_type=None,
quantizeTransformer=False,
dtype=torch.bfloat16,
save_quantized=False,
**kwargs,
):
model_def = model_def or {}
transformer_filename = model_filename[0] if isinstance(model_filename, (list, tuple)) else model_filename
if transformer_filename is None:
raise ValueError("No transformer filename provided for HiDream O1.")
self.model_type = model_type
self.base_model_type = base_model_type
self.model_def = model_def
self.dtype = dtype
self._abort = False
processor_folder = model_def.get("processor_folder", base_model_type)
processor_path = os.path.dirname(fl.locate_file(os.path.join(processor_folder, "tokenizer_config.json")))
config_path = fl.locate_file(os.path.join(processor_folder, "config.json"))
register_qwen3_vl_config()
self.processor = load_processor(processor_path)
self.tokenizer = get_tokenizer(self.processor)
add_special_tokens(self.tokenizer)
source = model_def.get("source", None)
load_filename = fl.locate_file(source) if source is not None else transformer_filename
self.transformer = offload.fast_load_transformers_model(
load_filename,
writable_tensors=False,
modelClass=Qwen3VLForConditionalGeneration,
defaultConfigPath=config_path,
default_dtype=dtype,
ignore_unused_weights=True,
do_quantize=quantizeTransformer and not save_quantized,
)
self.transformer.eval().requires_grad_(False)
self.model = self.transformer
_attach_lora_preprocessor(self.transformer)
self._set_interrupt(False)
if source is not None:
from wgp import save_model
save_model(self.transformer, model_type, dtype, config_path)
if save_quantized:
save_quantized_transformer(self.transformer, transformer_filename, dtype, config_path)
def generate(
self,
input_prompt="",
alt_prompt="",
image_start=None,
image_end=None,
input_frames=None,
input_frames2=None,
input_ref_images=None,
input_ref_masks=None,
input_masks=None,
input_masks2=None,
input_video=None,
input_faces=None,
input_custom=None,
denoising_strength=1.0,
masking_strength=1.0,
prefix_frames_count=0,
frame_num=1,
batch_size=1,
height=1024,
width=1024,
fit_into_canvas=None,
shift=None,
sample_solver="default",
sampling_steps=50,
guide_scale=5.0,
guide2_scale=5.0,
guide3_scale=5.0,
switch_threshold=0,
switch2_threshold=0,
guide_phases=1,
model_switch_phase=1,
embedded_guidance_scale=0.0,
n_prompt=None,
seed=None,
callback=None,
enable_RIFLEx=False,
VAE_tile_size=None,
joint_pass=True,
perturbation_switch=0,
perturbation_layers=None,
perturbation_start=0.0,
perturbation_end=1.0,
apg_switch=0,
cfg_star_switch=0,
cfg_zero_step=-1,
alt_guide_scale=1.0,
audio_cfg_scale=4.0,
input_waveform=None,
input_waveform_sample_rate=0,
audio_guide=None,
audio_guide2=None,
audio_prompt_type="",
audio_proj=None,
audio_scale=None,
audio_context_lens=None,
context_scale=None,
control_scale_alt=1.0,
alt_scale=0.0,
motion_amplitude=1.0,
model_mode=0,
causal_block_size=5,
causal_attention=True,
fps=1,
overlapped_latents=None,
return_latent_slice=False,
overlap_noise=0,
overlap_size=0,
color_correction_strength=0,
conditioning_latents_size=0,
input_video_is_hdr=False,
lora_dir=None,
keep_frames_parsed=None,
model_filename=None,
model_type=None,
loras_slists=None,
NAG_scale=1.0,
NAG_tau=3.5,
NAG_alpha=0.5,
speakers_bboxes=None,
image_mode=1,
video_prompt_type="",
window_no=1,
offloadobj=None,
set_header_text=None,
pre_video_frame=None,
prefix_video=None,
original_input_ref_images=None,
image_refs_relative_size=50,
outpainting_dims=None,
face_arc_embeds=None,
custom_settings=None,
temperature=0.8,
window_start_frame_no=0,
input_video_strength=1.0,
self_refiner_setting=0,
self_refiner_plan="",
self_refiner_f_uncertainty=0.0,
self_refiner_certain_percentage=0.999,
duration_seconds=0,
pause_seconds=0,
top_p=0.9,
top_k=50,
set_progress_status=None,
loras_selected=None,
frames_relative_positions_list=None,
frames_to_inject=None,
**kwargs
):
self._set_interrupt(False)
is_dev = self.base_model_type == "hidream_o1_dev"
custom_settings = custom_settings or {}
sampling_steps = int(sampling_steps)
if seed is None or int(seed) < 0:
seed = int(torch.seed() % (2**31 - 1))
else:
seed = int(seed)
if is_dev:
scheduler_name = "flash"
timesteps_list = resample_timesteps(DEFAULT_TIMESTEPS, sampling_steps)
guide_scale = 0.0
shift = 1.0 if shift is None else shift
noise_scale_start = float(custom_settings.get("noise_scale_start", 7.5))
noise_scale_end = float(custom_settings.get("noise_scale_end", 7.5))
noise_clip_std = float(custom_settings.get("noise_clip_std", 2.5))
else:
scheduler_name = "default"
timesteps_list = None
shift = 3.0 if shift is None else shift
noise_scale_start = float(custom_settings.get("noise_scale_start", NOISE_SCALE))
noise_scale_end = float(custom_settings.get("noise_scale_end", NOISE_SCALE))
noise_clip_std = float(custom_settings.get("noise_clip_std", 0.0))
ref_images = []
if image_start is not None:
ref_images.append(_as_pil(image_start))
if input_frames is not None:
ref_images.append(_as_pil(input_frames))
image_ref_source = original_input_ref_images if original_input_ref_images else input_ref_images
if image_ref_source is not None:
ref_images.extend(_as_pil(img) for img in image_ref_source)
batch_size = max(1, int(batch_size))
with torch.inference_mode():
try:
images = generate_image(
model=self.transformer,
processor=self.processor,
prompt=input_prompt,
ref_images=ref_images,
height=height,
width=width,
num_inference_steps=sampling_steps,
guidance_scale=guide_scale,
shift=shift,
timesteps_list=timesteps_list,
scheduler_name=scheduler_name,
seed=seed,
noise_scale_start=noise_scale_start,
noise_scale_end=noise_scale_end,
noise_clip_std=noise_clip_std,
keep_original_aspect=False,
batch_size=batch_size,
joint_pass=joint_pass,
callback=callback,
abort_callback=lambda: self._interrupt,
)
finally:
if hasattr(self.transformer, "clear_runtime_caches"):
self.transformer.clear_runtime_caches()
if images is None:
return None
if not isinstance(images, list):
images = [images]
images = [convert_image_to_tensor(image) for image in images]
return torch.stack(images, dim=1)
def get_loras_transformer(self, *args, **kwargs):
return [], []
def _set_interrupt(self, value):
self._abort = bool(value)
for module in (
getattr(self, "transformer", None),
getattr(getattr(self, "transformer", None), "model", None),
getattr(getattr(self, "transformer", None), "visual", None),
getattr(getattr(self, "transformer", None), "language_model", None),
):
if module is not None:
setattr(module, "_interrupt", self._abort)
@property
def _interrupt(self):
return self._abort
@_interrupt.setter
def _interrupt(self, value):
self._set_interrupt(value)