diff --git a/cli/train.py b/cli/train.py index 57dc5eab0..3206180ec 100755 --- a/cli/train.py +++ b/cli/train.py @@ -4,7 +4,7 @@ Examples: - sd15: train.py --type lora --tag girl --comments sdnext --input ~/generative/Input/mia --process original,interrogate,resize --name mia - sdxl: train.py --type lora --tag girl --comments sdnext --input ~/generative/Input/mia --process original,interrogate,resize --precision fp32 --optimizer Adafactor --sdxl --name miaxl -- offline: train.py --type lora --tag girl --comments sdnext --input ~/generative/Input/mia --model /home/vlado/dev/sdnext/models/Stable-diffusion/sdxl/miaanimeSFWNSFWSDXL_v40.safetensors --dir /home/vlado/dev/sdnext/models/Lora/ --precision fp32 --optimizer Adafactor --sdxl --name miaxl +- offline: train.py --type lora --tag girl --comments sdnext --input ~/generative/Input/mia --model /home/vlado/dev/sdnext/models/Stable-diffusion/sdxl/miaanimeSFWNSFWSDXL_v40.safetensors --dir /home/vlado/dev/sdnext/models/Lora/ --precision fp32 --optimizer Adafactor --sdxl --name miaxl """ # system imports diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler index 546e69974..b085fd31e 160000 --- a/extensions-builtin/sd-webui-agent-scheduler +++ b/extensions-builtin/sd-webui-agent-scheduler @@ -1 +1 @@ -Subproject commit 546e6997472d071d2f4e822c8fce2dd1293372be +Subproject commit b085fd31e6aa20086a25f7786ed0c770c087c5d2 diff --git a/html/locale_en.json b/html/locale_en.json index e3b1118d8..fc17b4475 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -576,9 +576,9 @@ {"id":"","label":"GFPGAN","localized":"","hint":"Restore low quality faces using GFPGAN neural network"}, {"id":"","label":"CodeFormer weight parameter","localized":"","hint":"0 = maximum effect; 1 = minimum effect"}, {"id":"","label":"Move face restoration model from VRAM into RAM after processing","localized":"","hint":""}, - {"id":"","label":"Token merging ratio","localized":"","hint":"Enable redundant token merging via tomesd for speed and memory improvements, 0=disabled"}, - {"id":"","label":"Token merging ratio for img2img","localized":"","hint":"Enable redundant token merging for img2img via tomesd for speed and memory improvements, 0=disabled"}, - {"id":"","label":"Token merging ratio for hires pass","localized":"","hint":"Enable redundant token merging for hires pass via tomesd for speed and memory improvements, 0=disabled"}, + {"id":"","label":"Token merging ratio (txt2img)","localized":"","hint":"Enable redundant token merging via tomesd for speed and memory improvements, 0=disabled"}, + {"id":"","label":"Token merging ratio (img2img)","localized":"","hint":"Enable redundant token merging for img2img via tomesd for speed and memory improvements, 0=disabled"}, + {"id":"","label":"Token merging ratio (hires)","localized":"","hint":"Enable redundant token merging for hires pass via tomesd for speed and memory improvements, 0=disabled"}, {"id":"","label":"Diffusers pipeline","localized":"","hint":"If autodetect does not detect model automatically, select model type before loading a model"}, {"id":"","label":"Move base model to CPU when using refiner","localized":"","hint":""}, {"id":"","label":"Move base model to CPU when using VAE","localized":"","hint":""}, diff --git a/installer.py b/installer.py index 9d19e8c35..a24406103 100644 --- a/installer.py +++ b/installer.py @@ -535,7 +535,7 @@ def install_packages(): install('pi-heif', 'pi_heif', ignore=True) tensorflow_package = os.environ.get('TENSORFLOW_PACKAGE', 'tensorflow==2.13.0') install(tensorflow_package, 'tensorflow', ignore=True) - install('nvidia-ml-py', 'pynvml', ignore=True) + # install('nvidia-ml-py', 'pynvml', ignore=True) bitsandbytes_package = os.environ.get('BITSANDBYTES_PACKAGE', None) if bitsandbytes_package is not None: install(bitsandbytes_package, 'bitsandbytes', ignore=True) @@ -693,6 +693,14 @@ def install_submodules(): def ensure_base_requirements(): + try: + import setuptools # pylint: disable=unused-import + except ImportError: + install('setuptools', 'setuptools') + try: + import setuptools # pylint: disable=unused-import + except ImportError: + pass try: import rich # pylint: disable=unused-import except ImportError: diff --git a/javascript/black-teal.css b/javascript/black-teal.css index bc4d43350..0bc36ce1b 100644 --- a/javascript/black-teal.css +++ b/javascript/black-teal.css @@ -101,7 +101,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #div.gradio-container { overflow-x: hidden; } #img2img_label_copy_to_img2img { font-weight: normal; } #txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt { background-color: var(--background-color); box-shadow: 4px 4px 4px 0px #333333 !important; } -#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.1rem; } +#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.0em; line-height: 1.4em; } #img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; padding-top: 16px; } #interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; } #quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; } diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index f59e5c3dd..e2cc4f92f 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -262,23 +262,45 @@ settings_map = {} infotext_to_setting_name_mapping = [ - ('VAE', 'sd_vae'), - ('Conditional mask weight', 'inpainting_mask_weight'), - ('Model hash', 'sd_model_checkpoint'), ('Backed', 'sd_backend'), + ('Model hash', 'sd_model_checkpoint'), ('Refiner', 'sd_model_refiner'), + ('VAE', 'sd_vae'), ('Parser', 'prompt_attention'), - ('ENSD', 'eta_noise_seed_delta'), - ('Noise multiplier', 'initial_noise_multiplier'), - ('Eta', 'scheduler_eta'), + ('Color correction', 'img2img_color_correction'), ('LoRA method', 'diffusers_lora_loader'), - ('Discard penultimate sigma', 'discard_next_to_last_sigma'), - ('UniPC variant', 'uni_pc_variant'), + # Samplers + ('Sampler Eta', 'scheduler_eta'), + ('Sampler ENSD', 'eta_noise_seed_delta'), + ('Sampler order', 'schedulers_solver_order'), + # Samplers diffusers + ('Sampler beta schedule', 'schedulers_beta_schedule'), + ('Sampler beta start', 'schedulers_beta_start'), + ('Sampler beta end', 'schedulers_beta_end'), + ('Sampler DPM solver', 'schedulers_dpm_solver'), + # Samplers original + ('Sampler brownian', 'schedulers_brownian_noise'), + ('Sampler discard', 'schedulers_discard_penultimate'), + ('Sampler dyn threshold', 'schedulers_use_thresholding'), + ('Sampler karras', 'schedulers_use_karras'), + ('Sampler low order', 'schedulers_use_loworder'), + ('Sampler quantization', 'enable_quantization'), + ('Sampler sigma', 'schedulers_sigma'), + ('Sampler sigma min', 's_min'), + ('Sampler sigma max', 's_max'), + ('Sampler sigma churn', 's_churn'), + ('Sampler sigma uncond', 's_min_uncond'), + ('Sampler sigma noise', 's_noise'), + ('Sampler sigma tmin', 's_tmin'), + ('Sampler ENSM', 'initial_noise_multiplier'), # img2img only ('UniPC skip type', 'uni_pc_skip_type'), - ('UniPC order', 'schedulers_solver_order'), - ('UniPC lower order final', 'schedulers_use_loworder'), + ('UniPC variant', 'uni_pc_variant'), + # Token Merging + ('Mask weight', 'inpainting_mask_weight'), ('Token merging ratio', 'token_merging_ratio'), - ('Token merging ratio hr', 'token_merging_ratio_hr'), + ('ToMe', 'token_merging_ratio'), + ('ToMe hires', 'token_merging_ratio_hr'), + ('ToMe img2img', 'token_merging_ratio_img2img'), ] @@ -348,12 +370,14 @@ def connect_paste(button, local_paste_fields, input_comp, override_settings_comp if v is None: continue if shared.opts.disable_weights_auto_swap: - if setting_name == "sd_model_checkpoint" or setting_name == 'sd_model_refiner' or setting_name == 'sd_backend': + if setting_name == "sd_model_checkpoint" or setting_name == 'sd_model_refiner' or setting_name == 'sd_backend' or setting_name == 'sd_vae': continue v = shared.opts.cast_value(setting_name, v) current_value = getattr(shared.opts, setting_name, None) if v == current_value: continue + if type(current_value) == str and v == os.path.splitext(current_value)[0]: + continue vals[param_name] = v vals_pairs = [f"{k}: {v}" for k, v in vals.items()] return gr.Dropdown.update(value=vals_pairs, choices=vals_pairs, visible=len(vals_pairs) > 0) diff --git a/modules/processing.py b/modules/processing.py index 95bd10004..d79ebe695 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -483,11 +483,11 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su "Clip skip": p.clip_skip if p.clip_skip > 1 else None, "Prompt2": p.refiner_prompt if len(p.refiner_prompt) > 0 else None, "Negative2": p.refiner_negative if len(p.refiner_negative) > 0 else None, - # other - "ENSD": shared.opts.eta_noise_seed_delta if shared.opts.eta_noise_seed_delta != 0 and modules.sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p) else None, + "Styles": "; ".join(p.styles) if p.styles is not None and len(p.styles) > 0 else None, "Tiling": p.tiling if p.tiling else None, # sdnext "Backend": 'Diffusers' if shared.backend == shared.Backend.DIFFUSERS else 'Original', + "App": 'SD.Next', "Version": git_commit, "Comment": comment, "Operations": '; '.join(ops).replace('"', '') if len(p.ops) > 0 else 'none', @@ -495,6 +495,8 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su if 'txt2img' in p.ops: pass if 'hires' in p.ops or 'upscale' in p.ops: + args["Second pass"] = p.enable_hr + args["Hires force"] = p.hr_force args["Hires steps"] = p.hr_second_pass_steps args["Hires upscaler"] = p.hr_upscaler args["Hires upscale"] = p.hr_scale @@ -505,6 +507,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su args["Image CFG scale"] = p.image_cfg_scale args["CFG rescale"] = p.diffusers_guidance_rescale if shared.backend == shared.Backend.DIFFUSERS else None if 'refine' in p.ops: + args["Second pass"] = p.enable_hr args["Refiner"] = None if (not shared.opts.add_model_name_to_info) or (not shared.sd_refiner) or (not shared.sd_refiner.sd_checkpoint_info.model_name) else shared.sd_refiner.sd_checkpoint_info.model_name.replace(',', '').replace(':', '') args['Image CFG scale'] = p.image_cfg_scale args['Refiner steps'] = p.refiner_steps @@ -515,10 +518,9 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su if 'img2img' in p.ops or 'inpaint' in p.ops: args["Init image size"] = f"{getattr(p, 'init_img_width', 0)}x{getattr(p, 'init_img_height', 0)}" args["Init image hash"] = getattr(p, 'init_img_hash', None) - args["Conditional mask weight"] = getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None + args["Mask weight"] = getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None args['Resize mode'] = getattr(p, 'resize_mode', None) args["Mask blur"] = p.mask_blur if getattr(p, 'mask', None) is not None and getattr(p, 'mask_blur', 0) > 0 else None - args["Noise multiplier"] = p.initial_noise_multiplier if getattr(p, 'initial_noise_multiplier', 1.0) != 1.0 else None args["Denoising strength"] = getattr(p, 'denoising_strength', None) if 'face' in p.ops: args["Face restoration"] = shared.opts.face_restoration_model @@ -528,11 +530,34 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su if hasattr(modules.sd_hijack.model_hijack, 'embedding_db') and len(modules.sd_hijack.model_hijack.embedding_db.embeddings_used) > 0: # this is for original hijaacked models only, diffusers are handled separately args["Embeddings"] = ', '.join(modules.sd_hijack.model_hijack.embedding_db.embeddings_used) + # samplers + args["Sampler ENSD"] = shared.opts.eta_noise_seed_delta if shared.opts.eta_noise_seed_delta != 0 and modules.sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p) else None + args["Sampler ENSM"] = p.initial_noise_multiplier if getattr(p, 'initial_noise_multiplier', 1.0) != 1.0 else None + args['Sampler order'] = shared.opts.schedulers_solver_order if shared.opts.schedulers_solver_order != shared.opts.data_labels.get('schedulers_solver_order').default else None + if shared.backend == shared.Backend.DIFFUSERS: + args['Sampler beta schedule'] = shared.opts.schedulers_beta_schedule if shared.opts.schedulers_beta_schedule != shared.opts.data_labels.get('schedulers_beta_schedule').default else None + args['Sampler beta start'] = shared.opts.schedulers_beta_start if shared.opts.schedulers_beta_start != shared.opts.data_labels.get('schedulers_beta_start').default else None + args['Sampler beta end'] = shared.opts.schedulers_beta_end if shared.opts.schedulers_beta_end != shared.opts.data_labels.get('schedulers_beta_end').default else None + args['Sampler DPM solver'] = shared.opts.schedulers_dpm_solver if shared.opts.schedulers_dpm_solver != shared.opts.data_labels.get('schedulers_dpm_solver').default else None + if shared.backend == shared.Backend.ORIGINAL: + args['Sampler brownian'] = shared.opts.schedulers_brownian_noise if shared.opts.schedulers_brownian_noise != shared.opts.data_labels.get('schedulers_brownian_noise').default else None + args['Sampler discard'] = shared.opts.schedulers_discard_penultimate if shared.opts.schedulers_discard_penultimate != shared.opts.data_labels.get('schedulers_discard_penultimate').default else None + args['Sampler dyn threshold'] = shared.opts.schedulers_use_thresholding if shared.opts.schedulers_use_thresholding != shared.opts.data_labels.get('schedulers_use_thresholding').default else None + args['Sampler karras'] = shared.opts.schedulers_use_karras if shared.opts.schedulers_use_karras != shared.opts.data_labels.get('schedulers_use_karras').default else None + args['Sampler low order'] = shared.opts.schedulers_use_loworder if shared.opts.schedulers_use_loworder != shared.opts.data_labels.get('schedulers_use_loworder').default else None + args['Sampler quantization'] = shared.opts.enable_quantization if shared.opts.enable_quantization != shared.opts.data_labels.get('enable_quantization').default else None + args['Sampler sigma'] = shared.opts.schedulers_sigma if shared.opts.schedulers_sigma != shared.opts.data_labels.get('schedulers_sigma').default else None + args['Sampler sigma min'] = shared.opts.s_min if shared.opts.s_min != shared.opts.data_labels.get('s_min').default else None + args['Sampler sigma max'] = shared.opts.s_max if shared.opts.s_max != shared.opts.data_labels.get('s_max').default else None + args['Sampler sigma churn'] = shared.opts.s_churn if shared.opts.s_churn != shared.opts.data_labels.get('s_churn').default else None + args['Sampler sigma uncond'] = shared.opts.s_churn if shared.opts.s_churn != shared.opts.data_labels.get('s_churn').default else None + args['Sampler sigma noise'] = shared.opts.s_noise if shared.opts.s_noise != shared.opts.data_labels.get('s_noise').default else None + args['Sampler sigma tmin'] = shared.opts.s_tmin if shared.opts.s_tmin != shared.opts.data_labels.get('s_tmin').default else None # tome token_merging_ratio = p.get_token_merging_ratio() token_merging_ratio_hr = p.get_token_merging_ratio(for_hr=True) if p.enable_hr else None - args['Token merging ratio'] = token_merging_ratio if token_merging_ratio != 0 else None - args['Token merging ratio hr'] = token_merging_ratio_hr if token_merging_ratio_hr != 0 else None + args['ToMe'] = token_merging_ratio if token_merging_ratio != 0 else None + args['ToMe hires'] = token_merging_ratio_hr if token_merging_ratio_hr != 0 else None args.update(p.extra_generation_params) params_text = ", ".join([k if k == v else f'{k}: {modules.generation_parameters_copypaste.quote(v)}' for k, v in args.items() if v is not None]) @@ -579,7 +604,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: stored_opts = {} for k, v in p.override_settings.copy().items(): orig = shared.opts.data.get(k, None) or shared.opts.data_labels[k].default - if orig == v or os.path.splitext(orig)[0] == v: + if orig == v or (type(orig) == str and os.path.splitext(orig)[0] == v): p.override_settings.pop(k, None) for k in p.override_settings.keys(): stored_opts[k] = shared.opts.data.get(k, None) or shared.opts.data_labels[k].default @@ -596,7 +621,9 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if p.override_settings.get('sd_vae', None) is not None: if p.override_settings.get('sd_vae', None) == 'TAESD': p.full_quality = False - # p.override_settings.pop('sd_vae', None) + p.override_settings.pop('sd_vae', None) + if p.override_settings.get('Hires upscaler', None) is not None: + p.enable_hr = True if len(p.override_settings.keys()) > 0: shared.log.debug(f'Override: {p.override_settings}') for k, v in p.override_settings.items(): diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index dbc223625..a3b8fb0f1 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -197,12 +197,6 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro return task_args def set_pipeline_args(model, prompts: list, negative_prompts: list, prompts_2: typing.Optional[list]=None, negative_prompts_2: typing.Optional[list]=None, desc:str='', **kwargs): - # if hasattr(model, 'embedding_db'): - # del model.embedding_db - try: - is_refiner = model.text_encoder.__class__.__name__ != 'CLIPTextModel' - except Exception: - is_refiner = False if hasattr(model, "set_progress_bar_config"): model.set_progress_bar_config(bar_format='Progress {rate_fmt}{postfix} {bar} {percentage:3.0f}% {n_fmt}/{total_fmt} {elapsed} {remaining} ' + '\x1b[38;5;71m' + desc, ncols=80, colour='#327fba') args = {} @@ -324,7 +318,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro if sampler is None: sampler = sd_samplers.all_samplers_map.get("UniPC") sd_samplers.create_sampler(sampler.name, shared.sd_model) # TODO(Patrick): For wrapped pipelines this is currently a no-op - # p.extra_generation_params['Sampler options'] = '' # TODO + # p.extra_generation_params['Sampler options'] = '' # TODO sampler_options p.extra_generation_params['Pipeline'] = shared.sd_model.__class__.__name__ @@ -375,7 +369,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro ) # p.steps = base_args['num_inference_steps'] p.extra_generation_params['CFG rescale'] = p.diffusers_guidance_rescale - p.extra_generation_params["Eta"] = shared.opts.scheduler_eta if shared.opts.scheduler_eta is not None and shared.opts.scheduler_eta > 0 and shared.opts.scheduler_eta < 1 else None + p.extra_generation_params["Sampler Eta"] = shared.opts.scheduler_eta if shared.opts.scheduler_eta is not None and shared.opts.scheduler_eta > 0 and shared.opts.scheduler_eta < 1 else None try: output = shared.sd_model(**base_args) # pylint: disable=not-callable except AssertionError as e: diff --git a/modules/sd_samplers_compvis.py b/modules/sd_samplers_compvis.py index 8e2e8a814..cfad6dca8 100644 --- a/modules/sd_samplers_compvis.py +++ b/modules/sd_samplers_compvis.py @@ -136,14 +136,14 @@ class VanillaStableDiffusionSampler: else: self.eta = 0.0 if self.eta != 0.0: - p.extra_generation_params["Eta DDIM"] = self.eta + p.extra_generation_params["Sampler Eta"] = self.eta if self.is_unipc: keys = [ + ('Solver order', 'schedulers_solver_order'), + ('Sampler low order', 'schedulers_use_loworder'), ('UniPC variant', 'uni_pc_variant'), ('UniPC skip type', 'uni_pc_skip_type'), - ('UniPC order', 'schedulers_solver_order'), - ('UniPC lower order final', 'schedulers_use_loworder'), ] for name, key in keys: diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 8e5bfb086..e6eb1daa3 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -294,7 +294,7 @@ class KDiffusionSampler: extra_params_kwargs[param_name] = getattr(p, param_name) if 'eta' in inspect.signature(self.func).parameters: if self.eta != 1.0: - p.extra_generation_params["Eta"] = self.eta + p.extra_generation_params["Sampler Eta"] = self.eta extra_params_kwargs['eta'] = self.eta return extra_params_kwargs diff --git a/modules/shared.py b/modules/shared.py index 6a3f8f26c..f0d66daf7 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -407,9 +407,9 @@ options_templates.update(options_section(('optimizations', "Optimizations"), { "sub_quad_kv_chunk_size": OptionInfo(512, "cross-attention kv chunk size", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8}), "sub_quad_chunk_threshold": OptionInfo(80, "cross-attention chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), "token_merging_sep": OptionInfo("