| import logging |
| import os |
| from pathlib import Path |
| from typing import Dict, Iterable, Iterator |
|
|
| import torch |
|
|
| from bitsandbytes.cextension import get_cuda_bnb_library_path |
| from bitsandbytes.consts import NONPYTORCH_DOC_URL |
| from bitsandbytes.cuda_specs import CUDASpecs |
| from bitsandbytes.diagnostics.utils import print_dedented |
|
|
| CUDART_PATH_PREFERRED_ENVVARS = ("CONDA_PREFIX", "LD_LIBRARY_PATH") |
|
|
| CUDART_PATH_IGNORED_ENVVARS = { |
| "DBUS_SESSION_BUS_ADDRESS", |
| "GOOGLE_VM_CONFIG_LOCK_FILE", |
| "HOME", |
| "LESSCLOSE", |
| "LESSOPEN", |
| "MAIL", |
| "OLDPWD", |
| "PATH", |
| "PWD", |
| "SHELL", |
| "SSH_AUTH_SOCK", |
| "SSH_TTY", |
| "TMUX", |
| "XDG_DATA_DIRS", |
| "XDG_GREETER_DATA_DIR", |
| "XDG_RUNTIME_DIR", |
| "_", |
| } |
|
|
| CUDA_RUNTIME_LIB_PATTERNS = ( |
| "cudart64*.dll", |
| "libcudart*.so*", |
| "nvcuda*.dll", |
| ) |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| def find_cuda_libraries_in_path_list(paths_list_candidate: str) -> Iterable[Path]: |
| for dir_string in paths_list_candidate.split(os.pathsep): |
| if not dir_string: |
| continue |
| if os.sep not in dir_string: |
| continue |
| try: |
| dir = Path(dir_string) |
| try: |
| if not dir.exists(): |
| logger.warning(f"The directory listed in your path is found to be non-existent: {dir}") |
| continue |
| except OSError: |
| pass |
| for lib_pattern in CUDA_RUNTIME_LIB_PATTERNS: |
| for pth in dir.glob(lib_pattern): |
| if pth.is_file(): |
| yield pth |
| except (OSError, PermissionError): |
| pass |
|
|
|
|
| def is_relevant_candidate_env_var(env_var: str, value: str) -> bool: |
| return ( |
| env_var in CUDART_PATH_PREFERRED_ENVVARS |
| or ( |
| os.sep in value |
| and env_var not in CUDART_PATH_IGNORED_ENVVARS |
| and "CONDA" not in env_var |
| and "BASH_FUNC" not in env_var |
| and "\n" not in value |
| ) |
| ) |
|
|
|
|
| def get_potentially_lib_path_containing_env_vars() -> Dict[str, str]: |
| return {env_var: value for env_var, value in os.environ.items() if is_relevant_candidate_env_var(env_var, value)} |
|
|
|
|
| def find_cudart_libraries() -> Iterator[Path]: |
| """ |
| Searches for a cuda installations, in the following order of priority: |
| 1. active conda env |
| 2. LD_LIBRARY_PATH |
| 3. any other env vars, while ignoring those that |
| - are known to be unrelated |
| - don't contain the path separator `/` |
| |
| If multiple libraries are found in part 3, we optimistically try one, |
| while giving a warning message. |
| """ |
| candidate_env_vars = get_potentially_lib_path_containing_env_vars() |
|
|
| for envvar in CUDART_PATH_PREFERRED_ENVVARS: |
| if envvar in candidate_env_vars: |
| directory = candidate_env_vars[envvar] |
| yield from find_cuda_libraries_in_path_list(directory) |
| candidate_env_vars.pop(envvar) |
|
|
| for env_var, value in candidate_env_vars.items(): |
| yield from find_cuda_libraries_in_path_list(value) |
|
|
|
|
| def print_cuda_diagnostics(cuda_specs: CUDASpecs) -> None: |
| print( |
| f"PyTorch settings found: CUDA_VERSION={cuda_specs.cuda_version_string}, " |
| f"Highest Compute Capability: {cuda_specs.highest_compute_capability}.", |
| ) |
|
|
| binary_path = get_cuda_bnb_library_path(cuda_specs) |
| if not binary_path.exists(): |
| print_dedented( |
| f""" |
| Library not found: {binary_path}. Maybe you need to compile it from source? |
| If you compiled from source, try again with `make CUDA_VERSION=DETECTED_CUDA_VERSION`, |
| for example, `make CUDA_VERSION=113`. |
| |
| The CUDA version for the compile might depend on your conda install, if using conda. |
| Inspect CUDA version via `conda list | grep cuda`. |
| """, |
| ) |
|
|
| cuda_major, cuda_minor = cuda_specs.cuda_version_tuple |
| if cuda_major < 11: |
| print_dedented( |
| """ |
| WARNING: CUDA versions lower than 11 are currently not supported for LLM.int8(). |
| You will be only to use 8-bit optimizers and quantization routines! |
| """, |
| ) |
|
|
| print(f"To manually override the PyTorch CUDA version please see: {NONPYTORCH_DOC_URL}") |
|
|
| |
| if not cuda_specs.has_cublaslt: |
| print_dedented( |
| """ |
| WARNING: Compute capability < 7.5 detected! Only slow 8-bit matmul is supported for your GPU! |
| If you run into issues with 8-bit matmul, you can try 4-bit quantization: |
| https://huggingface.co/blog/4bit-transformers-bitsandbytes |
| """, |
| ) |
|
|
| |
| |
| |
|
|
|
|
| def print_cuda_runtime_diagnostics() -> None: |
| cudart_paths = list(find_cudart_libraries()) |
| if not cudart_paths: |
| print("CUDA SETUP: WARNING! CUDA runtime files not found in any environmental path.") |
| elif len(cudart_paths) > 1: |
| print_dedented( |
| f""" |
| Found duplicate CUDA runtime files (see below). |
| |
| We select the PyTorch default CUDA runtime, which is {torch.version.cuda}, |
| but this might mismatch with the CUDA version that is needed for bitsandbytes. |
| To override this behavior set the `BNB_CUDA_VERSION=<version string, e.g. 122>` environmental variable. |
| |
| For example, if you want to use the CUDA version 122, |
| BNB_CUDA_VERSION=122 python ... |
| |
| OR set the environmental variable in your .bashrc: |
| export BNB_CUDA_VERSION=122 |
| |
| In the case of a manual override, make sure you set LD_LIBRARY_PATH, e.g. |
| export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-11.2, |
| """, |
| ) |
| for pth in cudart_paths: |
| print(f"* Found CUDA runtime at: {pth}") |
|
|