diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index f16c9e522..c5fbfc31d 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit f16c9e5221bcf9490f5fd93ff0d38027a14bc4d6 +Subproject commit c5fbfc31d002ff83bc692e1f24b7b1c9183dbe72 diff --git a/extensions-builtin/seed_travel b/extensions-builtin/seed_travel index 1a97ebb43..ffe0553c5 160000 --- a/extensions-builtin/seed_travel +++ b/extensions-builtin/seed_travel @@ -1 +1 @@ -Subproject commit 1a97ebb43428b43c41001cfe79e50b468126d99f +Subproject commit ffe0553c59e91067ebf1e4fc7ad85ca9c870bf57 diff --git a/modules/dml/__init__.py b/modules/dml/__init__.py new file mode 100644 index 000000000..fbda39384 --- /dev/null +++ b/modules/dml/__init__.py @@ -0,0 +1,32 @@ +import torch +import torch_directml + +import modules.dml.kdiffusion +import modules.dml.stablediffusion +import modules.dml.torch + +from optimizer.unknown import UnknownOptimizer + +class DirectML(): + def get_optimizer(self, device: torch.device): + assert(device.type == 'privateuseone') + try: + device_name = torch_directml.device_name(device.index) + if 'NVIDIA' in device_name or 'GeForce' in device_name: + from optimizer.nvidia import nVidiaOptimizer as optimizer + elif 'AMD' in device_name or 'Radeon' in device_name: + from optimizer.amd import AMDOptimizer as optimizer + elif 'Intel' in device_name: + from optimizer.intel import IntelOptimizer as optimizer + else: + return UnknownOptimizer + return optimizer + except: + return UnknownOptimizer + + def memory_stats(self, device: torch.device): + optimizer = self.get_optimizer(device) + return optimizer.memory_stats(device.index) + +# Alternative of torch.cuda for DirectML. +torch.dml = DirectML diff --git a/modules/dml_specific.py b/modules/dml/kdiffusion.py similarity index 52% rename from modules/dml_specific.py rename to modules/dml/kdiffusion.py index e8503d745..2eced885f 100644 --- a/modules/dml_specific.py +++ b/modules/dml/kdiffusion.py @@ -2,9 +2,6 @@ import torch from tqdm.auto import tqdm from modules.shared import device -from modules.sd_hijack_utils import CondFunc - -# k-diffusion from k_diffusion import sampling def dpm_solver_adaptive(self, x, t_start, t_end, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None): @@ -89,88 +86,4 @@ def sample_dpm_adaptive(model, x, sigma_min, sigma_max, extra_args=None, callbac sampling.DPMSolver.dpm_solver_adaptive = dpm_solver_adaptive sampling.sample_dpm_fast = sample_dpm_fast -sampling.sample_dpm_adaptive = sample_dpm_adaptive - -# stablediffusion -from ldm.models.diffusion.ddim import DDIMSampler -from ldm.modules.diffusionmodules.util import noise_like - -@torch.no_grad() -def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False, - temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None, - unconditional_guidance_scale=1., unconditional_conditioning=None, - dynamic_threshold=None): - b, *_, device = *x.shape, x.device - - if unconditional_conditioning is None or unconditional_guidance_scale == 1.: - model_output = self.model.apply_model(x, t, c) - else: - x_in = torch.cat([x] * 2) - t_in = torch.cat([t] * 2) - if isinstance(c, dict): - assert isinstance(unconditional_conditioning, dict) - c_in = dict() - for k in c: - if isinstance(c[k], list): - c_in[k] = [torch.cat([ - unconditional_conditioning[k][i], - c[k][i]]) for i in range(len(c[k]))] - else: - c_in[k] = torch.cat([ - unconditional_conditioning[k], - c[k]]) - elif isinstance(c, list): - c_in = list() - assert isinstance(unconditional_conditioning, list) - for i in range(len(c)): - c_in.append(torch.cat([unconditional_conditioning[i], c[i]])) - else: - c_in = torch.cat([unconditional_conditioning, c]) - model_uncond, model_t = self.model.apply_model(x_in, t_in, c_in).chunk(2) - model_output = model_uncond + unconditional_guidance_scale * (model_t - model_uncond) - - if self.model.parameterization == "v": - e_t = self.model.predict_eps_from_z_and_v(x, t, model_output) - else: - e_t = model_output - - if score_corrector is not None: - assert self.model.parameterization == "eps", 'not implemented' - e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs) - - alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas - alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev - sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas - sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas - # select parameters corresponding to the currently considered timestep - print(alphas[index]) # DML Solution: DDIM Sampling does not work without this print. - a_t = torch.full((b, 1, 1, 1), alphas[index], device=device) - a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device) - sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device) - sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device) - - # current prediction for x_0 - if self.model.parameterization != "v": - pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt() - else: - pred_x0 = self.model.predict_start_from_z_and_v(x, t, model_output) - - if quantize_denoised: - pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0) - - if dynamic_threshold is not None: - raise NotImplementedError() - - # direction pointing to x_t - dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t - noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature - if noise_dropout > 0.: - noise = torch.nn.functional.dropout(noise, p=noise_dropout) - x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise - return x_prev, pred_x0 - -DDIMSampler.p_sample_ddim = p_sample_ddim - -# torch - -CondFunc('torchsde._brownian.brownian_interval._randn', lambda _, size, dtype, device, seed: torch.randn(size, dtype=dtype, device=torch.device("cpu"), generator=torch.Generator(torch.device("cpu")).manual_seed(int(seed))).to(device), lambda _, size, dtype, device, seed: device.type == 'privateuseone') +sampling.sample_dpm_adaptive = sample_dpm_adaptive \ No newline at end of file diff --git a/modules/dml/optimizer/amd/__init__.py b/modules/dml/optimizer/amd/__init__.py new file mode 100644 index 000000000..37ea3ea91 --- /dev/null +++ b/modules/dml/optimizer/amd/__init__.py @@ -0,0 +1,7 @@ +from modules.dml.optimizer.optimizer import Optimizer +from driver.atiadlxx import ATIADLxx + +class AMDOptimizer(Optimizer): + driver: ATIADLxx = ATIADLxx() + def memory_stats(self, index): + return (AMDOptimizer.driver.iHyperMemorySize, AMDOptimizer.driver.get_dedicated_vram_usage(index)) diff --git a/modules/dml/optimizer/amd/driver/atiadlxx.py b/modules/dml/optimizer/amd/driver/atiadlxx.py new file mode 100644 index 000000000..abb5eca96 --- /dev/null +++ b/modules/dml/optimizer/amd/driver/atiadlxx.py @@ -0,0 +1,43 @@ +import ctypes as C +from .atiadlxx_apis import * +from .atiadlxx_structures import * +from .atiadlxx_defines import * + +class ATIADLxx(object): + iHyperMemorySize = 0 + + def __init__(self): + self.context = ADL_CONTEXT_HANDLE() + ADL2_Main_Control_Create(ADL_Main_Memory_Alloc, 1, C.byref(self.context)) + num_adapters = C.c_int(-1) + ADL2_Adapter_NumberOfAdapters_Get(self.context, C.byref(num_adapters)) + AdapterInfoArray = (AdapterInfo * num_adapters.value)() + ADL2_Adapter_AdapterInfo_Get(self.context, C.cast(AdapterInfoArray, LPAdapterInfo), C.sizeof(AdapterInfoArray)) + self.devices = [] + for adapter in AdapterInfoArray: + self.devices.append(adapter) + self.iHyperMemorySize = self.get_memory_info2(0).iHyperMemorySize + + def get_memory_info2(self, adapterIndex: int) -> ADLMemoryInfo2: + info = ADLMemoryInfo2() + + if ADL2_Adapter_MemoryInfo2_Get(self.context, adapterIndex, C.byref(info)) != ADL_OK: + raise RuntimeError("ADL2: Failed to get MemoryInfo2") + + return info + + def get_dedicated_vram_usage(self, index: int) -> int: + usage = C.c_int(-1) + + if ADL2_Adapter_DedicatedVRAMUsage_Get(self.context, self.devices[index].iAdapterIndex, C.byref(usage)) != ADL_OK: + raise RuntimeError("ADL2: Failed to get DedicatedVRAMUsage") + + return usage.value + + def get_vram_usage(self, index: int) -> int: + usage = C.c_int(-1) + + if ADL2_Adapter_VRAMUsage_Get(self.context, self.devices[index].iAdapterIndex, C.byref(usage)) != ADL_OK: + raise RuntimeError("ADL2: Failed to get VRAMUsage") + + return usage.value diff --git a/modules/dml/optimizer/amd/driver/atiadlxx_apis.py b/modules/dml/optimizer/amd/driver/atiadlxx_apis.py new file mode 100644 index 000000000..23b7da3b1 --- /dev/null +++ b/modules/dml/optimizer/amd/driver/atiadlxx_apis.py @@ -0,0 +1,50 @@ +import ctypes as C +import platform +from .atiadlxx_structures import * + +_platform = platform.system() + +try: + if _platform == "Windows": + atiadlxx = C.WinDLL("atiadlxx.dll") + + ADL_MAIN_MALLOC_CALLBACK = C.CFUNCTYPE(C.c_void_p, C.c_int) + ADL_MAIN_FREE_CALLBACK = C.CFUNCTYPE(None, C.POINTER(C.c_void_p)) + + @ADL_MAIN_MALLOC_CALLBACK + def ADL_Main_Memory_Alloc(iSize): + return C._malloc(iSize) + + @ADL_MAIN_FREE_CALLBACK + def ADL_Main_Memory_Free(lpBuffer): + if lpBuffer[0] is not None: + C._free(lpBuffer[0]) + lpBuffer[0] = None + + ADL2_Main_Control_Create = atiadlxx.ADL2_Main_Control_Create + ADL2_Main_Control_Create.restype = C.c_int + ADL2_Main_Control_Create.argtypes = [ADL_MAIN_MALLOC_CALLBACK, C.c_int, ADL_CONTEXT_HANDLE] + + ADL2_Adapter_NumberOfAdapters_Get = atiadlxx.ADL2_Adapter_NumberOfAdapters_Get + ADL2_Adapter_NumberOfAdapters_Get.restype = C.c_int + ADL2_Adapter_NumberOfAdapters_Get.argtypes = [ADL_CONTEXT_HANDLE, C.POINTER(C.c_int)] + + ADL2_Adapter_AdapterInfo_Get = atiadlxx.ADL2_Adapter_AdapterInfo_Get + ADL2_Adapter_AdapterInfo_Get.restype = C.c_int + ADL2_Adapter_AdapterInfo_Get.argtypes = [ADL_CONTEXT_HANDLE, LPAdapterInfo, C.c_int] + + ADL2_Adapter_MemoryInfo2_Get = atiadlxx.ADL2_Adapter_MemoryInfo2_Get + ADL2_Adapter_MemoryInfo2_Get.restype = C.c_int + ADL2_Adapter_MemoryInfo2_Get.argtypes = [ADL_CONTEXT_HANDLE, C.c_int, C.POINTER(ADLMemoryInfo2)] + + ADL2_Adapter_DedicatedVRAMUsage_Get = atiadlxx.ADL2_Adapter_DedicatedVRAMUsage_Get + ADL2_Adapter_DedicatedVRAMUsage_Get.restype = C.c_int + ADL2_Adapter_DedicatedVRAMUsage_Get.argtypes = [ADL_CONTEXT_HANDLE, C.c_int, C.POINTER(C.c_int)] + + ADL2_Adapter_VRAMUsage_Get = atiadlxx.ADL2_Adapter_VRAMUsage_Get + ADL2_Adapter_VRAMUsage_Get.restype = C.c_int + ADL2_Adapter_VRAMUsage_Get.argtypes = [ADL_CONTEXT_HANDLE, C.c_int, C.POINTER(C.c_int)] + else: + print("Warning: experimental graphic memory optimization for AMDGPU is disabled. Because this is not Windows platform.") +except FileNotFoundError: + print("Warning: memory optimization for AMDGPU is disabled. Because couldn't find 'atiadlxx.dll'. Please install GPU driver downloaded from AMD.com.") \ No newline at end of file diff --git a/modules/dml/optimizer/amd/driver/atiadlxx_defines.py b/modules/dml/optimizer/amd/driver/atiadlxx_defines.py new file mode 100644 index 000000000..c242b9819 --- /dev/null +++ b/modules/dml/optimizer/amd/driver/atiadlxx_defines.py @@ -0,0 +1 @@ +ADL_OK = 0 \ No newline at end of file diff --git a/modules/dml/optimizer/amd/driver/atiadlxx_structures.py b/modules/dml/optimizer/amd/driver/atiadlxx_structures.py new file mode 100644 index 000000000..a68392ec4 --- /dev/null +++ b/modules/dml/optimizer/amd/driver/atiadlxx_structures.py @@ -0,0 +1,87 @@ +import ctypes as C + +class _ADLPMActivity(C.Structure): + __slot__ = [ + 'iActivityPercent', + 'iCurrentBusLanes', + 'iCurrentBusSpeed', + 'iCurrentPerformanceLevel', + 'iEngineClock', + 'iMaximumBusLanes', + 'iMemoryClock', + 'iReserved', + 'iSize', + 'iVddc', + ] +_ADLPMActivity._fields_ = [ + ('iActivityPercent', C.c_int), + ('iCurrentBusLanes', C.c_int), + ('iCurrentBusSpeed', C.c_int), + ('iCurrentPerformanceLevel', C.c_int), + ('iEngineClock', C.c_int), + ('iMaximumBusLanes', C.c_int), + ('iMemoryClock', C.c_int), + ('iReserved', C.c_int), + ('iSize', C.c_int), + ('iVddc', C.c_int), +] +ADLPMActivity = _ADLPMActivity + +class _ADLMemoryInfo2(C.Structure): + __slot__ = [ + 'iHyperMemorySize', + 'iInvisibleMemorySize', + 'iMemoryBandwidth', + 'iMemorySize', + 'iVisibleMemorySize', + 'strMemoryType' + ] +_ADLMemoryInfo2._fields_ = [ + ('iHyperMemorySize', C.c_longlong), + ('iInvisibleMemorySize', C.c_longlong), + ('iMemoryBandwidth', C.c_longlong), + ('iMemorySize', C.c_longlong), + ('iVisibleMemorySize', C.c_longlong), + ('strMemoryType', C.c_char * 256) +] +ADLMemoryInfo2 = _ADLMemoryInfo2 + +class _AdapterInfo(C.Structure): + __slot__ = [ + 'iSize', + 'iAdapterIndex', + 'strUDID', + 'iBusNumber', + 'iDeviceNumber', + 'iFunctionNumber', + 'iVendorID', + 'strAdapterName', + 'strDisplayName', + 'iPresent', + 'iExist', + 'strDriverPath', + 'strDriverPathExt', + 'strPNPString', + 'iOSDisplayIndex', + ] +_AdapterInfo._fields_ = [ + ('iSize', C.c_int), + ('iAdapterIndex', C.c_int), + ('strUDID', C.c_char * 256), + ('iBusNumber', C.c_int), + ('iDeviceNumber', C.c_int), + ('iFunctionNumber', C.c_int), + ('iVendorID', C.c_int), + ('strAdapterName', C.c_char * 256), + ('strDisplayName', C.c_char * 256), + ('iPresent', C.c_int), + ('iExist', C.c_int), + ('strDriverPath', C.c_char * 256), + ('strDriverPathExt', C.c_char * 256), + ('strPNPString', C.c_char * 256), + ('iOSDisplayIndex', C.c_int) +] +AdapterInfo = _AdapterInfo +LPAdapterInfo = C.POINTER(_AdapterInfo) + +ADL_CONTEXT_HANDLE = C.c_void_p \ No newline at end of file diff --git a/modules/dml/optimizer/amd/memory.py b/modules/dml/optimizer/amd/memory.py new file mode 100644 index 000000000..e69de29bb diff --git a/modules/dml/optimizer/intel/__init__.py b/modules/dml/optimizer/intel/__init__.py new file mode 100644 index 000000000..d17cd59d2 --- /dev/null +++ b/modules/dml/optimizer/intel/__init__.py @@ -0,0 +1,7 @@ +from modules.dml.optimizer.optimizer import Optimizer + +class IntelOptimizer(Optimizer): + def memory_stats(): + raise NotImplementedError() + # DML TODO: Implement + return diff --git a/modules/dml/optimizer/nvidia/__init__.py b/modules/dml/optimizer/nvidia/__init__.py new file mode 100644 index 000000000..d467e8ae5 --- /dev/null +++ b/modules/dml/optimizer/nvidia/__init__.py @@ -0,0 +1,7 @@ +from modules.dml.optimizer.optimizer import Optimizer + +class nVidiaOptimizer(Optimizer): + def memory_stats(): + raise NotImplementedError() + # DML TODO: Implement + return diff --git a/modules/dml/optimizer/optimizer.py b/modules/dml/optimizer/optimizer.py new file mode 100644 index 000000000..2b2d9ed64 --- /dev/null +++ b/modules/dml/optimizer/optimizer.py @@ -0,0 +1,8 @@ +from abc import * +from typing import * + +class Optimizer(metaclass=ABCMeta): + driver: Any = None + @abstractmethod + def memory_stats(self, index: int) -> Tuple[int, int]: + pass diff --git a/modules/dml/optimizer/unknown/__init__.py b/modules/dml/optimizer/unknown/__init__.py new file mode 100644 index 000000000..f2fbc2ae2 --- /dev/null +++ b/modules/dml/optimizer/unknown/__init__.py @@ -0,0 +1,6 @@ +from modules.dml.optimizer.optimizer import Optimizer + +class UnknownOptimizer(Optimizer): + def memory_stats(): + # DML TODO: Implement + return (1073741824, 0) diff --git a/modules/dml/stablediffusion.py b/modules/dml/stablediffusion.py new file mode 100644 index 000000000..cbc4b85fb --- /dev/null +++ b/modules/dml/stablediffusion.py @@ -0,0 +1,80 @@ +import torch + +from ldm.models.diffusion.ddim import DDIMSampler +from ldm.modules.diffusionmodules.util import noise_like + +@torch.no_grad() +def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False, + temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None, + unconditional_guidance_scale=1., unconditional_conditioning=None, + dynamic_threshold=None): + b, *_, device = *x.shape, x.device + + if unconditional_conditioning is None or unconditional_guidance_scale == 1.: + model_output = self.model.apply_model(x, t, c) + else: + x_in = torch.cat([x] * 2) + t_in = torch.cat([t] * 2) + if isinstance(c, dict): + assert isinstance(unconditional_conditioning, dict) + c_in = dict() + for k in c: + if isinstance(c[k], list): + c_in[k] = [torch.cat([ + unconditional_conditioning[k][i], + c[k][i]]) for i in range(len(c[k]))] + else: + c_in[k] = torch.cat([ + unconditional_conditioning[k], + c[k]]) + elif isinstance(c, list): + c_in = list() + assert isinstance(unconditional_conditioning, list) + for i in range(len(c)): + c_in.append(torch.cat([unconditional_conditioning[i], c[i]])) + else: + c_in = torch.cat([unconditional_conditioning, c]) + model_uncond, model_t = self.model.apply_model(x_in, t_in, c_in).chunk(2) + model_output = model_uncond + unconditional_guidance_scale * (model_t - model_uncond) + + if self.model.parameterization == "v": + e_t = self.model.predict_eps_from_z_and_v(x, t, model_output) + else: + e_t = model_output + + if score_corrector is not None: + assert self.model.parameterization == "eps", 'not implemented' + e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs) + + alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas + alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev + sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas + sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas + # select parameters corresponding to the currently considered timestep + print(alphas[index]) # DML Solution: DDIM Sampling does not work without this print. + a_t = torch.full((b, 1, 1, 1), alphas[index], device=device) + a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device) + sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device) + sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device) + + # current prediction for x_0 + if self.model.parameterization != "v": + pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt() + else: + pred_x0 = self.model.predict_start_from_z_and_v(x, t, model_output) + + if quantize_denoised: + pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0) + + if dynamic_threshold is not None: + raise NotImplementedError() + + # direction pointing to x_t + dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t + noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature + if noise_dropout > 0.: + noise = torch.nn.functional.dropout(noise, p=noise_dropout) + x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise + return x_prev, pred_x0 + +DDIMSampler.p_sample_ddim = p_sample_ddim diff --git a/modules/dml/torch.py b/modules/dml/torch.py new file mode 100644 index 000000000..04e777258 --- /dev/null +++ b/modules/dml/torch.py @@ -0,0 +1,5 @@ +import torch + +from modules.sd_hijack_utils import CondFunc + +CondFunc('torchsde._brownian.brownian_interval._randn', lambda _, size, dtype, device, seed: torch.randn(size, dtype=dtype, device=torch.device("cpu"), generator=torch.Generator(torch.device("cpu")).manual_seed(int(seed))).to(device), lambda _, size, dtype, device, seed: device.type == 'privateuseone') diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 7e1ba79b3..79b8e3b47 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -20,6 +20,9 @@ if shared.opts.cross_attention_optimization == "xFormers": except Exception: pass +if shared.device.type == 'privateuseone': + import dml + def get_available_vram(): if shared.device.type == 'cuda': @@ -31,8 +34,8 @@ def get_available_vram(): mem_free_total = mem_free_cuda + mem_free_torch return mem_free_total elif shared.device.type == 'privateuseone': - # DML ISSUE: There's no way to get any memory info. - return 1073741824 + mem_total, mem_active = torch.dml.memory_stats(shared.device) + return mem_total - mem_active * (1 << 20) else: return psutil.virtual_memory().available @@ -199,8 +202,9 @@ def einsum_op_cuda(q, k, v): return einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20)) def einsum_op_dml(q, k, v): - # DML ISSUE: There's no way to get any memory info. - return einsum_op_tensor_mem(q, k, v, 1073741824) + mem_total, mem_active = devices.adl.memory_stats() + mem_reserved = mem_total / (1 << 20) * 0.7 + return einsum_op_tensor_mem(q, k, v, (mem_reserved - mem_active) if mem_reserved > mem_active else 1) def einsum_op(q, k, v): if q.device.type == 'cuda': diff --git a/modules/shared.py b/modules/shared.py index 34748c0b9..08ff22cfa 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -64,7 +64,7 @@ clip_model = None if device.type == 'privateuseone': - import modules.dml_specific + import modules.dml is_device_dml = True @@ -429,7 +429,7 @@ options_templates.update(options_section(('ui', "Live previews"), { "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("Approx NN", "Image creation progress preview mode", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap"]}), # DML ISSUE: Approx NN does not work well on DirectML device. + "show_progress_type": OptionInfo("Approx cheap" if is_device_dml else "Approx NN", "Image creation progress preview mode", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap"]}), # DML Solution: Use Approx cheap instead of Approx NN as a default progress type. "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/wiki b/wiki index 066ea609f..12603bcde 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 066ea609f6a2630bceb07c679142d83a41a6db0f +Subproject commit 12603bcdec55df780b18612d58b6d0dcd4c27f96