Upload edit\Qwen3-TTS-test\.venv\Lib\site-packages\accelerate\big_modeling.py with huggingface_hub
Browse files
edit//Qwen3-TTS-test//.venv//Lib//site-packages//accelerate//big_modeling.py
ADDED
|
@@ -0,0 +1,789 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import logging
|
| 16 |
+
import os
|
| 17 |
+
import re
|
| 18 |
+
from contextlib import contextmanager
|
| 19 |
+
from functools import wraps
|
| 20 |
+
from typing import Optional, Union
|
| 21 |
+
|
| 22 |
+
import torch
|
| 23 |
+
import torch.nn as nn
|
| 24 |
+
|
| 25 |
+
from .hooks import (
|
| 26 |
+
AlignDevicesHook,
|
| 27 |
+
CpuOffload,
|
| 28 |
+
LayerwiseCastingHook,
|
| 29 |
+
UserCpuOffloadHook,
|
| 30 |
+
add_hook_to_module,
|
| 31 |
+
attach_align_device_hook,
|
| 32 |
+
attach_align_device_hook_on_blocks,
|
| 33 |
+
)
|
| 34 |
+
from .utils import (
|
| 35 |
+
OffloadedWeightsLoader,
|
| 36 |
+
check_cuda_p2p_ib_support,
|
| 37 |
+
check_device_map,
|
| 38 |
+
extract_submodules_state_dict,
|
| 39 |
+
find_tied_parameters,
|
| 40 |
+
get_balanced_memory,
|
| 41 |
+
infer_auto_device_map,
|
| 42 |
+
is_bnb_available,
|
| 43 |
+
is_mlu_available,
|
| 44 |
+
is_musa_available,
|
| 45 |
+
is_npu_available,
|
| 46 |
+
is_sdaa_available,
|
| 47 |
+
is_xpu_available,
|
| 48 |
+
load_checkpoint_in_model,
|
| 49 |
+
offload_state_dict,
|
| 50 |
+
parse_flag_from_env,
|
| 51 |
+
retie_parameters,
|
| 52 |
+
)
|
| 53 |
+
from .utils.constants import SUPPORTED_PYTORCH_LAYERS_FOR_UPCASTING
|
| 54 |
+
from .utils.other import recursive_getattr
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
logger = logging.getLogger(__name__)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
@contextmanager
|
| 61 |
+
def init_empty_weights(include_buffers: Optional[bool] = None):
|
| 62 |
+
"""
|
| 63 |
+
A context manager under which models are initialized with all parameters on the meta device, therefore creating an
|
| 64 |
+
empty model. Useful when just initializing the model would blow the available RAM.
|
| 65 |
+
|
| 66 |
+
Args:
|
| 67 |
+
include_buffers (`bool`, *optional*):
|
| 68 |
+
Whether or not to also put all buffers on the meta device while initializing.
|
| 69 |
+
|
| 70 |
+
Example:
|
| 71 |
+
|
| 72 |
+
```python
|
| 73 |
+
import torch.nn as nn
|
| 74 |
+
from accelerate import init_empty_weights
|
| 75 |
+
|
| 76 |
+
# Initialize a model with 100 billions parameters in no time and without using any RAM.
|
| 77 |
+
with init_empty_weights():
|
| 78 |
+
tst = nn.Sequential(*[nn.Linear(10000, 10000) for _ in range(1000)])
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
<Tip warning={true}>
|
| 82 |
+
|
| 83 |
+
Any model created under this context manager has no weights. As such you can't do something like
|
| 84 |
+
`model.to(some_device)` with it. To load weights inside your empty model, see [`load_checkpoint_and_dispatch`].
|
| 85 |
+
Make sure to overwrite the default device_map param for [`load_checkpoint_and_dispatch`], otherwise dispatch is not
|
| 86 |
+
called.
|
| 87 |
+
|
| 88 |
+
</Tip>
|
| 89 |
+
"""
|
| 90 |
+
if include_buffers is None:
|
| 91 |
+
include_buffers = parse_flag_from_env("ACCELERATE_INIT_INCLUDE_BUFFERS", False)
|
| 92 |
+
with init_on_device(torch.device("meta"), include_buffers=include_buffers) as f:
|
| 93 |
+
yield f
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
@contextmanager
|
| 97 |
+
def init_on_device(device: torch.device, include_buffers: Optional[bool] = None):
|
| 98 |
+
"""
|
| 99 |
+
A context manager under which models are initialized with all parameters on the specified device.
|
| 100 |
+
|
| 101 |
+
Args:
|
| 102 |
+
device (`torch.device`):
|
| 103 |
+
Device to initialize all parameters on.
|
| 104 |
+
include_buffers (`bool`, *optional*):
|
| 105 |
+
Whether or not to also put all buffers on the meta device while initializing.
|
| 106 |
+
|
| 107 |
+
Example:
|
| 108 |
+
|
| 109 |
+
```python
|
| 110 |
+
import torch.nn as nn
|
| 111 |
+
from accelerate import init_on_device
|
| 112 |
+
|
| 113 |
+
with init_on_device(device=torch.device("cuda")):
|
| 114 |
+
tst = nn.Linear(100, 100) # on `cuda` device
|
| 115 |
+
```
|
| 116 |
+
"""
|
| 117 |
+
if include_buffers is None:
|
| 118 |
+
include_buffers = parse_flag_from_env("ACCELERATE_INIT_INCLUDE_BUFFERS", False)
|
| 119 |
+
|
| 120 |
+
if include_buffers:
|
| 121 |
+
with device:
|
| 122 |
+
yield
|
| 123 |
+
return
|
| 124 |
+
|
| 125 |
+
old_register_parameter = nn.Module.register_parameter
|
| 126 |
+
if include_buffers:
|
| 127 |
+
old_register_buffer = nn.Module.register_buffer
|
| 128 |
+
|
| 129 |
+
def register_empty_parameter(module, name, param):
|
| 130 |
+
old_register_parameter(module, name, param)
|
| 131 |
+
if param is not None:
|
| 132 |
+
param_cls = type(module._parameters[name])
|
| 133 |
+
kwargs = module._parameters[name].__dict__
|
| 134 |
+
kwargs["requires_grad"] = param.requires_grad
|
| 135 |
+
module._parameters[name] = param_cls(module._parameters[name].to(device), **kwargs)
|
| 136 |
+
|
| 137 |
+
def register_empty_buffer(module, name, buffer, persistent=True):
|
| 138 |
+
old_register_buffer(module, name, buffer, persistent=persistent)
|
| 139 |
+
if buffer is not None:
|
| 140 |
+
module._buffers[name] = module._buffers[name].to(device)
|
| 141 |
+
|
| 142 |
+
# Patch tensor creation
|
| 143 |
+
if include_buffers:
|
| 144 |
+
tensor_constructors_to_patch = {
|
| 145 |
+
torch_function_name: getattr(torch, torch_function_name)
|
| 146 |
+
for torch_function_name in ["empty", "zeros", "ones", "full"]
|
| 147 |
+
}
|
| 148 |
+
else:
|
| 149 |
+
tensor_constructors_to_patch = {}
|
| 150 |
+
|
| 151 |
+
def patch_tensor_constructor(fn):
|
| 152 |
+
def wrapper(*args, **kwargs):
|
| 153 |
+
kwargs["device"] = device
|
| 154 |
+
return fn(*args, **kwargs)
|
| 155 |
+
|
| 156 |
+
return wrapper
|
| 157 |
+
|
| 158 |
+
try:
|
| 159 |
+
nn.Module.register_parameter = register_empty_parameter
|
| 160 |
+
if include_buffers:
|
| 161 |
+
nn.Module.register_buffer = register_empty_buffer
|
| 162 |
+
for torch_function_name in tensor_constructors_to_patch.keys():
|
| 163 |
+
setattr(torch, torch_function_name, patch_tensor_constructor(getattr(torch, torch_function_name)))
|
| 164 |
+
yield
|
| 165 |
+
finally:
|
| 166 |
+
nn.Module.register_parameter = old_register_parameter
|
| 167 |
+
if include_buffers:
|
| 168 |
+
nn.Module.register_buffer = old_register_buffer
|
| 169 |
+
for torch_function_name, old_torch_function in tensor_constructors_to_patch.items():
|
| 170 |
+
setattr(torch, torch_function_name, old_torch_function)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def cpu_offload(
|
| 174 |
+
model: nn.Module,
|
| 175 |
+
execution_device: Optional[torch.device] = None,
|
| 176 |
+
offload_buffers: bool = False,
|
| 177 |
+
state_dict: Optional[dict[str, torch.Tensor]] = None,
|
| 178 |
+
preload_module_classes: Optional[list[str]] = None,
|
| 179 |
+
):
|
| 180 |
+
"""
|
| 181 |
+
Activates full CPU offload for a model. As a result, all parameters of the model will be offloaded and only one
|
| 182 |
+
copy of the state dict of the model will be kept. During the forward pass, parameters will be extracted from that
|
| 183 |
+
state dict and put on the execution device passed as they are needed, then offloaded again.
|
| 184 |
+
|
| 185 |
+
Args:
|
| 186 |
+
model (`torch.nn.Module`):
|
| 187 |
+
The model to offload.
|
| 188 |
+
execution_device (`torch.device`, *optional*):
|
| 189 |
+
The device on which the forward pass of the model will be executed (should be a GPU). Will default to the
|
| 190 |
+
model first parameter device.
|
| 191 |
+
offload_buffers (`bool`, *optional*, defaults to `False`):
|
| 192 |
+
Whether or not to offload the buffers with the model parameters.
|
| 193 |
+
state_dict (`Dict[str, torch.Tensor]`, *optional*):
|
| 194 |
+
The state dict of the model that will be kept on CPU.
|
| 195 |
+
preload_module_classes (`List[str]`, *optional*):
|
| 196 |
+
A list of classes whose instances should load all their weights (even in the submodules) at the beginning
|
| 197 |
+
of the forward. This should only be used for classes that have submodules which are registered but not
|
| 198 |
+
called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
|
| 199 |
+
`dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
|
| 200 |
+
"""
|
| 201 |
+
if execution_device is None:
|
| 202 |
+
execution_device = next(iter(model.parameters())).device
|
| 203 |
+
if state_dict is None:
|
| 204 |
+
state_dict = {n: p.to("cpu") for n, p in model.state_dict().items()}
|
| 205 |
+
|
| 206 |
+
add_hook_to_module(model, AlignDevicesHook(io_same_device=True), append=True)
|
| 207 |
+
attach_align_device_hook(
|
| 208 |
+
model,
|
| 209 |
+
execution_device=execution_device,
|
| 210 |
+
offload=True,
|
| 211 |
+
offload_buffers=offload_buffers,
|
| 212 |
+
weights_map=state_dict,
|
| 213 |
+
preload_module_classes=preload_module_classes,
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
return model
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
def cpu_offload_with_hook(
|
| 220 |
+
model: torch.nn.Module,
|
| 221 |
+
execution_device: Optional[Union[int, str, torch.device]] = None,
|
| 222 |
+
prev_module_hook: Optional[UserCpuOffloadHook] = None,
|
| 223 |
+
):
|
| 224 |
+
"""
|
| 225 |
+
Offloads a model on the CPU and puts it back to an execution device when executed. The difference with
|
| 226 |
+
[`cpu_offload`] is that the model stays on the execution device after the forward and is only offloaded again when
|
| 227 |
+
the `offload` method of the returned `hook` is called. Useful for pipelines running a model in a loop.
|
| 228 |
+
|
| 229 |
+
Args:
|
| 230 |
+
model (`torch.nn.Module`):
|
| 231 |
+
The model to offload.
|
| 232 |
+
execution_device(`str`, `int` or `torch.device`, *optional*):
|
| 233 |
+
The device on which the model should be executed. Will default to the MPS device if it's available, then
|
| 234 |
+
GPU 0 if there is a GPU, and finally to the CPU.
|
| 235 |
+
prev_module_hook (`UserCpuOffloadHook`, *optional*):
|
| 236 |
+
The hook sent back by this function for a previous model in the pipeline you are running. If passed, its
|
| 237 |
+
offload method will be called just before the forward of the model to which this hook is attached.
|
| 238 |
+
|
| 239 |
+
Example:
|
| 240 |
+
|
| 241 |
+
```py
|
| 242 |
+
model_1, hook_1 = cpu_offload_with_hook(model_1, cuda_device)
|
| 243 |
+
model_2, hook_2 = cpu_offload_with_hook(model_2, cuda_device, prev_module_hook=hook_1)
|
| 244 |
+
model_3, hook_3 = cpu_offload_with_hook(model_3, cuda_device, prev_module_hook=hook_2)
|
| 245 |
+
|
| 246 |
+
hid_1 = model_1(input)
|
| 247 |
+
for i in range(50):
|
| 248 |
+
# model1 is offloaded on the CPU at the first iteration, model 2 stays on the GPU for this whole loop.
|
| 249 |
+
hid_2 = model_2(hid_1)
|
| 250 |
+
# model2 is offloaded to the CPU just before this forward.
|
| 251 |
+
hid_3 = model_3(hid_3)
|
| 252 |
+
|
| 253 |
+
# For model3, you need to manually call the hook offload method.
|
| 254 |
+
hook_3.offload()
|
| 255 |
+
```
|
| 256 |
+
"""
|
| 257 |
+
hook = CpuOffload(execution_device=execution_device, prev_module_hook=prev_module_hook)
|
| 258 |
+
add_hook_to_module(model, hook, append=True)
|
| 259 |
+
user_hook = UserCpuOffloadHook(model, hook)
|
| 260 |
+
return model, user_hook
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
def disk_offload(
|
| 264 |
+
model: nn.Module,
|
| 265 |
+
offload_dir: Union[str, os.PathLike],
|
| 266 |
+
execution_device: Optional[torch.device] = None,
|
| 267 |
+
offload_buffers: bool = False,
|
| 268 |
+
preload_module_classes: Optional[list[str]] = None,
|
| 269 |
+
):
|
| 270 |
+
"""
|
| 271 |
+
Activates full disk offload for a model. As a result, all parameters of the model will be offloaded as
|
| 272 |
+
memory-mapped array in a given folder. During the forward pass, parameters will be accessed from that folder and
|
| 273 |
+
put on the execution device passed as they are needed, then offloaded again.
|
| 274 |
+
|
| 275 |
+
Args:
|
| 276 |
+
model (`torch.nn.Module`): The model to offload.
|
| 277 |
+
offload_dir (`str` or `os.PathLike`):
|
| 278 |
+
The folder in which to offload the model weights (or where the model weights are already offloaded).
|
| 279 |
+
execution_device (`torch.device`, *optional*):
|
| 280 |
+
The device on which the forward pass of the model will be executed (should be a GPU). Will default to the
|
| 281 |
+
model's first parameter device.
|
| 282 |
+
offload_buffers (`bool`, *optional*, defaults to `False`):
|
| 283 |
+
Whether or not to offload the buffers with the model parameters.
|
| 284 |
+
preload_module_classes (`List[str]`, *optional*):
|
| 285 |
+
A list of classes whose instances should load all their weights (even in the submodules) at the beginning
|
| 286 |
+
of the forward. This should only be used for classes that have submodules which are registered but not
|
| 287 |
+
called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
|
| 288 |
+
`dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
|
| 289 |
+
"""
|
| 290 |
+
if not os.path.isdir(offload_dir) or not os.path.isfile(os.path.join(offload_dir, "index.json")):
|
| 291 |
+
offload_state_dict(offload_dir, model.state_dict())
|
| 292 |
+
if execution_device is None:
|
| 293 |
+
execution_device = next(iter(model.parameters())).device
|
| 294 |
+
weights_map = OffloadedWeightsLoader(save_folder=offload_dir)
|
| 295 |
+
|
| 296 |
+
add_hook_to_module(model, AlignDevicesHook(io_same_device=True), append=True)
|
| 297 |
+
attach_align_device_hook(
|
| 298 |
+
model,
|
| 299 |
+
execution_device=execution_device,
|
| 300 |
+
offload=True,
|
| 301 |
+
offload_buffers=offload_buffers,
|
| 302 |
+
weights_map=weights_map,
|
| 303 |
+
preload_module_classes=preload_module_classes,
|
| 304 |
+
)
|
| 305 |
+
|
| 306 |
+
return model
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
def dispatch_model(
|
| 310 |
+
model: nn.Module,
|
| 311 |
+
device_map: dict[str, Union[str, int, torch.device]],
|
| 312 |
+
main_device: Optional[torch.device] = None,
|
| 313 |
+
state_dict: Optional[dict[str, torch.Tensor]] = None,
|
| 314 |
+
offload_dir: Optional[Union[str, os.PathLike]] = None,
|
| 315 |
+
offload_index: Optional[dict[str, str]] = None,
|
| 316 |
+
offload_buffers: bool = False,
|
| 317 |
+
skip_keys: Optional[Union[str, list[str]]] = None,
|
| 318 |
+
preload_module_classes: Optional[list[str]] = None,
|
| 319 |
+
force_hooks: bool = False,
|
| 320 |
+
):
|
| 321 |
+
"""
|
| 322 |
+
Dispatches a model according to a given device map. Layers of the model might be spread across GPUs, offloaded on
|
| 323 |
+
the CPU or even the disk.
|
| 324 |
+
|
| 325 |
+
Args:
|
| 326 |
+
model (`torch.nn.Module`):
|
| 327 |
+
The model to dispatch.
|
| 328 |
+
device_map (`Dict[str, Union[str, int, torch.device]]`):
|
| 329 |
+
A dictionary mapping module names in the models `state_dict` to the device they should go to. Note that
|
| 330 |
+
`"disk"` is accepted even if it's not a proper value for `torch.device`.
|
| 331 |
+
main_device (`str`, `int` or `torch.device`, *optional*):
|
| 332 |
+
The main execution device. Will default to the first device in the `device_map` different from `"cpu"` or
|
| 333 |
+
`"disk"`.
|
| 334 |
+
state_dict (`Dict[str, torch.Tensor]`, *optional*):
|
| 335 |
+
The state dict of the part of the model that will be kept on CPU.
|
| 336 |
+
offload_dir (`str` or `os.PathLike`):
|
| 337 |
+
The folder in which to offload the model weights (or where the model weights are already offloaded).
|
| 338 |
+
offload_index (`Dict`, *optional*):
|
| 339 |
+
A dictionary from weight name to their information (`dtype`/ `shape` or safetensors filename). Will default
|
| 340 |
+
to the index saved in `save_folder`.
|
| 341 |
+
offload_buffers (`bool`, *optional*, defaults to `False`):
|
| 342 |
+
Whether or not to offload the buffers with the model parameters.
|
| 343 |
+
skip_keys (`str` or `List[str]`, *optional*):
|
| 344 |
+
A list of keys to ignore when moving inputs or outputs between devices.
|
| 345 |
+
preload_module_classes (`List[str]`, *optional*):
|
| 346 |
+
A list of classes whose instances should load all their weights (even in the submodules) at the beginning
|
| 347 |
+
of the forward. This should only be used for classes that have submodules which are registered but not
|
| 348 |
+
called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
|
| 349 |
+
`dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
|
| 350 |
+
force_hooks (`bool`, *optional*, defaults to `False`):
|
| 351 |
+
Whether or not to force device hooks to be attached to the model even if all layers are dispatched to a
|
| 352 |
+
single device.
|
| 353 |
+
"""
|
| 354 |
+
# Error early if the device map is incomplete.
|
| 355 |
+
check_device_map(model, device_map)
|
| 356 |
+
|
| 357 |
+
# We need to force hook for quantized model that can't be moved with to()
|
| 358 |
+
if getattr(model, "quantization_method", "bitsandbytes") == "bitsandbytes":
|
| 359 |
+
# since bnb 0.43.2, we can move 4-bit model
|
| 360 |
+
if getattr(model, "is_loaded_in_8bit", False) or (
|
| 361 |
+
getattr(model, "is_loaded_in_4bit", False) and not is_bnb_available(min_version="0.43.2")
|
| 362 |
+
):
|
| 363 |
+
force_hooks = True
|
| 364 |
+
|
| 365 |
+
# We attach hooks if the device_map has at least 2 different devices or if
|
| 366 |
+
# force_hooks is set to `True`. Otherwise, the model in already loaded
|
| 367 |
+
# in the unique device and the user can decide where to dispatch the model.
|
| 368 |
+
# If the model is quantized, we always force-dispatch the model
|
| 369 |
+
if (len(set(device_map.values())) > 1) or force_hooks:
|
| 370 |
+
if main_device is None:
|
| 371 |
+
if set(device_map.values()) == {"cpu"} or set(device_map.values()) == {"cpu", "disk"}:
|
| 372 |
+
main_device = "cpu"
|
| 373 |
+
else:
|
| 374 |
+
main_device = [d for d in device_map.values() if d not in ["cpu", "disk"]][0]
|
| 375 |
+
|
| 376 |
+
if main_device != "cpu":
|
| 377 |
+
cpu_modules = [name for name, device in device_map.items() if device == "cpu"]
|
| 378 |
+
if state_dict is None and len(cpu_modules) > 0:
|
| 379 |
+
state_dict = extract_submodules_state_dict(model.state_dict(), cpu_modules)
|
| 380 |
+
|
| 381 |
+
disk_modules = [name for name, device in device_map.items() if device == "disk"]
|
| 382 |
+
if offload_dir is None and offload_index is None and len(disk_modules) > 0:
|
| 383 |
+
raise ValueError(
|
| 384 |
+
"We need an `offload_dir` to dispatch this model according to this `device_map`, the following submodules "
|
| 385 |
+
f"need to be offloaded: {', '.join(disk_modules)}."
|
| 386 |
+
)
|
| 387 |
+
if (
|
| 388 |
+
len(disk_modules) > 0
|
| 389 |
+
and offload_index is None
|
| 390 |
+
and (not os.path.isdir(offload_dir) or not os.path.isfile(os.path.join(offload_dir, "index.json")))
|
| 391 |
+
):
|
| 392 |
+
disk_state_dict = extract_submodules_state_dict(model.state_dict(), disk_modules)
|
| 393 |
+
offload_state_dict(offload_dir, disk_state_dict)
|
| 394 |
+
|
| 395 |
+
execution_device = {
|
| 396 |
+
name: main_device if device in ["cpu", "disk"] else device for name, device in device_map.items()
|
| 397 |
+
}
|
| 398 |
+
execution_device[""] = main_device
|
| 399 |
+
offloaded_devices = ["disk"] if main_device == "cpu" or main_device == "mps" else ["cpu", "disk"]
|
| 400 |
+
offload = {name: device in offloaded_devices for name, device in device_map.items()}
|
| 401 |
+
save_folder = offload_dir if len(disk_modules) > 0 else None
|
| 402 |
+
if state_dict is not None or save_folder is not None or offload_index is not None:
|
| 403 |
+
device = main_device if offload_index is not None else None
|
| 404 |
+
weights_map = OffloadedWeightsLoader(
|
| 405 |
+
state_dict=state_dict, save_folder=save_folder, index=offload_index, device=device
|
| 406 |
+
)
|
| 407 |
+
else:
|
| 408 |
+
weights_map = None
|
| 409 |
+
|
| 410 |
+
# When dispatching the model's parameters to the devices specified in device_map, we want to avoid allocating memory several times for the
|
| 411 |
+
# tied parameters. The dictionary tied_params_map keeps track of the already allocated data for a given tied parameter (represented by its
|
| 412 |
+
# original pointer) on each devices.
|
| 413 |
+
tied_params = find_tied_parameters(model)
|
| 414 |
+
|
| 415 |
+
tied_params_map = {}
|
| 416 |
+
for group in tied_params:
|
| 417 |
+
for param_name in group:
|
| 418 |
+
# data_ptr() is enough here, as `find_tied_parameters` finds tied params simply by comparing `param1 is param2`, so we don't need
|
| 419 |
+
# to care about views of tensors through storage_offset.
|
| 420 |
+
data_ptr = recursive_getattr(model, param_name).data_ptr()
|
| 421 |
+
tied_params_map[data_ptr] = {}
|
| 422 |
+
|
| 423 |
+
# Note: To handle the disk offloading case, we can not simply use weights_map[param_name].data_ptr() as the reference pointer,
|
| 424 |
+
# as we have no guarantee that safetensors' `file.get_tensor()` will always give the same pointer.
|
| 425 |
+
|
| 426 |
+
attach_align_device_hook_on_blocks(
|
| 427 |
+
model,
|
| 428 |
+
execution_device=execution_device,
|
| 429 |
+
offload=offload,
|
| 430 |
+
offload_buffers=offload_buffers,
|
| 431 |
+
weights_map=weights_map,
|
| 432 |
+
skip_keys=skip_keys,
|
| 433 |
+
preload_module_classes=preload_module_classes,
|
| 434 |
+
tied_params_map=tied_params_map,
|
| 435 |
+
)
|
| 436 |
+
|
| 437 |
+
# warn if there is any params on the meta device
|
| 438 |
+
offloaded_devices_str = " and ".join(
|
| 439 |
+
[device for device in set(device_map.values()) if device in ("cpu", "disk")]
|
| 440 |
+
)
|
| 441 |
+
if len(offloaded_devices_str) > 0:
|
| 442 |
+
logger.warning(
|
| 443 |
+
f"Some parameters are on the meta device because they were offloaded to the {offloaded_devices_str}."
|
| 444 |
+
)
|
| 445 |
+
|
| 446 |
+
# Attaching the hook may break tied weights, so we retie them
|
| 447 |
+
retie_parameters(model, tied_params)
|
| 448 |
+
|
| 449 |
+
# add warning to cuda and to method
|
| 450 |
+
def add_warning(fn, model):
|
| 451 |
+
@wraps(fn)
|
| 452 |
+
def wrapper(*args, **kwargs):
|
| 453 |
+
warning_msg = "You shouldn't move a model that is dispatched using accelerate hooks."
|
| 454 |
+
if str(fn.__name__) == "to":
|
| 455 |
+
to_device = torch._C._nn._parse_to(*args, **kwargs)[0]
|
| 456 |
+
if to_device is not None:
|
| 457 |
+
logger.warning(warning_msg)
|
| 458 |
+
else:
|
| 459 |
+
logger.warning(warning_msg)
|
| 460 |
+
for param in model.parameters():
|
| 461 |
+
if param.device == torch.device("meta"):
|
| 462 |
+
raise RuntimeError("You can't move a model that has some modules offloaded to cpu or disk.")
|
| 463 |
+
return fn(*args, **kwargs)
|
| 464 |
+
|
| 465 |
+
return wrapper
|
| 466 |
+
|
| 467 |
+
# Make sure to update _accelerate_added_attributes in hooks.py if you add any hook
|
| 468 |
+
model.to = add_warning(model.to, model)
|
| 469 |
+
if is_npu_available():
|
| 470 |
+
model.npu = add_warning(model.npu, model)
|
| 471 |
+
elif is_mlu_available():
|
| 472 |
+
model.mlu = add_warning(model.mlu, model)
|
| 473 |
+
elif is_sdaa_available():
|
| 474 |
+
model.sdaa = add_warning(model.sdaa, model)
|
| 475 |
+
elif is_musa_available():
|
| 476 |
+
model.musa = add_warning(model.musa, model)
|
| 477 |
+
elif is_xpu_available():
|
| 478 |
+
model.xpu = add_warning(model.xpu, model)
|
| 479 |
+
else:
|
| 480 |
+
model.cuda = add_warning(model.cuda, model)
|
| 481 |
+
|
| 482 |
+
# Check if we are using multi-gpus with RTX 4000 series
|
| 483 |
+
use_multi_gpu = len([device for device in set(device_map.values()) if device not in ("cpu", "disk")]) > 1
|
| 484 |
+
if use_multi_gpu and not check_cuda_p2p_ib_support():
|
| 485 |
+
logger.warning(
|
| 486 |
+
"We've detected an older driver with an RTX 4000 series GPU. These drivers have issues with P2P. "
|
| 487 |
+
"This can affect the multi-gpu inference when using accelerate device_map."
|
| 488 |
+
"Please make sure to update your driver to the latest version which resolves this."
|
| 489 |
+
)
|
| 490 |
+
else:
|
| 491 |
+
device = list(device_map.values())[0]
|
| 492 |
+
# `torch.Tensor.to(<int num>)` is not supported by `torch_npu` (see this [issue](https://github.com/Ascend/pytorch/issues/16)).
|
| 493 |
+
if is_npu_available() and isinstance(device, int):
|
| 494 |
+
device = f"npu:{device}"
|
| 495 |
+
elif is_mlu_available() and isinstance(device, int):
|
| 496 |
+
device = f"mlu:{device}"
|
| 497 |
+
elif is_sdaa_available() and isinstance(device, int):
|
| 498 |
+
device = f"sdaa:{device}"
|
| 499 |
+
elif is_musa_available() and isinstance(device, int):
|
| 500 |
+
device = f"musa:{device}"
|
| 501 |
+
if device != "disk":
|
| 502 |
+
model.to(device)
|
| 503 |
+
else:
|
| 504 |
+
raise ValueError(
|
| 505 |
+
"You are trying to offload the whole model to the disk. Please use the `disk_offload` function instead."
|
| 506 |
+
)
|
| 507 |
+
# Convert OrderedDict back to dict for easier usage
|
| 508 |
+
model.hf_device_map = dict(device_map)
|
| 509 |
+
return model
|
| 510 |
+
|
| 511 |
+
|
| 512 |
+
def load_checkpoint_and_dispatch(
|
| 513 |
+
model: nn.Module,
|
| 514 |
+
checkpoint: Union[str, os.PathLike],
|
| 515 |
+
device_map: Optional[Union[str, dict[str, Union[int, str, torch.device]]]] = None,
|
| 516 |
+
max_memory: Optional[dict[Union[int, str], Union[int, str]]] = None,
|
| 517 |
+
no_split_module_classes: Optional[list[str]] = None,
|
| 518 |
+
offload_folder: Optional[Union[str, os.PathLike]] = None,
|
| 519 |
+
offload_buffers: bool = False,
|
| 520 |
+
dtype: Optional[Union[str, torch.dtype]] = None,
|
| 521 |
+
offload_state_dict: Optional[bool] = None,
|
| 522 |
+
skip_keys: Optional[Union[str, list[str]]] = None,
|
| 523 |
+
preload_module_classes: Optional[list[str]] = None,
|
| 524 |
+
force_hooks: bool = False,
|
| 525 |
+
strict: bool = False,
|
| 526 |
+
full_state_dict: bool = True,
|
| 527 |
+
broadcast_from_rank0: bool = False,
|
| 528 |
+
):
|
| 529 |
+
"""
|
| 530 |
+
Loads a (potentially sharded) checkpoint inside a model, potentially sending weights to a given device as they are
|
| 531 |
+
loaded and adds the various hooks that will make this model run properly (even if split across devices).
|
| 532 |
+
|
| 533 |
+
Args:
|
| 534 |
+
model (`torch.nn.Module`): The model in which we want to load a checkpoint.
|
| 535 |
+
checkpoint (`str` or `os.PathLike`):
|
| 536 |
+
The folder checkpoint to load. It can be:
|
| 537 |
+
- a path to a file containing a whole model state dict
|
| 538 |
+
- a path to a `.json` file containing the index to a sharded checkpoint
|
| 539 |
+
- a path to a folder containing a unique `.index.json` file and the shards of a checkpoint.
|
| 540 |
+
device_map (`Dict[str, Union[int, str, torch.device]]`, *optional*):
|
| 541 |
+
A map that specifies where each submodule should go. It doesn't need to be refined to each parameter/buffer
|
| 542 |
+
name, once a given module name is inside, every submodule of it will be sent to the same device.
|
| 543 |
+
|
| 544 |
+
To have Accelerate compute the most optimized `device_map` automatically, set `device_map="auto"`. For more
|
| 545 |
+
information about each option see [here](../concept_guides/big_model_inference#designing-a-device-map).
|
| 546 |
+
Defaults to None, which means [`dispatch_model`] will not be called.
|
| 547 |
+
max_memory (`Dict`, *optional*):
|
| 548 |
+
A dictionary device identifier to maximum memory. Will default to the maximum memory available for each GPU
|
| 549 |
+
and the available CPU RAM if unset.
|
| 550 |
+
no_split_module_classes (`List[str]`, *optional*):
|
| 551 |
+
A list of layer class names that should never be split across device (for instance any layer that has a
|
| 552 |
+
residual connection).
|
| 553 |
+
offload_folder (`str` or `os.PathLike`, *optional*):
|
| 554 |
+
If the `device_map` contains any value `"disk"`, the folder where we will offload weights.
|
| 555 |
+
offload_buffers (`bool`, *optional*, defaults to `False`):
|
| 556 |
+
In the layers that are offloaded on the CPU or the hard drive, whether or not to offload the buffers as
|
| 557 |
+
well as the parameters.
|
| 558 |
+
dtype (`str` or `torch.dtype`, *optional*):
|
| 559 |
+
If provided, the weights will be converted to that type when loaded.
|
| 560 |
+
offload_state_dict (`bool`, *optional*):
|
| 561 |
+
If `True`, will temporarily offload the CPU state dict on the hard drive to avoid getting out of CPU RAM if
|
| 562 |
+
the weight of the CPU state dict + the biggest shard does not fit. Will default to `True` if the device map
|
| 563 |
+
picked contains `"disk"` values.
|
| 564 |
+
skip_keys (`str` or `List[str]`, *optional*):
|
| 565 |
+
A list of keys to ignore when moving inputs or outputs between devices.
|
| 566 |
+
preload_module_classes (`List[str]`, *optional*):
|
| 567 |
+
A list of classes whose instances should load all their weights (even in the submodules) at the beginning
|
| 568 |
+
of the forward. This should only be used for classes that have submodules which are registered but not
|
| 569 |
+
called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
|
| 570 |
+
`dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
|
| 571 |
+
force_hooks (`bool`, *optional*, defaults to `False`):
|
| 572 |
+
Whether or not to force device hooks to be attached to the model even if all layers are dispatched to a
|
| 573 |
+
single device.
|
| 574 |
+
strict (`bool`, *optional*, defaults to `False`):
|
| 575 |
+
Whether to strictly enforce that the keys in the checkpoint state_dict match the keys of the model's
|
| 576 |
+
state_dict.
|
| 577 |
+
full_state_dict (`bool`, *optional*, defaults to `True`): if this is set to `True`, all the tensors in the
|
| 578 |
+
loaded state_dict will be gathered. No ShardedTensor and DTensor will be in the loaded state_dict.
|
| 579 |
+
broadcast_from_rank0 (`False`, *optional*, defaults to `False`): when the option is `True`, a distributed
|
| 580 |
+
`ProcessGroup` must be initialized. rank0 should receive a full state_dict and will broadcast the tensors
|
| 581 |
+
in the state_dict one by one to other ranks. Other ranks will receive the tensors and shard (if applicable)
|
| 582 |
+
according to the local shards in the model.
|
| 583 |
+
|
| 584 |
+
Example:
|
| 585 |
+
|
| 586 |
+
```python
|
| 587 |
+
>>> from accelerate import init_empty_weights, load_checkpoint_and_dispatch
|
| 588 |
+
>>> from huggingface_hub import hf_hub_download
|
| 589 |
+
>>> from transformers import AutoConfig, AutoModelForCausalLM
|
| 590 |
+
|
| 591 |
+
>>> # Download the Weights
|
| 592 |
+
>>> checkpoint = "EleutherAI/gpt-j-6B"
|
| 593 |
+
>>> weights_location = hf_hub_download(checkpoint, "pytorch_model.bin")
|
| 594 |
+
|
| 595 |
+
>>> # Create a model and initialize it with empty weights
|
| 596 |
+
>>> config = AutoConfig.from_pretrained(checkpoint)
|
| 597 |
+
>>> with init_empty_weights():
|
| 598 |
+
... model = AutoModelForCausalLM.from_config(config)
|
| 599 |
+
|
| 600 |
+
>>> # Load the checkpoint and dispatch it to the right devices
|
| 601 |
+
>>> model = load_checkpoint_and_dispatch(
|
| 602 |
+
... model, weights_location, device_map="auto", no_split_module_classes=["GPTJBlock"]
|
| 603 |
+
... )
|
| 604 |
+
```
|
| 605 |
+
"""
|
| 606 |
+
if isinstance(device_map, str) and device_map not in ["auto", "balanced", "balanced_low_0", "sequential"]:
|
| 607 |
+
raise ValueError(
|
| 608 |
+
"If passing a string for `device_map`, please choose 'auto', 'balanced', 'balanced_low_0' or 'sequential'."
|
| 609 |
+
)
|
| 610 |
+
if isinstance(device_map, str):
|
| 611 |
+
if device_map != "sequential":
|
| 612 |
+
max_memory = get_balanced_memory(
|
| 613 |
+
model,
|
| 614 |
+
max_memory=max_memory,
|
| 615 |
+
no_split_module_classes=no_split_module_classes,
|
| 616 |
+
dtype=dtype,
|
| 617 |
+
low_zero=(device_map == "balanced_low_0"),
|
| 618 |
+
)
|
| 619 |
+
device_map = infer_auto_device_map(
|
| 620 |
+
model,
|
| 621 |
+
max_memory=max_memory,
|
| 622 |
+
no_split_module_classes=no_split_module_classes,
|
| 623 |
+
dtype=dtype,
|
| 624 |
+
offload_buffers=offload_buffers,
|
| 625 |
+
)
|
| 626 |
+
if offload_state_dict is None and device_map is not None and "disk" in device_map.values():
|
| 627 |
+
offload_state_dict = True
|
| 628 |
+
load_checkpoint_in_model(
|
| 629 |
+
model,
|
| 630 |
+
checkpoint,
|
| 631 |
+
device_map=device_map,
|
| 632 |
+
offload_folder=offload_folder,
|
| 633 |
+
dtype=dtype,
|
| 634 |
+
offload_state_dict=offload_state_dict,
|
| 635 |
+
offload_buffers=offload_buffers,
|
| 636 |
+
strict=strict,
|
| 637 |
+
full_state_dict=full_state_dict,
|
| 638 |
+
broadcast_from_rank0=broadcast_from_rank0,
|
| 639 |
+
)
|
| 640 |
+
if device_map is None:
|
| 641 |
+
return model
|
| 642 |
+
return dispatch_model(
|
| 643 |
+
model,
|
| 644 |
+
device_map=device_map,
|
| 645 |
+
offload_dir=offload_folder,
|
| 646 |
+
offload_buffers=offload_buffers,
|
| 647 |
+
skip_keys=skip_keys,
|
| 648 |
+
preload_module_classes=preload_module_classes,
|
| 649 |
+
force_hooks=force_hooks,
|
| 650 |
+
)
|
| 651 |
+
|
| 652 |
+
|
| 653 |
+
def attach_layerwise_casting_hooks(
|
| 654 |
+
module: torch.nn.Module,
|
| 655 |
+
storage_dtype: torch.dtype,
|
| 656 |
+
compute_dtype: torch.dtype,
|
| 657 |
+
skip_modules_pattern: Optional[Union[str, tuple[str, ...]]] = None,
|
| 658 |
+
skip_modules_classes: Optional[tuple[type[torch.nn.Module], ...]] = None,
|
| 659 |
+
non_blocking: bool = False,
|
| 660 |
+
) -> None:
|
| 661 |
+
r"""
|
| 662 |
+
Applies layerwise casting to a given module. The module expected here is a PyTorch `nn.Module`. This is helpful for
|
| 663 |
+
reducing memory requirements when one doesn't want to fully quantize a model. Model params can be kept in say,
|
| 664 |
+
`torch.float8_e4m3fn` and upcasted to a higher precision like `torch.bfloat16` during forward pass and downcasted
|
| 665 |
+
back to `torch.float8_e4m3fn` to realize memory savings.
|
| 666 |
+
|
| 667 |
+
Args:
|
| 668 |
+
module (`torch.nn.Module`):
|
| 669 |
+
The module whose leaf modules will be cast to a high precision dtype for computation, and to a low
|
| 670 |
+
precision dtype for storage.
|
| 671 |
+
storage_dtype (`torch.dtype`):
|
| 672 |
+
The dtype to cast the module to before/after the forward pass for storage.
|
| 673 |
+
compute_dtype (`torch.dtype`):
|
| 674 |
+
The dtype to cast the module to during the forward pass for computation.
|
| 675 |
+
skip_modules_pattern (`tuple[str, ...]`, defaults to `None`):
|
| 676 |
+
A list of patterns to match the names of the modules to skip during the layerwise casting process. If set
|
| 677 |
+
to `None` alongside `skip_modules_classes` being `None`, the layerwise casting is applied directly to the
|
| 678 |
+
module instead of its internal submodules.
|
| 679 |
+
skip_modules_classes (`tuple[type[torch.nn.Module], ...]`, defaults to `None`):
|
| 680 |
+
A list of module classes to skip during the layerwise casting process.
|
| 681 |
+
non_blocking (`bool`, defaults to `False`):
|
| 682 |
+
If `True`, the weight casting operations are non-blocking.
|
| 683 |
+
|
| 684 |
+
Example:
|
| 685 |
+
|
| 686 |
+
```python
|
| 687 |
+
>>> from accelerate.hooks import attach_layerwise_casting_hooks
|
| 688 |
+
>>> from transformers import AutoModelForCausalLM
|
| 689 |
+
>>> import torch
|
| 690 |
+
|
| 691 |
+
>>> # Model
|
| 692 |
+
>>> checkpoint = "EleutherAI/gpt-j-6B"
|
| 693 |
+
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
| 694 |
+
|
| 695 |
+
>>> # Attach hooks and perform inference
|
| 696 |
+
>>> attach_layerwise_casting_hooks(model, storage_dtype=torch.float8_e4m3fn, compute_dtype=torch.bfloat16)
|
| 697 |
+
>>> with torch.no_grad():
|
| 698 |
+
... model(...)
|
| 699 |
+
```
|
| 700 |
+
|
| 701 |
+
Users can also pass modules they want to avoid from getting downcasted.
|
| 702 |
+
|
| 703 |
+
```py
|
| 704 |
+
>>> attach_layerwise_casting_hooks(
|
| 705 |
+
... model, storage_dtype=torch.float8_e4m3fn, compute_dtype=torch.bfloat16, skip_modules_pattern=["norm"]
|
| 706 |
+
... )
|
| 707 |
+
```
|
| 708 |
+
"""
|
| 709 |
+
_attach_layerwise_casting_hooks(
|
| 710 |
+
module, storage_dtype, compute_dtype, skip_modules_pattern, skip_modules_classes, non_blocking
|
| 711 |
+
)
|
| 712 |
+
|
| 713 |
+
|
| 714 |
+
def _attach_layerwise_casting_hooks(
|
| 715 |
+
module: torch.nn.Module,
|
| 716 |
+
storage_dtype: torch.dtype,
|
| 717 |
+
compute_dtype: torch.dtype,
|
| 718 |
+
skip_modules_pattern: Optional[Union[str, tuple[str, ...]]] = None,
|
| 719 |
+
skip_modules_classes: Optional[tuple[type[torch.nn.Module], ...]] = None,
|
| 720 |
+
non_blocking: bool = False,
|
| 721 |
+
_prefix: str = "",
|
| 722 |
+
):
|
| 723 |
+
should_skip = (skip_modules_classes is not None and isinstance(module, skip_modules_classes)) or (
|
| 724 |
+
skip_modules_pattern is not None and any(re.search(pattern, _prefix) for pattern in skip_modules_pattern)
|
| 725 |
+
)
|
| 726 |
+
if should_skip:
|
| 727 |
+
logger.debug(f'Skipping layerwise casting for layer "{_prefix}"')
|
| 728 |
+
return
|
| 729 |
+
|
| 730 |
+
if isinstance(module, SUPPORTED_PYTORCH_LAYERS_FOR_UPCASTING):
|
| 731 |
+
logger.debug(f'Applying layerwise casting to layer "{_prefix}"')
|
| 732 |
+
add_hook_to_module(
|
| 733 |
+
module,
|
| 734 |
+
LayerwiseCastingHook(storage_dtype=storage_dtype, compute_dtype=compute_dtype, non_blocking=non_blocking),
|
| 735 |
+
append=True,
|
| 736 |
+
)
|
| 737 |
+
return
|
| 738 |
+
|
| 739 |
+
for name, submodule in module.named_children():
|
| 740 |
+
layer_name = f"{_prefix}.{name}" if _prefix else name
|
| 741 |
+
_attach_layerwise_casting_hooks(
|
| 742 |
+
submodule,
|
| 743 |
+
storage_dtype,
|
| 744 |
+
compute_dtype,
|
| 745 |
+
skip_modules_pattern,
|
| 746 |
+
skip_modules_classes,
|
| 747 |
+
non_blocking,
|
| 748 |
+
_prefix=layer_name,
|
| 749 |
+
)
|
| 750 |
+
|
| 751 |
+
|
| 752 |
+
def _attach_context_parallel_hooks(
|
| 753 |
+
model: nn.Module,
|
| 754 |
+
):
|
| 755 |
+
"""
|
| 756 |
+
Monkeypatch huggingface's `transformers` model to fix attention mask issues when using context parallelism.
|
| 757 |
+
|
| 758 |
+
This function attaches forward_pre_hooks to each self_attn module of the model, where each hook checks the
|
| 759 |
+
args/kwargs, if they contain an attention mask, if it does, it will remove this mask, check if it is a causal mask,
|
| 760 |
+
if yes, will add a kwarg `is_causal=True`, otherwise will raise an error. This is because context parallelism does
|
| 761 |
+
not support attention masks. This function modifies the model in place.
|
| 762 |
+
|
| 763 |
+
Args:
|
| 764 |
+
model (`nn.Module`):
|
| 765 |
+
The model to attach the hooks to.
|
| 766 |
+
|
| 767 |
+
"""
|
| 768 |
+
|
| 769 |
+
def _self_attn_pre_forward_hook(_module, module_args, module_kwargs):
|
| 770 |
+
if "attention_mask" in module_kwargs:
|
| 771 |
+
module_kwargs["attention_mask"] = None
|
| 772 |
+
module_kwargs["is_causal"] = True
|
| 773 |
+
|
| 774 |
+
return module_args, module_kwargs
|
| 775 |
+
|
| 776 |
+
for name, module in model.named_modules():
|
| 777 |
+
# We hope (assume) that if user uses their own model (without this structure which transformers uses), they read the docs saying they can't pass in attention masks
|
| 778 |
+
# Then these cases can happen:
|
| 779 |
+
# 1) some modules end with a `self-attn` module, in which case we attach the hook, but the
|
| 780 |
+
# there's no attention mask kwarg -> hook is a no-op
|
| 781 |
+
# 2) some modules end with a `self-attn` module, in which case we attach the hook, and the
|
| 782 |
+
# attention mask kwarg is passed -> hook will remove the attention mask and add
|
| 783 |
+
# `is_causal=True` kwarg, which either crashes the training or fixes it
|
| 784 |
+
# (training would crash anyway as attention mask isn't supported)
|
| 785 |
+
# 3) no modules end with a `self-attn` module, in which case we don't attach the hook, this is
|
| 786 |
+
# a no-op as well
|
| 787 |
+
if name.endswith("self_attn"):
|
| 788 |
+
# we want the hook to be executed first, to avoid any other hooks doing work on the attention mask
|
| 789 |
+
module.register_forward_pre_hook(_self_attn_pre_forward_hook, with_kwargs=True, prepend=True)
|