Merge pull request #4579 from vladmandic/dev

merge dev
This commit is contained in:
Vladimir Mandic
2026-01-21 17:09:04 +01:00
committed by GitHub
12 changed files with 51 additions and 22 deletions
+9
View File
@@ -1,5 +1,14 @@
# Change Log for SD.Next
## Update for 2026-01-21
- add `SD_DEVICE_DEBUG` env variable to trace rocm/xpu/directml init failures
- fix lora load when using peft/diffusers loader
- fix rocm hipblaslt detection
- fix image delete
- fix `all_seeds` error
- improve `wrap_gradio` error handling
## Update for 2026-01-20
### Highlights for 2026-01-20
+6 -6
View File
@@ -37,7 +37,6 @@ def wrap_gradio_gpu_call(func, extra_outputs=None, name=None):
id_task = None
with get_lock():
progress.start_task(id_task)
res = [None, '', '', '']
try:
res = func(*args, **kwargs)
progress.record_results(id_task, res)
@@ -45,7 +44,8 @@ def wrap_gradio_gpu_call(func, extra_outputs=None, name=None):
shared.log.error(f"Exception: {e}")
shared.log.error(f"Arguments: args={str(args)[:10240]} kwargs={str(kwargs)[:10240]}")
errors.display(e, 'gradio call')
res[-1] = f"<div class='error'>{html.escape(str(e))}</div>"
res = extra_outputs or []
res.append(f"<div class='error'>{html.escape(str(e))}</div>")
finally:
progress.finish_task(id_task)
return res
@@ -70,7 +70,8 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False, name=None):
if res is None:
msg = "No result returned from function"
shared.log.warning(msg)
res = [None, '', '', f"<div class='error'>{html.escape(msg)}</div>"]
res = extra_outputs_array or []
res.append(f"<div class='error'>{html.escape(msg)}</div>")
else:
res = list(res)
if shared.cmd_opts.profile:
@@ -78,9 +79,8 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False, name=None):
errors.profile(pr, 'Wrap')
except Exception as e:
errors.display(e, 'gradio call')
if extra_outputs_array is None:
extra_outputs_array = [None, '']
res = extra_outputs_array + [f"<div class='error'>{html.escape(type(e).__name__+': '+str(e))}</div>"]
res = extra_outputs_array or []
res.append(f"<div class='error'>{html.escape(type(e).__name__+': '+str(e))}</div>")
shared.state.end(jobid)
if not add_stats:
return tuple(res)
+5 -3
View File
@@ -173,7 +173,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
def signature(self, names: List[str], te_multipliers: List, unet_multipliers: List):
return [f'{name}:{te}:{unet}' for name, te, unet in zip(names, te_multipliers, unet_multipliers)]
def changed(self, requested: List[str], include: List[str], exclude: List[str]):
def changed(self, requested: List[str], include: List[str] = None, exclude: List[str] = None) -> bool:
if shared.opts.lora_force_reload:
return True
sd_model = shared.sd_model.pipe if hasattr(shared.sd_model, 'pipe') else shared.sd_model
@@ -213,15 +213,17 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
debug_log(f'Network load: type=LoRA include={include} exclude={exclude} method={load_method} requested={requested} fn={fn}')
if load_method == 'diffusers':
has_changed = False # diffusers handles its own loading
if len(exclude) == 0:
has_changed = self.changed(requested)
if has_changed:
jobid = shared.state.begin('LoRA')
lora_load.network_load(names, te_multipliers, unet_multipliers, dyn_dims, lora_modules) # load only on first call
sd_models.set_diffuser_offload(shared.sd_model, op="model")
shared.state.end(jobid)
elif load_method == 'nunchaku':
from modules.lora import lora_nunchaku
has_changed = lora_nunchaku.load_nunchaku(names, unet_multipliers)
else: # native
lora_load.network_load(names, te_multipliers, unet_multipliers, dyn_dims) # load
has_changed = self.changed(requested, include, exclude)
+1 -1
View File
@@ -304,7 +304,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
shared.log.error(f'Network load: type=LoRA action=fuse {str(e)}')
if l.debug:
errors.display(e, 'LoRA')
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model, force=True) # some layers may end up on cpu without hook
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model, force=True, silent=True) # some layers may end up on cpu without hook
if len(l.loaded_networks) > 0 and l.debug:
shared.log.debug(f'Network load: type=LoRA loaded={[n.name for n in l.loaded_networks]} cache={list(lora_cache)} fuse={shared.opts.lora_fuse_native}:{shared.opts.lora_fuse_diffusers}')
+11 -5
View File
@@ -227,7 +227,7 @@ def decode_first_stage(model, x):
def get_fixed_seed(seed):
if seed is None or seed == '' or seed == -1:
if (seed is None) or (seed == '') or (seed == -1):
random.seed()
seed = int(random.randrange(4294967294))
return seed
@@ -236,10 +236,16 @@ def get_fixed_seed(seed):
def fix_seed(p):
p.seed = get_fixed_seed(p.seed)
p.subseed = get_fixed_seed(p.subseed)
for i in range(len(p.all_seeds)):
p.all_seeds[i] = get_fixed_seed(p.all_seeds[i])
for i in range(len(p.all_subseeds)):
p.all_subseeds[i] = get_fixed_seed(p.all_subseeds[i])
if p.all_seeds is None or len(p.all_seeds) == 0:
p.all_seeds = [p.seed]
else:
for i in range(len(p.all_seeds)):
p.all_seeds[i] = get_fixed_seed(p.all_seeds[i])
if p.all_subseeds is None or len(p.all_subseeds) == 0:
p.all_subseeds = [p.subseed]
else:
for i in range(len(p.all_subseeds)):
p.all_subseeds[i] = get_fixed_seed(p.all_subseeds[i])
def old_hires_fix_first_pass_dimensions(width, height):
+6 -2
View File
@@ -110,7 +110,7 @@ class Agent:
else:
self.arch = MicroArchitecture.GCN
self.is_apu = (self.gfx_version & 0xFFF0 == 0x1150) or self.gfx_version in (0x801, 0x902, 0x90c, 0x1013, 0x1033, 0x1035, 0x1036, 0x1103,)
self.blaslt_supported = False if blaslt_tensile_libpath is None else os.path.exists(os.path.join(blaslt_tensile_libpath, f"Kernels.so-000-{self.name}.hsaco" if sys.platform == "win32" else f"extop_{self.name}.co"))
self.blaslt_supported = False if blaslt_tensile_libpath is None else os.path.exists(os.path.join(blaslt_tensile_libpath, f"TensileLibrary_lazy_{self.name}.dat"))
def __str__(self) -> str:
return self.name
@@ -138,6 +138,8 @@ class Agent:
return None
def get_gfx_version(self) -> Union[str, None]:
if self.gfx_version is None:
return None
if self.gfx_version >= 0x1100 and self.gfx_version < 0x1200:
return "11.0.0"
elif self.gfx_version != 0x1030 and self.gfx_version >= 0x1000 and self.gfx_version < 0x1100:
@@ -293,12 +295,14 @@ if sys.platform == "win32":
build_targets = torch.cuda.get_arch_list()
agents = get_agents()
log.debug(f'ROCm: agents={agents}')
if all(available.name not in build_targets for available in agents):
log.warning('ROCm: torch-rocm is installed, but none of build targets is available')
log.warning('ROCm: torch-rocm is installed, but none of build targets are available')
# use cpu instead of crashing
torch.cuda.is_available = lambda: False
agent = get_hip_agent()
log.debug(f'ROCm: selected={agents}')
if not agent.blaslt_supported:
log.warning(f'ROCm: hipBLASLt unavailable agent={agent}')
if (agent.gfx_version & 0xFFF0) == 0x1200:
+1 -1
View File
@@ -59,7 +59,7 @@ if sys.platform == "win32":
return zluda.core.to_hip_stream(_cuda_getCurrentRawStream(device))
def get_default_agent() -> Union[Agent, None]:
if shared.devices.backend == "rocm":
if shared.devices.has_rocm():
return devices.get_hip_agent()
else:
from modules import zluda
+3 -2
View File
@@ -466,7 +466,7 @@ def report_model_stats(module_name, module):
shared.log.error(f'Module stats: name={module_name} {e}')
def apply_balanced_offload(sd_model=None, exclude=None, force=False):
def apply_balanced_offload(sd_model=None, exclude:list[str]=None, force:bool=False, silent:bool=False):
global offload_hook_instance # pylint: disable=global-statement
if shared.opts.diffusers_offload_mode != "balanced":
return sd_model
@@ -499,7 +499,8 @@ def apply_balanced_offload(sd_model=None, exclude=None, force=False):
module.module_name = module_name
module.offload_dir = os.path.join(shared.opts.accelerate_offload_path, checkpoint_name, module_name)
apply_balanced_offload_to_module(module, op='apply')
report_model_stats(module_name, module)
if not silent:
report_model_stats(module_name, module)
set_accelerate(sd_model)
t = time.time() - t0
+6
View File
@@ -87,16 +87,22 @@ elif cmd_opts.use_ipex or devices.has_xpu():
ok, e = ipex_init()
if not ok:
log.error(f'IPEX initialization failed: {e}')
if os.environ.get('SD_DEVICE_DEBUG', None) is not None:
errors.display(e, 'IPEX')
elif cmd_opts.use_directml:
from modules.dml import directml_init
ok, e = directml_init()
if not ok:
log.error(f'DirectML initialization failed: {e}')
if os.environ.get('SD_DEVICE_DEBUG', None) is not None:
errors.display(e, 'DirectML')
elif cmd_opts.use_rocm or devices.has_rocm():
from modules.rocm import rocm_init
ok, e = rocm_init()
if not ok:
log.error(f'ROCm initialization failed: {e}')
if os.environ.get('SD_DEVICE_DEBUG', None) is not None:
errors.display(e, 'ROCm')
devices.backend = devices.get_backend(cmd_opts)
devices.device = devices.get_optimal_device()
mem_stat = memory_stats()
+1 -1
View File
@@ -88,7 +88,7 @@ def delete_files(js_data, files, all_files, index):
continue
if os.path.exists(fn) and os.path.isfile(fn):
deleted.append(fn)
# os.remove(fn)
os.remove(fn)
if fn in all_files:
all_files.remove(fn)
shared.log.info(f'Delete: image="{fn}"')
+1
View File
@@ -11,6 +11,7 @@ debug = shared.log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None e
def generate(*args, **kwargs):
task_id, ui_state, engine, model, prompt, negative, styles, width, height, frames, steps, sampler_index, sampler_shift, dynamic_shift, seed, guidance_scale, guidance_true, init_image, init_strength, last_image, vae_type, vae_tile_frames, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, vlm_enhance, vlm_model, vlm_system_prompt, override_settings = args
if engine is None or model is None or engine == 'None' or model == 'None':
return video_utils.queue_err('model not selected')
# videojob = shared.state.begin('Video')
+1 -1
View File
@@ -190,7 +190,7 @@ def create_ui(prompt, negative, styles, overrides, init_image, init_strength, la
]
video_dict = dict(
fn=call_queue.wrap_gradio_gpu_call(video_run.generate, extra_outputs=[None, '', ''], name='Video'),
fn=call_queue.wrap_gradio_gpu_call(video_run.generate, extra_outputs=[gr.update(), gr.update(), gr.update(), gr.update()], name='Video'),
_js="submit_video",
inputs=state_inputs + video_inputs,
outputs=video_outputs,