diff --git a/installer.py b/installer.py index 0aae1b9b8..b8c17f632 100644 --- a/installer.py +++ b/installer.py @@ -405,10 +405,14 @@ def check_torch(): log.debug(f'Torch allowed: cuda={allow_cuda} rocm={allow_rocm} ipex={allow_ipex} diml={allow_directml} openvino={allow_openvino}') torch_command = os.environ.get('TORCH_COMMAND', '') xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') + zluda_need_dll_patch = False def is_rocm_available(): if not allow_rocm: return False + if installed('torch-directml'): + log.debug('DirectML installation is detected. Skipping HIP SDK check.') + return False if platform.system() == 'Windows': hip_path = os.environ.get('HIP_PATH', None) return hip_path is not None and os.path.exists(os.path.join(hip_path, 'bin')) @@ -474,7 +478,15 @@ def check_torch(): except Exception as e: log.debug(f'ROCm hipconfig failed: {e}') rocm_ver = None - if not is_windows: # remove after PyTorch built with ROCm for Windows is launched + if args.use_zluda: # ZLUDA is available on both Linux and Windows + torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.2.0 torchvision --index-url https://download.pytorch.org/whl/cu118') + log.warning("Currently, ZLUDA support is experimental and unstable.") + zluda_need_dll_patch = is_windows and not installed('torch') + elif is_windows: # remove this check after PyTorch built with ROCm for Windows is released + log.warning("HIP SDK is detected, but there's no PyTorch release for Windows at this moment. If you are trying ZLUDA, please add '--use-zluda'.") + log.info('Using CPU-only torch') + torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') + else: if rocm_ver in {"5.7"}: torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}') elif rocm_ver in {"5.5", "5.6"}: @@ -484,9 +496,6 @@ def check_torch(): torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/rocm5.5') if rocm_ver is not None: install(os.environ.get('ONNXRUNTIME_PACKAGE', get_onnxruntime_source_for_rocm(arr)), "onnxruntime-training built with ROCm", ignore=True) - else: - log.info('Using CPU-only Torch') - torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') elif allow_ipex and (args.use_ipex or shutil.which('sycl-ls') is not None or shutil.which('sycl-ls.exe') is not None or os.environ.get('ONEAPI_ROOT') is not None or os.path.exists('/opt/intel/oneapi') or os.path.exists("C:/Program Files (x86)/Intel/oneAPI") or os.path.exists("C:/oneAPI")): args.use_ipex = True # pylint: disable=attribute-defined-outside-init @@ -539,11 +548,15 @@ def check_torch(): install(torch_command, 'torch torchvision') install('onnxruntime-directml', 'onnxruntime-directml', ignore=True) else: + if args.use_zluda: + log.warning("Failed to initialize ZLUDA. There's no HIP SDK found in PATH.") log.info('Using CPU-only Torch') torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') if 'torch' in torch_command and not args.version: log.debug(f'Installing torch: {torch_command}') install(torch_command, 'torch torchvision') + if zluda_need_dll_patch: + patch_dlls_for_zluda() else: try: import torch @@ -896,6 +909,31 @@ def get_onnxruntime_source_for_rocm(rocm_ver): return 'onnxruntime-gpu' +def patch_dlls_for_zluda(): + zluda_path = os.environ.get('ZLUDA', None) + if zluda_path is None: + paths = os.environ.get('PATH', '').split(';') + for path in paths: + if os.path.exists(os.path.join(path, 'zluda_redirect.dll')): + zluda_path = path + break + if zluda_path is None: + log.warning('Failed to automatically patch torch with ZLUDA. Could not find ZLUDA from PATH.') + return + venv_path = os.path.dirname(shutil.which('python')) + dlls_to_patch = { + 'cublas.dll': 'cublas64_11.dll', + 'cudnn.dll': 'cudnn64_8.dll', + 'cusparse.dll': 'cusparse64_11.dll', + 'nvrtc.dll': 'nvrtc64_112_0.dll', + } + try: + for k, v in dlls_to_patch.items(): + shutil.copyfile(os.path.join(zluda_path, k), os.path.join(venv_path, 'Lib', 'site-packages', 'torch', 'lib', v)) + except Exception as e: + log.warning(f'Failed to automatically patch torch with ZLUDA: {e}') + + # check version of the main repo and optionally upgrade it def check_version(offline=False, reset=True): # pylint: disable=unused-argument if args.skip_all: diff --git a/modules/cmd_args.py b/modules/cmd_args.py index 49025613c..dcec93c87 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -41,6 +41,7 @@ group.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), act group.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help="Disable queues, default: %(default)s") group.add_argument('--debug', default=os.environ.get("SD_DEBUG", False), action='store_true', help = "Run installer with debug logging, default: %(default)s") group.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML", False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s") +group.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s") group.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO", False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s") group.add_argument("--use-ipex", default=os.environ.get("SD_USEIPX", False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s") group.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA", False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s") diff --git a/modules/shared.py b/modules/shared.py index 526d27731..f07c079b5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -407,9 +407,6 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "olive_vae_encoder_float32": OptionInfo(False, 'Olive force FP32 for VAE Encoder'), "olive_static_dims": OptionInfo(True, 'Olive use static dimensions'), "olive_cache_optimized": OptionInfo(True, 'Olive cache optimized models'), - - "zluda_sep": OptionInfo("

ZLUDA

(experimental)", "", gr.HTML, {"visible": devices.backend == "cuda"}), - "zluda_enable_cudnn": OptionInfo(False, 'ZLUDA enable cuDNN (restart required)', gr.Checkbox, {"visible": devices.backend == "cuda"}), })) options_templates.update(options_section(('advanced', "Inference Settings"), { diff --git a/modules/zluda.py b/modules/zluda.py index 795ea1f3e..6eb6f06bc 100644 --- a/modules/zluda.py +++ b/modules/zluda.py @@ -3,13 +3,29 @@ import torch from modules import shared, devices +def test(device: torch.device): + try: + ten1 = torch.randn((2, 4,), device=device) + ten2 = torch.randn((4, 8,), device=device) + out = torch.mm(ten1, ten2) + return out.sum().is_nonzero() + except Exception: + return False + + def initialize_zluda(): - if platform.system() == "Windows" and devices.cuda_ok and torch.cuda.get_device_name(devices.get_optimal_device()).endswith("[ZLUDA]"): - shared.log.warning("Detected ZLUDA device. Currently, ZLUDA support is experimental and unstable.") - torch.backends.cudnn.enabled = shared.opts.zluda_enable_cudnn - if torch.backends.cudnn.enabled: - shared.log.warning("cuDNN with ZLUDA won't work at this moment. Please wait for future update.") + device = devices.get_optimal_device() + if platform.system() == "Windows" and devices.cuda_ok and torch.cuda.get_device_name(device).endswith("[ZLUDA]"): + torch.backends.cudnn.enabled = False torch.backends.cuda.enable_flash_sdp(False) torch.backends.cuda.enable_math_sdp(True) torch.backends.cuda.enable_mem_efficient_sdp(False) shared.opts.sdp_options = ['Math attention'] + devices.device_codeformer = devices.cpu + + if not test(device): + shared.log.error(f'ZLUDA device failed to pass basic operation test: index={device.index}, device_name={torch.cuda.get_device_name(device)}') + torch.cuda.is_available = lambda: False + devices.cuda_ok = False + devices.backend = 'cpu' + devices.device = devices.device_esrgan = devices.device_gfpgan = devices.device_interrogate = devices.cpu