Spaces:
Running
on
Zero
Running
on
Zero
import gradio as gr | |
import spaces | |
import torch | |
from diffusers import AutoencoderKL, ControlNetUnionModel, DiffusionPipeline, TCDScheduler | |
def callback_cfg_cutoff(pipeline, step_index, timestep, callback_kwargs): | |
if step_index == int(pipeline.num_timesteps * 0.2): | |
prompt_embeds = callback_kwargs["prompt_embeds"] | |
prompt_embeds = prompt_embeds[-1:] | |
add_text_embeds = callback_kwargs["add_text_embeds"] | |
add_text_embeds = add_text_embeds[-1:] | |
add_time_ids = callback_kwargs["add_time_ids"] | |
add_time_ids = add_time_ids[-1:] | |
control_image = callback_kwargs["control_image"] | |
control_image[0] = control_image[0][-1:] | |
control_type = callback_kwargs["control_type"] | |
control_type = control_type[-1:] | |
pipeline._guidance_scale = 0.0 | |
callback_kwargs["prompt_embeds"] = prompt_embeds | |
callback_kwargs["add_text_embeds"] = add_text_embeds | |
callback_kwargs["add_time_ids"] = add_time_ids | |
callback_kwargs["control_image"] = control_image | |
callback_kwargs["control_type"] = control_type | |
return callback_kwargs | |
MODELS = { | |
"RealVisXL V5.0 Lightning": "SG161222/RealVisXL_V5.0_Lightning", | |
} | |
controlnet_model = ControlNetUnionModel.from_pretrained( | |
"OzzyGT/controlnet-union-promax-sdxl-1.0", variant="fp16", torch_dtype=torch.float16 | |
) | |
controlnet_model.to(device="cuda", dtype=torch.float16) | |
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16).to("cuda") | |
pipe = DiffusionPipeline.from_pretrained( | |
"SG161222/RealVisXL_V5.0_Lightning", | |
torch_dtype=torch.float16, | |
vae=vae, | |
controlnet=controlnet_model, | |
custom_pipeline="OzzyGT/custom_sdxl_cnet_union", | |
).to("cuda") | |
pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config) | |
prompt = "high quality" | |
( | |
prompt_embeds, | |
negative_prompt_embeds, | |
pooled_prompt_embeds, | |
negative_pooled_prompt_embeds, | |
) = pipe.encode_prompt(prompt, "cuda") | |
def fill_image(image, model_selection): | |
source = image["background"] | |
mask = image["layers"][0] | |
alpha_channel = mask.split()[3] | |
binary_mask = alpha_channel.point(lambda p: p > 0 and 255) | |
cnet_image = source.copy() | |
cnet_image.paste(0, (0, 0), binary_mask) | |
image = pipe( | |
prompt_embeds=prompt_embeds, | |
negative_prompt_embeds=negative_prompt_embeds, | |
pooled_prompt_embeds=pooled_prompt_embeds, | |
negative_pooled_prompt_embeds=negative_pooled_prompt_embeds, | |
control_image=[cnet_image], | |
controlnet_conditioning_scale=[1.0], | |
control_mode=[7], | |
num_inference_steps=8, | |
guidance_scale=1.5, | |
callback_on_step_end=callback_cfg_cutoff, | |
callback_on_step_end_tensor_inputs=[ | |
"prompt_embeds", | |
"add_text_embeds", | |
"add_time_ids", | |
"control_image", | |
"control_type", | |
], | |
).images[0] | |
image = image.convert("RGBA") | |
cnet_image.paste(image, (0, 0), binary_mask) | |
yield source, cnet_image | |
def clear_result(): | |
return gr.update(value=None) | |
title = """<h1 align="center">Diffusers Image Fill</h1> | |
<div align="center">Draw the mask over the subject you want to erase or change.</div> | |
<div align="center">This space is a PoC made for the guide <a href='https://huggingface.co/blog/OzzyGT/diffusers-image-fill'>Diffusers Image Fill</a>.</div> | |
""" | |
with gr.Blocks() as demo: | |
gr.HTML(title) | |
run_button = gr.Button("Generate") | |
with gr.Row(): | |
input_image = gr.ImageMask( | |
type="pil", | |
label="Input Image", | |
crop_size=(1024, 1024), | |
canvas_size=(1024, 1024), | |
layers=False, | |
sources=["upload"], | |
) | |
result = gr.ImageSlider( | |
interactive=False, | |
label="Generated Image", | |
) | |
model_selection = gr.Dropdown( | |
choices=list(MODELS.keys()), | |
value="RealVisXL V5.0 Lightning", | |
label="Model", | |
) | |
run_button.click( | |
fn=clear_result, | |
inputs=None, | |
outputs=result, | |
).then( | |
fn=fill_image, | |
inputs=[input_image, model_selection], | |
outputs=result, | |
) | |
demo.launch(share=False) | |