From 4aa115d5c167b03df5ad0fd2e966f5e4bc99233e Mon Sep 17 00:00:00 2001 From: Sakura-Luna <53183413+Sakura-Luna@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:28:44 +0800 Subject: [PATCH 1/9] Add bf16 support. --- modules/processing.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 6d9c6a8de..ce0dbbabf 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -653,8 +653,20 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength, prompts=prompts) x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))] - for x in x_samples_ddim: - devices.test_for_nans(x, "vae") + try: + for x in x_samples_ddim: + devices.test_for_nans(x, "vae") + except devices.NansException as e: + if not shared.cmd_opts.no_half and not shared.cmd_opts.no_half_vae and torch.cuda.get_device_capability()[0] >= 8: + print('\nA tensor with all NaNs was produced in VAE, try converting to bf16.') + devices.dtype_vae = torch.bfloat16 + vae_file, vae_source = sd_vae.resolve_vae(p.sd_model.sd_model_checkpoint) + sd_vae.load_vae(p.sd_model, vae_file, vae_source) + x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))] + for x in x_samples_ddim: + devices.test_for_nans(x, "vae") + else: + raise e x_samples_ddim = torch.stack(x_samples_ddim).float() x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0) From 157c25f123bfa24aa5d72d700016de5642fcb715 Mon Sep 17 00:00:00 2001 From: Sakura-Luna <53183413+Sakura-Luna@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:41:30 +0800 Subject: [PATCH 2/9] Restore type --- modules/sd_vae.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sd_vae.py b/modules/sd_vae.py index 9b00f76e9..707d1fb2c 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -183,6 +183,8 @@ unspecified = object() def reload_vae_weights(sd_model=None, vae_file=unspecified): from modules import lowvram, devices, sd_hijack + if devices.dtype_vae == torch.bfloat16: + devices.dtype_vae = torch.float16 if not sd_model: sd_model = shared.sd_model From c01dc1cb30f7cd87e1df6458580da99c702ee513 Mon Sep 17 00:00:00 2001 From: pangbo13 <373108669@qq.com> Date: Wed, 5 Apr 2023 19:22:51 +0800 Subject: [PATCH 3/9] add dropdown for X/Y/Z plot --- scripts/xyz_grid.py | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 3895a795c..774fa2c76 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -374,16 +374,19 @@ class Script(scripts.Script): with gr.Row(): x_type = gr.Dropdown(label="X type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[1].label, type="index", elem_id=self.elem_id("x_type")) x_values = gr.Textbox(label="X values", lines=1, elem_id=self.elem_id("x_values")) + x_values_dropdown = gr.Dropdown(label="X values",visible=False,multiselect=True,interactive=True) fill_x_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_x_tool_button", visible=False) with gr.Row(): y_type = gr.Dropdown(label="Y type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[0].label, type="index", elem_id=self.elem_id("y_type")) y_values = gr.Textbox(label="Y values", lines=1, elem_id=self.elem_id("y_values")) + y_values_dropdown = gr.Dropdown(label="Y values",visible=False,multiselect=True,interactive=True) fill_y_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_y_tool_button", visible=False) with gr.Row(): z_type = gr.Dropdown(label="Z type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[0].label, type="index", elem_id=self.elem_id("z_type")) z_values = gr.Textbox(label="Z values", lines=1, elem_id=self.elem_id("z_values")) + z_values_dropdown = gr.Dropdown(label="Z values",visible=False,multiselect=True,interactive=True) fill_z_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_z_tool_button", visible=False) with gr.Row(variant="compact", elem_id="axis_options"): @@ -413,18 +416,20 @@ class Script(scripts.Script): def fill(x_type): axis = self.current_axis_options[x_type] - return ", ".join(axis.choices()) if axis.choices else gr.update() + return axis.choices() if axis.choices else gr.update() - fill_x_button.click(fn=fill, inputs=[x_type], outputs=[x_values]) - fill_y_button.click(fn=fill, inputs=[y_type], outputs=[y_values]) - fill_z_button.click(fn=fill, inputs=[z_type], outputs=[z_values]) + fill_x_button.click(fn=fill, inputs=[x_type], outputs=[x_values_dropdown]) + fill_y_button.click(fn=fill, inputs=[y_type], outputs=[y_values_dropdown]) + fill_z_button.click(fn=fill, inputs=[z_type], outputs=[z_values_dropdown]) def select_axis(x_type): - return gr.Button.update(visible=self.current_axis_options[x_type].choices is not None) + choices = self.current_axis_options[x_type].choices + has_choices = choices is not None + return gr.Button.update(visible=has_choices),gr.Textbox.update(visible=not has_choices),gr.update(choices=choices() if has_choices else None,visible=has_choices,value=[]) - x_type.change(fn=select_axis, inputs=[x_type], outputs=[fill_x_button]) - y_type.change(fn=select_axis, inputs=[y_type], outputs=[fill_y_button]) - z_type.change(fn=select_axis, inputs=[z_type], outputs=[fill_z_button]) + x_type.change(fn=select_axis, inputs=[x_type], outputs=[fill_x_button,x_values,x_values_dropdown]) + y_type.change(fn=select_axis, inputs=[y_type], outputs=[fill_y_button,y_values,y_values_dropdown]) + z_type.change(fn=select_axis, inputs=[z_type], outputs=[fill_z_button,z_values,z_values_dropdown]) self.infotext_fields = ( (x_type, "X Type"), @@ -435,20 +440,23 @@ class Script(scripts.Script): (z_values, "Z Values"), ) - return [x_type, x_values, y_type, y_values, z_type, z_values, draw_legend, include_lone_images, include_sub_grids, no_fixed_seeds, margin_size] + return [x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, draw_legend, include_lone_images, include_sub_grids, no_fixed_seeds, margin_size] - def run(self, p, x_type, x_values, y_type, y_values, z_type, z_values, draw_legend, include_lone_images, include_sub_grids, no_fixed_seeds, margin_size): + def run(self, p, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, draw_legend, include_lone_images, include_sub_grids, no_fixed_seeds, margin_size): if not no_fixed_seeds: modules.processing.fix_seed(p) if not opts.return_grid: p.batch_size = 1 - def process_axis(opt, vals): + def process_axis(opt, vals, vals_dropdown): if opt.label == 'Nothing': return [0] - valslist = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(vals))) if x] + if opt.choices is not None: + valslist = vals_dropdown + else: + valslist = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(vals))) if x] if opt.type == int: valslist_ext = [] @@ -506,13 +514,13 @@ class Script(scripts.Script): return valslist x_opt = self.current_axis_options[x_type] - xs = process_axis(x_opt, x_values) + xs = process_axis(x_opt, x_values, x_values_dropdown) y_opt = self.current_axis_options[y_type] - ys = process_axis(y_opt, y_values) + ys = process_axis(y_opt, y_values, y_values_dropdown) z_opt = self.current_axis_options[z_type] - zs = process_axis(z_opt, z_values) + zs = process_axis(z_opt, z_values, z_values_dropdown) # this could be moved to common code, but unlikely to be ever triggered anywhere else Image.MAX_IMAGE_PIXELS = None # disable check in Pillow and rely on check below to allow large custom image sizes From 3ac5f9c471e4cfb5b664f9f0a7f7e7b171b1cee1 Mon Sep 17 00:00:00 2001 From: pangbo13 <373108669@qq.com> Date: Wed, 5 Apr 2023 21:43:27 +0800 Subject: [PATCH 4/9] fix axis swap and infotxt --- scripts/xyz_grid.py | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 774fa2c76..52ae1c6e1 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -404,14 +404,14 @@ class Script(scripts.Script): swap_yz_axes_button = gr.Button(value="Swap Y/Z axes", elem_id="yz_grid_swap_axes_button") swap_xz_axes_button = gr.Button(value="Swap X/Z axes", elem_id="xz_grid_swap_axes_button") - def swap_axes(axis1_type, axis1_values, axis2_type, axis2_values): - return self.current_axis_options[axis2_type].label, axis2_values, self.current_axis_options[axis1_type].label, axis1_values + def swap_axes(axis1_type, axis1_values, axis1_values_dropdown, axis2_type, axis2_values, axis2_values_dropdown): + return self.current_axis_options[axis2_type].label, axis2_values, axis2_values_dropdown, self.current_axis_options[axis1_type].label, axis1_values, axis1_values_dropdown - xy_swap_args = [x_type, x_values, y_type, y_values] + xy_swap_args = [x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown] swap_xy_axes_button.click(swap_axes, inputs=xy_swap_args, outputs=xy_swap_args) - yz_swap_args = [y_type, y_values, z_type, z_values] + yz_swap_args = [y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown] swap_yz_axes_button.click(swap_axes, inputs=yz_swap_args, outputs=yz_swap_args) - xz_swap_args = [x_type, x_values, z_type, z_values] + xz_swap_args = [x_type, x_values, x_values_dropdown, z_type, z_values, z_values_dropdown] swap_xz_axes_button.click(swap_axes, inputs=xz_swap_args, outputs=xz_swap_args) def fill(x_type): @@ -422,22 +422,37 @@ class Script(scripts.Script): fill_y_button.click(fn=fill, inputs=[y_type], outputs=[y_values_dropdown]) fill_z_button.click(fn=fill, inputs=[z_type], outputs=[z_values_dropdown]) - def select_axis(x_type): - choices = self.current_axis_options[x_type].choices + def select_axis(axis_type,axis_values_dropdown): + choices = self.current_axis_options[axis_type].choices has_choices = choices is not None - return gr.Button.update(visible=has_choices),gr.Textbox.update(visible=not has_choices),gr.update(choices=choices() if has_choices else None,visible=has_choices,value=[]) + current_values = axis_values_dropdown + if has_choices: + choices = choices() + if isinstance(current_values,str): + current_values = current_values.split(",") + current_values = list(filter(lambda x: x in choices, current_values)) + return gr.Button.update(visible=has_choices),gr.Textbox.update(visible=not has_choices),gr.update(choices=choices if has_choices else None,visible=has_choices,value=current_values) - x_type.change(fn=select_axis, inputs=[x_type], outputs=[fill_x_button,x_values,x_values_dropdown]) - y_type.change(fn=select_axis, inputs=[y_type], outputs=[fill_y_button,y_values,y_values_dropdown]) - z_type.change(fn=select_axis, inputs=[z_type], outputs=[fill_z_button,z_values,z_values_dropdown]) + x_type.change(fn=select_axis, inputs=[x_type,x_values_dropdown], outputs=[fill_x_button,x_values,x_values_dropdown]) + y_type.change(fn=select_axis, inputs=[y_type,y_values_dropdown], outputs=[fill_y_button,y_values,y_values_dropdown]) + z_type.change(fn=select_axis, inputs=[z_type,z_values_dropdown], outputs=[fill_z_button,z_values,z_values_dropdown]) + + def get_dropdown_update_from_params(axis,params): + val_key = axis + " Values" + vals = params.get(val_key,"") + valslist = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(vals))) if x] + return gr.update(value = valslist) self.infotext_fields = ( (x_type, "X Type"), (x_values, "X Values"), + (x_values_dropdown, lambda params:get_dropdown_update_from_params("X",params)), (y_type, "Y Type"), (y_values, "Y Values"), + (y_values_dropdown, lambda params:get_dropdown_update_from_params("Y",params)), (z_type, "Z Type"), (z_values, "Z Values"), + (z_values_dropdown, lambda params:get_dropdown_update_from_params("Z",params)), ) return [x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, draw_legend, include_lone_images, include_sub_grids, no_fixed_seeds, margin_size] @@ -514,12 +529,18 @@ class Script(scripts.Script): return valslist x_opt = self.current_axis_options[x_type] + if x_opt.choices is not None: + x_values = ",".join(x_values_dropdown) xs = process_axis(x_opt, x_values, x_values_dropdown) y_opt = self.current_axis_options[y_type] + if y_opt.choices is not None: + y_values = ",".join(y_values_dropdown) ys = process_axis(y_opt, y_values, y_values_dropdown) z_opt = self.current_axis_options[z_type] + if z_opt.choices is not None: + z_values = ",".join(z_values_dropdown) zs = process_axis(z_opt, z_values, z_values_dropdown) # this could be moved to common code, but unlikely to be ever triggered anywhere else From d19d227138c6f0448849ca7b19ac8a8e876f249c Mon Sep 17 00:00:00 2001 From: Sakura-Luna <53183413+Sakura-Luna@users.noreply.github.com> Date: Thu, 6 Apr 2023 19:52:18 +0800 Subject: [PATCH 5/9] Add startup parameters and version check --- modules/cmd_args.py | 1 + modules/processing.py | 2 +- modules/sd_vae.py | 2 +- webui.py | 10 ++++++++++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/cmd_args.py b/modules/cmd_args.py index 81c0b82a3..547e8dc89 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -101,3 +101,4 @@ parser.add_argument("--no-gradio-queue", action='store_true', help="Disables gra parser.add_argument("--skip-version-check", action='store_true', help="Do not check versions of torch and xformers") parser.add_argument("--no-hashing", action='store_true', help="disable sha256 hashing of checkpoints to help loading performance", default=False) parser.add_argument("--no-download-sd-model", action='store_true', help="don't download SD1.5 model even if no model is found in --ckpt-dir", default=False) +parser.add_argument("--rollback-vae", action='store_true', help="trying to roll back vae when produced nan image, need to enable nan check", default=False) diff --git a/modules/processing.py b/modules/processing.py index ce0dbbabf..98402aa57 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -657,7 +657,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: for x in x_samples_ddim: devices.test_for_nans(x, "vae") except devices.NansException as e: - if not shared.cmd_opts.no_half and not shared.cmd_opts.no_half_vae and torch.cuda.get_device_capability()[0] >= 8: + if not shared.cmd_opts.no_half and not shared.cmd_opts.no_half_vae and shared.cmd_opts.rollback_vae: print('\nA tensor with all NaNs was produced in VAE, try converting to bf16.') devices.dtype_vae = torch.bfloat16 vae_file, vae_source = sd_vae.resolve_vae(p.sd_model.sd_model_checkpoint) diff --git a/modules/sd_vae.py b/modules/sd_vae.py index 707d1fb2c..ee3902a4b 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -183,7 +183,7 @@ unspecified = object() def reload_vae_weights(sd_model=None, vae_file=unspecified): from modules import lowvram, devices, sd_hijack - if devices.dtype_vae == torch.bfloat16: + if shared.cmd_opts.rollback_vae and devices.dtype_vae == torch.bfloat16: devices.dtype_vae = torch.float16 if not sd_model: sd_model = shared.sd_model diff --git a/webui.py b/webui.py index b570895fb..2f8a3e9fc 100644 --- a/webui.py +++ b/webui.py @@ -97,9 +97,19 @@ To reinstall the desired version, run with commandline flag --reinstall-xformers Use --skip-version-check commandline argument to disable this check. """.strip()) +def check_rollback_vae(): + if shared.cmd_opts.rollback_vae: + if version.parse(torch.__version__) < version.parse('2.1'): + print("If your PyTorch version is lower than PyTorch 2.1, Rollback VAE will not work.") + shared.cmd_opts.rollback_vae = False + elif 0 < torch.cuda.get_device_capability()[0] < 8: + print('Rollback VAE will not work because your device does not support it.') + shared.cmd_opts.rollback_vae = False + def initialize(): check_versions() + check_rollback_vae() extensions.list_extensions() localization.list_localizations(cmd_opts.localizations_dir) From 942c7d6158a160bf675ef8d0ce2630318edb827c Mon Sep 17 00:00:00 2001 From: Sakura-Luna <53183413+Sakura-Luna@users.noreply.github.com> Date: Sat, 8 Apr 2023 23:50:22 +0800 Subject: [PATCH 6/9] Bug fix --- modules/sd_vae.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_vae.py b/modules/sd_vae.py index ee3902a4b..8cff15916 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -183,8 +183,6 @@ unspecified = object() def reload_vae_weights(sd_model=None, vae_file=unspecified): from modules import lowvram, devices, sd_hijack - if shared.cmd_opts.rollback_vae and devices.dtype_vae == torch.bfloat16: - devices.dtype_vae = torch.float16 if not sd_model: sd_model = shared.sd_model @@ -205,6 +203,8 @@ def reload_vae_weights(sd_model=None, vae_file=unspecified): sd_model.to(devices.cpu) sd_hijack.model_hijack.undo_hijack(sd_model) + if shared.cmd_opts.rollback_vae and devices.dtype_vae == torch.bfloat16: + devices.dtype_vae = torch.float16 load_vae(sd_model, vae_file, vae_source) From 5b9187d38bb70a09c36ef85558394a3b7b5842c1 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 24 Apr 2023 10:30:23 -0400 Subject: [PATCH 7/9] combo patch --- TODO.md | 15 +++------ .../SwinIR/scripts/swinir_model.py | 2 +- extensions-builtin/sd-webui-controlnet | 2 +- .../stable-diffusion-webui-images-browser | 2 +- modules/lora | 2 +- modules/processing.py | 3 +- modules/progress.py | 29 ++++------------- modules/sd_samplers_common.py | 2 -- modules/shared.py | 8 ++--- modules/styles.py | 9 ++---- requirements.txt | 1 - setup.py | 32 ++++++++++++------- 12 files changed, 43 insertions(+), 64 deletions(-) diff --git a/TODO.md b/TODO.md index 6c58525e1..92cb7d247 100644 --- a/TODO.md +++ b/TODO.md @@ -7,8 +7,7 @@ Stuff to be fixed... - ClipSkip not updated on read gen info - Usage of `sd_vae` in quick settings - Run VAE with hires at 1280 -- Make TensorFlow optional - +- Transformers version ## Features @@ -58,11 +57,7 @@ Tech that can be integrated as part of the core workflow... ### Pending Code Updates -- fix VAE dtype - should fix most issues with NaN or black images -- add built-in Gradio themes -- fix setup race conditions -- reduce requirements -- more AMD specific work -- initial work on Apple platform support -- additional PR merges +- Use samples format for live preview +- Identify race condition where generate locks up while fetching preview +- Use **Approx NN** for live preview +- Create default `styles.csv` diff --git a/extensions-builtin/SwinIR/scripts/swinir_model.py b/extensions-builtin/SwinIR/scripts/swinir_model.py index 6e8cb864a..86672cd9a 100644 --- a/extensions-builtin/SwinIR/scripts/swinir_model.py +++ b/extensions-builtin/SwinIR/scripts/swinir_model.py @@ -89,7 +89,7 @@ class UpscalerSwinIR(Upscaler): with progress.open(filename, 'rb', description=f'Loading weights: [cyan]{filename}', auto_refresh=True) as f: pretrained_model = torch.load(filename) - if params is not None: + if params is not None and params in pretrained_model: model.load_state_dict(pretrained_model[params], strict=True) else: model.load_state_dict(pretrained_model, strict=True) diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 1ce36722a..c5984671c 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 1ce36722acb09cf546979de3e92c53577761ef4b +Subproject commit c5984671ccd7da7d554f239143648b8157ae1c39 diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser index 0029d95a5..704e42c10 160000 --- a/extensions-builtin/stable-diffusion-webui-images-browser +++ b/extensions-builtin/stable-diffusion-webui-images-browser @@ -1 +1 @@ -Subproject commit 0029d95a5f720b387c530e916a9e166277aa66e2 +Subproject commit 704e42c10d01e6c6965493ec956a82bb8fc2da51 diff --git a/modules/lora b/modules/lora index 25c8279f2..852481e14 160000 --- a/modules/lora +++ b/modules/lora @@ -1 +1 @@ -Subproject commit 25c8279f2692983f262f7e024b52defff852ae46 +Subproject commit 852481e14d08d510377813790ade557b4e2313f5 diff --git a/modules/processing.py b/modules/processing.py index 12251870d..1bed52ac8 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -442,9 +442,8 @@ def create_random_tensors(shape, seeds, subseeds=None, subseed_strength=0.0, see def decode_first_stage(model, x): - with devices.autocast(disable=x.dtype == devices.dtype_vae): + with devices.autocast(disable = x.dtype==devices.dtype_vae): x = model.decode_first_stage(x) - return x diff --git a/modules/progress.py b/modules/progress.py index 07a5eba1d..93246eb08 100644 --- a/modules/progress.py +++ b/modules/progress.py @@ -1,11 +1,7 @@ import base64 import io import time - -from pydantic import BaseModel, Field - -from modules.shared import opts - +from pydantic import BaseModel, Field # pylint: disable=no-name-in-module import modules.shared as shared @@ -15,18 +11,15 @@ finished_tasks = [] def start_task(id_task): - global current_task - + global current_task # pylint: disable=global-statement current_task = id_task pending_tasks.pop(id_task, None) def finish_task(id_task): - global current_task - + global current_task # pylint: disable=global-statement if current_task == id_task: current_task = None - finished_tasks.append(id_task) if len(finished_tasks) > 16: finished_tasks.pop(0) @@ -60,39 +53,31 @@ def progressapi(req: ProgressRequest): active = req.id_task == current_task queued = req.id_task in pending_tasks completed = req.id_task in finished_tasks - if not active: return ProgressResponse(active=active, queued=queued, completed=completed, id_live_preview=-1, textinfo="In queue..." if queued else "Waiting...") - progress = 0 - job_count, job_no = shared.state.job_count, shared.state.job_no sampling_steps, sampling_step = shared.state.sampling_steps, shared.state.sampling_step - if job_count > 0: progress += job_no / job_count if sampling_steps > 0 and job_count > 0: progress += 1 / job_count * sampling_step / sampling_steps - progress = min(progress, 1) - elapsed_since_start = time.time() - shared.state.time_start predicted_duration = elapsed_since_start / progress if progress > 0 else None eta = predicted_duration - elapsed_since_start if predicted_duration is not None else None - id_live_preview = req.id_live_preview shared.state.set_current_image() - if opts.live_previews_enable and shared.state.id_live_preview != req.id_live_preview: + if shared.opts.live_previews_enable and shared.state.id_live_preview != req.id_live_preview: image = shared.state.current_image if image is not None: buffered = io.BytesIO() - image.save(buffered, format="png") - live_preview = 'data:image/png;base64,' + base64.b64encode(buffered.getvalue()).decode("ascii") + fmt = 'jpeg' if shared.opts.samples_format == 'jpg' else shared.opts.samples_format + image.save(buffered, format=fmt) + live_preview = f'data:image/{fmt};base64,{base64.b64encode(buffered.getvalue()).decode("ascii")}' id_live_preview = shared.state.id_live_preview else: live_preview = None else: live_preview = None - return ProgressResponse(active=active, queued=queued, completed=completed, progress=progress, eta=eta, live_preview=live_preview, id_live_preview=id_live_preview, textinfo=shared.state.textinfo) - diff --git a/modules/sd_samplers_common.py b/modules/sd_samplers_common.py index a1aac7cf0..888f9a30e 100644 --- a/modules/sd_samplers_common.py +++ b/modules/sd_samplers_common.py @@ -28,14 +28,12 @@ approximation_indexes = {"Full": 0, "Approx NN": 1, "Approx cheap": 2} def single_sample_to_image(sample, approximation=None): if approximation is None: approximation = approximation_indexes.get(opts.show_progress_type, 0) - if approximation == 2: x_sample = sd_vae_approx.cheap_approximation(sample) elif approximation == 1: x_sample = sd_vae_approx.model()(sample.to(devices.device, devices.dtype).unsqueeze(0))[0].detach() else: x_sample = processing.decode_first_stage(shared.sd_model, sample.unsqueeze(0))[0] - x_sample = torch.clamp((x_sample + 1.0) / 2.0, min=0.0, max=1.0) x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2) x_sample = x_sample.astype(np.uint8) diff --git a/modules/shared.py b/modules/shared.py index 664620561..a2e202735 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -112,7 +112,6 @@ class State: "sampling_step": self.sampling_step, "sampling_steps": self.sampling_steps, } - return obj def begin(self): @@ -142,20 +141,17 @@ class State: """sets self.current_image from self.current_latent if enough sampling steps have been made after the last call to this""" if not parallel_processing_allowed: return - if self.sampling_step - self.current_image_sampling_step >= opts.show_progress_every_n_steps and opts.live_previews_enable and opts.show_progress_every_n_steps != -1: self.do_set_current_image() def do_set_current_image(self): if self.current_latent is None: return - import modules.sd_samplers # pylint: disable=W0621 if opts.show_progress_grid: self.assign_current_image(modules.sd_samplers.samples_to_image_grid(self.current_latent)) else: self.assign_current_image(modules.sd_samplers.sample_to_image(self.current_latent)) - self.current_image_sampling_step = self.sampling_step def assign_current_image(self, image): @@ -425,8 +421,8 @@ options_templates.update(options_section(('ui', "Live previews"), { "show_progressbar": OptionInfo(True, "Show progressbar"), "live_previews_enable": OptionInfo(True, "Show live previews of the created image"), "show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"), - "show_progress_every_n_steps": OptionInfo(-1, "Show new live preview image every N sampling steps. Set to -1 to show after completion of batch.", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), - "show_progress_type": OptionInfo("Full", "Image creation progress preview mode", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap"]}), + "show_progress_every_n_steps": OptionInfo(1, "Show new live preview image every N sampling steps. Set to -1 to show after completion of batch.", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), + "show_progress_type": OptionInfo("Approx NN", "Image creation progress preview mode", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap"]}), "live_preview_content": OptionInfo("Combined", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"]}), "live_preview_refresh_period": OptionInfo(250, "Progressbar/preview update period, in milliseconds") })) diff --git a/modules/styles.py b/modules/styles.py index 990d56236..e7c33025d 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -49,7 +49,8 @@ class StyleDatabase: self.styles.clear() if not os.path.exists(self.path): - return + print(f'Creating styles database: {self.path}') + self.save_styles(self.path) with open(self.path, "r", encoding="utf-8-sig", newline='') as file: reader = csv.DictReader(file) @@ -79,9 +80,5 @@ class StyleDatabase: # and collections.NamedTuple has explicit documentation for accessing _fields. Same goes for _asdict() writer = csv.DictWriter(file, fieldnames=PromptStyle._fields) writer.writeheader() - writer.writerows(style._asdict() for k, style in self.styles.items()) - - # Always keep a backup file around - if os.path.exists(path): - shutil.move(path, path + ".bak") + writer.writerows(style._asdict() for k, style in self.styles.items()) shutil.move(temp_path, path) diff --git a/requirements.txt b/requirements.txt index 4519a69c8..3f7db3419 100644 --- a/requirements.txt +++ b/requirements.txt @@ -49,7 +49,6 @@ tqdm voluptuous yapf scikit-image - accelerate==0.18.0 opencv-python==4.7.0.72 diffusers==0.15.0 diff --git a/setup.py b/setup.py index b2e5f7441..dc2792e66 100644 --- a/setup.py +++ b/setup.py @@ -217,7 +217,7 @@ def check_torch(): log.debug(f'Cannot install xformers package: {e}') try: tensorflow_package = os.environ.get('TENSORFLOW_PACKAGE', 'tensorflow==2.12.0') - install(f'--no-deps {tensorflow_package}', ignore=True) + install(tensorflow_package, ignore=True) except Exception as e: log.debug(f'Cannot install tensorflow package: {e}') @@ -237,7 +237,6 @@ def install_packages(): def install_repositories(): def d(name): return os.path.join(os.path.dirname(__file__), 'repositories', name) - log.info('Installing repositories') os.makedirs(os.path.join(os.path.dirname(__file__), 'repositories'), exist_ok=True) stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git") @@ -263,7 +262,7 @@ def run_extension_installer(folder): if not os.path.isfile(path_installer): return try: - log.debug(f"Running extension installer: {path_installer}") + log.debug(f"Running extension installer: {folder} / {path_installer}") env = os.environ.copy() env['PYTHONPATH'] = os.path.abspath(".") result = subprocess.run(f'"{sys.executable}" "{path_installer}"', shell=True, env=env, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=folder) @@ -334,7 +333,7 @@ def install_submodules(): def ensure_package(pkg): try: - import pkg + import pkg # type: ignore except ImportError: install(pkg) @@ -394,6 +393,13 @@ def check_extensions(): # check version of the main repo and optionally upgrade it def check_version(): + if not os.path.exists('.git'): + log.error('Not a git repository') + exit(1) + status = git('status') + if 'branch' not in status: + log.error('Cannot get git repository status') + exit(1) ver = git('log -1 --pretty=format:"%h %ad"') log.info(f'Version: {ver}') commit = git('rev-parse HEAD') @@ -420,17 +426,20 @@ def check_version(): log.error('Error upgrading repository') else: log.info(f'Latest published version: {commits["commit"]["sha"]} {commits["commit"]["commit"]["author"]["date"]}') - if not args.noupdate: - log.info('Updating Wiki') - try: - update(os.path.join(os.path.dirname(__file__), "wiki")) - update(os.path.join(os.path.dirname(__file__), "wiki", "origin-wiki")) - except: - log.error('Error updating wiki') except Exception as e: log.error(f'Failed to check version: {e} {commits}') +def update_wiki(): + if not args.noupdate: + log.info('Updating Wiki') + try: + update(os.path.join(os.path.dirname(__file__), "wiki")) + update(os.path.join(os.path.dirname(__file__), "wiki", "origin-wiki")) + except: + log.error('Error updating wiki') + + # check if we can run setup in quick mode def check_timestamp(): if not quick_allowed or not os.path.isfile('setup.log'): @@ -535,6 +544,7 @@ def run_setup(): install_repositories() install_submodules() install_extensions() + update_wiki() if errors == 0: log.debug(f'Setup complete without errors: {round(time.time())}') else: From 6bf907a949b92caa71649f22d1d33aece0323e46 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 24 Apr 2023 10:56:49 -0400 Subject: [PATCH 8/9] update argparse --- TODO.md | 13 +++++++------ extensions-builtin/sd-webui-controlnet | 2 +- modules/cmd_args.py | 1 + modules/paths_internal.py | 2 +- setup.py | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/TODO.md b/TODO.md index 92cb7d247..a517659c1 100644 --- a/TODO.md +++ b/TODO.md @@ -5,9 +5,9 @@ Stuff to be fixed... - ClipSkip not updated on read gen info -- Usage of `sd_vae` in quick settings - Run VAE with hires at 1280 - Transformers version +- Move Restart Server from WebUI to Launch and reload modules ## Features @@ -15,7 +15,6 @@ Stuff to be added... - Add Gradio theme maker - Create new GitHub hooks/actions for CI/CD -- Move Restart Server from WebUI to Launch and reload modules - Redo Extensions tab: see - Stream-load models as option for slow storage - Autodetect nVidia and AMD: `nvidia-smi` vs `rocm-smi` @@ -57,7 +56,9 @@ Tech that can be integrated as part of the core workflow... ### Pending Code Updates -- Use samples format for live preview -- Identify race condition where generate locks up while fetching preview -- Use **Approx NN** for live preview -- Create default `styles.csv` +- use samples format for live preview +- identify race condition where generate locks up while fetching preview +- use **Approx NN** for live preview +- create default `styles.csv` +- fix setup not installing `tensorflow` dependencies +- update default git flags to reduce number of warnings diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index c5984671c..9eeb71a79 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit c5984671ccd7da7d554f239143648b8157ae1c39 +Subproject commit 9eeb71a796b06f912e1e66acecf4242d165db67b diff --git a/modules/cmd_args.py b/modules/cmd_args.py index b4e0e55a5..b4b3e154c 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -17,6 +17,7 @@ parser.add_argument("--lowram", action='store_true', help="Load checkpoint weigh parser.add_argument("--ckpt", type=str, default=sd_model_file, help="Path to checkpoint of stable diffusion model to load immediately",) parser.add_argument('--vae', type=str, help='Path to checkpoint of stable diffusion VAE model to load immediately', default=None) parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="Base path where all user data is stored") +parser.add_argument("--models-dir", type=str, default="models", help="Nase path where all models are stored",) parser.add_argument("--allow-code", action='store_true', help="Allow custom script execution") parser.add_argument("--share", action='store_true', help="Enable to make the UI accessible through Gradio site") diff --git a/modules/paths_internal.py b/modules/paths_internal.py index c529c97cf..7f2425cf3 100644 --- a/modules/paths_internal.py +++ b/modules/paths_internal.py @@ -15,7 +15,7 @@ parser_pre.add_argument("--data-dir", type=str, default=os.path.dirname(os.path. parser_pre.add_argument("--models-dir", type=str, default="models", help="base path where all models are stored",) cmd_opts_pre = parser_pre.parse_known_args()[0] data_path = cmd_opts_pre.data_dir - +print('HERE', data_path) models_path = os.path.join(data_path, cmd_opts_pre.models_dir) extensions_dir = os.path.join(data_path, "extensions") extensions_builtin_dir = os.path.join(script_path, "extensions-builtin") diff --git a/setup.py b/setup.py index dc2792e66..73269b0df 100644 --- a/setup.py +++ b/setup.py @@ -140,7 +140,7 @@ def update(folder): git('checkout master', folder) else: log.warning(f'Unknown branch for: {folder}') - git('pull --rebase --autostash', folder) + git('pull --autostash', folder) branch = git('branch', folder) From 2825ad11a065f4488ae87281ae64cf71822514ac Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 24 Apr 2023 11:37:18 -0400 Subject: [PATCH 9/9] premerge cleanup --- modules/generation_parameters_copypaste.py | 6 ++++-- modules/paths_internal.py | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 3e7a33bb7..bc58011f2 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -3,10 +3,10 @@ import io import os import re +from PIL import Image import gradio as gr from modules.paths import data_path from modules import shared, ui_tempdir, script_callbacks -from PIL import Image re_param_code = r'\s*([\w ]+):\s*("(?:\\"[^,]|\\"|\\|[^\"])+"|[^,]*)(?:,|$)' re_param = re.compile(re_param_code) @@ -251,7 +251,7 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model lines.append(lastline) lastline = '' - for i, line in enumerate(lines): + for _i, line in enumerate(lines): line = line.strip() if line.startswith("Negative prompt:"): done_with_prompt = True @@ -382,6 +382,8 @@ def connect_paste(button, paste_fields, input_comp, override_settings_component, if os.path.exists(filename): with open(filename, "r", encoding="utf8") as file: prompt = file.read() + else: + prompt = '' params = parse_generation_parameters(prompt) script_callbacks.infotext_pasted_callback(prompt, params) diff --git a/modules/paths_internal.py b/modules/paths_internal.py index 7f2425cf3..b5d81df51 100644 --- a/modules/paths_internal.py +++ b/modules/paths_internal.py @@ -15,7 +15,6 @@ parser_pre.add_argument("--data-dir", type=str, default=os.path.dirname(os.path. parser_pre.add_argument("--models-dir", type=str, default="models", help="base path where all models are stored",) cmd_opts_pre = parser_pre.parse_known_args()[0] data_path = cmd_opts_pre.data_dir -print('HERE', data_path) models_path = os.path.join(data_path, cmd_opts_pre.models_dir) extensions_dir = os.path.join(data_path, "extensions") extensions_builtin_dir = os.path.join(script_path, "extensions-builtin")