From 9d855091bf21a376e9478d6f3324c6056ef27c23 Mon Sep 17 00:00:00 2001 From: Kohya S Date: Fri, 4 Aug 2023 22:29:14 +0900 Subject: [PATCH] make bitsandbytes optional --- README.md | 80 ++-- bitsandbytes_windows/libbitsandbytes_cpu.dll | Bin 91648 -> 76288 bytes bitsandbytes_windows/main.py | 466 +++---------------- library/train_util.py | 1 + requirements.txt | 2 +- sdxl_minimal_inference.py | 2 +- 6 files changed, 125 insertions(+), 426 deletions(-) diff --git a/README.md b/README.md index e36cfeae4..017f4853a 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,17 @@ __Stable Diffusion web UI now seems to support LoRA trained by ``sd-scripts``.__ The feature of SDXL training is now available in sdxl branch as an experimental feature. +Aug 4, 2023: The feature will be merged into the main branch soon. Following are the changes from the previous version. + +- `bitsandbytes` is now optional. Please install it if you want to use it. The insructions are in the later section. +- `albumentations` is not required anymore. +- An issue for pooled output for Textual Inversion training is fixed. +- `--v_pred_like_loss ratio` option is added. This option adds the loss like v-prediction loss in SDXL training. `0.1` means that the loss is added 10% of the v-prediction loss. The default value is None (disabled). + - In v-prediction, the loss is higher in the early timesteps (near the noise). This option can be used to increase the loss in the early timesteps. +- Arbitrary options can be used for Diffusers' schedulers. For example `--lr_scheduler_args "lr_end=1e-8"`. +- `sdxl_gen_imgs.py` supports batch size > 1. +- Fix ControlNet to work with attention couple and reginal LoRA in `gen_img_diffusers.py`. + Summary of the feature: - `tools/cache_latents.py` is added. This script can be used to cache the latents to disk in advance. @@ -65,12 +76,17 @@ Summary of the feature: ### Tips for SDXL training - The default resolution of SDXL is 1024x1024. -- The fine-tuning can be done with 24GB GPU memory with the batch size of 1. For 24GB GPU, the following options are recommended: +- The fine-tuning can be done with 24GB GPU memory with the batch size of 1. For 24GB GPU, the following options are recommended __for the fine-tuning with 24GB GPU memory__: - Train U-Net only. - Use gradient checkpointing. - Use `--cache_text_encoder_outputs` option and caching latents. - Use Adafactor optimizer. RMSprop 8bit or Adagrad 8bit may work. AdamW 8bit doesn't seem to work. -- The LoRA training can be done with 12GB GPU memory. +- The LoRA training can be done with 8GB GPU memory (10GB recommended). For reducing the GPU memory usage, the following options are recommended: + - Train U-Net only. + - Use gradient checkpointing. + - Use `--cache_text_encoder_outputs` option and caching latents. + - Use one of 8bit optimizers or Adafactor optimizer. + - Use lower dim (-8 for 8GB GPU). - `--network_train_unet_only` option is highly recommended for SDXL LoRA. Because SDXL has two text encoders, the result of the training will be unexpected. - PyTorch 2 seems to use slightly less GPU memory than PyTorch 1. - `--bucket_reso_steps` can be set to 32 instead of the default value 64. Smaller values than 32 will not work for SDXL training. @@ -93,19 +109,11 @@ state_dict = {"clip_g": embs_for_text_encoder_1280, "clip_l": embs_for_text_enco save_file(state_dict, file) ``` -### TODO - -- [ ] Support conversion of Diffusers SDXL models. -- [ ] Support `--weighted_captions` option. -- [ ] Change `--output_config` option to continue the training. -- [ ] Extend `--full_bf16` for all the scripts. -- [x] Support Textual Inversion training. - ## About requirements.txt These files do not contain requirements for PyTorch. Because the versions of them depend on your environment. Please install PyTorch at first (see installation guide below.) -The scripts are tested with PyTorch 1.12.1 and 2.0.1, Diffusers 0.17.1. +The scripts are tested with PyTorch 1.12.1 and 2.0.1, Diffusers 0.18.2. ## Links to how-to-use documents @@ -151,13 +159,16 @@ pip install torch==1.12.1+cu116 torchvision==0.13.1+cu116 --extra-index-url http pip install --upgrade -r requirements.txt pip install -U -I --no-deps https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/f/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl -cp .\bitsandbytes_windows\*.dll .\venv\Lib\site-packages\bitsandbytes\ -cp .\bitsandbytes_windows\cextension.py .\venv\Lib\site-packages\bitsandbytes\cextension.py -cp .\bitsandbytes_windows\main.py .\venv\Lib\site-packages\bitsandbytes\cuda_setup\main.py - accelerate config ``` +__Note:__ Now bitsandbytes is optional. Please install any version of bitsandbytes as needed. Installation instructions are in the following section. + + Answers to accelerate config: ```txt @@ -190,10 +201,6 @@ pip install torch==2.0.1+cu118 torchvision==0.15.2+cu118 --index-url https://dow pip install --upgrade -r requirements.txt pip install xformers==0.0.20 -cp .\bitsandbytes_windows\*.dll .\venv\Lib\site-packages\bitsandbytes\ -cp .\bitsandbytes_windows\cextension.py .\venv\Lib\site-packages\bitsandbytes\cextension.py -cp .\bitsandbytes_windows\main.py .\venv\Lib\site-packages\bitsandbytes\cuda_setup\main.py - accelerate config ``` @@ -204,26 +211,43 @@ Answers to accelerate config should be the same as above. Other versions of PyTorch and xformers seem to have problems with training. If there is no other reason, please install the specified version. -### Optional: Use Lion8bit +### Optional: Use `bitsandbytes` (8bit optimizer) + +For 8bit optimizer, you need to install `bitsandbytes`. For Linux, please install `bitsandbytes` as usual (0.41.1 or later is recommended.) + +For Windows, there are several versions of `bitsandbytes`: + +- `bitsandbytes` 0.35.0: Stable version. AdamW8bit is available. `full_bf16` is not available. +- `bitsandbytes` 0.39.1: Lion8bit, PagedAdamW8bit and PagedLion8bit are available. `full_bf16` is available. + +Note: `bitsandbytes`above 0.35.0 till 0.41.0 seems to have an issue: https://github.com/TimDettmers/bitsandbytes/issues/659 -For Lion8bit, you need to upgrade `bitsandbytes` to 0.38.0 or later. Uninstall `bitsandbytes`, and for Windows, install the Windows version whl file from [here](https://github.com/jllllll/bitsandbytes-windows-webui) or other sources, like: +Follow the instructions below to install `bitsandbytes` for Windows. + +### bitsandbytes 0.35.0 for Windows + +Open a regular Powershell terminal and type the following inside: ```powershell -pip install https://github.com/jllllll/bitsandbytes-windows-webui/raw/main/bitsandbytes-0.38.1-py3-none-any.whl +cd sd-scripts +.\venv\Scripts\activate +pip install bitsandbytes==0.35.0 + +cp .\bitsandbytes_windows\*.dll .\venv\Lib\site-packages\bitsandbytes\ +cp .\bitsandbytes_windows\cextension.py .\venv\Lib\site-packages\bitsandbytes\cextension.py +cp .\bitsandbytes_windows\main.py .\venv\Lib\site-packages\bitsandbytes\cuda_setup\main.py ``` -For upgrading, upgrade this repo with `pip install .`, and upgrade necessary packages manually. +This will install `bitsandbytes` 0.35.0 and copy the necessary files to the `bitsandbytes` directory. -### Optional: Use PagedAdamW8bit and PagedLion8bit +### bitsandbytes 0.39.1 for Windows -For PagedAdamW8bit and PagedLion8bit, you need to upgrade `bitsandbytes` to 0.39.0 or later. Uninstall `bitsandbytes`, and for Windows, install the Windows version whl file from [here](https://github.com/jllllll/bitsandbytes-windows-webui) or other sources, like: +Install the Windows version whl file from [here](https://github.com/jllllll/bitsandbytes-windows-webui) or other sources, like: ```powershell -pip install https://github.com/jllllll/bitsandbytes-windows-webui/releases/download/wheels/bitsandbytes-0.39.1-py3-none-win_amd64.whl +pip install https://github.com/jllllll/bitsandbytes-windows-webui/raw/main/bitsandbytes-0.38.1-py3-none-any.whl ``` -For upgrading, upgrade this repo with `pip install .`, and upgrade necessary packages manually. - ## Upgrade When a new release comes out you can upgrade your repo with the following command: diff --git a/bitsandbytes_windows/libbitsandbytes_cpu.dll b/bitsandbytes_windows/libbitsandbytes_cpu.dll index 06d3226c46b4ec2d573d5f5b85f2a333cbd5699e..b733af475eb02eb04f5ad8cbf0530a78a58bc758 100644 GIT binary patch literal 76288 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 literal 91648 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 QQqzfeb{?`Fwjd_|51qOncK`qY diff --git a/bitsandbytes_windows/main.py b/bitsandbytes_windows/main.py index 50b48282e..380f85aec 100644 --- a/bitsandbytes_windows/main.py +++ b/bitsandbytes_windows/main.py @@ -4,7 +4,7 @@ [ ] TODO: Q - What if we have multiple GPUs of different makes? - CUDA version - Software: - - CPU-only: only CPU quantization functions (no optimizer, no matrix multipl) + - CPU-only: only CPU quantization functions (no optimizer, no matrix multiple) - CuBLAS-LT: full-build 8-bit optimizer - no CuBLAS-LT: no 8-bit matrix multiplication (`nomatmul`) @@ -16,367 +16,35 @@ - based on that set the default path """ -import ctypes as ct -import os -import errno -import torch -import platform -from warnings import warn -from itertools import product - -from pathlib import Path -from typing import Set, Union -from .env_vars import get_potentially_lib_path_containing_env_vars - -# these are the most common libs names -# libcudart.so is missing by default for a conda install with PyTorch 2.0 and instead -# we have libcudart.so.11.0 which causes a lot of errors before -# not sure if libcudart.so.12.0 exists in pytorch installs, but it does not hurt -CUDA_RUNTIME_LIBS: list = ["libcudart.so", 'libcudart.so.11.0', 'libcudart.so.12.0'] - -# this is a order list of backup paths to search CUDA in, if it cannot be found in the main environmental paths -backup_paths = [] - - -IS_WINDOWS_PLATFORM: bool = (platform.system()=="Windows") -PATH_COLLECTION_SEPARATOR: str = ":" if not IS_WINDOWS_PLATFORM else ";" -CUDA_RUNTIME_LIBS: list = ["libcudart.so", 'libcudart.so.11.0', 'libcudart.so.12.0'] if not IS_WINDOWS_PLATFORM else ["cudart64_110.dll", "cudart64_120.dll", "cudart64_12.dll"] -backup_paths.append('$CONDA_PREFIX/lib/libcudart.so.11.0' if not IS_WINDOWS_PLATFORM else '%CONDA_PREFIX%\\lib\\cudart64_110.dll') -CUDA_SHARED_LIB_NAME: str = "libcuda.so" if not IS_WINDOWS_PLATFORM else f"{os.environ['SystemRoot']}\\System32\\nvcuda.dll" -SHARED_LIB_EXTENSION: str = ".so" if not IS_WINDOWS_PLATFORM else ".dll" -class CUDASetup: - _instance = None - - def __init__(self): - raise RuntimeError("Call get_instance() instead") - - def generate_instructions(self): - if getattr(self, 'error', False): return - print(self.error) - self.error = True - if self.cuda is None: - self.add_log_entry('CUDA SETUP: Problem: The main issue seems to be that the main CUDA library was not detected.') - self.add_log_entry('CUDA SETUP: Solution 1): Your paths are probably not up-to-date. You can update them via: sudo ldconfig.') - self.add_log_entry('CUDA SETUP: Solution 2): If you do not have sudo rights, you can do the following:') - self.add_log_entry('CUDA SETUP: Solution 2a): Find the cuda library via: find / -name libcuda.so 2>/dev/null') - self.add_log_entry('CUDA SETUP: Solution 2b): Once the library is found add it to the LD_LIBRARY_PATH: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:FOUND_PATH_FROM_2a') - self.add_log_entry('CUDA SETUP: Solution 2c): For a permanent solution add the export from 2b into your .bashrc file, located at ~/.bashrc') - return - - if self.cudart_path is None: - self.add_log_entry('CUDA SETUP: Problem: The main issue seems to be that the main CUDA runtime library was not detected.') - self.add_log_entry('CUDA SETUP: Solution 1: To solve the issue the libcudart.so location needs to be added to the LD_LIBRARY_PATH variable') - self.add_log_entry('CUDA SETUP: Solution 1a): Find the cuda runtime library via: find / -name libcudart.so 2>/dev/null') - self.add_log_entry('CUDA SETUP: Solution 1b): Once the library is found add it to the LD_LIBRARY_PATH: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:FOUND_PATH_FROM_1a') - self.add_log_entry('CUDA SETUP: Solution 1c): For a permanent solution add the export from 1b into your .bashrc file, located at ~/.bashrc') - self.add_log_entry('CUDA SETUP: Solution 2: If no library was found in step 1a) you need to install CUDA.') - self.add_log_entry('CUDA SETUP: Solution 2a): Download CUDA install script: wget https://github.com/TimDettmers/bitsandbytes/blob/main/cuda_install.sh') - self.add_log_entry('CUDA SETUP: Solution 2b): Install desired CUDA version to desired location. The syntax is bash cuda_install.sh CUDA_VERSION PATH_TO_INSTALL_INTO.') - self.add_log_entry('CUDA SETUP: Solution 2b): For example, "bash cuda_install.sh 113 ~/local/" will download CUDA 11.3 and install into the folder ~/local') - return - - make_cmd = f'CUDA_VERSION={self.cuda_version_string}' - if len(self.cuda_version_string) < 3: - make_cmd += ' make cuda92' - elif self.cuda_version_string == '110': - make_cmd += ' make cuda110' - elif self.cuda_version_string[:2] == '11' and int(self.cuda_version_string[2]) > 0: - make_cmd += ' make cuda11x' - elif self.cuda_version_string == '100': - self.add_log_entry('CUDA SETUP: CUDA 10.0 not supported. Please use a different CUDA version.') - self.add_log_entry('CUDA SETUP: Before you try again running bitsandbytes, make sure old CUDA 10.0 versions are uninstalled and removed from $LD_LIBRARY_PATH variables.') - return - - - has_cublaslt = is_cublasLt_compatible(self.cc) - if not has_cublaslt: - make_cmd += '_nomatmul' - - self.add_log_entry('CUDA SETUP: Something unexpected happened. Please compile from source:') - self.add_log_entry('git clone git@github.com:TimDettmers/bitsandbytes.git') - self.add_log_entry('cd bitsandbytes') - self.add_log_entry(make_cmd) - self.add_log_entry('python setup.py install') - - def initialize(self): - if not getattr(self, 'initialized', False): - self.has_printed = False - self.lib = None - self.initialized = False - self.error = False - - def run_cuda_setup(self): - self.initialized = True - self.cuda_setup_log = [] - - binary_name, cudart_path, cuda, cc, cuda_version_string = evaluate_cuda_setup() - self.cudart_path = cudart_path - self.cuda = cuda - self.cc = cc - self.cuda_version_string = cuda_version_string - - package_dir = Path(__file__).parent.parent - binary_path = package_dir / binary_name - - print('bin', binary_path) - - try: - if not binary_path.exists(): - self.add_log_entry(f"CUDA SETUP: Required library version not found: {binary_name}. Maybe you need to compile it from source?") - legacy_binary_name = "libbitsandbytes_cpu" + SHARED_LIB_EXTENSION - self.add_log_entry(f"CUDA SETUP: Defaulting to {legacy_binary_name}...") - binary_path = package_dir / legacy_binary_name - if not binary_path.exists() or torch.cuda.is_available(): - self.add_log_entry('') - self.add_log_entry('='*48 + 'ERROR' + '='*37) - self.add_log_entry('CUDA SETUP: CUDA detection failed! Possible reasons:') - self.add_log_entry('1. CUDA driver not installed') - self.add_log_entry('2. CUDA not installed') - self.add_log_entry('3. You have multiple conflicting CUDA libraries') - self.add_log_entry('4. Required library not pre-compiled for this bitsandbytes release!') - self.add_log_entry('CUDA SETUP: If you compiled from source, try again with `make CUDA_VERSION=DETECTED_CUDA_VERSION` for example, `make CUDA_VERSION=113`.') - self.add_log_entry('CUDA SETUP: The CUDA version for the compile might depend on your conda install. Inspect CUDA version via `conda list | grep cuda`.') - self.add_log_entry('='*80) - self.add_log_entry('') - self.generate_instructions() - raise Exception('CUDA SETUP: Setup Failed!') - self.lib = ct.cdll.LoadLibrary(str(binary_path)) - else: - self.add_log_entry(f"CUDA SETUP: Loading binary {binary_path}...") - self.lib = ct.cdll.LoadLibrary(str(binary_path)) - except Exception as ex: - self.add_log_entry(str(ex)) - - def add_log_entry(self, msg, is_warning=False): - self.cuda_setup_log.append((msg, is_warning)) - - def print_log_stack(self): - for msg, is_warning in self.cuda_setup_log: - if is_warning: - warn(msg) - else: - print(msg) - - @classmethod - def get_instance(cls): - if cls._instance is None: - cls._instance = cls.__new__(cls) - cls._instance.initialize() - return cls._instance - - -def is_cublasLt_compatible(cc): - has_cublaslt = False - if cc is not None: - cc_major, cc_minor = cc.split('.') - if int(cc_major) < 7 or (int(cc_major) == 7 and int(cc_minor) < 5): - CUDASetup.get_instance().add_log_entry("WARNING: Compute capability < 7.5 detected! Only slow 8-bit matmul is supported for your GPU!", is_warning=True) - else: - has_cublaslt = True - return has_cublaslt - -def extract_candidate_paths(paths_list_candidate: str) -> Set[Path]: - return {Path(ld_path) for ld_path in paths_list_candidate.split(PATH_COLLECTION_SEPARATOR) if ld_path} - - -def remove_non_existent_dirs(candidate_paths: Set[Path]) -> Set[Path]: - existent_directories: Set[Path] = set() - for path in candidate_paths: - try: - if path.exists(): - existent_directories.add(path) - except OSError as exc: - if exc.errno != errno.ENAMETOOLONG: - raise exc - - non_existent_directories: Set[Path] = candidate_paths - existent_directories - if non_existent_directories: - CUDASetup.get_instance().add_log_entry("WARNING: The following directories listed in your path were found to " - f"be non-existent: {non_existent_directories}", is_warning=True) - - return existent_directories - - -def get_cuda_runtime_lib_paths(candidate_paths: Set[Path]) -> Set[Path]: - paths = set() - for libname in CUDA_RUNTIME_LIBS: - for path in candidate_paths: - if (path / libname).is_file(): - paths.add(path / libname) - return paths - - -def resolve_paths_list(paths_list_candidate: str) -> Set[Path]: - """ - Searches a given environmental var for the CUDA runtime library, - i.e. `libcudart.so`. - """ - return remove_non_existent_dirs(extract_candidate_paths(paths_list_candidate)) - - -def find_cuda_lib_in(paths_list_candidate: str) -> Set[Path]: - return get_cuda_runtime_lib_paths( - resolve_paths_list(paths_list_candidate) - ) - - -def warn_in_case_of_duplicates(results_paths: Set[Path]) -> None: - if len(results_paths) > 1: - warning_msg = ( - f"Found duplicate {CUDA_RUNTIME_LIBS} files: {results_paths}.. " - "We'll flip a coin and try one of these, in order to fail forward.\n" - "Either way, this might cause trouble in the future:\n" - "If you get `CUDA error: invalid device function` errors, the above " - "might be the cause and the solution is to make sure only one " - f"{CUDA_RUNTIME_LIBS} in the paths that we search based on your env.") - CUDASetup.get_instance().add_log_entry(warning_msg, is_warning=True) - - -def determine_cuda_runtime_lib_path() -> Union[Path, None]: - """ - 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 (see `bnb.cuda_setup.env_vars.to_be_ignored`) - - 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() - - if "CONDA_PREFIX" in candidate_env_vars: - conda_libs_path = Path(candidate_env_vars["CONDA_PREFIX"]) / "bin" - - conda_cuda_libs = find_cuda_lib_in(str(conda_libs_path)) - warn_in_case_of_duplicates(conda_cuda_libs) - - if conda_cuda_libs: - return next(iter(conda_cuda_libs)) - - conda_libs_path = Path(candidate_env_vars["CONDA_PREFIX"]) / "lib" - - conda_cuda_libs = find_cuda_lib_in(str(conda_libs_path)) - warn_in_case_of_duplicates(conda_cuda_libs) - - if conda_cuda_libs: - return next(iter(conda_cuda_libs)) - CUDASetup.get_instance().add_log_entry(f'{candidate_env_vars["CONDA_PREFIX"]} did not contain ' - f'{CUDA_RUNTIME_LIBS} as expected! Searching further paths...', is_warning=True) - - if "CUDA_PATH" in candidate_env_vars: - ld_cuda_libs_path = Path(candidate_env_vars["CUDA_PATH"]) / "bin" - - lib_ld_cuda_libs = find_cuda_lib_in(str(ld_cuda_libs_path)) - warn_in_case_of_duplicates(lib_ld_cuda_libs) - - if lib_ld_cuda_libs: - return next(iter(lib_ld_cuda_libs)) - - ld_cuda_libs_path = Path(candidate_env_vars["CUDA_PATH"]) / "lib" - - lib_ld_cuda_libs = find_cuda_lib_in(str(ld_cuda_libs_path)) - warn_in_case_of_duplicates(lib_ld_cuda_libs) +import ctypes - if lib_ld_cuda_libs: - return next(iter(lib_ld_cuda_libs)) - - CUDASetup.get_instance().add_log_entry(f'{candidate_env_vars["CUDA_PATH"]} did not contain ' - f'{CUDA_RUNTIME_LIBS} as expected! Searching further paths...', is_warning=True) - - if "CUDA_HOME" in candidate_env_vars: - ld_cuda_libs_path = Path(candidate_env_vars["CUDA_HOME"]) / "bin" - - lib_ld_cuda_libs = find_cuda_lib_in(str(ld_cuda_libs_path)) - warn_in_case_of_duplicates(lib_ld_cuda_libs) - - if lib_ld_cuda_libs: - return next(iter(lib_ld_cuda_libs)) - - ld_cuda_libs_path = Path(candidate_env_vars["CUDA_HOME"]) / "lib" - - lib_ld_cuda_libs = find_cuda_lib_in(str(ld_cuda_libs_path)) - warn_in_case_of_duplicates(lib_ld_cuda_libs) - - if lib_ld_cuda_libs: - return next(iter(lib_ld_cuda_libs)) - - CUDASetup.get_instance().add_log_entry(f'{candidate_env_vars["CUDA_HOME"]} did not contain ' - f'{CUDA_RUNTIME_LIBS} as expected! Searching further paths...', is_warning=True) - - if "LD_LIBRARY_PATH" in candidate_env_vars: - lib_ld_cuda_libs = find_cuda_lib_in(candidate_env_vars["LD_LIBRARY_PATH"]) - warn_in_case_of_duplicates(lib_ld_cuda_libs) - - if lib_ld_cuda_libs: - return next(iter(lib_ld_cuda_libs)) - - CUDASetup.get_instance().add_log_entry(f'{candidate_env_vars["LD_LIBRARY_PATH"]} did not contain ' - f'{CUDA_RUNTIME_LIBS} as expected! Searching further paths...', is_warning=True) - - if "PATH" in candidate_env_vars: - lib_ld_cuda_libs = find_cuda_lib_in(candidate_env_vars["PATH"]) - warn_in_case_of_duplicates(lib_ld_cuda_libs) - - if lib_ld_cuda_libs: - return next(iter(lib_ld_cuda_libs)) - - CUDASetup.get_instance().add_log_entry(f'{candidate_env_vars["PATH"]} did not contain ' - f'{CUDA_RUNTIME_LIBS} as expected! Searching further paths...', is_warning=True) - - remaining_candidate_env_vars = { - env_var: value for env_var, value in candidate_env_vars.items() - if env_var not in {"CONDA_PREFIX", "CUDA_HOME", "CUDA_PATH", "LD_LIBRARY_PATH", "PATH"} - } - - cuda_runtime_libs = set() - for env_var, value in remaining_candidate_env_vars.items(): - cuda_runtime_libs.update(find_cuda_lib_in(value)) - - if len(cuda_runtime_libs) == 0: - CUDASetup.get_instance().add_log_entry('CUDA_SETUP: WARNING! libcudart.so not found in any environmental path. Searching in backup paths...') - cuda_runtime_libs.update(find_cuda_lib_in('/usr/local/cuda/lib64')) - - warn_in_case_of_duplicates(cuda_runtime_libs) - - return next(iter(cuda_runtime_libs)) if cuda_runtime_libs else None +from .paths import determine_cuda_runtime_lib_path def check_cuda_result(cuda, result_val): # 3. Check for CUDA errors if result_val != 0: - error_str = ct.c_char_p() - cuda.cuGetErrorString(result_val, ct.byref(error_str)) - if error_str.value is not None: - CUDASetup.get_instance().add_log_entry(f"CUDA exception! Error code: {error_str.value.decode()}") - else: - CUDASetup.get_instance().add_log_entry(f"Unknown CUDA exception! Please check your CUDA install. It might also be that your GPU is too old.") - + error_str = ctypes.c_char_p() + cuda.cuGetErrorString(result_val, ctypes.byref(error_str)) + print(f"CUDA exception! Error code: {error_str.value.decode()}") -# https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART____VERSION.html#group__CUDART____VERSION def get_cuda_version(cuda, cudart_path): - if cuda is None: return None - + # https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART____VERSION.html#group__CUDART____VERSION try: - cudart = ct.CDLL(str(cudart_path)) + cudart = ctypes.CDLL(cudart_path) except OSError: - CUDASetup.get_instance().add_log_entry(f'ERROR: libcudart.so could not be read from path: {cudart_path}!') + # TODO: shouldn't we error or at least warn here? + print(f'ERROR: libcudart.so could not be read from path: {cudart_path}!') return None - version = ct.c_int() - try: - check_cuda_result(cuda, cudart.cudaRuntimeGetVersion(ct.byref(version))) - except AttributeError as e: - CUDASetup.get_instance().add_log_entry(f'ERROR: {str(e)}') - CUDASetup.get_instance().add_log_entry(f'CUDA SETUP: libcudart.so path is {cudart_path}') - CUDASetup.get_instance().add_log_entry(f'CUDA SETUP: Is seems that your cuda installation is not in your path. See https://github.com/TimDettmers/bitsandbytes/issues/85 for more information.') + version = ctypes.c_int() + check_cuda_result(cuda, cudart.cudaRuntimeGetVersion(ctypes.byref(version))) version = int(version.value) major = version//1000 minor = (version-(major*1000))//10 if major < 11: - CUDASetup.get_instance().add_log_entry('CUDA SETUP: CUDA version lower than 11 are currently not supported for LLM.int8(). You will be only to use 8-bit optimizers and quantization routines!!') + print('CUDA SETUP: CUDA version lower than 11 are currently not supported for LLM.int8(). You will be only to use 8-bit optimizers and quantization routines!!') return f'{major}{minor}' @@ -384,9 +52,10 @@ def get_cuda_version(cuda, cudart_path): def get_cuda_lib_handle(): # 1. find libcuda.so library (GPU driver) (/usr/lib) try: - cuda = ct.CDLL(CUDA_SHARED_LIB_NAME) + cuda = ctypes.CDLL("libcuda.so") except OSError: - CUDASetup.get_instance().add_log_entry('CUDA SETUP: WARNING! libcuda.so not found! Do you have a CUDA driver installed? If you are on a cluster, make sure you are on a CUDA machine!') + # TODO: shouldn't we error or at least warn here? + print('CUDA SETUP: WARNING! libcuda.so not found! Do you have a CUDA driver installed? If you are on a cluster, make sure you are on a CUDA machine!') return None check_cuda_result(cuda, cuda.cuInit(0)) @@ -404,20 +73,23 @@ def get_compute_capabilities(cuda): # bits taken from https://gist.github.com/f0k/63a664160d016a491b2cbea15913d549 """ - nGpus = ct.c_int() - cc_major = ct.c_int() - cc_minor = ct.c_int() - device = ct.c_int() + nGpus = ctypes.c_int() + cc_major = ctypes.c_int() + cc_minor = ctypes.c_int() - check_cuda_result(cuda, cuda.cuDeviceGetCount(ct.byref(nGpus))) + device = ctypes.c_int() + + check_cuda_result(cuda, cuda.cuDeviceGetCount(ctypes.byref(nGpus))) ccs = [] for i in range(nGpus.value): - check_cuda_result(cuda, cuda.cuDeviceGet(ct.byref(device), i)) - ref_major = ct.byref(cc_major) - ref_minor = ct.byref(cc_minor) + check_cuda_result(cuda, cuda.cuDeviceGet(ctypes.byref(device), i)) + ref_major = ctypes.byref(cc_major) + ref_minor = ctypes.byref(cc_minor) # 2. call extern C function to determine CC - check_cuda_result(cuda, cuda.cuDeviceComputeCapability(ref_major, ref_minor, device)) + check_cuda_result( + cuda, cuda.cuDeviceComputeCapability(ref_major, ref_minor, device) + ) ccs.append(f"{cc_major.value}.{cc_minor.value}") return ccs @@ -430,49 +102,48 @@ def get_compute_capability(cuda): capabilities are downwards compatible. If no GPUs are detected, it returns None. """ - if cuda is None: return None - - # TODO: handle different compute capabilities; for now, take the max ccs = get_compute_capabilities(cuda) - if ccs: return ccs[-1] + if ccs is not None: + # TODO: handle different compute capabilities; for now, take the max + return ccs[-1] + return None def evaluate_cuda_setup(): - if 'BITSANDBYTES_NOWELCOME' not in os.environ or str(os.environ['BITSANDBYTES_NOWELCOME']) == '0': - print('') - print('='*35 + 'BUG REPORT' + '='*35) - print(('Welcome to bitsandbytes. For bug reports, please run\n\npython -m bitsandbytes\n\n'), - ('and submit this information together with your error trace to: https://github.com/TimDettmers/bitsandbytes/issues')) - print('='*80) - return 'libbitsandbytes_cuda118.dll', None, None, None, None - if not torch.cuda.is_available(): return 'libbitsandbytes_cpu'+SHARED_LIB_EXTENSION, None, None, None, None - - cuda_setup = CUDASetup.get_instance() + print('') + print('='*35 + 'BUG REPORT' + '='*35) + print('Welcome to bitsandbytes. For bug reports, please submit your error trace to: https://github.com/TimDettmers/bitsandbytes/issues') + print('For effortless bug reporting copy-paste your error into this form: https://docs.google.com/forms/d/e/1FAIpQLScPB8emS3Thkp66nvqwmjTEgxp8Y9ufuWTzFyr9kJ5AoI47dQ/viewform?usp=sf_link') + print('='*80) + return "libbitsandbytes_cuda116.dll" # $$$ + + binary_name = "libbitsandbytes_cpu.so" + #if not torch.cuda.is_available(): + #print('No GPU detected. Loading CPU library...') + #return binary_name + cudart_path = determine_cuda_runtime_lib_path() + if cudart_path is None: + print( + "WARNING: No libcudart.so found! Install CUDA or the cudatoolkit package (anaconda)!" + ) + return binary_name + + print(f"CUDA SETUP: CUDA runtime path found: {cudart_path}") cuda = get_cuda_lib_handle() cc = get_compute_capability(cuda) + print(f"CUDA SETUP: Highest compute capability among GPUs detected: {cc}") cuda_version_string = get_cuda_version(cuda, cudart_path) - failure = False - if cudart_path is None: - failure = True - cuda_setup.add_log_entry("WARNING: No libcudart.so found! Install CUDA or the cudatoolkit package (anaconda)!", is_warning=True) - else: - cuda_setup.add_log_entry(f"CUDA SETUP: CUDA runtime path found: {cudart_path}") - - if cc == '' or cc is None: - failure = True - cuda_setup.add_log_entry("WARNING: No GPU detected! Check your CUDA paths. Proceeding to load CPU-only library...", is_warning=True) - else: - cuda_setup.add_log_entry(f"CUDA SETUP: Highest compute capability among GPUs detected: {cc}") - - if cuda is None: - failure = True - else: - cuda_setup.add_log_entry(f'CUDA SETUP: Detected CUDA version {cuda_version_string}') + + if cc == '': + print( + "WARNING: No GPU detected! Check your CUDA paths. Processing to load CPU-only library..." + ) + return binary_name # 7.5 is the minimum CC vor cublaslt - has_cublaslt = is_cublasLt_compatible(cc) + has_cublaslt = cc in ["7.5", "8.0", "8.6"] # TODO: # (1) CUDA missing cases (no CUDA installed by CUDA driver (nvidia-smi accessible) @@ -480,13 +151,16 @@ def evaluate_cuda_setup(): # we use ls -l instead of nvcc to determine the cuda version # since most installations will have the libcudart.so installed, but not the compiler + print(f'CUDA SETUP: Detected CUDA version {cuda_version_string}') + + def get_binary_name(): + "if not has_cublaslt (CC < 7.5), then we have to choose _nocublaslt.so" + bin_base_name = "libbitsandbytes_cuda" + if has_cublaslt: + return f"{bin_base_name}{cuda_version_string}.so" + else: + return f"{bin_base_name}{cuda_version_string}_nocublaslt.so" - if failure: - binary_name = "libbitsandbytes_cpu" + SHARED_LIB_EXTENSION - elif has_cublaslt: - binary_name = f"libbitsandbytes_cuda{cuda_version_string}" + SHARED_LIB_EXTENSION - else: - "if not has_cublaslt (CC < 7.5), then we have to choose _nocublaslt" - binary_name = f"libbitsandbytes_cuda{cuda_version_string}_nocublaslt" + SHARED_LIB_EXTENSION + binary_name = get_binary_name() - return binary_name, cudart_path, cuda, cc, cuda_version_string + return binary_name diff --git a/library/train_util.py b/library/train_util.py index 23f7f6344..8a73445e6 100644 --- a/library/train_util.py +++ b/library/train_util.py @@ -2164,6 +2164,7 @@ def cache_batch_latents( if flip_aug: info.latents_flipped = flipped_latent + # FIXME this slows down caching a lot, specify this as an option if torch.cuda.is_available(): torch.cuda.empty_cache() diff --git a/requirements.txt b/requirements.txt index 427621d24..9909ad753 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ ftfy==6.1.1 opencv-python==4.7.0.68 einops==0.6.0 pytorch-lightning==1.9.0 -bitsandbytes==0.39.1 +# bitsandbytes==0.39.1 tensorboard==2.10.1 safetensors==0.3.1 # gradio==3.16.2 diff --git a/sdxl_minimal_inference.py b/sdxl_minimal_inference.py index c30444930..72ffe97f4 100644 --- a/sdxl_minimal_inference.py +++ b/sdxl_minimal_inference.py @@ -213,7 +213,7 @@ def call_text_encoder(text, text2): enc_out = text_model2(tokens, output_hidden_states=True, return_dict=True) text_embedding2_penu = enc_out["hidden_states"][-2] # print("hidden_states2", text_embedding2_penu.shape) - text_embedding2_pool = enc_out["text_embeds"] # do not suport Textual Inversion + text_embedding2_pool = enc_out["text_embeds"] # do not support Textual Inversion # 連結して終了 concat and finish text_embedding = torch.cat([text_embedding1, text_embedding2_penu], dim=2)