import gradio as gr
from modules import scripts_manager, processing, shared, sd_models
registered = False
class Script(scripts_manager.Script):
def __init__(self):
super().__init__()
self.orig_pipe = None
self.orig_slice = None
self.orig_tile = None
self.is_img2img = False
def title(self):
return 'FreeScale: Tuning-Free Scale Fusion'
def show(self, is_img2img):
self.is_img2img = is_img2img
return True
def ui(self, _is_img2img): # ui elements
with gr.Row():
gr.HTML('  FreeScale: Tuning-Free Scale Fusion
')
with gr.Row():
cosine_scale = gr.Slider(minimum=0.1, maximum=5.0, value=2.0, label='Cosine scale')
override_sampler = gr.Checkbox(value=True, label='Override sampler')
with gr.Row(visible=self.is_img2img):
cosine_scale_bg = gr.Slider(minimum=0.1, maximum=5.0, value=1.0, label='Cosine Background')
dilate_tau = gr.Slider(minimum=1, maximum=100, value=35, label='Dilate tau')
with gr.Row():
s1_enable = gr.Checkbox(value=True, label='1st Stage', interactive=False)
s1_scale = gr.Slider(minimum=1, maximum=8.0, value=1.0, label='Scale')
s1_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='Restart step')
with gr.Row():
s2_enable = gr.Checkbox(value=True, label='2nd Stage')
s2_scale = gr.Slider(minimum=1, maximum=8.0, value=2.0, label='2nd Scale')
s2_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='2nd Restart step')
with gr.Row():
s3_enable = gr.Checkbox(value=False, label='3rd Stage')
s3_scale = gr.Slider(minimum=1, maximum=8.0, value=3.0, label='3rd Scale')
s3_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='3rd Restart step')
with gr.Row():
s4_enable = gr.Checkbox(value=False, label='4th Stage')
s4_scale = gr.Slider(minimum=1, maximum=8.0, value=4.0, label='4th Scale')
s4_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='4th Restart step')
return [cosine_scale, override_sampler, cosine_scale_bg, dilate_tau, s1_enable, s1_scale, s1_restart, s2_enable, s2_scale, s2_restart, s3_enable, s3_scale, s3_restart, s4_enable, s4_scale, s4_restart]
def run(self, p: processing.StableDiffusionProcessing, cosine_scale, override_sampler, cosine_scale_bg, dilate_tau, s1_enable, s1_scale, s1_restart, s2_enable, s2_scale, s2_restart, s3_enable, s3_scale, s3_restart, s4_enable, s4_scale, s4_restart): # pylint: disable=arguments-differ
supported_model_list = ['sdxl']
if shared.sd_model_type not in supported_model_list:
shared.log.warning(f'FreeScale: class={shared.sd_model.__class__.__name__} model={shared.sd_model_type} required={supported_model_list}')
return None
if self.is_img2img:
if p.init_images is None or len(p.init_images) == 0:
shared.log.warning('FreeScale: missing input image')
return None
from scripts.freescale import StableDiffusionXLFreeScale, StableDiffusionXLFreeScaleImg2Img
self.orig_pipe = shared.sd_model
self.orig_slice = shared.opts.diffusers_vae_slicing
self.orig_tile = shared.opts.diffusers_vae_tiling
def scale(x):
if (p.width == 0 or p.height == 0) and p.init_images is not None:
p.width, p.height = p.init_images[0].width, p.init_images[0].height
resolution = [int(8 * p.width * x // 8), int(8 * p.height * x // 8)]
return resolution
scales = []
resolutions_list = []
restart_steps = []
if s1_enable:
scales.append(s1_scale)
resolutions_list.append(scale(s1_scale))
restart_steps.append(int(p.steps * s1_restart))
if s2_enable and s2_scale > s1_scale:
scales.append(s2_scale)
resolutions_list.append(scale(s2_scale))
restart_steps.append(int(p.steps * s2_restart))
if s3_enable and s3_scale > s2_scale:
scales.append(s3_scale)
resolutions_list.append(scale(s3_scale))
restart_steps.append(int(p.steps * s3_restart))
if s4_enable and s4_scale > s3_scale:
scales.append(s4_scale)
resolutions_list.append(scale(s4_scale))
restart_steps.append(int(p.steps * s4_restart))
p.task_args['resolutions_list'] = resolutions_list
p.task_args['cosine_scale'] = cosine_scale
p.task_args['restart_steps'] = [min(max(1, step), p.steps-1) for step in restart_steps]
if self.is_img2img:
p.task_args['cosine_scale_bg'] = cosine_scale_bg
p.task_args['dilate_tau'] = dilate_tau
p.task_args['img_path'] = p.init_images[0]
p.init_images = None
if override_sampler:
p.sampler_name = 'Euler a'
if p.width < 1024 or p.height < 1024:
shared.log.error(f'FreeScale: width={p.width} height={p.height} minimum=1024')
return None
if not self.is_img2img:
shared.sd_model = sd_models.switch_pipe(StableDiffusionXLFreeScale, shared.sd_model)
else:
shared.sd_model = sd_models.switch_pipe(StableDiffusionXLFreeScaleImg2Img, shared.sd_model)
shared.sd_model.enable_vae_slicing()
shared.sd_model.enable_vae_tiling()
shared.log.info(f'FreeScale: mode={"txt" if not self.is_img2img else "img"} cosine={cosine_scale} bg={cosine_scale_bg} tau={dilate_tau} scales={scales} resolutions={resolutions_list} steps={restart_steps} sampler={p.sampler_name}')
resolutions = ','.join([f'{x[0]}x{x[1]}' for x in resolutions_list])
steps = ','.join([str(x) for x in restart_steps])
p.extra_generation_params["FreeScale"] = f'cosine {cosine_scale} resolutions {resolutions} steps {steps}'
def after(self, p: processing.StableDiffusionProcessing, processed: processing.Processed, *args): # pylint: disable=arguments-differ, unused-argument
if self.orig_pipe is None:
return processed
# restore pipeline
if shared.sd_model_type == "sdxl":
shared.sd_model = self.orig_pipe
self.orig_pipe = None
if not self.orig_slice:
shared.sd_model.disable_vae_slicing()
if not self.orig_tile:
shared.sd_model.disable_vae_tiling()
return processed