Files
vnassets/vnassets/generate.py
Michele Rossi 06fba9c234 Add vnasset SDXL generate command
ROCm-safe bfloat16 inference with custom matmul attention.
Automatic output directories, random seed, timing metadata.
2026-07-06 16:29:38 +02:00

75 lines
1.9 KiB
Python

"""SDXL text-to-image generation."""
import json
import random
import time
from pathlib import Path
import torch
from diffusers import StableDiffusionXLPipeline
from .attention import patch_unet_attention
def generate(
checkpoint_path: str,
prompt: str,
negative_prompt: str = "",
width: int = 1024,
height: int = 1024,
steps: int = 20,
cfg: float = 4.5,
seed: int | None = None,
output_path: str = "output.png",
) -> None:
device = "cuda" if torch.cuda.is_available() else "cpu"
# bfloat16 avoids ROCm kernel crashes on RDNA 3.5; float16 segfaults
dtype = torch.bfloat16
if seed is None:
seed = random.randint(0, 2**32 - 1)
output = Path(output_path)
output.parent.mkdir(parents=True, exist_ok=True)
t0 = time.perf_counter()
pipe = StableDiffusionXLPipeline.from_single_file(
checkpoint_path,
torch_dtype=dtype,
)
pipe.to(device)
patch_unet_attention(pipe.unet)
t_load = time.perf_counter() - t0
generator = torch.Generator(device=device).manual_seed(seed)
t1 = time.perf_counter()
image = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
width=width,
height=height,
num_inference_steps=steps,
guidance_scale=cfg,
generator=generator,
).images[0]
t_infer = time.perf_counter() - t1
image.save(output)
print(f"Saved {output}")
meta_path = output.with_suffix(".json")
meta = {
"checkpoint": str(Path(checkpoint_path).resolve()),
"prompt": prompt,
"negative_prompt": negative_prompt,
"width": width,
"height": height,
"steps": steps,
"cfg": cfg,
"seed": seed,
"load_time_s": round(t_load, 2),
"inference_time_s": round(t_infer, 2),
}
meta_path.write_text(json.dumps(meta, indent=2))
print(f"Saved {meta_path}")