Lempicka / inference.py
cai-qi's picture
Update Space
c6d3f05
Raw
History Blame Contribute Delete
5.89 kB
import argparse
import torch
import os
from transformers import AutoProcessor
from models.qwen3_vl_transformers import Qwen3VLForConditionalGeneration
from models.pipeline import generate_image, DEFAULT_TIMESTEPS
def add_special_tokens(tokenizer):
"""Attach the special-token shortcuts that the pipeline relies on."""
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):
from transformers import PreTrainedTokenizerBase
if isinstance(processor, PreTrainedTokenizerBase):
return processor
return processor.tokenizer
def main():
p = argparse.ArgumentParser("Standalone Pixel-DiT inference")
p.add_argument("--model_path", type=str, default = "/root/converted_models/HiDream-O1-Image", help="Path to huggingface model")
p.add_argument("--prompt", type=str, default = "medium shot, eye-level, front view. A woman is seated in an ornate bedroom, illuminated by candlelight, with a calm and composed expression. The subject is a young woman with fair skin, light brown hair styled in an updo with loose tendrils framing her face, and blue eyes. She wears a cream-colored satin robe with delicate floral embroidery and lace trim along the neckline. Her ears are adorned with pearl drop earrings. She is seated on a bed with a dark, intricately carved wooden headboard. To her left, a wooden nightstand holds three lit white candles and a candelabra with multiple lit candles in the background. The bed is covered with patterned pillows and a dark, textured blanket. The walls are paneled with dark wood and feature a large, ornate tapestry with muted earth tones. The lighting creates soft highlights on her face and robe, with warm shadows cast across the room.")
p.add_argument("--ref_images", nargs="*", default=[], help="Path to reference images.")
p.add_argument(
"--layout_bboxes",
type=str,
default=None,
help=(
"Layout boxes as a JSON string or JSON file path. "
"Input order is xxyy relative coordinates: [[x1,x2,y1,y2], ...], "
"[{\"bbox\": [x1,x2,y1,y2], \"text\": \"...\"}, ...], "
"or {\"bboxes\": ...}. Example: [0.1,0.15,0.2,0.36]."
),
)
p.add_argument("--output_image", type=str, default="output.png")
p.add_argument("--height", type=int, default=2048)
p.add_argument("--width", type=int, default=2048)
p.add_argument("--model_type", type=str, default="dev", choices=["full", "dev"])
p.add_argument("--seed", type=int, default=42)
p.add_argument("--shift", type=float, default=3.0)
p.add_argument("--guidance_scale", type=float, default=5.0)
p.add_argument("--noise_scale_start", type=float, default=8.0)
p.add_argument("--noise_scale_end", type=float, default=8.0)
p.add_argument("--noise_clip_std", type=float, default=8.0)
p.add_argument(
"--editing_scheduler",
type=str,
default="flow_match",
choices=["flow_match", "flash"],
help="Scheduler used for editing (exactly one reference image) when "
"--model_type dev. Default: flow_match. Ignored for full model "
"and for non-editing tasks.",
)
p.add_argument(
"--keep_original_aspect",
action="store_true",
help="When exactly one reference image is provided, resize it with "
"max_size=2048 and use its dimensions for the target image "
"(preserves the reference's aspect ratio).",
)
args = p.parse_args()
assert torch.cuda.is_available(), "CUDA is required for inference."
print(f"[inference] Loading processor and model from {args.model_path}")
processor = AutoProcessor.from_pretrained(args.model_path)
# NOTE: torch_dtype = torch.float32 will generate more detailed images but with more memory usage
model = Qwen3VLForConditionalGeneration.from_pretrained(
args.model_path, torch_dtype=torch.float32, device_map="cuda"
).eval()
os.makedirs(os.path.dirname(os.path.abspath(args.output_image)), exist_ok=True)
tokenizer = get_tokenizer(processor)
add_special_tokens(tokenizer)
extra_kwargs = {}
if args.model_type == "full":
num_inference_steps = 50
guidance_scale = args.guidance_scale
shift = args.shift
timesteps_list = None
scheduler_name = "default"
else:
is_editing = len(args.ref_images) == 1
if is_editing and args.editing_scheduler == "flow_match":
num_inference_steps = 28
guidance_scale = 0.0
shift = 1.0
timesteps_list = DEFAULT_TIMESTEPS
scheduler_name = "flow_match"
else:
num_inference_steps = 28
guidance_scale = 0.0
shift = 1.0
timesteps_list = DEFAULT_TIMESTEPS
scheduler_name = "flash"
extra_kwargs["noise_scale_start"] = args.noise_scale_start
extra_kwargs["noise_scale_end"] = args.noise_scale_end
extra_kwargs["noise_clip_std"] = args.noise_clip_std
image = generate_image(
model=model,
processor=processor,
prompt=args.prompt,
ref_image_paths=args.ref_images,
height=args.height,
width=args.width,
num_inference_steps=num_inference_steps,
guidance_scale=guidance_scale,
shift=shift,
timesteps_list=timesteps_list,
scheduler_name=scheduler_name,
seed=args.seed,
keep_original_aspect=args.keep_original_aspect,
layout_bboxes = args.layout_bboxes,
**extra_kwargs,
)
image.save(args.output_image)
print(f"[inference] Saved -> {args.output_image}")
if __name__ == "__main__":
main()