add new attention dispatcher

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2026-05-29 21:10:53 +02:00
parent d2d9f7caea
commit a0531c70fd
5 changed files with 75 additions and 2 deletions
+6
View File
@@ -57,6 +57,12 @@ Plus continued work on modernization of codebase: UI is now fully TypeScript bas
- **Gallery** add clear cache button to folder menu
- **UV** much updated `--uv` support for fast installs
now also supports global `uv` if present in the system
- **Attention Dispatcher** new attention backends dispatcher
in *settings -> attention Dispatcher*
allows to use pluggable kernels defines either in packages or in new [kernels](https://huggingface.co/docs/kernels/index) library
see [backends](https://huggingface.co/docs/diffusers/optimization/attention_backends#available-backends) for list of available attention backends
*note* compatiblity matrix between torch backend, torch version and model specifics is relatively small at the moment
*note* does not replace existing *attention* settings
- **Changes**
- all **Guidance** params are now set to *-1* by default to allow using model defaults and avoid confusion with different model behaviour
log will print default values used by model if not set by user
+62 -1
View File
@@ -1,6 +1,6 @@
from functools import wraps
import torch
from modules import rocm
from modules import rocm, errors
from modules.logger import log
from installer import install, installed, torch_info
@@ -255,3 +255,64 @@ def set_diffusers_attention(pipe, quiet = False):
log.debug(f"Torch attention: slicing={shared.opts.attention_slicing}")
pipe.current_attn_name = shared.opts.cross_attention_optimization
orig_get_kernel = None
def get_kernel_hijack(repo_id, revision=None, version=None, backend=None, user_agent=None, trust_remote_code: bool | list[str] = False): # pylint: disable=unused-argument
log.debug(f'Attention dispatcher hub: repo="{repo_id}" revision={revision} version={version} backend={backend}')
user_agent = 'kernels/0.14.1'
module = None
try:
module = orig_get_kernel(repo_id, revision=revision, version=version, backend=backend, user_agent=user_agent, trust_remote_code=True)
except Exception as e:
log.error(f'Attention dispatcher hub: {e}')
errors.display(e, 'kernels')
return module
def get_hf_api_hijack(user_agent = None): # pylint: disable=unused-argument
from huggingface_hub import HfApi
return HfApi(library_name="kernels", user_agent="donottrack")
def set_attention_dispatcher(pipe):
global orig_get_kernel # pylint: disable=global-statement
from modules import shared
attn = shared.opts.hf_attention.strip().lower()
if pipe is None or not hasattr(pipe, 'transformer') or not hasattr(pipe.transformer, 'set_attention_backend'):
return
from diffusers.models import attention_dispatch as a
backends = [b.value for b in a._AttentionBackendRegistry.list_backends()] # pylint: disable=protected-access
# https://huggingface.co/docs/kernels/index
# https://huggingface.co/docs/diffusers/optimization/attention_backends#available-backends
if 'hub' in attn:
try:
install('kernels==0.14.1')
import kernels
import kernels.utils
log.debug(f'Attention dispatcher: kernels={kernels.__version__}')
if orig_get_kernel is None:
orig_get_kernel = kernels.get_kernel
kernels.get_kernel = get_kernel_hijack
kernels.utils._get_hf_api = get_hf_api_hijack # pylint: disable=protected-access
from diffusers.utils import import_utils
import_utils._kernels_available = True # pylint: disable=protected-access
import_utils._kernels_version = kernels.__version__ # pylint: disable=protected-access
except Exception as e:
log.error(f'Attention dispatcher kernels: {e}')
return
prev = a._AttentionBackendRegistry.get_active_backend() # pylint: disable=protected-access
if attn in backends:
try:
pipe.transformer.set_attention_backend(attn)
except Exception as e:
log.error(f'Attention dispatcher: target={attn} {e}')
current = a._AttentionBackendRegistry.get_active_backend() # pylint: disable=protected-access
log.debug(f'Attention dispatcher: target={attn} previous={prev[0].value} active={current[0]} list={backends}')
elif len(attn) > 0:
log.warning(f'Attention dispatcher: active={prev[0].value} list={backends} target={attn} not found')
else:
log.debug(f'Attention dispatcher: active={prev[0].value} list={backends}')
+1
View File
@@ -208,6 +208,7 @@ try:
except Exception as e:
log.error(f'Loader: diffusers=={diffusers.__version__ if "diffusers" in sys.modules else None} {e}')
log.error('Please restart re-run the installer')
# errors.display(e, 'diffusers')
sys.exit(1)
try:
+3 -1
View File
@@ -197,7 +197,7 @@ def set_diffuser_options(sd_model, vae=None, op:str='model', offload:bool=True,
shared.opts.sdnq_use_quantized_matmul = False
if module.quantization_config.use_quantized_matmul != shared.opts.sdnq_use_quantized_matmul:
from modules.sdnq.loader import apply_sdnq_options_to_model
log.debug(f'Setting {op} {module_name}: sdnq_use_quantized_matmul={shared.opts.sdnq_use_quantized_matmul}')
# log.debug(f'Setting {op} {module_name}: sdnq_use_quantized_matmul={shared.opts.sdnq_use_quantized_matmul}')
module = apply_sdnq_options_to_model(module, use_quantized_matmul=shared.opts.sdnq_use_quantized_matmul)
setattr(sd_model, module_name, module)
@@ -968,6 +968,7 @@ def load_diffuser(checkpoint_info=None, op='model', revision=None): # pylint: di
prompt_parser_diffusers.cache.clear()
set_diffuser_options(sd_model, vae, op, offload=False)
attention.set_attention_dispatcher(sd_model)
sd_model = model_quant.do_post_load_quant(sd_model, allow=allow_post_quant) # run this before move model so it can be compressed in CPU
timer.load.record("options")
@@ -1018,6 +1019,7 @@ def load_diffuser(checkpoint_info=None, op='model', revision=None): # pylint: di
if shared.opts.diffusers_offload_mode != 'balanced':
devices.torch_gc(force=True, reason='load')
if sd_model is not None:
script_callbacks.model_loaded_callback(sd_model)
+3
View File
@@ -230,6 +230,9 @@ def create_settings(cmd_opts):
"xformers_options": OptionInfo(['Flash attention'], "xFormers options", gr.CheckboxGroup, {"choices": ['Flash attention'] }),
"dynamic_attention_slice_rate": OptionInfo(0.5, "Dynamic Attention slicing rate", gr.Slider, {"minimum": 0.01, "maximum": max(gpu_memory,4), "step": 0.01}),
"dynamic_attention_trigger_rate": OptionInfo(1, "Dynamic Attention trigger rate", gr.Slider, {"minimum": 0.01, "maximum": max(gpu_memory,4)*2, "step": 0.01}),
"hf_attention_sep": OptionInfo("<h2>Attention Dispatcher</h2>", "", gr.HTML),
"hf_attention": OptionInfo('', "Attention dispatcher kernel", gr.Textbox),
}))
# --- Server Settings ---