SuperRealCo commited on
Commit
d95e807
·
verified ·
1 Parent(s): 59fcc05

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +3 -0
  2. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/INSTALLER +1 -0
  3. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/METADATA +397 -0
  4. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/RECORD +177 -0
  5. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/REQUESTED +0 -0
  6. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/WHEEL +5 -0
  7. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/entry_points.txt +6 -0
  8. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/licenses/LICENSE +201 -0
  9. venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/top_level.txt +1 -0
  10. venv/lib/python3.10/site-packages/accelerate/__init__.py +50 -0
  11. venv/lib/python3.10/site-packages/accelerate/__pycache__/__init__.cpython-310.pyc +0 -0
  12. venv/lib/python3.10/site-packages/accelerate/__pycache__/big_modeling.cpython-310.pyc +0 -0
  13. venv/lib/python3.10/site-packages/accelerate/__pycache__/checkpointing.cpython-310.pyc +0 -0
  14. venv/lib/python3.10/site-packages/accelerate/__pycache__/data_loader.cpython-310.pyc +0 -0
  15. venv/lib/python3.10/site-packages/accelerate/__pycache__/hooks.cpython-310.pyc +0 -0
  16. venv/lib/python3.10/site-packages/accelerate/__pycache__/inference.cpython-310.pyc +0 -0
  17. venv/lib/python3.10/site-packages/accelerate/__pycache__/launchers.cpython-310.pyc +0 -0
  18. venv/lib/python3.10/site-packages/accelerate/__pycache__/local_sgd.cpython-310.pyc +0 -0
  19. venv/lib/python3.10/site-packages/accelerate/__pycache__/logging.cpython-310.pyc +0 -0
  20. venv/lib/python3.10/site-packages/accelerate/__pycache__/memory_utils.cpython-310.pyc +0 -0
  21. venv/lib/python3.10/site-packages/accelerate/__pycache__/optimizer.cpython-310.pyc +0 -0
  22. venv/lib/python3.10/site-packages/accelerate/__pycache__/scheduler.cpython-310.pyc +0 -0
  23. venv/lib/python3.10/site-packages/accelerate/__pycache__/state.cpython-310.pyc +0 -0
  24. venv/lib/python3.10/site-packages/accelerate/__pycache__/tracking.cpython-310.pyc +0 -0
  25. venv/lib/python3.10/site-packages/accelerate/accelerator.py +0 -0
  26. venv/lib/python3.10/site-packages/accelerate/big_modeling.py +749 -0
  27. venv/lib/python3.10/site-packages/accelerate/checkpointing.py +330 -0
  28. venv/lib/python3.10/site-packages/accelerate/data_loader.py +1446 -0
  29. venv/lib/python3.10/site-packages/accelerate/hooks.py +765 -0
  30. venv/lib/python3.10/site-packages/accelerate/inference.py +184 -0
  31. venv/lib/python3.10/site-packages/accelerate/launchers.py +306 -0
  32. venv/lib/python3.10/site-packages/accelerate/local_sgd.py +106 -0
  33. venv/lib/python3.10/site-packages/accelerate/logging.py +125 -0
  34. venv/lib/python3.10/site-packages/accelerate/memory_utils.py +22 -0
  35. venv/lib/python3.10/site-packages/accelerate/optimizer.py +213 -0
  36. venv/lib/python3.10/site-packages/accelerate/scheduler.py +98 -0
  37. venv/lib/python3.10/site-packages/accelerate/state.py +1347 -0
  38. venv/lib/python3.10/site-packages/accelerate/test_utils/__init__.py +65 -0
  39. venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/__init__.cpython-310.pyc +0 -0
  40. venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/examples.cpython-310.pyc +0 -0
  41. venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/testing.cpython-310.pyc +0 -0
  42. venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/training.cpython-310.pyc +0 -0
  43. venv/lib/python3.10/site-packages/accelerate/test_utils/examples.py +145 -0
  44. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__init__.py +13 -0
  45. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_merge_weights.cpython-310.pyc +0 -0
  46. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_notebook.cpython-310.pyc +0 -0
  47. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_ops.cpython-310.pyc +0 -0
  48. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_script.cpython-310.pyc +0 -0
  49. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_sync.cpython-310.pyc +0 -0
  50. venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/test_cli.py +32 -0
.gitattributes CHANGED
@@ -69,3 +69,6 @@ venv/lib/python3.10/site-packages/chardet/__pycache__/johabfreq.cpython-310.pyc
69
  venv/lib/python3.10/site-packages/nacl/_sodium.abi3.so filter=lfs diff=lfs merge=lfs -text
70
  venv/lib/python3.10/site-packages/pygments/lexers/__pycache__/lisp.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
71
  venv/lib/python3.10/site-packages/wrapt/_wrappers.cpython-310-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
 
 
 
 
69
  venv/lib/python3.10/site-packages/nacl/_sodium.abi3.so filter=lfs diff=lfs merge=lfs -text
70
  venv/lib/python3.10/site-packages/pygments/lexers/__pycache__/lisp.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
71
  venv/lib/python3.10/site-packages/wrapt/_wrappers.cpython-310-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
72
+ venv/lib/python3.10/site-packages/diffusers/models/__pycache__/attention_processor.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
73
+ venv/lib/python3.10/site-packages/accelerate/utils/__pycache__/dataclasses.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
74
+ venv/lib/python3.10/site-packages/diffusers/loaders/__pycache__/lora_pipeline.cpython-310.pyc filter=lfs diff=lfs merge=lfs -text
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/METADATA ADDED
@@ -0,0 +1,397 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: accelerate
3
+ Version: 1.9.0
4
+ Summary: Accelerate
5
+ Home-page: https://github.com/huggingface/accelerate
6
+ Author: The HuggingFace team
7
+ Author-email: zach.mueller@huggingface.co
8
+ License: Apache
9
+ Keywords: deep learning
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.9.0
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy<3.0.0,>=1.17
23
+ Requires-Dist: packaging>=20.0
24
+ Requires-Dist: psutil
25
+ Requires-Dist: pyyaml
26
+ Requires-Dist: torch>=2.0.0
27
+ Requires-Dist: huggingface_hub>=0.21.0
28
+ Requires-Dist: safetensors>=0.4.3
29
+ Provides-Extra: quality
30
+ Requires-Dist: black~=23.1; extra == "quality"
31
+ Requires-Dist: hf-doc-builder>=0.3.0; extra == "quality"
32
+ Requires-Dist: ruff~=0.11.2; extra == "quality"
33
+ Provides-Extra: docs
34
+ Provides-Extra: test-prod
35
+ Requires-Dist: pytest<=8.0.0,>=7.2.0; extra == "test-prod"
36
+ Requires-Dist: pytest-xdist; extra == "test-prod"
37
+ Requires-Dist: pytest-subtests; extra == "test-prod"
38
+ Requires-Dist: parameterized; extra == "test-prod"
39
+ Requires-Dist: pytest-order; extra == "test-prod"
40
+ Provides-Extra: test-dev
41
+ Requires-Dist: datasets; extra == "test-dev"
42
+ Requires-Dist: diffusers; extra == "test-dev"
43
+ Requires-Dist: evaluate; extra == "test-dev"
44
+ Requires-Dist: torchdata>=0.8.0; extra == "test-dev"
45
+ Requires-Dist: torchpippy>=0.2.0; extra == "test-dev"
46
+ Requires-Dist: transformers; extra == "test-dev"
47
+ Requires-Dist: scipy; extra == "test-dev"
48
+ Requires-Dist: scikit-learn; extra == "test-dev"
49
+ Requires-Dist: tqdm; extra == "test-dev"
50
+ Requires-Dist: bitsandbytes; extra == "test-dev"
51
+ Requires-Dist: timm; extra == "test-dev"
52
+ Provides-Extra: testing
53
+ Requires-Dist: pytest<=8.0.0,>=7.2.0; extra == "testing"
54
+ Requires-Dist: pytest-xdist; extra == "testing"
55
+ Requires-Dist: pytest-subtests; extra == "testing"
56
+ Requires-Dist: parameterized; extra == "testing"
57
+ Requires-Dist: pytest-order; extra == "testing"
58
+ Requires-Dist: datasets; extra == "testing"
59
+ Requires-Dist: diffusers; extra == "testing"
60
+ Requires-Dist: evaluate; extra == "testing"
61
+ Requires-Dist: torchdata>=0.8.0; extra == "testing"
62
+ Requires-Dist: torchpippy>=0.2.0; extra == "testing"
63
+ Requires-Dist: transformers; extra == "testing"
64
+ Requires-Dist: scipy; extra == "testing"
65
+ Requires-Dist: scikit-learn; extra == "testing"
66
+ Requires-Dist: tqdm; extra == "testing"
67
+ Requires-Dist: bitsandbytes; extra == "testing"
68
+ Requires-Dist: timm; extra == "testing"
69
+ Provides-Extra: deepspeed
70
+ Requires-Dist: deepspeed; extra == "deepspeed"
71
+ Provides-Extra: rich
72
+ Requires-Dist: rich; extra == "rich"
73
+ Provides-Extra: test-fp8
74
+ Requires-Dist: torchao; extra == "test-fp8"
75
+ Provides-Extra: test-trackers
76
+ Requires-Dist: wandb; extra == "test-trackers"
77
+ Requires-Dist: comet-ml; extra == "test-trackers"
78
+ Requires-Dist: tensorboard; extra == "test-trackers"
79
+ Requires-Dist: dvclive; extra == "test-trackers"
80
+ Requires-Dist: mlflow; extra == "test-trackers"
81
+ Requires-Dist: matplotlib; extra == "test-trackers"
82
+ Requires-Dist: swanlab; extra == "test-trackers"
83
+ Requires-Dist: trackio; extra == "test-trackers"
84
+ Provides-Extra: dev
85
+ Requires-Dist: black~=23.1; extra == "dev"
86
+ Requires-Dist: hf-doc-builder>=0.3.0; extra == "dev"
87
+ Requires-Dist: ruff~=0.11.2; extra == "dev"
88
+ Requires-Dist: pytest<=8.0.0,>=7.2.0; extra == "dev"
89
+ Requires-Dist: pytest-xdist; extra == "dev"
90
+ Requires-Dist: pytest-subtests; extra == "dev"
91
+ Requires-Dist: parameterized; extra == "dev"
92
+ Requires-Dist: pytest-order; extra == "dev"
93
+ Requires-Dist: datasets; extra == "dev"
94
+ Requires-Dist: diffusers; extra == "dev"
95
+ Requires-Dist: evaluate; extra == "dev"
96
+ Requires-Dist: torchdata>=0.8.0; extra == "dev"
97
+ Requires-Dist: torchpippy>=0.2.0; extra == "dev"
98
+ Requires-Dist: transformers; extra == "dev"
99
+ Requires-Dist: scipy; extra == "dev"
100
+ Requires-Dist: scikit-learn; extra == "dev"
101
+ Requires-Dist: tqdm; extra == "dev"
102
+ Requires-Dist: bitsandbytes; extra == "dev"
103
+ Requires-Dist: timm; extra == "dev"
104
+ Requires-Dist: rich; extra == "dev"
105
+ Provides-Extra: sagemaker
106
+ Requires-Dist: sagemaker; extra == "sagemaker"
107
+ Dynamic: author
108
+ Dynamic: author-email
109
+ Dynamic: classifier
110
+ Dynamic: description
111
+ Dynamic: description-content-type
112
+ Dynamic: home-page
113
+ Dynamic: keywords
114
+ Dynamic: license
115
+ Dynamic: license-file
116
+ Dynamic: provides-extra
117
+ Dynamic: requires-dist
118
+ Dynamic: requires-python
119
+ Dynamic: summary
120
+
121
+ <!---
122
+ Copyright 2021 The HuggingFace Team. All rights reserved.
123
+
124
+ Licensed under the Apache License, Version 2.0 (the "License");
125
+ you may not use this file except in compliance with the License.
126
+ You may obtain a copy of the License at
127
+
128
+ http://www.apache.org/licenses/LICENSE-2.0
129
+
130
+ Unless required by applicable law or agreed to in writing, software
131
+ distributed under the License is distributed on an "AS IS" BASIS,
132
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133
+ See the License for the specific language governing permissions and
134
+ limitations under the License.
135
+ -->
136
+
137
+ <p align="center">
138
+ <br>
139
+ <img src="https://raw.githubusercontent.com/huggingface/accelerate/main/docs/source/imgs/accelerate_logo.png" width="400"/>
140
+ <br>
141
+ <p>
142
+
143
+ <p align="center">
144
+ <!-- Uncomment when CircleCI is set up
145
+ <a href="https://circleci.com/gh/huggingface/accelerate"><img alt="Build" src="https://img.shields.io/circleci/build/github/huggingface/transformers/master"></a>
146
+ -->
147
+ <a href="https://github.com/huggingface/accelerate/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/huggingface/accelerate.svg?color=blue"></a>
148
+ <a href="https://huggingface.co/docs/accelerate/index.html"><img alt="Documentation" src="https://img.shields.io/website/http/huggingface.co/docs/accelerate/index.html.svg?down_color=red&down_message=offline&up_message=online"></a>
149
+ <a href="https://github.com/huggingface/accelerate/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/huggingface/accelerate.svg"></a>
150
+ <a href="https://github.com/huggingface/accelerate/blob/main/CODE_OF_CONDUCT.md"><img alt="Contributor Covenant" src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg"></a>
151
+ </p>
152
+
153
+ <h3 align="center">
154
+ <p>Run your *raw* PyTorch training script on any kind of device
155
+ </h3>
156
+
157
+ <h3 align="center">
158
+ <a href="https://hf.co/course"><img src="https://raw.githubusercontent.com/huggingface/accelerate/main/docs/source/imgs/course_banner.png"></a>
159
+ </h3>
160
+
161
+ ## Easy to integrate
162
+
163
+ 🤗 Accelerate was created for PyTorch users who like to write the training loop of PyTorch models but are reluctant to write and maintain the boilerplate code needed to use multi-GPUs/TPU/fp16.
164
+
165
+ 🤗 Accelerate abstracts exactly and only the boilerplate code related to multi-GPUs/TPU/fp16 and leaves the rest of your code unchanged.
166
+
167
+ Here is an example:
168
+
169
+ ```diff
170
+ import torch
171
+ import torch.nn.functional as F
172
+ from datasets import load_dataset
173
+ + from accelerate import Accelerator
174
+
175
+ + accelerator = Accelerator()
176
+ - device = 'cpu'
177
+ + device = accelerator.device
178
+
179
+ model = torch.nn.Transformer().to(device)
180
+ optimizer = torch.optim.Adam(model.parameters())
181
+
182
+ dataset = load_dataset('my_dataset')
183
+ data = torch.utils.data.DataLoader(dataset, shuffle=True)
184
+
185
+ + model, optimizer, data = accelerator.prepare(model, optimizer, data)
186
+
187
+ model.train()
188
+ for epoch in range(10):
189
+ for source, targets in data:
190
+ source = source.to(device)
191
+ targets = targets.to(device)
192
+
193
+ optimizer.zero_grad()
194
+
195
+ output = model(source)
196
+ loss = F.cross_entropy(output, targets)
197
+
198
+ - loss.backward()
199
+ + accelerator.backward(loss)
200
+
201
+ optimizer.step()
202
+ ```
203
+
204
+ As you can see in this example, by adding 5-lines to any standard PyTorch training script you can now run on any kind of single or distributed node setting (single CPU, single GPU, multi-GPUs and TPUs) as well as with or without mixed precision (fp8, fp16, bf16).
205
+
206
+ In particular, the same code can then be run without modification on your local machine for debugging or your training environment.
207
+
208
+ 🤗 Accelerate even handles the device placement for you (which requires a few more changes to your code, but is safer in general), so you can even simplify your training loop further:
209
+
210
+ ```diff
211
+ import torch
212
+ import torch.nn.functional as F
213
+ from datasets import load_dataset
214
+ + from accelerate import Accelerator
215
+
216
+ - device = 'cpu'
217
+ + accelerator = Accelerator()
218
+
219
+ - model = torch.nn.Transformer().to(device)
220
+ + model = torch.nn.Transformer()
221
+ optimizer = torch.optim.Adam(model.parameters())
222
+
223
+ dataset = load_dataset('my_dataset')
224
+ data = torch.utils.data.DataLoader(dataset, shuffle=True)
225
+
226
+ + model, optimizer, data = accelerator.prepare(model, optimizer, data)
227
+
228
+ model.train()
229
+ for epoch in range(10):
230
+ for source, targets in data:
231
+ - source = source.to(device)
232
+ - targets = targets.to(device)
233
+
234
+ optimizer.zero_grad()
235
+
236
+ output = model(source)
237
+ loss = F.cross_entropy(output, targets)
238
+
239
+ - loss.backward()
240
+ + accelerator.backward(loss)
241
+
242
+ optimizer.step()
243
+ ```
244
+
245
+ Want to learn more? Check out the [documentation](https://huggingface.co/docs/accelerate) or have a look at our [examples](https://github.com/huggingface/accelerate/tree/main/examples).
246
+
247
+ ## Launching script
248
+
249
+ 🤗 Accelerate also provides an optional CLI tool that allows you to quickly configure and test your training environment before launching the scripts. No need to remember how to use `torch.distributed.run` or to write a specific launcher for TPU training!
250
+ On your machine(s) just run:
251
+
252
+ ```bash
253
+ accelerate config
254
+ ```
255
+
256
+ and answer the questions asked. This will generate a config file that will be used automatically to properly set the default options when doing
257
+
258
+ ```bash
259
+ accelerate launch my_script.py --args_to_my_script
260
+ ```
261
+
262
+ For instance, here is how you would run the GLUE example on the MRPC task (from the root of the repo):
263
+
264
+ ```bash
265
+ accelerate launch examples/nlp_example.py
266
+ ```
267
+
268
+ This CLI tool is **optional**, and you can still use `python my_script.py` or `python -m torchrun my_script.py` at your convenience.
269
+
270
+ You can also directly pass in the arguments you would to `torchrun` as arguments to `accelerate launch` if you wish to not run` accelerate config`.
271
+
272
+ For example, here is how to launch on two GPUs:
273
+
274
+ ```bash
275
+ accelerate launch --multi_gpu --num_processes 2 examples/nlp_example.py
276
+ ```
277
+
278
+ To learn more, check the CLI documentation available [here](https://huggingface.co/docs/accelerate/package_reference/cli).
279
+
280
+ Or view the configuration zoo [here](https://github.com/huggingface/accelerate/blob/main/examples/config_yaml_templates/)
281
+
282
+ ## Launching multi-CPU run using MPI
283
+
284
+ 🤗 Here is another way to launch multi-CPU run using MPI. You can learn how to install Open MPI on [this page](https://www.open-mpi.org/faq/?category=building#easy-build). You can use Intel MPI or MVAPICH as well.
285
+ Once you have MPI setup on your cluster, just run:
286
+ ```bash
287
+ accelerate config
288
+ ```
289
+ Answer the questions that are asked, selecting to run using multi-CPU, and answer "yes" when asked if you want accelerate to launch mpirun.
290
+ Then, use `accelerate launch` with your script like:
291
+ ```bash
292
+ accelerate launch examples/nlp_example.py
293
+ ```
294
+ Alternatively, you can use mpirun directly, without using the CLI like:
295
+ ```bash
296
+ mpirun -np 2 python examples/nlp_example.py
297
+ ```
298
+
299
+ ## Launching training using DeepSpeed
300
+
301
+ 🤗 Accelerate supports training on single/multiple GPUs using DeepSpeed. To use it, you don't need to change anything in your training code; you can set everything using just `accelerate config`. However, if you desire to tweak your DeepSpeed related args from your Python script, we provide you the `DeepSpeedPlugin`.
302
+
303
+ ```python
304
+ from accelerate import Accelerator, DeepSpeedPlugin
305
+
306
+ # deepspeed needs to know your gradient accumulation steps beforehand, so don't forget to pass it
307
+ # Remember you still need to do gradient accumulation by yourself, just like you would have done without deepspeed
308
+ deepspeed_plugin = DeepSpeedPlugin(zero_stage=2, gradient_accumulation_steps=2)
309
+ accelerator = Accelerator(mixed_precision='fp16', deepspeed_plugin=deepspeed_plugin)
310
+
311
+ # How to save your 🤗 Transformer?
312
+ accelerator.wait_for_everyone()
313
+ unwrapped_model = accelerator.unwrap_model(model)
314
+ unwrapped_model.save_pretrained(save_dir, save_function=accelerator.save, state_dict=accelerator.get_state_dict(model))
315
+ ```
316
+
317
+ Note: DeepSpeed support is experimental for now. In case you get into some problem, please open an issue.
318
+
319
+ ## Launching your training from a notebook
320
+
321
+ 🤗 Accelerate also provides a `notebook_launcher` function you can use in a notebook to launch a distributed training. This is especially useful for Colab or Kaggle notebooks with a TPU backend. Just define your training loop in a `training_function` then in your last cell, add:
322
+
323
+ ```python
324
+ from accelerate import notebook_launcher
325
+
326
+ notebook_launcher(training_function)
327
+ ```
328
+
329
+ An example can be found in [this notebook](https://github.com/huggingface/notebooks/blob/main/examples/accelerate_examples/simple_nlp_example.ipynb). [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/accelerate_examples/simple_nlp_example.ipynb)
330
+
331
+ ## Why should I use 🤗 Accelerate?
332
+
333
+ You should use 🤗 Accelerate when you want to easily run your training scripts in a distributed environment without having to renounce full control over your training loop. This is not a high-level framework above PyTorch, just a thin wrapper so you don't have to learn a new library. In fact, the whole API of 🤗 Accelerate is in one class, the `Accelerator` object.
334
+
335
+ ## Why shouldn't I use 🤗 Accelerate?
336
+
337
+ You shouldn't use 🤗 Accelerate if you don't want to write a training loop yourself. There are plenty of high-level libraries above PyTorch that will offer you that, 🤗 Accelerate is not one of them.
338
+
339
+ ## Frameworks using 🤗 Accelerate
340
+
341
+ If you like the simplicity of 🤗 Accelerate but would prefer a higher-level abstraction around its capabilities, some frameworks and libraries that are built on top of 🤗 Accelerate are listed below:
342
+
343
+ * [Amphion](https://github.com/open-mmlab/Amphion) is a toolkit for Audio, Music, and Speech Generation. Its purpose is to support reproducible research and help junior researchers and engineers get started in the field of audio, music, and speech generation research and development.
344
+ * [Animus](https://github.com/Scitator/animus) is a minimalistic framework to run machine learning experiments. Animus highlights common "breakpoints" in ML experiments and provides a unified interface for them within [IExperiment](https://github.com/Scitator/animus/blob/main/animus/core.py#L76).
345
+ * [Catalyst](https://github.com/catalyst-team/catalyst#getting-started) is a PyTorch framework for Deep Learning Research and Development. It focuses on reproducibility, rapid experimentation, and codebase reuse so you can create something new rather than write yet another train loop. Catalyst provides a [Runner](https://catalyst-team.github.io/catalyst/api/core.html#runner) to connect all parts of the experiment: hardware backend, data transformations, model training, and inference logic.
346
+ * [fastai](https://github.com/fastai/fastai#installing) is a PyTorch framework for Deep Learning that simplifies training fast and accurate neural nets using modern best practices. fastai provides a [Learner](https://docs.fast.ai/learner.html#Learner) to handle the training, fine-tuning, and inference of deep learning algorithms.
347
+ * [Finetuner](https://github.com/jina-ai/finetuner) is a service that enables models to create higher-quality embeddings for semantic search, visual similarity search, cross-modal text<->image search, recommendation systems, clustering, duplication detection, anomaly detection, or other uses.
348
+ * [InvokeAI](https://github.com/invoke-ai/InvokeAI) is a creative engine for Stable Diffusion models, offering industry-leading WebUI, terminal usage support, and serves as the foundation for many commercial products.
349
+ * [Kornia](https://kornia.readthedocs.io/en/latest/get-started/introduction.html) is a differentiable library that allows classical computer vision to be integrated into deep learning models. Kornia provides a [Trainer](https://kornia.readthedocs.io/en/latest/x.html#kornia.x.Trainer) with the specific purpose to train and fine-tune the supported deep learning algorithms within the library.
350
+ * [Open Assistant](https://projects.laion.ai/Open-Assistant/) is a chat-based assistant that understands tasks, can interact with their party systems, and retrieve information dynamically to do so.
351
+ * [pytorch-accelerated](https://github.com/Chris-hughes10/pytorch-accelerated) is a lightweight training library, with a streamlined feature set centered around a general-purpose [Trainer](https://pytorch-accelerated.readthedocs.io/en/latest/trainer.html), that places a huge emphasis on simplicity and transparency; enabling users to understand exactly what is going on under the hood, but without having to write and maintain the boilerplate themselves!
352
+ * [Stable Diffusion web UI](https://github.com/AUTOMATIC1111/stable-diffusion-webui) is an open-source browser-based easy-to-use interface based on the Gradio library for Stable Diffusion.
353
+ * [torchkeras](https://github.com/lyhue1991/torchkeras) is a simple tool for training pytorch model just in a keras style, a dynamic and beautiful plot is provided in notebook to monitor your loss or metric.
354
+ * [transformers](https://github.com/huggingface/transformers) as a tool for helping train state-of-the-art machine learning models in PyTorch, Tensorflow, and JAX. (Accelerate is the backend for the PyTorch side).
355
+
356
+
357
+ ## Installation
358
+
359
+ This repository is tested on Python 3.8+ and PyTorch 1.10.0+
360
+
361
+ You should install 🤗 Accelerate in a [virtual environment](https://docs.python.org/3/library/venv.html). If you're unfamiliar with Python virtual environments, check out the [user guide](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/).
362
+
363
+ First, create a virtual environment with the version of Python you're going to use and activate it.
364
+
365
+ Then, you will need to install PyTorch: refer to the [official installation page](https://pytorch.org/get-started/locally/#start-locally) regarding the specific install command for your platform. Then 🤗 Accelerate can be installed using pip as follows:
366
+
367
+ ```bash
368
+ pip install accelerate
369
+ ```
370
+
371
+ ## Supported integrations
372
+
373
+ - CPU only
374
+ - multi-CPU on one node (machine)
375
+ - multi-CPU on several nodes (machines)
376
+ - single GPU
377
+ - multi-GPU on one node (machine)
378
+ - multi-GPU on several nodes (machines)
379
+ - TPU
380
+ - FP16/BFloat16 mixed precision
381
+ - FP8 mixed precision with [Transformer Engine](https://github.com/NVIDIA/TransformerEngine) or [MS-AMP](https://github.com/Azure/MS-AMP/)
382
+ - DeepSpeed support (Experimental)
383
+ - PyTorch Fully Sharded Data Parallel (FSDP) support (Experimental)
384
+ - Megatron-LM support (Experimental)
385
+
386
+ ## Citing 🤗 Accelerate
387
+
388
+ If you use 🤗 Accelerate in your publication, please cite it by using the following BibTeX entry.
389
+
390
+ ```bibtex
391
+ @Misc{accelerate,
392
+ title = {Accelerate: Training and inference at scale made simple, efficient and adaptable.},
393
+ author = {Sylvain Gugger and Lysandre Debut and Thomas Wolf and Philipp Schmid and Zachary Mueller and Sourab Mangrulkar and Marc Sun and Benjamin Bossan},
394
+ howpublished = {\url{https://github.com/huggingface/accelerate}},
395
+ year = {2022}
396
+ }
397
+ ```
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/RECORD ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ../../../bin/accelerate,sha256=pJLu-G8APkkbztTcu7dVc9nJQqoWaX6tRJMFbGk4rYY,251
2
+ ../../../bin/accelerate-config,sha256=5kNl4YYg0LvQP_PSDMsBgOEznOasBtSkMlPRHBdKu14,243
3
+ ../../../bin/accelerate-estimate-memory,sha256=SjoEbmGByXY58ySjRkLX4r_lpsqDOevAaGewm4SDzQ8,245
4
+ ../../../bin/accelerate-launch,sha256=vIEs89n_ZJS1V7y2Ggvt_9KGNSNyFZatek118eKrvWI,243
5
+ ../../../bin/accelerate-merge-weights,sha256=U_3uPjQ1AVtg0rUvrT4mScxYcue2lKnEqYVBADZ2UcE,242
6
+ accelerate-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
7
+ accelerate-1.9.0.dist-info/METADATA,sha256=nHhgqcSMeeHtgWVysVrwXnLx8yO-CqvYKFWNgQpTHsM,19866
8
+ accelerate-1.9.0.dist-info/RECORD,,
9
+ accelerate-1.9.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ accelerate-1.9.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
11
+ accelerate-1.9.0.dist-info/entry_points.txt,sha256=Vpy8gUGfZ-1VnM2229fb8CpJNLBdMH_wtJ9PQ7b_2tQ,296
12
+ accelerate-1.9.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
13
+ accelerate-1.9.0.dist-info/top_level.txt,sha256=esVfdxTidsjQ90zsN_rPpjLFJ4ijRlx4mnLrG09hlt4,11
14
+ accelerate/__init__.py,sha256=DOfEIpDInu8FrrQgZuJXl_mj_H2XIPjcKacOidSd174,1504
15
+ accelerate/__pycache__/__init__.cpython-310.pyc,,
16
+ accelerate/__pycache__/accelerator.cpython-310.pyc,,
17
+ accelerate/__pycache__/big_modeling.cpython-310.pyc,,
18
+ accelerate/__pycache__/checkpointing.cpython-310.pyc,,
19
+ accelerate/__pycache__/data_loader.cpython-310.pyc,,
20
+ accelerate/__pycache__/hooks.cpython-310.pyc,,
21
+ accelerate/__pycache__/inference.cpython-310.pyc,,
22
+ accelerate/__pycache__/launchers.cpython-310.pyc,,
23
+ accelerate/__pycache__/local_sgd.cpython-310.pyc,,
24
+ accelerate/__pycache__/logging.cpython-310.pyc,,
25
+ accelerate/__pycache__/memory_utils.cpython-310.pyc,,
26
+ accelerate/__pycache__/optimizer.cpython-310.pyc,,
27
+ accelerate/__pycache__/scheduler.cpython-310.pyc,,
28
+ accelerate/__pycache__/state.cpython-310.pyc,,
29
+ accelerate/__pycache__/tracking.cpython-310.pyc,,
30
+ accelerate/accelerator.py,sha256=Z0TCu7R50DQCvIk_VVmUrx0cPDs7PEWldDB585ByreE,181670
31
+ accelerate/big_modeling.py,sha256=bqqO4Lw00YErTup7MUM6saOVHRFvMNOdNqAwg96fBG0,34765
32
+ accelerate/checkpointing.py,sha256=ARi8ZNFlLQW2uz9hd2D5-5rRUNoY2zL7BSe8HQKBFjs,13957
33
+ accelerate/commands/__init__.py,sha256=m1PPTDT4ziIAvM0-FDSgIMIZ69Konn126s6LwuzH6v8,606
34
+ accelerate/commands/__pycache__/__init__.cpython-310.pyc,,
35
+ accelerate/commands/__pycache__/accelerate_cli.cpython-310.pyc,,
36
+ accelerate/commands/__pycache__/env.cpython-310.pyc,,
37
+ accelerate/commands/__pycache__/estimate.cpython-310.pyc,,
38
+ accelerate/commands/__pycache__/launch.cpython-310.pyc,,
39
+ accelerate/commands/__pycache__/merge.cpython-310.pyc,,
40
+ accelerate/commands/__pycache__/test.cpython-310.pyc,,
41
+ accelerate/commands/__pycache__/to_fsdp2.cpython-310.pyc,,
42
+ accelerate/commands/__pycache__/tpu.cpython-310.pyc,,
43
+ accelerate/commands/__pycache__/utils.cpython-310.pyc,,
44
+ accelerate/commands/accelerate_cli.py,sha256=SkwFad6Z1ZsGjtm7TiXFq8je-akshp_0WxX_6rGSBw8,1972
45
+ accelerate/commands/config/__init__.py,sha256=iJK8dgj3pc5Vdr1E7UuGoFu-BlybyXLxYDoTg9gXngE,1645
46
+ accelerate/commands/config/__pycache__/__init__.cpython-310.pyc,,
47
+ accelerate/commands/config/__pycache__/cluster.cpython-310.pyc,,
48
+ accelerate/commands/config/__pycache__/config.cpython-310.pyc,,
49
+ accelerate/commands/config/__pycache__/config_args.cpython-310.pyc,,
50
+ accelerate/commands/config/__pycache__/config_utils.cpython-310.pyc,,
51
+ accelerate/commands/config/__pycache__/default.cpython-310.pyc,,
52
+ accelerate/commands/config/__pycache__/sagemaker.cpython-310.pyc,,
53
+ accelerate/commands/config/__pycache__/update.cpython-310.pyc,,
54
+ accelerate/commands/config/cluster.py,sha256=Ln8AbiHX0fDLYV8Gxk3WjC2JL94CEAjuhhn6BKdQ1zE,37544
55
+ accelerate/commands/config/config.py,sha256=FuRlQvOjgATEtyqOSsGD-KEtOCvACOHjs2C-krrtldk,3035
56
+ accelerate/commands/config/config_args.py,sha256=hJo7E3J_T7MPNkgtyNjPilJuH-wJK09mGWF6CvGFYIQ,9970
57
+ accelerate/commands/config/config_utils.py,sha256=lbV9iKAVSF5bUyQDGpzFduhH5JENYgAilPpRLLlCEq8,3299
58
+ accelerate/commands/config/default.py,sha256=UY0dQ7w1peBkQe8QDCm3XJrTnsRcm_G-_hf44NzNAbU,6213
59
+ accelerate/commands/config/sagemaker.py,sha256=SRLup9XrV_Z-23A3d8gZbkqbonDcscMDDmbpmytCzbY,10636
60
+ accelerate/commands/config/update.py,sha256=NXW1J7GkUHpg71QlIXsmMB_0z8S8IZo2FWax5POwrhc,2395
61
+ accelerate/commands/env.py,sha256=gRGwtPhMMWmZ5NTMaMrgHXaOzBV6SvAtP78TuuJvC6g,4336
62
+ accelerate/commands/estimate.py,sha256=Qduq4xudVyIede37BMEe1rNhXf-rfW-MHV2KtwxdfEA,12585
63
+ accelerate/commands/launch.py,sha256=h-d1W1y6NEwciGdzeLY-aTQG2N6dx3iBgcwSZZ_Yjn0,46889
64
+ accelerate/commands/menu/__init__.py,sha256=uqSlBM0TFHBwzdv3p3SXfpAk1lZFp4h1a7mbBdscPHs,645
65
+ accelerate/commands/menu/__pycache__/__init__.cpython-310.pyc,,
66
+ accelerate/commands/menu/__pycache__/cursor.cpython-310.pyc,,
67
+ accelerate/commands/menu/__pycache__/helpers.cpython-310.pyc,,
68
+ accelerate/commands/menu/__pycache__/input.cpython-310.pyc,,
69
+ accelerate/commands/menu/__pycache__/keymap.cpython-310.pyc,,
70
+ accelerate/commands/menu/__pycache__/selection_menu.cpython-310.pyc,,
71
+ accelerate/commands/menu/cursor.py,sha256=-lmpJVAzvNc0c3EOtSuLoKB59zqylVCbYyWLPnrOmvQ,2028
72
+ accelerate/commands/menu/helpers.py,sha256=KrSB5fJjH4MUEUAQJ6bYaN16AYcnl9UalDrPD3DYeeg,1483
73
+ accelerate/commands/menu/input.py,sha256=T8Mdd-Y_OURgqfDV9qZh4Wf6hmT22AneNtJzj4JA1Rk,2512
74
+ accelerate/commands/menu/keymap.py,sha256=eXj-suyYs1m5dEHoUKN4mKAMLc8DWHnwhP6G6JSU0jQ,4086
75
+ accelerate/commands/menu/selection_menu.py,sha256=bxy-DHaKKC6SCToOlMBv5_z0MdUzylEg6Sio9OuV3GM,4921
76
+ accelerate/commands/merge.py,sha256=3Uo14LADvk8RJwZ_i6kIsGwWB3Ul5y8Uq47oHkDYqKU,2387
77
+ accelerate/commands/test.py,sha256=YrPYEaAACOGZ6btn2MV6NbMSEdBUcMWADLbQWaZSHtk,2149
78
+ accelerate/commands/to_fsdp2.py,sha256=gfbhoUT4qFB3LVDMNmckElgLG0yWm8aj_aofszeiJmM,5991
79
+ accelerate/commands/tpu.py,sha256=KyxDP7IuveidZrbW4rx2s8Ku3o_ptI6tzwr_R7ck0os,5548
80
+ accelerate/commands/utils.py,sha256=aT8xUCe2pCkFII7yZxcfaohEjgBAzMUM7WiD4UuWSOY,4150
81
+ accelerate/data_loader.py,sha256=ecNfEwXrFqhBzUEaa6_IUvr-yMfPcj1AoATqSffyUtU,65318
82
+ accelerate/hooks.py,sha256=y4eN7blCjOkXY9_mVBmkgiTKqJfasAKrHOddEHj91Vg,33293
83
+ accelerate/inference.py,sha256=NLANdzXm5PwmDWbPYkFmoRoQSLLvuhfvIG33xfpapT0,7668
84
+ accelerate/launchers.py,sha256=gKB8sH5YwV-hOM8ptbzHgm16729X6864vKdLOls4eUY,14176
85
+ accelerate/local_sgd.py,sha256=aCj_yqXK_FhhZRWEpzXIkgXBERH6fC3HyrC3nsOj1uA,4160
86
+ accelerate/logging.py,sha256=4XcgY_BV7Qn_enh2tZ-8fNtuaE_3n-LsYJbgwhRx_PI,5042
87
+ accelerate/memory_utils.py,sha256=3R5LoeHl6GgTZ-IMPrDZMdaEehWarGdPqODushb-6pg,862
88
+ accelerate/optimizer.py,sha256=p5qfCOMi8DAjvx6eECypo4ej3pvmQ_U_bgmrEAKc4hY,8158
89
+ accelerate/scheduler.py,sha256=des_4M_Tt1W8gCYZZbLla0GHBEgJY3Wx2EGBQPTzeiY,4238
90
+ accelerate/state.py,sha256=7GgdLMjGHLuv0t4SftscosFgbgIXTO0Itp1VwG9qdaM,56508
91
+ accelerate/test_utils/__init__.py,sha256=ROl3bvBqmuI6ueRlPRNkNC-83yb6u6z_FFzrHJtq8rM,1809
92
+ accelerate/test_utils/__pycache__/__init__.cpython-310.pyc,,
93
+ accelerate/test_utils/__pycache__/examples.cpython-310.pyc,,
94
+ accelerate/test_utils/__pycache__/testing.cpython-310.pyc,,
95
+ accelerate/test_utils/__pycache__/training.cpython-310.pyc,,
96
+ accelerate/test_utils/examples.py,sha256=CO3SlkkrORUjroreoPfBPwfcNCDlHSgNWIt81iz2oQ8,7257
97
+ accelerate/test_utils/scripts/__init__.py,sha256=m1PPTDT4ziIAvM0-FDSgIMIZ69Konn126s6LwuzH6v8,606
98
+ accelerate/test_utils/scripts/__pycache__/__init__.cpython-310.pyc,,
99
+ accelerate/test_utils/scripts/__pycache__/test_cli.cpython-310.pyc,,
100
+ accelerate/test_utils/scripts/__pycache__/test_ddp_comm_hook.cpython-310.pyc,,
101
+ accelerate/test_utils/scripts/__pycache__/test_distributed_data_loop.cpython-310.pyc,,
102
+ accelerate/test_utils/scripts/__pycache__/test_merge_weights.cpython-310.pyc,,
103
+ accelerate/test_utils/scripts/__pycache__/test_notebook.cpython-310.pyc,,
104
+ accelerate/test_utils/scripts/__pycache__/test_ops.cpython-310.pyc,,
105
+ accelerate/test_utils/scripts/__pycache__/test_script.cpython-310.pyc,,
106
+ accelerate/test_utils/scripts/__pycache__/test_sync.cpython-310.pyc,,
107
+ accelerate/test_utils/scripts/external_deps/__init__.py,sha256=m1PPTDT4ziIAvM0-FDSgIMIZ69Konn126s6LwuzH6v8,606
108
+ accelerate/test_utils/scripts/external_deps/__pycache__/__init__.cpython-310.pyc,,
109
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_checkpointing.cpython-310.pyc,,
110
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_ds_multiple_model.cpython-310.pyc,,
111
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_metrics.cpython-310.pyc,,
112
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_peak_memory_usage.cpython-310.pyc,,
113
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_performance.cpython-310.pyc,,
114
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_pippy.cpython-310.pyc,,
115
+ accelerate/test_utils/scripts/external_deps/__pycache__/test_zero3_integration.cpython-310.pyc,,
116
+ accelerate/test_utils/scripts/external_deps/test_checkpointing.py,sha256=XHaNRmnrARd1izXFjWGi5UjYGas-4vqayW51jAHBPCA,10699
117
+ accelerate/test_utils/scripts/external_deps/test_ds_multiple_model.py,sha256=Cg4-h0B4UcOQ5CxXjIdrsPVR5fFsWCv24DqZGjXEwW8,13790
118
+ accelerate/test_utils/scripts/external_deps/test_metrics.py,sha256=Ev2XKaiwmznoxKujskAAuISGChW646MOiyf0CXEPb9Y,12168
119
+ accelerate/test_utils/scripts/external_deps/test_peak_memory_usage.py,sha256=9Yn9Rc7d-yWr1fU0RagASPG5l8vrKeHVYbuYABbA-fU,12498
120
+ accelerate/test_utils/scripts/external_deps/test_performance.py,sha256=4SW108BHEdpzDA_VY4B0GKKAdms4QxVlVywhZ-CZwRI,11721
121
+ accelerate/test_utils/scripts/external_deps/test_pippy.py,sha256=rYF5bqSCe_pfylxDv2_2Q7S2mHIb9_6fGns-IcLgE_E,4789
122
+ accelerate/test_utils/scripts/external_deps/test_zero3_integration.py,sha256=P9alBOHZ9Lfqs5LoRP7bCbXl-tnsNrBkvJZGseibBeA,1665
123
+ accelerate/test_utils/scripts/test_cli.py,sha256=-p78NTJgKdeTNDqyrQuGEZZqMpnzdUHPyWZ05FMl5EI,1081
124
+ accelerate/test_utils/scripts/test_ddp_comm_hook.py,sha256=k_-2MBjLKNdMGIcneTbuGd84K05Wp1GEQX6DUVF9UBw,3566
125
+ accelerate/test_utils/scripts/test_distributed_data_loop.py,sha256=RUWTwd7DIpr2fl7JtKOsvTjMiJioTxO8FdSr2Lw_5uI,15137
126
+ accelerate/test_utils/scripts/test_merge_weights.py,sha256=r1oqPOMOqLe5zWenWWTyl9cDbbkFJadpNNiPNBlgR18,5982
127
+ accelerate/test_utils/scripts/test_notebook.py,sha256=qfIy3IvH74-kGn8nadBn_k7qrviqvsxy5ijsnUhuY6o,3894
128
+ accelerate/test_utils/scripts/test_ops.py,sha256=Bcs-h8EMJwULTfbizlFN5qkv3JraWEpoSZWMn-HswiI,6265
129
+ accelerate/test_utils/scripts/test_script.py,sha256=zns5-YNj5h3YHBk79XisiqDQfX2nl9UL8K_NS5IoqFg,36446
130
+ accelerate/test_utils/scripts/test_sync.py,sha256=PDe8sYZLCL2LKjj_L9b-Bh2BjAjeii9EZ8sZNfuYx5s,18817
131
+ accelerate/test_utils/testing.py,sha256=5cb7oMSn4y5vvcWaTF-1rWQ6YB6h_XaKKxOd81T8oM4,29698
132
+ accelerate/test_utils/training.py,sha256=jO5YEIr34jAcnJ_9WNp_x3zuHzSam_I6IgMvmcGm7yI,6456
133
+ accelerate/tracking.py,sha256=GNJRg-yFrDP5D4_Ru1PwJI3uBQdw_FuSH1_3fEFrlww,51450
134
+ accelerate/utils/__init__.py,sha256=9oseM-5xSca7nKEQvlvdrMifxDVcPVp5tuK6KwAbfuo,8029
135
+ accelerate/utils/__pycache__/__init__.cpython-310.pyc,,
136
+ accelerate/utils/__pycache__/ao.cpython-310.pyc,,
137
+ accelerate/utils/__pycache__/bnb.cpython-310.pyc,,
138
+ accelerate/utils/__pycache__/constants.cpython-310.pyc,,
139
+ accelerate/utils/__pycache__/dataclasses.cpython-310.pyc,,
140
+ accelerate/utils/__pycache__/deepspeed.cpython-310.pyc,,
141
+ accelerate/utils/__pycache__/environment.cpython-310.pyc,,
142
+ accelerate/utils/__pycache__/fsdp_utils.cpython-310.pyc,,
143
+ accelerate/utils/__pycache__/imports.cpython-310.pyc,,
144
+ accelerate/utils/__pycache__/launch.cpython-310.pyc,,
145
+ accelerate/utils/__pycache__/megatron_lm.cpython-310.pyc,,
146
+ accelerate/utils/__pycache__/memory.cpython-310.pyc,,
147
+ accelerate/utils/__pycache__/modeling.cpython-310.pyc,,
148
+ accelerate/utils/__pycache__/offload.cpython-310.pyc,,
149
+ accelerate/utils/__pycache__/operations.cpython-310.pyc,,
150
+ accelerate/utils/__pycache__/other.cpython-310.pyc,,
151
+ accelerate/utils/__pycache__/random.cpython-310.pyc,,
152
+ accelerate/utils/__pycache__/rich.cpython-310.pyc,,
153
+ accelerate/utils/__pycache__/torch_xla.cpython-310.pyc,,
154
+ accelerate/utils/__pycache__/tqdm.cpython-310.pyc,,
155
+ accelerate/utils/__pycache__/transformer_engine.cpython-310.pyc,,
156
+ accelerate/utils/__pycache__/versions.cpython-310.pyc,,
157
+ accelerate/utils/ao.py,sha256=yfi84ywNpXsKZ6di4jbmtd6bIvRi9bmygr3giN92_Pg,4777
158
+ accelerate/utils/bnb.py,sha256=PdgdXwjhQ4Sg9orj4hlUiMQlPxSsdsiNfFVq4yBtl-g,20651
159
+ accelerate/utils/constants.py,sha256=A5KmcIry76B9p4Fa8CuI5ugv7bVcyTc5g4IBU1cvky0,3516
160
+ accelerate/utils/dataclasses.py,sha256=REC089NzoyU3TfL-Tx5xYgzY6Ks4MLClMUWQVgzcGBQ,134397
161
+ accelerate/utils/deepspeed.py,sha256=gt-jwOpOtRs6N4sohuSO2I3x1qLoO6uYYjnPrKp6Zk4,14796
162
+ accelerate/utils/environment.py,sha256=h0zacbBkAp9szltTf5-aTr5NcbVsQp7wl6DFWp8XNuI,15257
163
+ accelerate/utils/fsdp_utils.py,sha256=D0RIBcvdWLdnpha0HS0L484GEYKSfDYCWvtBul737zg,36481
164
+ accelerate/utils/imports.py,sha256=7_8VRwewcD2O9MlpQjR7F1rZvZs8P5b2rr9U0eD1-zU,16715
165
+ accelerate/utils/launch.py,sha256=8kqF22yFrWVsuaEBsDGlpSSt_FR_8SBhVy0mtv4uUhQ,33421
166
+ accelerate/utils/megatron_lm.py,sha256=ZMxcYAdGnMWla2PtB04ctb9mhMfKUP8qLYusGNjyScU,58054
167
+ accelerate/utils/memory.py,sha256=N7QGA6wdx8Xw7F0V-0TFshJLiXWtRnoXgezNZesvinw,7213
168
+ accelerate/utils/modeling.py,sha256=g4OsRSSnJQMJ7q-CnUg2hUWQ2M0-0reeevD_CX0rdKQ,95847
169
+ accelerate/utils/offload.py,sha256=VFaL8oSJzqZ_47VuUQ69xZi9bF2heRSFoOSnnOxbGXc,7825
170
+ accelerate/utils/operations.py,sha256=84SpXwKsbNHHePboL9gUqK6bA5vo0kyH_gLAdwnzE_s,31266
171
+ accelerate/utils/other.py,sha256=fAUxeRbhs3y3827xRpqVWqgCPjE1Qt4Vxf1NMdNiWak,20283
172
+ accelerate/utils/random.py,sha256=Xv_ZJm9eaC2Q7rgZy9OpOunKuTingMiDQCH00qhNVxE,6220
173
+ accelerate/utils/rich.py,sha256=8JZX_uGMQX-BufdXxJpdne7BWd1KyLHSgbiGxrDMYr8,847
174
+ accelerate/utils/torch_xla.py,sha256=Pq1tuqN0X_pWDVza6YgjfO45uoJdoRVRForLeLQzFus,1908
175
+ accelerate/utils/tqdm.py,sha256=k8e9JnieTEQHCCNBaiBys7hPxWlEbyRASdIma-qy_X8,1657
176
+ accelerate/utils/transformer_engine.py,sha256=PENq1zhDzENnFFfV4hLzhZiiLo28tQFvmuhpQPlc3S0,6594
177
+ accelerate/utils/versions.py,sha256=UgmcbjBm--6CIx1ZamSAMjAK_B_2l48LbeaNygqej8M,2149
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/REQUESTED ADDED
File without changes
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (78.1.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/entry_points.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ [console_scripts]
2
+ accelerate = accelerate.commands.accelerate_cli:main
3
+ accelerate-config = accelerate.commands.config:main
4
+ accelerate-estimate-memory = accelerate.commands.estimate:main
5
+ accelerate-launch = accelerate.commands.launch:main
6
+ accelerate-merge-weights = accelerate.commands.merge:main
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
venv/lib/python3.10/site-packages/accelerate-1.9.0.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ accelerate
venv/lib/python3.10/site-packages/accelerate/__init__.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 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
+ __version__ = "1.9.0"
15
+
16
+ from .accelerator import Accelerator
17
+ from .big_modeling import (
18
+ cpu_offload,
19
+ cpu_offload_with_hook,
20
+ disk_offload,
21
+ dispatch_model,
22
+ init_empty_weights,
23
+ init_on_device,
24
+ load_checkpoint_and_dispatch,
25
+ )
26
+ from .data_loader import skip_first_batches
27
+ from .inference import prepare_pippy
28
+ from .launchers import debug_launcher, notebook_launcher
29
+ from .state import PartialState
30
+ from .utils import (
31
+ AutocastKwargs,
32
+ DataLoaderConfiguration,
33
+ DDPCommunicationHookType,
34
+ DeepSpeedPlugin,
35
+ DistributedDataParallelKwargs,
36
+ DistributedType,
37
+ FullyShardedDataParallelPlugin,
38
+ GradScalerKwargs,
39
+ InitProcessGroupKwargs,
40
+ ProfileKwargs,
41
+ find_executable_batch_size,
42
+ infer_auto_device_map,
43
+ is_rich_available,
44
+ load_checkpoint_in_model,
45
+ synchronize_rng_states,
46
+ )
47
+
48
+
49
+ if is_rich_available():
50
+ from .utils import rich
venv/lib/python3.10/site-packages/accelerate/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (1.22 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/big_modeling.cpython-310.pyc ADDED
Binary file (27.9 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/checkpointing.cpython-310.pyc ADDED
Binary file (9.71 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/data_loader.cpython-310.pyc ADDED
Binary file (43.5 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/hooks.cpython-310.pyc ADDED
Binary file (24.5 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/inference.cpython-310.pyc ADDED
Binary file (5.92 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/launchers.cpython-310.pyc ADDED
Binary file (10 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/local_sgd.cpython-310.pyc ADDED
Binary file (3.67 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/logging.cpython-310.pyc ADDED
Binary file (4.47 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/memory_utils.cpython-310.pyc ADDED
Binary file (421 Bytes). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/optimizer.cpython-310.pyc ADDED
Binary file (7.32 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/scheduler.cpython-310.pyc ADDED
Binary file (3.34 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/state.cpython-310.pyc ADDED
Binary file (43.6 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/__pycache__/tracking.cpython-310.pyc ADDED
Binary file (48.1 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/accelerator.py ADDED
The diff for this file is too large to render. See raw diff
 
venv/lib/python3.10/site-packages/accelerate/big_modeling.py ADDED
@@ -0,0 +1,749 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: 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: 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: 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: 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
+ )
venv/lib/python3.10/site-packages/accelerate/checkpointing.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 random
16
+ from pathlib import Path
17
+
18
+ import numpy as np
19
+ import torch
20
+ from safetensors.torch import load_model
21
+
22
+ from .utils import (
23
+ MODEL_NAME,
24
+ OPTIMIZER_NAME,
25
+ RNG_STATE_NAME,
26
+ SAFE_MODEL_NAME,
27
+ SAFE_WEIGHTS_NAME,
28
+ SAMPLER_NAME,
29
+ SCALER_NAME,
30
+ SCHEDULER_NAME,
31
+ WEIGHTS_NAME,
32
+ get_pretty_name,
33
+ is_cuda_available,
34
+ is_hpu_available,
35
+ is_mlu_available,
36
+ is_musa_available,
37
+ is_sdaa_available,
38
+ is_torch_version,
39
+ is_torch_xla_available,
40
+ is_xpu_available,
41
+ load,
42
+ save,
43
+ )
44
+
45
+
46
+ if is_torch_version(">=", "2.4.0"):
47
+ from torch.amp import GradScaler
48
+ else:
49
+ from torch.cuda.amp import GradScaler
50
+
51
+ if is_torch_xla_available():
52
+ import torch_xla.core.xla_model as xm
53
+
54
+ from .logging import get_logger
55
+ from .state import PartialState
56
+
57
+
58
+ logger = get_logger(__name__)
59
+
60
+
61
+ def save_accelerator_state(
62
+ output_dir: str,
63
+ model_states: list[dict],
64
+ optimizers: list,
65
+ schedulers: list,
66
+ dataloaders: list,
67
+ process_index: int,
68
+ step: int,
69
+ scaler: GradScaler = None,
70
+ save_on_each_node: bool = False,
71
+ safe_serialization: bool = True,
72
+ ):
73
+ """
74
+ Saves the current states of the models, optimizers, scaler, and RNG generators to a given directory.
75
+
76
+ <Tip>
77
+
78
+ If `safe_serialization` is `True`, models will be saved with `safetensors` while the rest are saved using native
79
+ `pickle`.
80
+
81
+ </Tip>
82
+
83
+ Args:
84
+ output_dir (`str` or `os.PathLike`):
85
+ The name of the folder to save all relevant weights and states.
86
+ model_states (`List[torch.nn.Module]`):
87
+ A list of model states
88
+ optimizers (`List[torch.optim.Optimizer]`):
89
+ A list of optimizer instances
90
+ schedulers (`List[torch.optim.lr_scheduler._LRScheduler]`):
91
+ A list of learning rate schedulers
92
+ dataloaders (`List[torch.utils.data.DataLoader]`):
93
+ A list of dataloader instances to save their sampler states
94
+ process_index (`int`):
95
+ The current process index in the Accelerator state
96
+ step (`int`):
97
+ The current step in the internal step tracker
98
+ scaler (`torch.amp.GradScaler`, *optional*):
99
+ An optional gradient scaler instance to save;
100
+ save_on_each_node (`bool`, *optional*):
101
+ Whether to save on every node, or only the main node.
102
+ safe_serialization (`bool`, *optional*, defaults to `True`):
103
+ Whether to save the model using `safetensors` or the traditional PyTorch way (that uses `pickle`).
104
+ """
105
+ output_dir = Path(output_dir)
106
+ # Model states
107
+ for i, state in enumerate(model_states):
108
+ weights_name = WEIGHTS_NAME if not safe_serialization else SAFE_WEIGHTS_NAME
109
+ if i > 0:
110
+ weights_name = weights_name.replace(".", f"_{i}.")
111
+ output_model_file = output_dir.joinpath(weights_name)
112
+ save(state, output_model_file, save_on_each_node=save_on_each_node, safe_serialization=safe_serialization)
113
+ logger.info(f"Model weights saved in {output_model_file}")
114
+ # Optimizer states
115
+ for i, opt in enumerate(optimizers):
116
+ state = opt.state_dict()
117
+ optimizer_name = f"{OPTIMIZER_NAME}.bin" if i == 0 else f"{OPTIMIZER_NAME}_{i}.bin"
118
+ output_optimizer_file = output_dir.joinpath(optimizer_name)
119
+ save(state, output_optimizer_file, save_on_each_node=save_on_each_node, safe_serialization=False)
120
+ logger.info(f"Optimizer state saved in {output_optimizer_file}")
121
+ # Scheduler states
122
+ for i, scheduler in enumerate(schedulers):
123
+ state = scheduler.state_dict()
124
+ scheduler_name = f"{SCHEDULER_NAME}.bin" if i == 0 else f"{SCHEDULER_NAME}_{i}.bin"
125
+ output_scheduler_file = output_dir.joinpath(scheduler_name)
126
+ save(state, output_scheduler_file, save_on_each_node=save_on_each_node, safe_serialization=False)
127
+ logger.info(f"Scheduler state saved in {output_scheduler_file}")
128
+ # DataLoader states
129
+ for i, dataloader in enumerate(dataloaders):
130
+ sampler_name = f"{SAMPLER_NAME}.bin" if i == 0 else f"{SAMPLER_NAME}_{i}.bin"
131
+ output_sampler_file = output_dir.joinpath(sampler_name)
132
+ # Only save if we have our custom sampler
133
+ from .data_loader import IterableDatasetShard, SeedableRandomSampler
134
+
135
+ if isinstance(dataloader.dataset, IterableDatasetShard):
136
+ sampler = dataloader.get_sampler()
137
+ if isinstance(sampler, SeedableRandomSampler):
138
+ save(sampler, output_sampler_file, save_on_each_node=save_on_each_node, safe_serialization=False)
139
+ if getattr(dataloader, "use_stateful_dataloader", False):
140
+ dataloader_state_dict_name = "dl_state_dict.bin" if i == 0 else f"dl_state_dict_{i}.bin"
141
+ output_dataloader_state_dict_file = output_dir.joinpath(dataloader_state_dict_name)
142
+ state_dict = dataloader.state_dict()
143
+ torch.save(state_dict, output_dataloader_state_dict_file)
144
+ logger.info(f"Sampler state for dataloader {i} saved in {output_sampler_file}")
145
+
146
+ # GradScaler state
147
+ if scaler is not None:
148
+ state = scaler.state_dict()
149
+ output_scaler_file = output_dir.joinpath(SCALER_NAME)
150
+ torch.save(state, output_scaler_file)
151
+ logger.info(f"Gradient scaler state saved in {output_scaler_file}")
152
+ # Random number generator states
153
+ states = {}
154
+ states_name = f"{RNG_STATE_NAME}_{process_index}.pkl"
155
+ states["step"] = step
156
+ states["random_state"] = random.getstate()
157
+ states["numpy_random_seed"] = np.random.get_state()
158
+ states["torch_manual_seed"] = torch.get_rng_state()
159
+ if is_xpu_available():
160
+ states["torch_xpu_manual_seed"] = torch.xpu.get_rng_state_all()
161
+ if is_mlu_available():
162
+ states["torch_mlu_manual_seed"] = torch.mlu.get_rng_state_all()
163
+ elif is_sdaa_available():
164
+ states["torch_sdaa_manual_seed"] = torch.sdaa.get_rng_state_all()
165
+ elif is_musa_available():
166
+ states["torch_musa_manual_seed"] = torch.musa.get_rng_state_all()
167
+ if is_hpu_available():
168
+ states["torch_hpu_manual_seed"] = torch.hpu.get_rng_state_all()
169
+ if is_cuda_available():
170
+ states["torch_cuda_manual_seed"] = torch.cuda.get_rng_state_all()
171
+ if is_torch_xla_available():
172
+ states["xm_seed"] = xm.get_rng_state()
173
+ output_states_file = output_dir.joinpath(states_name)
174
+ torch.save(states, output_states_file)
175
+ logger.info(f"Random states saved in {output_states_file}")
176
+ return output_dir
177
+
178
+
179
+ def load_accelerator_state(
180
+ input_dir,
181
+ models,
182
+ optimizers,
183
+ schedulers,
184
+ dataloaders,
185
+ process_index,
186
+ scaler=None,
187
+ map_location=None,
188
+ load_kwargs=None,
189
+ **load_model_func_kwargs,
190
+ ):
191
+ """
192
+ Loads states of the models, optimizers, scaler, and RNG generators from a given directory.
193
+
194
+ Args:
195
+ input_dir (`str` or `os.PathLike`):
196
+ The name of the folder to load all relevant weights and states.
197
+ models (`List[torch.nn.Module]`):
198
+ A list of model instances
199
+ optimizers (`List[torch.optim.Optimizer]`):
200
+ A list of optimizer instances
201
+ schedulers (`List[torch.optim.lr_scheduler._LRScheduler]`):
202
+ A list of learning rate schedulers
203
+ process_index (`int`):
204
+ The current process index in the Accelerator state
205
+ scaler (`torch.amp.GradScaler`, *optional*):
206
+ An optional *GradScaler* instance to load
207
+ map_location (`str`, *optional*):
208
+ What device to load the optimizer state onto. Should be one of either "cpu" or "on_device".
209
+ load_kwargs (`dict`, *optional*):
210
+ Additional arguments that can be passed to the `load` function.
211
+ load_model_func_kwargs (`dict`, *optional*):
212
+ Additional arguments that can be passed to the model's `load_state_dict` method.
213
+
214
+ Returns:
215
+ `dict`: Contains the `Accelerator` attributes to override while loading the state.
216
+ """
217
+ # stores the `Accelerator` attributes to override
218
+ override_attributes = dict()
219
+ if map_location not in [None, "cpu", "on_device"]:
220
+ raise TypeError(
221
+ "Unsupported optimizer map location passed, please choose one of `None`, `'cpu'`, or `'on_device'`"
222
+ )
223
+ if map_location is None:
224
+ map_location = "cpu"
225
+ elif map_location == "on_device":
226
+ map_location = PartialState().device
227
+
228
+ if load_kwargs is None:
229
+ load_kwargs = {}
230
+
231
+ input_dir = Path(input_dir)
232
+ # Model states
233
+ for i, model in enumerate(models):
234
+ ending = f"_{i}" if i > 0 else ""
235
+ input_model_file = input_dir.joinpath(f"{SAFE_MODEL_NAME}{ending}.safetensors")
236
+ if input_model_file.exists():
237
+ load_model(model, input_model_file, device=str(map_location), **load_model_func_kwargs)
238
+ else:
239
+ # Load with torch
240
+ input_model_file = input_dir.joinpath(f"{MODEL_NAME}{ending}.bin")
241
+ state_dict = load(input_model_file, map_location=map_location)
242
+ model.load_state_dict(state_dict, **load_model_func_kwargs)
243
+ logger.info("All model weights loaded successfully")
244
+
245
+ # Optimizer states
246
+ for i, opt in enumerate(optimizers):
247
+ optimizer_name = f"{OPTIMIZER_NAME}.bin" if i == 0 else f"{OPTIMIZER_NAME}_{i}.bin"
248
+ input_optimizer_file = input_dir.joinpath(optimizer_name)
249
+ optimizer_state = load(input_optimizer_file, map_location=map_location, **load_kwargs)
250
+ optimizers[i].load_state_dict(optimizer_state)
251
+ logger.info("All optimizer states loaded successfully")
252
+
253
+ # Scheduler states
254
+ for i, scheduler in enumerate(schedulers):
255
+ scheduler_name = f"{SCHEDULER_NAME}.bin" if i == 0 else f"{SCHEDULER_NAME}_{i}.bin"
256
+ input_scheduler_file = input_dir.joinpath(scheduler_name)
257
+ scheduler_state = load(input_scheduler_file, **load_kwargs)
258
+ scheduler.load_state_dict(scheduler_state)
259
+ logger.info("All scheduler states loaded successfully")
260
+
261
+ for i, dataloader in enumerate(dataloaders):
262
+ sampler_name = f"{SAMPLER_NAME}.bin" if i == 0 else f"{SAMPLER_NAME}_{i}.bin"
263
+ input_sampler_file = input_dir.joinpath(sampler_name)
264
+ # Only load if we have our custom sampler
265
+ from .data_loader import IterableDatasetShard, SeedableRandomSampler
266
+
267
+ if isinstance(dataloader.dataset, IterableDatasetShard):
268
+ sampler = dataloader.get_sampler()
269
+ if isinstance(sampler, SeedableRandomSampler):
270
+ sampler = dataloader.set_sampler(load(input_sampler_file))
271
+ if getattr(dataloader, "use_stateful_dataloader", False):
272
+ dataloader_state_dict_name = "dl_state_dict.bin" if i == 0 else f"dl_state_dict_{i}.bin"
273
+ input_dataloader_state_dict_file = input_dir.joinpath(dataloader_state_dict_name)
274
+ if input_dataloader_state_dict_file.exists():
275
+ state_dict = load(input_dataloader_state_dict_file, **load_kwargs)
276
+ dataloader.load_state_dict(state_dict)
277
+ logger.info("All dataloader sampler states loaded successfully")
278
+
279
+ # GradScaler state
280
+ if scaler is not None:
281
+ input_scaler_file = input_dir.joinpath(SCALER_NAME)
282
+ scaler_state = load(input_scaler_file)
283
+ scaler.load_state_dict(scaler_state)
284
+ logger.info("GradScaler state loaded successfully")
285
+
286
+ # Random states
287
+ try:
288
+ states = load(input_dir.joinpath(f"{RNG_STATE_NAME}_{process_index}.pkl"))
289
+ if "step" in states:
290
+ override_attributes["step"] = states["step"]
291
+ random.setstate(states["random_state"])
292
+ np.random.set_state(states["numpy_random_seed"])
293
+ torch.set_rng_state(states["torch_manual_seed"])
294
+ if is_xpu_available():
295
+ torch.xpu.set_rng_state_all(states["torch_xpu_manual_seed"])
296
+ if is_mlu_available():
297
+ torch.mlu.set_rng_state_all(states["torch_mlu_manual_seed"])
298
+ elif is_sdaa_available():
299
+ torch.sdaa.set_rng_state_all(states["torch_sdaa_manual_seed"])
300
+ elif is_musa_available():
301
+ torch.musa.set_rng_state_all(states["torch_musa_manual_seed"])
302
+ else:
303
+ torch.cuda.set_rng_state_all(states["torch_cuda_manual_seed"])
304
+ if is_torch_xla_available():
305
+ xm.set_rng_state(states["xm_seed"])
306
+ logger.info("All random states loaded successfully")
307
+ except Exception:
308
+ logger.info("Could not load random states")
309
+
310
+ return override_attributes
311
+
312
+
313
+ def save_custom_state(obj, path, index: int = 0, save_on_each_node: bool = False):
314
+ """
315
+ Saves the state of `obj` to `{path}/custom_checkpoint_{index}.pkl`
316
+ """
317
+ # Should this be the right way to get a qual_name type value from `obj`?
318
+ save_location = Path(path) / f"custom_checkpoint_{index}.pkl"
319
+ logger.info(f"Saving the state of {get_pretty_name(obj)} to {save_location}")
320
+ save(obj.state_dict(), save_location, save_on_each_node=save_on_each_node)
321
+
322
+
323
+ def load_custom_state(obj, path, index: int = 0):
324
+ """
325
+ Loads the state of `obj` at `{path}/custom_checkpoint_{index}.pkl`. Will always set `weights_only=False` when
326
+ loading the state.
327
+ """
328
+ load_location = f"{path}/custom_checkpoint_{index}.pkl"
329
+ logger.info(f"Loading the state of {get_pretty_name(obj)} from {load_location}")
330
+ obj.load_state_dict(load(load_location, map_location="cpu", weights_only=False))
venv/lib/python3.10/site-packages/accelerate/data_loader.py ADDED
@@ -0,0 +1,1446 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2021 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 importlib
16
+ import math
17
+ from contextlib import suppress
18
+ from typing import Callable, Optional, Union
19
+
20
+ import torch
21
+ from packaging import version
22
+ from torch.utils.data import BatchSampler, DataLoader, IterableDataset, RandomSampler
23
+
24
+ from .logging import get_logger
25
+ from .state import DistributedType, GradientState, PartialState, is_torch_xla_available
26
+ from .utils import (
27
+ RNGType,
28
+ broadcast,
29
+ broadcast_object_list,
30
+ compare_versions,
31
+ concatenate,
32
+ find_batch_size,
33
+ get_data_structure,
34
+ initialize_tensors,
35
+ is_datasets_available,
36
+ is_torch_version,
37
+ is_torchdata_stateful_dataloader_available,
38
+ send_to_device,
39
+ slice_tensors,
40
+ synchronize_rng_states,
41
+ )
42
+
43
+
44
+ logger = get_logger(__name__)
45
+
46
+ # kwargs of the DataLoader in min version 2.0
47
+ _PYTORCH_DATALOADER_KWARGS = {
48
+ "batch_size": 1,
49
+ "shuffle": False,
50
+ "sampler": None,
51
+ "batch_sampler": None,
52
+ "num_workers": 0,
53
+ "collate_fn": None,
54
+ "pin_memory": False,
55
+ "drop_last": False,
56
+ "timeout": 0,
57
+ "worker_init_fn": None,
58
+ "multiprocessing_context": None,
59
+ "generator": None,
60
+ "prefetch_factor": 2,
61
+ "persistent_workers": False,
62
+ "pin_memory_device": "",
63
+ }
64
+
65
+ # kwargs added after by version
66
+ _PYTORCH_DATALOADER_ADDITIONAL_KWARGS = {"2.6.0": {"in_order": True}}
67
+
68
+ for v, additional_kwargs in _PYTORCH_DATALOADER_ADDITIONAL_KWARGS.items():
69
+ if is_torch_version(">=", v):
70
+ _PYTORCH_DATALOADER_KWARGS.update(additional_kwargs)
71
+
72
+
73
+ class SeedableRandomSampler(RandomSampler):
74
+ """
75
+ Same as a random sampler, except that in `__iter__` a seed can be used.
76
+
77
+ Needed specifically in distributed cases, when the random generator for each GPU needs to start from the same seed
78
+ and be fully reproducable on multiple iterations.
79
+
80
+ If a custom `generator` is passed, it will rely on its initial seed as well as the current iteration it is on
81
+ (stored in `self.epoch`).
82
+ """
83
+
84
+ def __init__(self, *args, **kwargs):
85
+ data_seed = kwargs.pop("data_seed", None)
86
+ super().__init__(*args, **kwargs)
87
+
88
+ self.initial_seed = data_seed if data_seed is not None else torch.random.initial_seed()
89
+ self.epoch = 0
90
+
91
+ def __iter__(self):
92
+ if self.generator is None:
93
+ self.generator = torch.Generator(
94
+ device=torch.get_default_device() if hasattr(torch, "get_default_device") else "cpu"
95
+ )
96
+ self.generator.manual_seed(self.initial_seed)
97
+
98
+ # Allow `self.epoch` to modify the seed of the generator
99
+ seed = self.epoch + self.initial_seed
100
+ # print("Setting seed at epoch", self.epoch, seed)
101
+ self.generator.manual_seed(seed)
102
+ yield from super().__iter__()
103
+ self.set_epoch(self.epoch + 1)
104
+
105
+ def set_epoch(self, epoch: int):
106
+ "Sets the current iteration of the sampler."
107
+ self.epoch = epoch
108
+
109
+
110
+ class BatchSamplerShard(BatchSampler):
111
+ """
112
+ Wraps a PyTorch `BatchSampler` to generate batches for one of the processes only. Instances of this class will
113
+ always yield a number of batches that is a round multiple of `num_processes` and that all have the same size.
114
+ Depending on the value of the `drop_last` attribute of the batch sampler passed, it will either stop the iteration
115
+ at the first batch that would be too small / not present on all processes or loop with indices from the beginning.
116
+
117
+ Args:
118
+ batch_sampler (`torch.utils.data.sampler.BatchSampler`):
119
+ The batch sampler to split in several shards.
120
+ num_processes (`int`, *optional*, defaults to 1):
121
+ The number of processes running concurrently.
122
+ process_index (`int`, *optional*, defaults to 0):
123
+ The index of the current process.
124
+ split_batches (`bool`, *optional*, defaults to `False`):
125
+ Whether the shards should be created by splitting a batch to give a piece of it on each process, or by
126
+ yielding different full batches on each process.
127
+
128
+ On two processes with a sampler of `[[0, 1, 2, 3], [4, 5, 6, 7]]`, this will result in:
129
+
130
+ - the sampler on process 0 to yield `[0, 1, 2, 3]` and the sampler on process 1 to yield `[4, 5, 6, 7]` if
131
+ this argument is set to `False`.
132
+ - the sampler on process 0 to yield `[0, 1]` then `[4, 5]` and the sampler on process 1 to yield `[2, 3]`
133
+ then `[6, 7]` if this argument is set to `True`.
134
+ even_batches (`bool`, *optional*, defaults to `True`):
135
+ Whether or not to loop back at the beginning of the sampler when the number of samples is not a round
136
+ multiple of (original batch size / number of processes).
137
+
138
+ <Tip warning={true}>
139
+
140
+ `BatchSampler`s with varying batch sizes are not enabled by default. To enable this behaviour, set `even_batches`
141
+ equal to `False`
142
+
143
+ </Tip>"""
144
+
145
+ def __init__(
146
+ self,
147
+ batch_sampler: BatchSampler,
148
+ num_processes: int = 1,
149
+ process_index: int = 0,
150
+ split_batches: bool = False,
151
+ even_batches: bool = True,
152
+ ):
153
+ if split_batches and batch_sampler.batch_size % num_processes != 0:
154
+ raise ValueError(
155
+ f"To use `BatchSamplerShard` in `split_batches` mode, the batch size ({batch_sampler.batch_size}) "
156
+ f"needs to be a round multiple of the number of processes ({num_processes})."
157
+ )
158
+ self.batch_sampler = batch_sampler
159
+ self.num_processes = num_processes
160
+ self.process_index = process_index
161
+ self.split_batches = split_batches
162
+ self.even_batches = even_batches
163
+ self.batch_size = getattr(batch_sampler, "batch_size", None)
164
+ self.drop_last = getattr(batch_sampler, "drop_last", False)
165
+ if self.batch_size is None and self.even_batches:
166
+ raise ValueError(
167
+ "You need to use `even_batches=False` when the batch sampler has no batch size. If you "
168
+ "are not calling this method directly, set `accelerator.even_batches=False` instead."
169
+ )
170
+
171
+ @property
172
+ def total_length(self):
173
+ return len(self.batch_sampler)
174
+
175
+ def __len__(self):
176
+ if self.split_batches:
177
+ # Split batches does not change the length of the batch sampler
178
+ return len(self.batch_sampler)
179
+ if len(self.batch_sampler) % self.num_processes == 0:
180
+ # If the length is a round multiple of the number of processes, it's easy.
181
+ return len(self.batch_sampler) // self.num_processes
182
+ length = len(self.batch_sampler) // self.num_processes
183
+ if self.drop_last:
184
+ # Same if we drop the remainder.
185
+ return length
186
+ elif self.even_batches:
187
+ # When we even batches we always get +1
188
+ return length + 1
189
+ else:
190
+ # Otherwise it depends on the process index.
191
+ return length + 1 if self.process_index < len(self.batch_sampler) % self.num_processes else length
192
+
193
+ def __iter__(self):
194
+ return self._iter_with_split() if self.split_batches else self._iter_with_no_split()
195
+
196
+ def _iter_with_split(self):
197
+ initial_data = []
198
+ batch_length = self.batch_sampler.batch_size // self.num_processes
199
+ for idx, batch in enumerate(self.batch_sampler):
200
+ if idx == 0:
201
+ initial_data = batch
202
+ if len(batch) == self.batch_size:
203
+ # If the batch is full, we yield the part of it this process is responsible of.
204
+ yield batch[batch_length * self.process_index : batch_length * (self.process_index + 1)]
205
+
206
+ # If drop_last is True of the last batch was full, iteration is over, otherwise...
207
+ if not self.drop_last and len(initial_data) > 0 and len(batch) < self.batch_size:
208
+ if not self.even_batches:
209
+ if len(batch) > batch_length * self.process_index:
210
+ yield batch[batch_length * self.process_index : batch_length * (self.process_index + 1)]
211
+ else:
212
+ # For degenerate cases where the dataset has less than num_process * batch_size samples
213
+ while len(initial_data) < self.batch_size:
214
+ initial_data += initial_data
215
+ batch = batch + initial_data
216
+ yield batch[batch_length * self.process_index : batch_length * (self.process_index + 1)]
217
+
218
+ def _iter_with_no_split(self):
219
+ initial_data = []
220
+ batch_to_yield = []
221
+ for idx, batch in enumerate(self.batch_sampler):
222
+ # We gather the initial indices in case we need to circle back at the end.
223
+ if not self.drop_last and idx < self.num_processes:
224
+ initial_data += batch
225
+ # We identify the batch to yield but wait until we ar sure every process gets a full batch before actually
226
+ # yielding it.
227
+ if idx % self.num_processes == self.process_index:
228
+ batch_to_yield = batch
229
+ if idx % self.num_processes == self.num_processes - 1 and (
230
+ self.batch_size is None or len(batch) == self.batch_size
231
+ ):
232
+ yield batch_to_yield
233
+ batch_to_yield = []
234
+
235
+ # If drop_last is True, iteration is over, otherwise...
236
+ if not self.drop_last and len(initial_data) > 0:
237
+ if not self.even_batches:
238
+ if len(batch_to_yield) > 0:
239
+ yield batch_to_yield
240
+ else:
241
+ # ... we yield the complete batch we had saved before if it has the proper length
242
+ if len(batch_to_yield) == self.batch_size:
243
+ yield batch_to_yield
244
+
245
+ # For degenerate cases where the dataset has less than num_process * batch_size samples
246
+ while len(initial_data) < self.num_processes * self.batch_size:
247
+ initial_data += initial_data
248
+
249
+ # If the last batch seen was of the proper size, it has been yielded by its process so we move to the next
250
+ if len(batch) == self.batch_size:
251
+ batch = []
252
+ idx += 1
253
+
254
+ # Make sure we yield a multiple of self.num_processes batches
255
+ cycle_index = 0
256
+ while idx % self.num_processes != 0 or len(batch) > 0:
257
+ end_index = cycle_index + self.batch_size - len(batch)
258
+ batch += initial_data[cycle_index:end_index]
259
+ if idx % self.num_processes == self.process_index:
260
+ yield batch
261
+ cycle_index = end_index
262
+ batch = []
263
+ idx += 1
264
+
265
+
266
+ class IterableDatasetShard(IterableDataset):
267
+ """
268
+ Wraps a PyTorch `IterableDataset` to generate samples for one of the processes only. Instances of this class will
269
+ always yield a number of samples that is a round multiple of the actual batch size (depending of the value of
270
+ `split_batches`, this is either `batch_size` or `batch_size x num_processes`). Depending on the value of the
271
+ `drop_last` attribute of the batch sampler passed, it will either stop the iteration at the first batch that would
272
+ be too small or loop with indices from the beginning.
273
+
274
+ Args:
275
+ dataset (`torch.utils.data.dataset.IterableDataset`):
276
+ The batch sampler to split in several shards.
277
+ batch_size (`int`, *optional*, defaults to 1):
278
+ The size of the batches per shard (if `split_batches=False`) or the size of the batches (if
279
+ `split_batches=True`).
280
+ drop_last (`bool`, *optional*, defaults to `False`):
281
+ Whether or not to drop the last incomplete batch or complete the last batches by using the samples from the
282
+ beginning.
283
+ num_processes (`int`, *optional*, defaults to 1):
284
+ The number of processes running concurrently.
285
+ process_index (`int`, *optional*, defaults to 0):
286
+ The index of the current process.
287
+ split_batches (`bool`, *optional*, defaults to `False`):
288
+ Whether the shards should be created by splitting a batch to give a piece of it on each process, or by
289
+ yielding different full batches on each process.
290
+
291
+ On two processes with an iterable dataset yielding of `[0, 1, 2, 3, 4, 5, 6, 7]`, this will result in:
292
+
293
+ - the shard on process 0 to yield `[0, 1, 2, 3]` and the shard on process 1 to yield `[4, 5, 6, 7]` if this
294
+ argument is set to `False`.
295
+ - the shard on process 0 to yield `[0, 1, 4, 5]` and the sampler on process 1 to yield `[2, 3, 6, 7]` if
296
+ this argument is set to `True`.
297
+ """
298
+
299
+ def __init__(
300
+ self,
301
+ dataset: IterableDataset,
302
+ batch_size: int = 1,
303
+ drop_last: bool = False,
304
+ num_processes: int = 1,
305
+ process_index: int = 0,
306
+ split_batches: bool = False,
307
+ ):
308
+ if split_batches and batch_size > 1 and batch_size % num_processes != 0:
309
+ raise ValueError(
310
+ f"To use `IterableDatasetShard` in `split_batches` mode, the batch size ({batch_size}) "
311
+ f"needs to be a round multiple of the number of processes ({num_processes})."
312
+ )
313
+ self.dataset = dataset
314
+ self.batch_size = batch_size
315
+ self.drop_last = drop_last
316
+ self.num_processes = num_processes
317
+ self.process_index = process_index
318
+ self.split_batches = split_batches
319
+
320
+ def set_epoch(self, epoch):
321
+ self.epoch = epoch
322
+ if hasattr(self.dataset, "set_epoch"):
323
+ self.dataset.set_epoch(epoch)
324
+
325
+ def __len__(self):
326
+ # We will just raise the downstream error if the underlying dataset is not sized
327
+ if self.drop_last:
328
+ return (len(self.dataset) // (self.batch_size * self.num_processes)) * self.batch_size
329
+ else:
330
+ return math.ceil(len(self.dataset) / (self.batch_size * self.num_processes)) * self.batch_size
331
+
332
+ def __iter__(self):
333
+ if (
334
+ not hasattr(self.dataset, "set_epoch")
335
+ and hasattr(self.dataset, "generator")
336
+ and isinstance(self.dataset.generator, torch.Generator)
337
+ ):
338
+ self.dataset.generator.manual_seed(self.epoch)
339
+ real_batch_size = self.batch_size if self.split_batches else (self.batch_size * self.num_processes)
340
+ process_batch_size = (self.batch_size // self.num_processes) if self.split_batches else self.batch_size
341
+ process_slice = range(self.process_index * process_batch_size, (self.process_index + 1) * process_batch_size)
342
+
343
+ first_batch = None
344
+ current_batch = []
345
+ for element in self.dataset:
346
+ current_batch.append(element)
347
+ # Wait to have a full batch before yielding elements.
348
+ if len(current_batch) == real_batch_size:
349
+ for i in process_slice:
350
+ yield current_batch[i]
351
+ if first_batch is None:
352
+ first_batch = current_batch.copy()
353
+ current_batch = []
354
+
355
+ # Finished if drop_last is True, otherwise complete the last batch with elements from the beginning.
356
+ if not self.drop_last and len(current_batch) > 0:
357
+ if first_batch is None:
358
+ first_batch = current_batch.copy()
359
+ while len(current_batch) < real_batch_size:
360
+ current_batch += first_batch
361
+ for i in process_slice:
362
+ yield current_batch[i]
363
+
364
+
365
+ class DataLoaderStateMixin:
366
+ """
367
+ Mixin class that adds a state to a `DataLoader` to keep track of the status inside the dataloader such as at the
368
+ end of the iteration, the number of items in the dataset in the last batch relative to the batch size, and other
369
+ useful information that might be needed.
370
+
371
+ **Available attributes:**
372
+
373
+ - **end_of_dataloader** (`bool`) -- Whether at the last iteration or batch
374
+ - **remainder** (`int`) -- The number of items that are remaining in the last batch, relative to the total
375
+ batch size
376
+
377
+ <Tip warning={true}>
378
+
379
+ Inheriters of this class should ensure that the class creates a `GradientState()` instance, stored in
380
+ `self.gradient_state`.
381
+
382
+ </Tip>
383
+
384
+ """
385
+
386
+ def __init_subclass__(cls, **kwargs):
387
+ cls.end_of_dataloader = False
388
+ cls.remainder = -1
389
+
390
+ def reset(self):
391
+ self.end_of_dataloader = False
392
+ self.remainder = -1
393
+
394
+ def begin(self):
395
+ "Prepares the gradient state for the current dataloader"
396
+ self.reset()
397
+ with suppress(Exception):
398
+ if not self._drop_last:
399
+ length = getattr(self.dataset, "total_dataset_length", len(self.dataset))
400
+ self.remainder = length % self.total_batch_size
401
+ self.gradient_state._add_dataloader(self)
402
+
403
+ def end(self):
404
+ "Cleans up the gradient state after exiting the dataloader"
405
+ self.gradient_state._remove_dataloader(self)
406
+
407
+
408
+ class DataLoaderAdapter:
409
+ """
410
+ A class which wraps around a PyTorch `DataLoader` (or variants of it) to be used with the `Accelerator`. For
411
+ compatability reasons, this class inherits from the class it wraps around, so it can be used as a drop-in.
412
+ """
413
+
414
+ def __init__(self, dataset, use_stateful_dataloader=False, batch_sampler=None, **kwargs):
415
+ self.use_stateful_dataloader = use_stateful_dataloader
416
+ if is_torchdata_stateful_dataloader_available():
417
+ from torchdata.stateful_dataloader import StatefulDataLoader
418
+
419
+ if use_stateful_dataloader and not is_torchdata_stateful_dataloader_available():
420
+ raise ImportError(
421
+ "StatefulDataLoader is not available. Please install torchdata version 0.8.0 or higher to use it."
422
+ )
423
+ if use_stateful_dataloader:
424
+ torchdata_version = version.parse(importlib.metadata.version("torchdata"))
425
+ if (
426
+ "in_order" in kwargs
427
+ and compare_versions(torchdata_version, "<", "0.11")
428
+ and is_torch_version(">=", "2.6.0")
429
+ ):
430
+ kwargs.pop("in_order")
431
+ self.base_dataloader = StatefulDataLoader(dataset, batch_sampler=batch_sampler, **kwargs)
432
+ else:
433
+ self.base_dataloader = DataLoader(dataset, batch_sampler=batch_sampler, **kwargs)
434
+
435
+ if hasattr(self.base_dataloader, "state_dict"):
436
+ self.dl_state_dict = self.base_dataloader.state_dict()
437
+
438
+ def __getattr__(self, name):
439
+ # Avoid infinite recursion if we try to access a nonexistent base_dataloader attribute.
440
+ if name == "base_dataloader":
441
+ raise AttributeError()
442
+ # Delegate attribute access to the internal dataloader
443
+ return getattr(self.base_dataloader, name)
444
+
445
+ def state_dict(self):
446
+ return self.dl_state_dict
447
+
448
+ def load_state_dict(self, state_dict):
449
+ self.base_dataloader.load_state_dict(state_dict)
450
+
451
+ @property
452
+ def __class__(self):
453
+ """
454
+ In order to maintain backwards compatability with other code, we need to ensure `isinstance(obj, DataLoader)`
455
+ returs true. This is because some downstream code assumes that the `DataLoader` is the base class of the
456
+ object.
457
+ """
458
+ return self.base_dataloader.__class__
459
+
460
+ def __len__(self):
461
+ return len(self.base_dataloader)
462
+
463
+ def adjust_state_dict_for_prefetch(self):
464
+ """
465
+ Adjusts the state dict for prefetching. Natively, this will adjust all of the iters yielded keys in
466
+ `self.dl_state_dict` by a factor of `num_processes - 1`, however if a custom correction is needed, this can be
467
+ overridden.
468
+
469
+ This should modify `self.dl_state_dict` directly
470
+ """
471
+ # The state dict will be off by a factor of `n-1` batch too many during DDP,
472
+ # so we need to adjust it here
473
+ if PartialState().distributed_type != DistributedType.NO:
474
+ factor = PartialState().num_processes - 1
475
+ if self.dl_state_dict["_sampler_iter_yielded"] > 0:
476
+ self.dl_state_dict["_sampler_iter_yielded"] -= factor
477
+ if self.dl_state_dict["_num_yielded"] > 0:
478
+ self.dl_state_dict["_num_yielded"] -= factor
479
+ if self.dl_state_dict["_index_sampler_state"] is not None:
480
+ if (
481
+ "samples_yielded" in self.dl_state_dict["_index_sampler_state"]
482
+ and self.dl_state_dict["_index_sampler_state"]["samples_yielded"] > 0
483
+ ):
484
+ self.dl_state_dict["_index_sampler_state"]["samples_yielded"] -= self.batch_size * factor
485
+
486
+ def _update_state_dict(self):
487
+ # The state_dict of the underlying base_dataloader may be ahead of what is currently being yielded.
488
+ # E.g. the implementation of DataLoaderShard involves having an underlying iterator 1 element ahead of
489
+ # what it wants to yield.
490
+ #
491
+ # _update_state_dict is called to snapshot the state_dict that would properly recover the DataLoaderAdapter.
492
+ if hasattr(self.base_dataloader, "state_dict"):
493
+ self.dl_state_dict = self.base_dataloader.state_dict()
494
+ # Potentially modify the state_dict to adjust for prefetching
495
+ self.adjust_state_dict_for_prefetch()
496
+ # Then tag if we are at the end of the dataloader
497
+ self.dl_state_dict["_iterator_finished"] = self.end_of_dataloader
498
+
499
+
500
+ class DataLoaderShard(DataLoaderAdapter, DataLoaderStateMixin):
501
+ """
502
+ Subclass of `DataLoaderAdapter` that will deal with device placement and current distributed setup.
503
+
504
+ Args:
505
+ dataset (`torch.utils.data.dataset.Dataset`):
506
+ The dataset to use to build this dataloader.
507
+ device (`torch.device`, *optional*):
508
+ If passed, the device to put all batches on.
509
+ rng_types (list of `str` or [`~utils.RNGType`]):
510
+ The list of random number generators to synchronize at the beginning of each iteration. Should be one or
511
+ several of:
512
+
513
+ - `"torch"`: the base torch random number generator
514
+ - `"cuda"`: the CUDA random number generator (GPU only)
515
+ - `"xla"`: the XLA random number generator (TPU only)
516
+ - `"generator"`: an optional `torch.Generator`
517
+ synchronized_generator (`torch.Generator`, *optional*):
518
+ A random number generator to keep synchronized across processes.
519
+ skip_batches (`int`, *optional*, defaults to 0):
520
+ The number of batches to skip at the beginning.
521
+ use_stateful_dataloader (`bool`, *optional*, defaults to `False`):
522
+ Whether to have this class adapt `StatefulDataLoader` from `torchdata` instead of the regular `DataLoader`.
523
+ **kwargs (additional keyword arguments, *optional*):
524
+ All other keyword arguments to pass to the regular `DataLoader` initialization.
525
+
526
+ **Available attributes:**
527
+
528
+ - **total_batch_size** (`int`) -- Total batch size of the dataloader across all processes.
529
+ Equal to the original batch size when `split_batches=True`; otherwise the original batch size * the total
530
+ number of processes
531
+
532
+ - **total_dataset_length** (`int`) -- Total length of the inner dataset across all processes.
533
+ """
534
+
535
+ def __init__(
536
+ self,
537
+ dataset,
538
+ device=None,
539
+ rng_types=None,
540
+ synchronized_generator=None,
541
+ skip_batches=0,
542
+ use_stateful_dataloader=False,
543
+ _drop_last: bool = False,
544
+ _non_blocking: bool = False,
545
+ torch_device_mesh=None,
546
+ **kwargs,
547
+ ):
548
+ super().__init__(dataset, use_stateful_dataloader=use_stateful_dataloader, **kwargs)
549
+ self.device = device
550
+ self.rng_types = rng_types
551
+ self.synchronized_generator = synchronized_generator
552
+ self.skip_batches = skip_batches
553
+ self.gradient_state = GradientState()
554
+ self._drop_last = _drop_last
555
+ self._non_blocking = _non_blocking
556
+ self.iteration = 0
557
+
558
+ def __iter__(self):
559
+ if self.rng_types is not None:
560
+ synchronize_rng_states(self.rng_types, self.synchronized_generator)
561
+ self.begin()
562
+
563
+ self.set_epoch(self.iteration)
564
+ dataloader_iter = self.base_dataloader.__iter__()
565
+ # We iterate one batch ahead to check when we are at the end
566
+ try:
567
+ current_batch = next(dataloader_iter)
568
+ except StopIteration:
569
+ self.end()
570
+ return
571
+
572
+ batch_index = 0
573
+ while True:
574
+ try:
575
+ # But we still move it to the device so it is done before `StopIteration` is reached
576
+ if self.device is not None:
577
+ current_batch = send_to_device(current_batch, self.device, non_blocking=self._non_blocking)
578
+ self._update_state_dict()
579
+ next_batch = next(dataloader_iter)
580
+ if batch_index >= self.skip_batches:
581
+ yield current_batch
582
+ batch_index += 1
583
+ current_batch = next_batch
584
+ except StopIteration:
585
+ self.end_of_dataloader = True
586
+ self._update_state_dict()
587
+ if batch_index >= self.skip_batches:
588
+ yield current_batch
589
+ break
590
+
591
+ self.iteration += 1
592
+ self.end()
593
+
594
+ def __reduce__(self):
595
+ """
596
+ Define the `__reduce__` method to ensure a `DataLoaderShard` can be pickled and unpickled. This needs to be
597
+ explicitly defined since default pickling behavior is broken by `DataLoaderAdapter` messing with its
598
+ `__class__` member.
599
+ """
600
+ args = super().__reduce__()
601
+ return (DataLoaderShard, *args[1:])
602
+
603
+ def set_epoch(self, epoch: int):
604
+ # In case it is manually passed in, the user can set it to what they like
605
+ if self.iteration != epoch:
606
+ self.iteration = epoch
607
+ if hasattr(self.batch_sampler, "set_epoch"):
608
+ self.batch_sampler.set_epoch(epoch)
609
+ if hasattr(self.batch_sampler, "sampler") and hasattr(self.batch_sampler.sampler, "set_epoch"):
610
+ self.batch_sampler.sampler.set_epoch(epoch)
611
+ if (
612
+ hasattr(self.batch_sampler, "batch_sampler")
613
+ and hasattr(self.batch_sampler.batch_sampler, "sampler")
614
+ and hasattr(self.batch_sampler.batch_sampler.sampler, "set_epoch")
615
+ ):
616
+ self.batch_sampler.batch_sampler.sampler.set_epoch(epoch)
617
+ # We support if a custom `Dataset` implementation has `set_epoch`
618
+ # or in general HF datasets `Datasets`
619
+ elif hasattr(self.dataset, "set_epoch"):
620
+ self.dataset.set_epoch(epoch)
621
+
622
+ @property
623
+ def total_batch_size(self):
624
+ batch_sampler = self.sampler if isinstance(self.sampler, BatchSampler) else self.batch_sampler
625
+ return (
626
+ batch_sampler.batch_size
627
+ if getattr(batch_sampler, "split_batches", False)
628
+ else (batch_sampler.batch_size * getattr(batch_sampler, "num_processes", 1))
629
+ )
630
+
631
+ @property
632
+ def total_dataset_length(self):
633
+ if hasattr(self.dataset, "total_length"):
634
+ return self.dataset.total_length
635
+ else:
636
+ return len(self.dataset)
637
+
638
+ def get_sampler(self):
639
+ return get_sampler(self)
640
+
641
+ def set_sampler(self, sampler):
642
+ sampler_is_batch_sampler = isinstance(self.sampler, BatchSampler)
643
+ if sampler_is_batch_sampler:
644
+ self.sampler.sampler = sampler
645
+ else:
646
+ self.batch_sampler.sampler = sampler
647
+ if hasattr(self.batch_sampler, "batch_sampler"):
648
+ self.batch_sampler.batch_sampler.sampler = sampler
649
+
650
+
651
+ if is_torch_xla_available():
652
+ import torch_xla.distributed.parallel_loader as xpl
653
+
654
+ class MpDeviceLoaderWrapper(xpl.MpDeviceLoader):
655
+ """
656
+ Wrapper for the xpl.MpDeviceLoader class that knows the total batch size.
657
+
658
+ XLA preloading threads will all call DataLoaderShard's __iter__(). Remove rng_types from DataLoaderShard to
659
+ prevent it from using the XLA device in the preloading threads, and synchronize the RNG once from the main
660
+ thread only.
661
+
662
+ **Available attributes:**
663
+
664
+ - **total_batch_size** (`int`) -- Total batch size of the dataloader across all processes.
665
+ Equal to the original batch size when `split_batches=True`; otherwise the original batch size * the total
666
+ number of processes
667
+
668
+ - **total_dataset_length** (`int`) -- Total length of the inner dataset across all processes.
669
+ """
670
+
671
+ def __init__(self, dataloader: DataLoaderShard, device: torch.device):
672
+ super().__init__(dataloader, device)
673
+ self._rng_types = self._loader.rng_types
674
+ self._loader.rng_types = None
675
+ self.device = device
676
+
677
+ def __iter__(self):
678
+ if self._rng_types is not None:
679
+ synchronize_rng_states(self._rng_types, self._loader.synchronized_generator)
680
+
681
+ return super().__iter__()
682
+
683
+ def set_epoch(self, epoch: int):
684
+ if hasattr(self.dataloader, "set_epoch"):
685
+ self.dataloader.set_epoch(epoch)
686
+
687
+ @property
688
+ def total_batch_size(self):
689
+ return self._loader.total_batch_size
690
+
691
+ @property
692
+ def total_dataset_length(self):
693
+ return self._loader.total_dataset_length
694
+
695
+ @property
696
+ def batch_sampler(self):
697
+ return self._loader.batch_sampler
698
+
699
+ @property
700
+ def dataloader(self):
701
+ return self._loader
702
+
703
+
704
+ class DataLoaderDispatcher(DataLoaderAdapter, DataLoaderStateMixin):
705
+ """
706
+ Subclass of `DataLoaderAdapter` that will iterate and preprocess on process 0 only, then dispatch on each process
707
+ their part of the batch.
708
+
709
+ Args:
710
+ split_batches (`bool`, *optional*, defaults to `False`):
711
+ Whether the resulting `DataLoader` should split the batches of the original data loader across devices or
712
+ yield full batches (in which case it will yield batches starting at the `process_index`-th and advancing of
713
+ `num_processes` batches at each iteration). Another way to see this is that the observed batch size will be
714
+ the same as the initial `dataloader` if this option is set to `True`, the batch size of the initial
715
+ `dataloader` multiplied by `num_processes` otherwise. Setting this option to `True` requires that the batch
716
+ size of the `dataloader` is a round multiple of `batch_size`.
717
+ skip_batches (`int`, *optional*, defaults to 0):
718
+ The number of batches to skip at the beginning of an iteration.
719
+ use_stateful_dataloader (`bool`, *optional*, defaults to `False`):
720
+ Whether to have this class adapt `StatefulDataLoader` from `torchdata` instead of the regular `DataLoader`.
721
+
722
+ **Available attributes:**
723
+
724
+ - **total_batch_size** (`int`) -- Total batch size of the dataloader across all processes.
725
+ Equal to the original batch size when `split_batches=True`; otherwise the original batch size * the total
726
+ number of processes
727
+
728
+ - **total_dataset_length** (`int`) -- Total length of the inner dataset across all processes.
729
+ """
730
+
731
+ def __init__(
732
+ self,
733
+ dataset,
734
+ split_batches: bool = False,
735
+ skip_batches=0,
736
+ use_stateful_dataloader=False,
737
+ _drop_last: bool = False,
738
+ _non_blocking: bool = False,
739
+ slice_fn=None,
740
+ torch_device_mesh=None,
741
+ **kwargs,
742
+ ):
743
+ shuffle = False
744
+ from torch.utils.data.datapipes.iter.combinatorics import ShufflerIterDataPipe
745
+
746
+ # We need to save the shuffling state of the DataPipe
747
+ if isinstance(dataset, ShufflerIterDataPipe):
748
+ shuffle = dataset._shuffle_enabled
749
+ super().__init__(dataset, use_stateful_dataloader=use_stateful_dataloader, **kwargs)
750
+ self.split_batches = split_batches
751
+ if shuffle:
752
+ torch.utils.data.graph_settings.apply_shuffle_settings(dataset, shuffle=shuffle)
753
+
754
+ self.gradient_state = GradientState()
755
+ self.state = PartialState()
756
+ self._drop_last = _drop_last
757
+ self._non_blocking = _non_blocking
758
+ self.skip_batches = skip_batches
759
+ self.torch_device_mesh = torch_device_mesh
760
+
761
+ self.slice_fn = slice_tensors if slice_fn is None else slice_fn
762
+ self.iteration = 0
763
+
764
+ # if a device mesh is provided extract each dimension (dp, fsdp, tp)
765
+ # device mesh may hold any number of dimensions, however,
766
+ # below code is for targetted support for dp, fsdp and tp
767
+
768
+ # device mesh will be used only if there is tp involved
769
+ # or any multi-dimensional parallelism involving tp
770
+ # (dp, tp) (fsdp, tp) (dp, fsdp, tp)
771
+ # otherwise the default behavour not using device mesh should be sufficient
772
+ # since multi dimensional parallelism devoid of tp would anyway need
773
+ # different batches for each process irrespective of dp or fsdp
774
+ self.submesh_tp = None
775
+ self.submesh_dp = None
776
+ self.submesh_fsdp = None
777
+ if self.torch_device_mesh and "tp" in self.torch_device_mesh.mesh_dim_names:
778
+ self.submesh_tp = self.torch_device_mesh["tp"]
779
+ if "dp" in self.torch_device_mesh.mesh_dim_names:
780
+ self.submesh_dp = self.torch_device_mesh["dp"]
781
+ if "fsdp" in self.torch_device_mesh.mesh_dim_names:
782
+ self.submesh_fsdp = self.torch_device_mesh["fsdp"]
783
+ if self.submesh_tp and (self.submesh_dp or self.submesh_fsdp):
784
+ raise ValueError("TP + (DP/FSDP) is not yet supported in dispatch mode")
785
+
786
+ def _fetch_batches(self, iterator):
787
+ batches, batch = None, None
788
+ # On process 0, we gather the batch to dispatch.
789
+ if self.state.process_index == 0:
790
+ # Procedure to support TP only is simpler
791
+ # since we want to dispatch the same batch of samples across all ranks
792
+ # this removes complexity of handling multiple tp rank groups when TP + DP
793
+ # combination is involved.
794
+
795
+ try:
796
+ # for TP case avoid using split_batches
797
+ # since it would mean that the dataloader should be spilling out
798
+ # duplicates of batches.
799
+ if self.split_batches:
800
+ # One batch of the main iterator is dispatched and split.
801
+ if self.submesh_tp:
802
+ logger.warning(
803
+ "Use of split_batches for TP would need the dataloader to produce duplicate batches,"
804
+ "otherwise, use dispatch_batches=True instead."
805
+ )
806
+ self._update_state_dict()
807
+ batch = next(iterator)
808
+ else:
809
+ # num_processes batches of the main iterator are concatenated then dispatched and split.
810
+ # We add the batches one by one so we have the remainder available when drop_last=False.
811
+ batches = []
812
+ if self.submesh_tp:
813
+ # when tp, extract single batch and then replicate
814
+ self._update_state_dict()
815
+ batch = next(iterator)
816
+ batches = [batch] * self.state.num_processes
817
+ else:
818
+ for _ in range(self.state.num_processes):
819
+ self._update_state_dict()
820
+ batches.append(next(iterator))
821
+ try:
822
+ batch = concatenate(batches, dim=0)
823
+ except RuntimeError as e:
824
+ raise RuntimeError(
825
+ "You can't use batches of different size with `dispatch_batches=True` or when using an `IterableDataset`."
826
+ "either pass `dispatch_batches=False` and have each process fetch its own batch "
827
+ " or pass `split_batches=True`. By doing so, the main process will fetch a full batch and "
828
+ "slice it into `num_processes` batches for each process."
829
+ ) from e
830
+ # In both cases, we need to get the structure of the batch that we will broadcast on other
831
+ # processes to initialize the tensors with the right shape.
832
+ # data_structure, stop_iteration
833
+ batch_info = [get_data_structure(batch), False]
834
+ except StopIteration:
835
+ batch_info = [None, True]
836
+ else:
837
+ batch_info = [None, self._stop_iteration]
838
+ # This is inplace, so after this instruction, every process has the same `batch_info` as process 0.
839
+ broadcast_object_list(batch_info)
840
+ self._stop_iteration = batch_info[1]
841
+ if self._stop_iteration:
842
+ # If drop_last is False and split_batches is False, we may have a remainder to take care of.
843
+ if not self.split_batches and not self._drop_last:
844
+ if self.state.process_index == 0 and len(batches) > 0:
845
+ batch = concatenate(batches, dim=0)
846
+ batch_info = [get_data_structure(batch), False]
847
+ else:
848
+ batch_info = [None, True]
849
+ broadcast_object_list(batch_info)
850
+ return batch, batch_info
851
+
852
+ def __iter__(self):
853
+ self.begin()
854
+ self.set_epoch(self.iteration)
855
+ main_iterator = None
856
+ if is_torch_version(">=", "2.0.1"):
857
+ # NOTE PyTorch DataLoader adds forward compatibilities for DataPipes, which broadcasts
858
+ # shared seed to all dist processes. Thus, we need to create iterator for all dist processes.
859
+ # But, we only iterate through the DataLoader on process 0.
860
+ main_iterator = self.base_dataloader.__iter__()
861
+ elif self.state.process_index == 0:
862
+ main_iterator = self.base_dataloader.__iter__()
863
+ stop_iteration = False
864
+ self._stop_iteration = False
865
+ first_batch = None
866
+ next_batch, next_batch_info = self._fetch_batches(main_iterator)
867
+ batch_index = 0
868
+ while not stop_iteration:
869
+ batch, batch_info = next_batch, next_batch_info
870
+
871
+ if self.state.process_index != 0:
872
+ # Initialize tensors on other processes than process 0.
873
+ batch = initialize_tensors(batch_info[0])
874
+ batch = send_to_device(batch, self.state.device, non_blocking=self._non_blocking)
875
+ # Broadcast the batch before splitting it.
876
+ batch = broadcast(batch, from_process=0)
877
+
878
+ if not self._drop_last and first_batch is None:
879
+ # We keep at least num processes elements of the first batch to be able to complete the last batch
880
+ first_batch = self.slice_fn(
881
+ batch,
882
+ slice(0, self.state.num_processes),
883
+ process_index=self.state.process_index,
884
+ num_processes=self.state.num_processes,
885
+ )
886
+
887
+ if batch is None:
888
+ raise ValueError(
889
+ f"Batch does not contain any data (`{batch}`). At the end of all iterable data available before expected stop iteration."
890
+ )
891
+
892
+ observed_batch_size = find_batch_size(batch)
893
+ batch_size = observed_batch_size // self.state.num_processes
894
+
895
+ stop_iteration = self._stop_iteration
896
+ if not stop_iteration:
897
+ # We may still be at the end of the dataloader without knowing it yet: if there is nothing left in
898
+ # the dataloader since the number of batches is a round multiple of the number of processes.
899
+ next_batch, next_batch_info = self._fetch_batches(main_iterator)
900
+ # next_batch_info[0] is None when there are no more batches, otherwise we still need to process them.
901
+ if self._stop_iteration and next_batch_info[0] is None:
902
+ stop_iteration = True
903
+
904
+ if not self._drop_last and stop_iteration and observed_batch_size % self.state.num_processes != 0:
905
+ # If the last batch is not complete, let's add the first batch to it.
906
+ batch = concatenate([batch, first_batch], dim=0)
907
+ # Batch size computation above is wrong, it's off by 1 so we fix it.
908
+ batch_size += 1
909
+
910
+ data_slice = slice(self.state.process_index * batch_size, (self.state.process_index + 1) * batch_size)
911
+ batch = self.slice_fn(
912
+ batch,
913
+ data_slice,
914
+ process_index=self.state.process_index,
915
+ num_processes=self.state.num_processes,
916
+ )
917
+
918
+ if stop_iteration:
919
+ self.end_of_dataloader = True
920
+ self._update_state_dict()
921
+ self.remainder = observed_batch_size
922
+ if batch_index >= self.skip_batches:
923
+ yield batch
924
+ batch_index += 1
925
+ self.iteration += 1
926
+ self.end()
927
+
928
+ def set_epoch(self, epoch: int):
929
+ # In case it is manually passed in, the user can set it to what they like
930
+ if self.iteration != epoch:
931
+ self.iteration = epoch
932
+ if hasattr(self.batch_sampler, "sampler") and hasattr(self.batch_sampler.sampler, "set_epoch"):
933
+ self.batch_sampler.sampler.set_epoch(epoch)
934
+ elif hasattr(self.dataset, "set_epoch"):
935
+ self.dataset.set_epoch(epoch)
936
+
937
+ def __len__(self):
938
+ whole_length = len(self.base_dataloader)
939
+ if self.split_batches:
940
+ return whole_length
941
+ elif self._drop_last:
942
+ return whole_length // self.state.num_processes
943
+ else:
944
+ return math.ceil(whole_length / self.state.num_processes)
945
+
946
+ def __reduce__(self):
947
+ """
948
+ Define the `__reduce__` method to ensure a `DataLoaderDispatcher` can be pickled and unpickled. This needs to
949
+ be explicitly defined since default pickling behavior is broken by `DataLoaderAdapter` messing with its
950
+ `__class__` member.
951
+ """
952
+ args = super().__reduce__()
953
+ return (DataLoaderDispatcher, *args[1:])
954
+
955
+ @property
956
+ def total_batch_size(self):
957
+ return (
958
+ self.dataset.batch_size if self.split_batches else (self.dataset.batch_size * self.dataset.num_processes)
959
+ )
960
+
961
+ @property
962
+ def total_dataset_length(self):
963
+ return len(self.dataset)
964
+
965
+ def get_sampler(self):
966
+ return get_sampler(self)
967
+
968
+ def set_sampler(self, sampler):
969
+ sampler_is_batch_sampler = isinstance(self.sampler, BatchSampler)
970
+ if sampler_is_batch_sampler:
971
+ self.sampler.sampler = sampler
972
+ else:
973
+ self.batch_sampler.sampler = sampler
974
+ if hasattr(self.batch_sampler, "batch_sampler"):
975
+ self.batch_sampler.batch_sampler.sampler = sampler
976
+
977
+
978
+ def get_sampler(dataloader):
979
+ """
980
+ Get the sampler associated to the dataloader
981
+
982
+ Args:
983
+ dataloader (`torch.utils.data.dataloader.DataLoader`):
984
+ The data loader to split across several devices.
985
+ Returns:
986
+ `torch.utils.data.Sampler`: The sampler associated to the dataloader
987
+ """
988
+ sampler_is_batch_sampler = isinstance(dataloader.sampler, BatchSampler)
989
+ if sampler_is_batch_sampler:
990
+ sampler = getattr(dataloader.sampler, "sampler", None)
991
+ else:
992
+ sampler = getattr(dataloader.batch_sampler, "sampler", None)
993
+ return sampler
994
+
995
+
996
+ def prepare_data_loader(
997
+ dataloader: DataLoader,
998
+ device: Optional[torch.device] = None,
999
+ num_processes: Optional[int] = None,
1000
+ process_index: Optional[int] = None,
1001
+ split_batches: bool = False,
1002
+ put_on_device: bool = False,
1003
+ rng_types: Optional[list[Union[str, RNGType]]] = None,
1004
+ dispatch_batches: Optional[bool] = None,
1005
+ even_batches: bool = True,
1006
+ slice_fn_for_dispatch: Optional[Callable] = None,
1007
+ use_seedable_sampler: bool = False,
1008
+ data_seed: Optional[int] = None,
1009
+ non_blocking: bool = False,
1010
+ use_stateful_dataloader: bool = False,
1011
+ torch_device_mesh=None,
1012
+ ) -> DataLoader:
1013
+ """
1014
+ Wraps a PyTorch `DataLoader` to generate batches for one of the processes only.
1015
+
1016
+ Depending on the value of the `drop_last` attribute of the `dataloader` passed, it will either stop the iteration
1017
+ at the first batch that would be too small / not present on all processes or loop with indices from the beginning.
1018
+
1019
+ Args:
1020
+ dataloader (`torch.utils.data.dataloader.DataLoader`):
1021
+ The data loader to split across several devices.
1022
+ device (`torch.device`):
1023
+ The target device for the returned `DataLoader`.
1024
+ num_processes (`int`, *optional*):
1025
+ The number of processes running concurrently. Will default to the value given by [`~state.PartialState`].
1026
+ process_index (`int`, *optional*):
1027
+ The index of the current process. Will default to the value given by [`~state.PartialState`].
1028
+ split_batches (`bool`, *optional*, defaults to `False`):
1029
+ Whether the resulting `DataLoader` should split the batches of the original data loader across devices or
1030
+ yield full batches (in which case it will yield batches starting at the `process_index`-th and advancing of
1031
+ `num_processes` batches at each iteration).
1032
+
1033
+ Another way to see this is that the observed batch size will be the same as the initial `dataloader` if
1034
+ this option is set to `True`, the batch size of the initial `dataloader` multiplied by `num_processes`
1035
+ otherwise.
1036
+
1037
+ Setting this option to `True` requires that the batch size of the `dataloader` is a round multiple of
1038
+ `batch_size`.
1039
+ put_on_device (`bool`, *optional*, defaults to `False`):
1040
+ Whether or not to put the batches on `device` (only works if the batches are nested list, tuples or
1041
+ dictionaries of tensors).
1042
+ rng_types (list of `str` or [`~utils.RNGType`]):
1043
+ The list of random number generators to synchronize at the beginning of each iteration. Should be one or
1044
+ several of:
1045
+
1046
+ - `"torch"`: the base torch random number generator
1047
+ - `"cuda"`: the CUDA random number generator (GPU only)
1048
+ - `"xla"`: the XLA random number generator (TPU only)
1049
+ - `"generator"`: the `torch.Generator` of the sampler (or batch sampler if there is no sampler in your
1050
+ dataloader) or of the iterable dataset (if it exists) if the underlying dataset is of that type.
1051
+
1052
+ dispatch_batches (`bool`, *optional*):
1053
+ If set to `True`, the dataloader prepared is only iterated through on the main process and then the batches
1054
+ are split and broadcast to each process. Will default to `True` when the underlying dataset is an
1055
+ `IterableDataset`, `False` otherwise.
1056
+ even_batches (`bool`, *optional*, defaults to `True`):
1057
+ If set to `True`, in cases where the total batch size across all processes does not exactly divide the
1058
+ dataset, samples at the start of the dataset will be duplicated so the batch can be divided equally among
1059
+ all workers.
1060
+ slice_fn_for_dispatch (`Callable`, *optional*`):
1061
+ If passed, this function will be used to slice tensors across `num_processes`. Will default to
1062
+ [`~utils.slice_tensors`]. This argument is used only when `dispatch_batches` is set to `True` and will be
1063
+ ignored otherwise.
1064
+ use_seedable_sampler (`bool`, *optional*, defaults to `False`):
1065
+ Whether to use the [`~data_loader.SeedableRandomSampler`] instead of a `RandomSampler` for better
1066
+ reproducability. Comes at a cost of potentially different performances due to different shuffling
1067
+ algorithms but ensures results will be the *exact* same. Should be paired with `set_seed()` at every
1068
+ `self.set_epoch`
1069
+ data_seed (`int`, *optional*, defaults to `None`):
1070
+ The seed to use for the underlying generator when using `use_seedable_sampler`. If `None`, the generator
1071
+ will use the current default seed from torch.
1072
+ non_blocking (`bool`, *optional*, defaults to `False`):
1073
+ If set to `True`, dataloader will utilize non-blocking host-to-device transfers. If the dataloader has
1074
+ `pin_memory` set to `True`, this will help to increase overlap between data transfer and computations.
1075
+ use_stateful_dataloader (`bool`, *optional*, defaults to `False`):
1076
+ "If set to true, the dataloader prepared by the Accelerator will be backed by "
1077
+ "[torchdata.StatefulDataLoader](https://github.com/pytorch/data/tree/main/torchdata/stateful_dataloader).
1078
+ This requires `torchdata` version 0.8.0 or higher that supports StatefulDataLoader to be installed."
1079
+ torch_device_mesh (`torch.distributed.DeviceMesh`, *optional*, defaults to `None`):
1080
+ PyTorch device mesh.
1081
+
1082
+
1083
+ Returns:
1084
+ `torch.utils.data.dataloader.DataLoader`: A new data loader that will yield the portion of the batches
1085
+
1086
+ <Tip warning={true}>
1087
+
1088
+ `BatchSampler`s with varying batch sizes are not enabled by default. To enable this behaviour, set `even_batches`
1089
+ equal to `False`
1090
+
1091
+ </Tip>
1092
+ """
1093
+ if dispatch_batches is None:
1094
+ if not put_on_device:
1095
+ dispatch_batches = False
1096
+ else:
1097
+ dispatch_batches = isinstance(dataloader.dataset, IterableDataset)
1098
+
1099
+ if dispatch_batches and not put_on_device:
1100
+ raise ValueError("Using `dispatch_batches=True` requires `put_on_device=True`.")
1101
+ # Grab defaults from PartialState
1102
+ state = PartialState()
1103
+ if num_processes is None:
1104
+ num_processes = state.num_processes
1105
+
1106
+ if process_index is None:
1107
+ process_index = state.process_index
1108
+
1109
+ if torch_device_mesh:
1110
+ if state.distributed_type == DistributedType.DEEPSPEED:
1111
+ # In DeepSpeed, the optimizer sharing level in DP is determined by the config file.
1112
+ # Only considers "dp" and "tp".
1113
+ # Given a device mesh (dp, tp) = (2, 3):
1114
+ # - From the data parallel perspective, ranks should be structured as: 0 0 0 1 1 1
1115
+ # - Processes with the same DP rank will receive the same batch.
1116
+ if "tp" in torch_device_mesh.mesh_dim_names:
1117
+ submesh_tp_size = torch_device_mesh["tp"].size()
1118
+ process_index = process_index // submesh_tp_size
1119
+ num_processes = num_processes // submesh_tp_size
1120
+ else:
1121
+ # when device mesh is used, specifically with TP
1122
+ # then there is need to update process_index and num_processes
1123
+ # to bring in the effect of generating same batch across TP ranks
1124
+ # and different batch across FSDP and DP ranks.
1125
+ # Example:
1126
+ # if device mesh is (dp,fsdp,tp) = (2, 2, 3)
1127
+ # ranks would range from 0...11
1128
+ # from data angle ranks should look like 0 0 0 1 1 1 2 2 2 3 3 3
1129
+ # processes with same ranks/ids would receive the same batch
1130
+ submesh_fsdp_size = 1
1131
+ submesh_dp_size = 1
1132
+ submesh_tp_size = 1
1133
+ if "tp" in torch_device_mesh.mesh_dim_names:
1134
+ submesh_tp_size = torch_device_mesh["tp"].size()
1135
+ if "dp" in torch_device_mesh.mesh_dim_names:
1136
+ submesh_dp_size = torch_device_mesh["dp"].size()
1137
+ if "fsdp" in torch_device_mesh.mesh_dim_names:
1138
+ submesh_fsdp_size = torch_device_mesh["fsdp"].size()
1139
+ process_index = process_index // submesh_tp_size
1140
+ num_processes = submesh_fsdp_size * submesh_dp_size
1141
+
1142
+ # Sanity check
1143
+ if split_batches:
1144
+ if dataloader.batch_size is not None:
1145
+ batch_size_for_check = dataloader.batch_size
1146
+ else:
1147
+ # For custom batch_sampler
1148
+ if hasattr(dataloader.batch_sampler, "batch_size"):
1149
+ batch_size_for_check = dataloader.batch_sampler.batch_size
1150
+ else:
1151
+ raise ValueError(
1152
+ "In order to use `split_batches==True` you must have a `batch_size` attribute either in the passed "
1153
+ "`dataloader` or `dataloader.batch_sampler` objects, and it has to return a natural number. "
1154
+ "Your `dataloader.batch_size` is None and `dataloader.batch_sampler` "
1155
+ f"(`{type(dataloader.batch_sampler)}`) does not have the `batch_size` attribute set."
1156
+ )
1157
+
1158
+ if batch_size_for_check > 1 and batch_size_for_check % num_processes != 0:
1159
+ raise ValueError(
1160
+ f"To use a `DataLoader` in `split_batches` mode, the batch size ({dataloader.batch_size}) "
1161
+ f"needs to be a round multiple of the number of processes ({num_processes})."
1162
+ )
1163
+
1164
+ new_dataset = dataloader.dataset
1165
+ # Iterable dataset doesn't like batch_sampler, but data_loader creates a default one for it
1166
+ new_batch_sampler = dataloader.batch_sampler if not isinstance(new_dataset, IterableDataset) else None
1167
+ sampler_is_batch_sampler = isinstance(dataloader.sampler, BatchSampler)
1168
+ synchronized_generator = None
1169
+
1170
+ sampler = get_sampler(dataloader)
1171
+ if isinstance(sampler, RandomSampler) and use_seedable_sampler:
1172
+ # When iterating through the dataloader during distributed processes
1173
+ # we want to ensure that on each process we are iterating through the same
1174
+ # samples in the same order if a seed is set. This requires a tweak
1175
+ # to the `torch.utils.data.RandomSampler` class (if used).
1176
+ sampler = SeedableRandomSampler(
1177
+ data_source=sampler.data_source,
1178
+ replacement=sampler.replacement,
1179
+ num_samples=sampler._num_samples,
1180
+ generator=getattr(
1181
+ sampler,
1182
+ "generator",
1183
+ torch.Generator(device=torch.get_default_device() if hasattr(torch, "get_default_device") else "cpu"),
1184
+ ),
1185
+ data_seed=data_seed,
1186
+ )
1187
+
1188
+ if isinstance(dataloader.sampler, RandomSampler) and state.distributed_type == DistributedType.XLA:
1189
+ # isinstance(dataloader.sampler, RandomSampler) indicates the original dataloader has `shuffle` enabled.
1190
+ generator = torch.Generator(
1191
+ device=torch.get_default_device() if hasattr(torch, "get_default_device") else "cpu"
1192
+ )
1193
+ seed = int(torch.empty((), dtype=torch.int64).random_().item())
1194
+ generator.manual_seed(seed)
1195
+ dataloader.generator = generator
1196
+ dataloader.sampler.generator = generator
1197
+ # No change if no multiprocess
1198
+ if (num_processes != 1 or state.distributed_type == DistributedType.MEGATRON_LM) and not dispatch_batches:
1199
+ if is_datasets_available():
1200
+ from datasets import IterableDataset as DatasetsIterableDataset
1201
+ if (
1202
+ is_datasets_available()
1203
+ and isinstance(new_dataset, DatasetsIterableDataset)
1204
+ and not split_batches
1205
+ and new_dataset.n_shards > num_processes
1206
+ ):
1207
+ new_dataset = new_dataset.shard(num_shards=num_processes, index=process_index)
1208
+ elif isinstance(new_dataset, IterableDataset):
1209
+ if getattr(dataloader.dataset, "generator", None) is not None:
1210
+ synchronized_generator = dataloader.dataset.generator
1211
+ new_dataset = IterableDatasetShard(
1212
+ new_dataset,
1213
+ batch_size=dataloader.batch_size,
1214
+ drop_last=dataloader.drop_last,
1215
+ num_processes=num_processes,
1216
+ process_index=process_index,
1217
+ split_batches=split_batches,
1218
+ )
1219
+ else:
1220
+ if not use_seedable_sampler and hasattr(sampler, "generator"):
1221
+ if sampler.generator is None:
1222
+ sampler.generator = torch.Generator(
1223
+ device=torch.get_default_device() if hasattr(torch, "get_default_device") else "cpu"
1224
+ )
1225
+ seed = int(torch.empty((), dtype=torch.int64).random_().item())
1226
+ sampler.generator.manual_seed(seed)
1227
+ synchronized_generator = sampler.generator
1228
+ batch_sampler = dataloader.sampler if sampler_is_batch_sampler else dataloader.batch_sampler
1229
+ new_batch_sampler = BatchSamplerShard(
1230
+ batch_sampler,
1231
+ num_processes=num_processes,
1232
+ process_index=process_index,
1233
+ split_batches=split_batches,
1234
+ even_batches=even_batches,
1235
+ )
1236
+
1237
+ # We ignore all of those since they are all dealt with by our new_batch_sampler
1238
+ ignore_kwargs = [
1239
+ "batch_size",
1240
+ "shuffle",
1241
+ "sampler",
1242
+ "batch_sampler",
1243
+ "drop_last",
1244
+ ]
1245
+
1246
+ if rng_types is not None and synchronized_generator is None and "generator" in rng_types:
1247
+ rng_types.remove("generator")
1248
+
1249
+ kwargs = {
1250
+ k: getattr(dataloader, k, _PYTORCH_DATALOADER_KWARGS[k])
1251
+ for k in _PYTORCH_DATALOADER_KWARGS
1252
+ if k not in ignore_kwargs
1253
+ }
1254
+
1255
+ # Need to provide batch_size as batch_sampler is None for Iterable dataset
1256
+ if new_batch_sampler is None:
1257
+ kwargs["drop_last"] = dataloader.drop_last
1258
+ kwargs["batch_size"] = (
1259
+ dataloader.batch_size // num_processes if split_batches and not dispatch_batches else dataloader.batch_size
1260
+ )
1261
+ if dispatch_batches:
1262
+ kwargs.pop("generator")
1263
+ dataloader = DataLoaderDispatcher(
1264
+ new_dataset,
1265
+ split_batches=split_batches,
1266
+ batch_sampler=new_batch_sampler,
1267
+ _drop_last=dataloader.drop_last,
1268
+ _non_blocking=non_blocking,
1269
+ slice_fn=slice_fn_for_dispatch,
1270
+ use_stateful_dataloader=use_stateful_dataloader,
1271
+ torch_device_mesh=torch_device_mesh,
1272
+ **kwargs,
1273
+ )
1274
+ elif sampler_is_batch_sampler:
1275
+ dataloader = DataLoaderShard(
1276
+ new_dataset,
1277
+ device=device if put_on_device and state.distributed_type != DistributedType.XLA else None,
1278
+ sampler=new_batch_sampler,
1279
+ batch_size=dataloader.batch_size,
1280
+ rng_types=rng_types,
1281
+ _drop_last=dataloader.drop_last,
1282
+ _non_blocking=non_blocking,
1283
+ synchronized_generator=synchronized_generator,
1284
+ use_stateful_dataloader=use_stateful_dataloader,
1285
+ **kwargs,
1286
+ )
1287
+ else:
1288
+ dataloader = DataLoaderShard(
1289
+ new_dataset,
1290
+ device=device if put_on_device and state.distributed_type != DistributedType.XLA else None,
1291
+ batch_sampler=new_batch_sampler,
1292
+ rng_types=rng_types,
1293
+ synchronized_generator=synchronized_generator,
1294
+ _drop_last=dataloader.drop_last,
1295
+ _non_blocking=non_blocking,
1296
+ use_stateful_dataloader=use_stateful_dataloader,
1297
+ **kwargs,
1298
+ )
1299
+
1300
+ if isinstance(sampler, SeedableRandomSampler) and use_seedable_sampler:
1301
+ dataloader.set_sampler(sampler)
1302
+ if state.distributed_type == DistributedType.XLA:
1303
+ return MpDeviceLoaderWrapper(dataloader, device)
1304
+ return dataloader
1305
+
1306
+
1307
+ class SkipBatchSampler(BatchSampler):
1308
+ """
1309
+ A `torch.utils.data.BatchSampler` that skips the first `n` batches of another `torch.utils.data.BatchSampler`.
1310
+ Should not be used if the original dataloader is a `StatefulDataLoader`.
1311
+ """
1312
+
1313
+ def __init__(self, batch_sampler, skip_batches=0):
1314
+ self.batch_sampler = batch_sampler
1315
+ self.skip_batches = skip_batches
1316
+
1317
+ def __iter__(self):
1318
+ for index, samples in enumerate(self.batch_sampler):
1319
+ if index >= self.skip_batches:
1320
+ yield samples
1321
+
1322
+ @property
1323
+ def total_length(self):
1324
+ return len(self.batch_sampler)
1325
+
1326
+ def __len__(self):
1327
+ return len(self.batch_sampler) - self.skip_batches
1328
+
1329
+
1330
+ class SkipDataLoader(DataLoaderAdapter, DataLoaderStateMixin):
1331
+ """
1332
+ Subclass of a PyTorch `DataLoader` that will skip the first batches. Generally it's preferable to use
1333
+ `skip_first_batches`/`torchdata.StatefulDataLoader` instead of this class.
1334
+
1335
+ Args:
1336
+ dataset (`torch.utils.data.dataset.Dataset`):
1337
+ The dataset to use to build this dataloader.
1338
+ skip_batches (`int`, *optional*, defaults to 0):
1339
+ The number of batches to skip at the beginning.
1340
+ kwargs:
1341
+ All other keyword arguments to pass to the regular `DataLoader` initialization.
1342
+ """
1343
+
1344
+ def __init__(self, dataset, skip_batches=0, use_stateful_dataloader=False, **kwargs):
1345
+ super().__init__(dataset, use_stateful_dataloader=use_stateful_dataloader, **kwargs)
1346
+ self.skip_batches = skip_batches
1347
+ self.gradient_state = GradientState()
1348
+
1349
+ def __iter__(self):
1350
+ self.begin()
1351
+ for index, batch in enumerate(self.base_dataloader.__iter__()):
1352
+ if index >= self.skip_batches:
1353
+ self._update_state_dict()
1354
+ yield batch
1355
+ self.end()
1356
+
1357
+ def __len__(self):
1358
+ return len(self.base_dataloader) - self.skip_batches
1359
+
1360
+ def __reduce__(self):
1361
+ """
1362
+ Define the `__reduce__` method to ensure a `SkipDataLoader` can be pickled and unpickled. This needs to be
1363
+ explicitly defined since default pickling behavior is broken by `DataLoaderAdapter` messing with its
1364
+ `__class__` member.
1365
+ """
1366
+ args = super().__reduce__()
1367
+ return (SkipDataLoader, *args[1:])
1368
+
1369
+
1370
+ def skip_first_batches(dataloader, num_batches=0):
1371
+ """
1372
+ Creates a `torch.utils.data.DataLoader` that will efficiently skip the first `num_batches`. Should not be used if
1373
+ the original dataloader is a `StatefulDataLoader`.
1374
+ """
1375
+ state = PartialState()
1376
+ if state.distributed_type == DistributedType.XLA:
1377
+ device = dataloader.device
1378
+ dataloader = dataloader.dataloader
1379
+
1380
+ dataset = dataloader.dataset
1381
+ sampler_is_batch_sampler = False
1382
+ if isinstance(dataset, IterableDataset):
1383
+ new_batch_sampler = None
1384
+ else:
1385
+ sampler_is_batch_sampler = isinstance(dataloader.sampler, BatchSampler)
1386
+ batch_sampler = dataloader.sampler if sampler_is_batch_sampler else dataloader.batch_sampler
1387
+ new_batch_sampler = SkipBatchSampler(batch_sampler, skip_batches=num_batches)
1388
+
1389
+ # We ignore all of those since they are all dealt with by our new_batch_sampler
1390
+ ignore_kwargs = [
1391
+ "batch_size",
1392
+ "shuffle",
1393
+ "sampler",
1394
+ "batch_sampler",
1395
+ "drop_last",
1396
+ ]
1397
+
1398
+ kwargs = {
1399
+ k: getattr(dataloader, k, _PYTORCH_DATALOADER_KWARGS[k])
1400
+ for k in _PYTORCH_DATALOADER_KWARGS
1401
+ if k not in ignore_kwargs
1402
+ }
1403
+
1404
+ # Need to provide batch_size as batch_sampler is None for Iterable dataset
1405
+ if new_batch_sampler is None:
1406
+ kwargs["drop_last"] = dataloader.drop_last
1407
+ kwargs["batch_size"] = dataloader.batch_size
1408
+
1409
+ if isinstance(dataloader, DataLoaderDispatcher):
1410
+ if new_batch_sampler is None:
1411
+ # Need to manually skip batches in the dataloader
1412
+ kwargs["skip_batches"] = num_batches
1413
+ dataloader = DataLoaderDispatcher(
1414
+ dataset,
1415
+ split_batches=dataloader.split_batches,
1416
+ batch_sampler=new_batch_sampler,
1417
+ _drop_last=dataloader._drop_last,
1418
+ **kwargs,
1419
+ )
1420
+ elif isinstance(dataloader, DataLoaderShard):
1421
+ if new_batch_sampler is None:
1422
+ # Need to manually skip batches in the dataloader
1423
+ kwargs["skip_batches"] = num_batches
1424
+ elif sampler_is_batch_sampler:
1425
+ kwargs["sampler"] = new_batch_sampler
1426
+ kwargs["batch_size"] = dataloader.batch_size
1427
+ else:
1428
+ kwargs["batch_sampler"] = new_batch_sampler
1429
+ dataloader = DataLoaderShard(
1430
+ dataset,
1431
+ device=dataloader.device,
1432
+ rng_types=dataloader.rng_types,
1433
+ synchronized_generator=dataloader.synchronized_generator,
1434
+ **kwargs,
1435
+ )
1436
+ else:
1437
+ if new_batch_sampler is None:
1438
+ # Need to manually skip batches in the dataloader
1439
+ dataloader = SkipDataLoader(dataset, skip_batches=num_batches, **kwargs)
1440
+ else:
1441
+ dataloader = DataLoader(dataset, batch_sampler=new_batch_sampler, **kwargs)
1442
+
1443
+ if state.distributed_type == DistributedType.XLA:
1444
+ dataloader = MpDeviceLoaderWrapper(dataloader, device)
1445
+
1446
+ return dataloader
venv/lib/python3.10/site-packages/accelerate/hooks.py ADDED
@@ -0,0 +1,765 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 functools
16
+ from collections.abc import Mapping
17
+ from typing import Optional, Union
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+
22
+ from .state import PartialState
23
+ from .utils import (
24
+ PrefixedDataset,
25
+ find_device,
26
+ named_module_tensors,
27
+ send_to_device,
28
+ set_module_tensor_to_device,
29
+ )
30
+ from .utils.imports import (
31
+ is_mlu_available,
32
+ is_musa_available,
33
+ is_npu_available,
34
+ )
35
+ from .utils.memory import clear_device_cache
36
+ from .utils.modeling import get_non_persistent_buffers
37
+ from .utils.other import recursive_getattr
38
+
39
+
40
+ _accelerate_added_attributes = ["to", "cuda", "npu", "xpu", "mlu", "sdaa", "musa"]
41
+
42
+
43
+ class ModelHook:
44
+ """
45
+ A hook that contains callbacks to be executed just before and after the forward method of a model. The difference
46
+ with PyTorch existing hooks is that they get passed along the kwargs.
47
+
48
+ Class attribute:
49
+ - **no_grad** (`bool`, *optional*, defaults to `False`) -- Whether or not to execute the actual forward pass under
50
+ the `torch.no_grad()` context manager.
51
+ """
52
+
53
+ no_grad = False
54
+
55
+ def init_hook(self, module):
56
+ """
57
+ To be executed when the hook is attached to the module.
58
+
59
+ Args:
60
+ module (`torch.nn.Module`): The module attached to this hook.
61
+ """
62
+ return module
63
+
64
+ def pre_forward(self, module, *args, **kwargs):
65
+ """
66
+ To be executed just before the forward method of the model.
67
+
68
+ Args:
69
+ module (`torch.nn.Module`): The module whose forward pass will be executed just after this event.
70
+ args (`Tuple[Any]`): The positional arguments passed to the module.
71
+ kwargs (`Dict[Str, Any]`): The keyword arguments passed to the module.
72
+
73
+ Returns:
74
+ `Tuple[Tuple[Any], Dict[Str, Any]]`: A tuple with the treated `args` and `kwargs`.
75
+ """
76
+ return args, kwargs
77
+
78
+ def post_forward(self, module, output):
79
+ """
80
+ To be executed just after the forward method of the model.
81
+
82
+ Args:
83
+ module (`torch.nn.Module`): The module whose forward pass been executed just before this event.
84
+ output (`Any`): The output of the module.
85
+
86
+ Returns:
87
+ `Any`: The processed `output`.
88
+ """
89
+ return output
90
+
91
+ def detach_hook(self, module):
92
+ """
93
+ To be executed when the hook is detached from a module.
94
+
95
+ Args:
96
+ module (`torch.nn.Module`): The module detached from this hook.
97
+ """
98
+ return module
99
+
100
+
101
+ class SequentialHook(ModelHook):
102
+ """
103
+ A hook that can contain several hooks and iterates through them at each event.
104
+ """
105
+
106
+ def __init__(self, *hooks):
107
+ self.hooks = hooks
108
+
109
+ def init_hook(self, module):
110
+ for hook in self.hooks:
111
+ module = hook.init_hook(module)
112
+ return module
113
+
114
+ def pre_forward(self, module, *args, **kwargs):
115
+ for hook in self.hooks:
116
+ args, kwargs = hook.pre_forward(module, *args, **kwargs)
117
+ return args, kwargs
118
+
119
+ def post_forward(self, module, output):
120
+ for hook in self.hooks:
121
+ output = hook.post_forward(module, output)
122
+ return output
123
+
124
+ def detach_hook(self, module):
125
+ for hook in self.hooks:
126
+ module = hook.detach_hook(module)
127
+ return module
128
+
129
+
130
+ def add_hook_to_module(module: nn.Module, hook: ModelHook, append: bool = False):
131
+ """
132
+ Adds a hook to a given module. This will rewrite the `forward` method of the module to include the hook, to remove
133
+ this behavior and restore the original `forward` method, use `remove_hook_from_module`.
134
+
135
+ <Tip warning={true}>
136
+
137
+ If the module already contains a hook, this will replace it with the new hook passed by default. To chain two hooks
138
+ together, pass `append=True`, so it chains the current and new hook into an instance of the `SequentialHook` class.
139
+
140
+ </Tip>
141
+
142
+ Args:
143
+ module (`torch.nn.Module`):
144
+ The module to attach a hook to.
145
+ hook (`ModelHook`):
146
+ The hook to attach.
147
+ append (`bool`, *optional*, defaults to `False`):
148
+ Whether the hook should be chained with an existing one (if module already contains a hook) or not.
149
+
150
+ Returns:
151
+ `torch.nn.Module`: The same module, with the hook attached (the module is modified in place, so the result can
152
+ be discarded).
153
+ """
154
+ if append and (getattr(module, "_hf_hook", None) is not None):
155
+ old_hook = module._hf_hook
156
+ remove_hook_from_module(module)
157
+ hook = SequentialHook(old_hook, hook)
158
+
159
+ if hasattr(module, "_hf_hook") and hasattr(module, "_old_forward"):
160
+ # If we already put some hook on this module, we replace it with the new one.
161
+ old_forward = module._old_forward
162
+ else:
163
+ old_forward = module.forward
164
+ module._old_forward = old_forward
165
+
166
+ module = hook.init_hook(module)
167
+ module._hf_hook = hook
168
+
169
+ def new_forward(module, *args, **kwargs):
170
+ args, kwargs = module._hf_hook.pre_forward(module, *args, **kwargs)
171
+ if module._hf_hook.no_grad:
172
+ with torch.no_grad():
173
+ output = module._old_forward(*args, **kwargs)
174
+ else:
175
+ output = module._old_forward(*args, **kwargs)
176
+ return module._hf_hook.post_forward(module, output)
177
+
178
+ # Overriding a GraphModuleImpl forward freezes the forward call and later modifications on the graph will fail.
179
+ # Reference: https://pytorch.slack.com/archives/C3PDTEV8E/p1705929610405409
180
+ if "GraphModuleImpl" in str(type(module)):
181
+ module.__class__.forward = functools.update_wrapper(functools.partial(new_forward, module), old_forward)
182
+ else:
183
+ module.forward = functools.update_wrapper(functools.partial(new_forward, module), old_forward)
184
+
185
+ return module
186
+
187
+
188
+ def remove_hook_from_module(module: nn.Module, recurse=False):
189
+ """
190
+ Removes any hook attached to a module via `add_hook_to_module`.
191
+
192
+ Args:
193
+ module (`torch.nn.Module`): The module to attach a hook to.
194
+ recurse (`bool`, **optional**): Whether to remove the hooks recursively
195
+
196
+ Returns:
197
+ `torch.nn.Module`: The same module, with the hook detached (the module is modified in place, so the result can
198
+ be discarded).
199
+ """
200
+
201
+ if hasattr(module, "_hf_hook"):
202
+ module._hf_hook.detach_hook(module)
203
+ delattr(module, "_hf_hook")
204
+
205
+ if hasattr(module, "_old_forward"):
206
+ # Overriding a GraphModuleImpl forward freezes the forward call and later modifications on the graph will fail.
207
+ # Reference: https://pytorch.slack.com/archives/C3PDTEV8E/p1705929610405409
208
+ if "GraphModuleImpl" in str(type(module)):
209
+ module.__class__.forward = module._old_forward
210
+ else:
211
+ module.forward = module._old_forward
212
+ delattr(module, "_old_forward")
213
+
214
+ # Remove accelerate added warning hooks from dispatch_model
215
+ for attr in _accelerate_added_attributes:
216
+ module.__dict__.pop(attr, None)
217
+
218
+ if recurse:
219
+ for child in module.children():
220
+ remove_hook_from_module(child, recurse)
221
+
222
+ return module
223
+
224
+
225
+ class AlignDevicesHook(ModelHook):
226
+ """
227
+ A generic `ModelHook` that ensures inputs and model weights are on the same device for the forward pass of the
228
+ associated module, potentially offloading the weights after the forward pass.
229
+
230
+ Args:
231
+ execution_device (`torch.device`, *optional*):
232
+ The device on which inputs and model weights should be placed before the forward pass.
233
+ offload (`bool`, *optional*, defaults to `False`):
234
+ Whether or not the weights should be offloaded after the forward pass.
235
+ io_same_device (`bool`, *optional*, defaults to `False`):
236
+ Whether or not the output should be placed on the same device as the input was.
237
+ weights_map (`Mapping[str, torch.Tensor]`, *optional*):
238
+ When the model weights are offloaded, a (potentially lazy) map from param names to the tensor values.
239
+ offload_buffers (`bool`, *optional*, defaults to `False`):
240
+ Whether or not to include the associated module's buffers when offloading.
241
+ place_submodules (`bool`, *optional*, defaults to `False`):
242
+ Whether to place the submodules on `execution_device` during the `init_hook` event.
243
+ """
244
+
245
+ def __init__(
246
+ self,
247
+ execution_device: Optional[Union[int, str, torch.device]] = None,
248
+ offload: bool = False,
249
+ io_same_device: bool = False,
250
+ weights_map: Optional[Mapping] = None,
251
+ offload_buffers: bool = False,
252
+ place_submodules: bool = False,
253
+ skip_keys: Optional[Union[str, list[str]]] = None,
254
+ tied_params_map: Optional[dict[int, dict[torch.device, torch.Tensor]]] = None,
255
+ ):
256
+ self.execution_device = execution_device
257
+ self.offload = offload
258
+ self.io_same_device = io_same_device
259
+ self.weights_map = weights_map
260
+ self.offload_buffers = offload_buffers
261
+ self.place_submodules = place_submodules
262
+ self.skip_keys = skip_keys
263
+
264
+ # Will contain the input device when `io_same_device=True`.
265
+ self.input_device = None
266
+ self.param_original_devices = {}
267
+ self.buffer_original_devices = {}
268
+ self.tied_params_names = set()
269
+
270
+ # The hook pre_forward/post_forward need to have knowledge of this dictionary, as with offloading we want to avoid duplicating memory
271
+ # for tied weights already loaded on the target execution device.
272
+ self.tied_params_map = tied_params_map
273
+
274
+ def __repr__(self):
275
+ return (
276
+ f"AlignDevicesHook(execution_device={self.execution_device}, offload={self.offload}, "
277
+ f"io_same_device={self.io_same_device}, offload_buffers={self.offload_buffers}, "
278
+ f"place_submodules={self.place_submodules}, skip_keys={repr(self.skip_keys)})"
279
+ )
280
+
281
+ def init_hook(self, module):
282
+ # In case the AlignDevicesHook is on meta device, ignore tied weights as data_ptr() is then always zero.
283
+ if self.execution_device == "meta" or self.execution_device == torch.device("meta"):
284
+ self.tied_params_map = None
285
+
286
+ if not self.offload and self.execution_device is not None:
287
+ for name, _ in named_module_tensors(module, recurse=self.place_submodules):
288
+ set_module_tensor_to_device(module, name, self.execution_device, tied_params_map=self.tied_params_map)
289
+ elif self.offload:
290
+ self.original_devices = {
291
+ name: param.device for name, param in named_module_tensors(module, recurse=self.place_submodules)
292
+ }
293
+ if self.weights_map is None:
294
+ self.weights_map = {
295
+ name: param.to("cpu")
296
+ for name, param in named_module_tensors(
297
+ module, include_buffers=self.offload_buffers, recurse=self.place_submodules
298
+ )
299
+ }
300
+ for name, _ in named_module_tensors(
301
+ module, include_buffers=self.offload_buffers, recurse=self.place_submodules, remove_non_persistent=True
302
+ ):
303
+ # When using disk offloading, we can not rely on `weights_map[name].data_ptr()` as the reference pointer,
304
+ # as we have no guarantee that safetensors' `file.get_tensor()` will always give the same pointer.
305
+ # As we have no reliable way to track the shared data pointer of tied weights in this case, we use tied_params_names: List[str]
306
+ # to add on the fly pointers to `tied_params_map` in the pre_forward call.
307
+ if (
308
+ self.tied_params_map is not None
309
+ and recursive_getattr(module, name).data_ptr() in self.tied_params_map
310
+ ):
311
+ self.tied_params_names.add(name)
312
+
313
+ set_module_tensor_to_device(module, name, "meta")
314
+
315
+ if not self.offload_buffers and self.execution_device is not None:
316
+ for name, _ in module.named_buffers(recurse=self.place_submodules):
317
+ set_module_tensor_to_device(
318
+ module, name, self.execution_device, tied_params_map=self.tied_params_map
319
+ )
320
+ elif self.offload_buffers and self.execution_device is not None:
321
+ for name in get_non_persistent_buffers(module, recurse=self.place_submodules):
322
+ set_module_tensor_to_device(
323
+ module, name, self.execution_device, tied_params_map=self.tied_params_map
324
+ )
325
+
326
+ return module
327
+
328
+ def pre_forward(self, module, *args, **kwargs):
329
+ if self.io_same_device:
330
+ self.input_device = find_device([args, kwargs])
331
+ if self.offload:
332
+ self.tied_pointers_to_remove = set()
333
+
334
+ for name, _ in named_module_tensors(
335
+ module,
336
+ include_buffers=self.offload_buffers,
337
+ recurse=self.place_submodules,
338
+ remove_non_persistent=True,
339
+ ):
340
+ fp16_statistics = None
341
+ value = self.weights_map[name]
342
+ if "weight" in name and name.replace("weight", "SCB") in self.weights_map.keys():
343
+ if value.dtype == torch.int8:
344
+ fp16_statistics = self.weights_map[name.replace("weight", "SCB")]
345
+
346
+ # In case we are using offloading with tied weights, we need to keep track of the offloaded weights
347
+ # that are loaded on device at this point, as we will need to remove them as well from the dictionary
348
+ # self.tied_params_map in order to allow to free memory.
349
+ if name in self.tied_params_names and value.data_ptr() not in self.tied_params_map:
350
+ self.tied_params_map[value.data_ptr()] = {}
351
+
352
+ if (
353
+ value is not None
354
+ and self.tied_params_map is not None
355
+ and value.data_ptr() in self.tied_params_map
356
+ and self.execution_device not in self.tied_params_map[value.data_ptr()]
357
+ ):
358
+ self.tied_pointers_to_remove.add((value.data_ptr(), self.execution_device))
359
+
360
+ set_module_tensor_to_device(
361
+ module,
362
+ name,
363
+ self.execution_device,
364
+ value=value,
365
+ fp16_statistics=fp16_statistics,
366
+ tied_params_map=self.tied_params_map,
367
+ )
368
+
369
+ return send_to_device(args, self.execution_device), send_to_device(
370
+ kwargs, self.execution_device, skip_keys=self.skip_keys
371
+ )
372
+
373
+ def post_forward(self, module, output):
374
+ if self.offload:
375
+ for name, _ in named_module_tensors(
376
+ module,
377
+ include_buffers=self.offload_buffers,
378
+ recurse=self.place_submodules,
379
+ remove_non_persistent=True,
380
+ ):
381
+ set_module_tensor_to_device(module, name, "meta")
382
+ if type(module).__name__ == "Linear8bitLt":
383
+ module.state.SCB = None
384
+ module.state.CxB = None
385
+
386
+ # We may have loaded tied weights into self.tied_params_map (avoiding to load them several times in e.g. submodules): remove them from
387
+ # this dictionary to allow the garbage collector to do its job.
388
+ for value_pointer, device in self.tied_pointers_to_remove:
389
+ if isinstance(device, int):
390
+ if is_npu_available():
391
+ device = f"npu:{device}"
392
+ elif is_mlu_available():
393
+ device = f"mlu:{device}"
394
+ elif is_musa_available():
395
+ device = f"musa:{device}"
396
+ if device in self.tied_params_map[value_pointer]:
397
+ del self.tied_params_map[value_pointer][device]
398
+ self.tied_pointers_to_remove = set()
399
+ if self.io_same_device and self.input_device is not None:
400
+ output = send_to_device(output, self.input_device, skip_keys=self.skip_keys)
401
+
402
+ return output
403
+
404
+ def detach_hook(self, module):
405
+ if self.offload:
406
+ for name, device in self.original_devices.items():
407
+ if device != torch.device("meta"):
408
+ set_module_tensor_to_device(module, name, device, value=self.weights_map.get(name, None))
409
+ return module
410
+
411
+
412
+ def attach_execution_device_hook(
413
+ module: torch.nn.Module,
414
+ execution_device: Union[int, str, torch.device],
415
+ skip_keys: Optional[Union[str, list[str]]] = None,
416
+ preload_module_classes: Optional[list[str]] = None,
417
+ tied_params_map: Optional[dict[int, dict[torch.device, torch.Tensor]]] = None,
418
+ ):
419
+ """
420
+ Recursively attaches `AlignDevicesHook` to all submodules of a given model to make sure they have the right
421
+ execution device
422
+
423
+ Args:
424
+ module (`torch.nn.Module`):
425
+ The module where we want to attach the hooks.
426
+ execution_device (`int`, `str` or `torch.device`):
427
+ The device on which inputs and model weights should be placed before the forward pass.
428
+ skip_keys (`str` or `List[str]`, *optional*):
429
+ A list of keys to ignore when moving inputs or outputs between devices.
430
+ preload_module_classes (`List[str]`, *optional*):
431
+ A list of classes whose instances should load all their weights (even in the submodules) at the beginning
432
+ of the forward. This should only be used for classes that have submodules which are registered but not
433
+ called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
434
+ `dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
435
+ tied_params_map (Optional[Dict[int, Dict[torch.device, torch.Tensor]]], *optional*, defaults to `None`):
436
+ A map of data pointers to dictionaries of devices to already dispatched tied weights. For a given execution
437
+ device, this parameter is useful to reuse the first available pointer of a shared weight for all others,
438
+ instead of duplicating memory.
439
+ """
440
+ if not hasattr(module, "_hf_hook") and len(module.state_dict()) > 0:
441
+ add_hook_to_module(
442
+ module,
443
+ AlignDevicesHook(execution_device, skip_keys=skip_keys, tied_params_map=tied_params_map),
444
+ )
445
+
446
+ # Break the recursion if we get to a preload module.
447
+ if preload_module_classes is not None and module.__class__.__name__ in preload_module_classes:
448
+ return
449
+
450
+ for child in module.children():
451
+ attach_execution_device_hook(
452
+ child,
453
+ execution_device,
454
+ skip_keys=skip_keys,
455
+ preload_module_classes=preload_module_classes,
456
+ tied_params_map=tied_params_map,
457
+ )
458
+
459
+
460
+ def attach_align_device_hook(
461
+ module: torch.nn.Module,
462
+ execution_device: Optional[torch.device] = None,
463
+ offload: bool = False,
464
+ weights_map: Optional[Mapping] = None,
465
+ offload_buffers: bool = False,
466
+ module_name: str = "",
467
+ skip_keys: Optional[Union[str, list[str]]] = None,
468
+ preload_module_classes: Optional[list[str]] = None,
469
+ tied_params_map: Optional[dict[int, dict[torch.device, torch.Tensor]]] = None,
470
+ ):
471
+ """
472
+ Recursively attaches `AlignDevicesHook` to all submodules of a given model that have direct parameters and/or
473
+ buffers.
474
+
475
+ Args:
476
+ module (`torch.nn.Module`):
477
+ The module where we want to attach the hooks.
478
+ execution_device (`torch.device`, *optional*):
479
+ The device on which inputs and model weights should be placed before the forward pass.
480
+ offload (`bool`, *optional*, defaults to `False`):
481
+ Whether or not the weights should be offloaded after the forward pass.
482
+ weights_map (`Mapping[str, torch.Tensor]`, *optional*):
483
+ When the model weights are offloaded, a (potentially lazy) map from param names to the tensor values.
484
+ offload_buffers (`bool`, *optional*, defaults to `False`):
485
+ Whether or not to include the associated module's buffers when offloading.
486
+ module_name (`str`, *optional*, defaults to `""`):
487
+ The name of the module.
488
+ skip_keys (`str` or `List[str]`, *optional*):
489
+ A list of keys to ignore when moving inputs or outputs between devices.
490
+ preload_module_classes (`List[str]`, *optional*):
491
+ A list of classes whose instances should load all their weights (even in the submodules) at the beginning
492
+ of the forward. This should only be used for classes that have submodules which are registered but not
493
+ called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
494
+ `dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
495
+ tied_params_map (Optional[Dict[int, Dict[torch.device, torch.Tensor]]], *optional*, defaults to `None`):
496
+ A map of data pointers to dictionaries of devices to already dispatched tied weights. For a given execution
497
+ device, this parameter is useful to reuse the first available pointer of a shared weight for all others,
498
+ instead of duplicating memory.
499
+ """
500
+ # Attach the hook on this module if it has any direct tensor.
501
+ directs = named_module_tensors(module)
502
+ full_offload = (
503
+ offload and preload_module_classes is not None and module.__class__.__name__ in preload_module_classes
504
+ )
505
+
506
+ if len(list(directs)) > 0 or full_offload:
507
+ if weights_map is not None:
508
+ prefix = f"{module_name}." if len(module_name) > 0 else ""
509
+ prefixed_weights_map = PrefixedDataset(weights_map, prefix)
510
+ else:
511
+ prefixed_weights_map = None
512
+ hook = AlignDevicesHook(
513
+ execution_device=execution_device,
514
+ offload=offload,
515
+ weights_map=prefixed_weights_map,
516
+ offload_buffers=offload_buffers,
517
+ place_submodules=full_offload,
518
+ skip_keys=skip_keys,
519
+ tied_params_map=tied_params_map,
520
+ )
521
+ add_hook_to_module(module, hook, append=True)
522
+
523
+ # We stop the recursion in case we hit the full offload.
524
+ if full_offload:
525
+ return
526
+
527
+ # Recurse on all children of the module.
528
+ for child_name, child in module.named_children():
529
+ child_name = f"{module_name}.{child_name}" if len(module_name) > 0 else child_name
530
+ attach_align_device_hook(
531
+ child,
532
+ execution_device=execution_device,
533
+ offload=offload,
534
+ weights_map=weights_map,
535
+ offload_buffers=offload_buffers,
536
+ module_name=child_name,
537
+ preload_module_classes=preload_module_classes,
538
+ skip_keys=skip_keys,
539
+ tied_params_map=tied_params_map,
540
+ )
541
+
542
+
543
+ def remove_hook_from_submodules(module: nn.Module):
544
+ """
545
+ Recursively removes all hooks attached on the submodules of a given model.
546
+
547
+ Args:
548
+ module (`torch.nn.Module`): The module on which to remove all hooks.
549
+ """
550
+ remove_hook_from_module(module)
551
+ for child in module.children():
552
+ remove_hook_from_submodules(child)
553
+
554
+
555
+ def attach_align_device_hook_on_blocks(
556
+ module: nn.Module,
557
+ execution_device: Optional[Union[torch.device, dict[str, torch.device]]] = None,
558
+ offload: Union[bool, dict[str, bool]] = False,
559
+ weights_map: Mapping = None,
560
+ offload_buffers: bool = False,
561
+ module_name: str = "",
562
+ skip_keys: Optional[Union[str, list[str]]] = None,
563
+ preload_module_classes: Optional[list[str]] = None,
564
+ tied_params_map: Optional[dict[int, dict[torch.device, torch.Tensor]]] = None,
565
+ ):
566
+ """
567
+ Attaches `AlignDevicesHook` to all blocks of a given model as needed.
568
+
569
+ Args:
570
+ module (`torch.nn.Module`):
571
+ The module where we want to attach the hooks.
572
+ execution_device (`torch.device` or `Dict[str, torch.device]`, *optional*):
573
+ The device on which inputs and model weights should be placed before the forward pass. It can be one device
574
+ for the whole module, or a dictionary mapping module name to device.
575
+ offload (`bool`, *optional*, defaults to `False`):
576
+ Whether or not the weights should be offloaded after the forward pass. It can be one boolean for the whole
577
+ module, or a dictionary mapping module name to boolean.
578
+ weights_map (`Mapping[str, torch.Tensor]`, *optional*):
579
+ When the model weights are offloaded, a (potentially lazy) map from param names to the tensor values.
580
+ offload_buffers (`bool`, *optional*, defaults to `False`):
581
+ Whether or not to include the associated module's buffers when offloading.
582
+ module_name (`str`, *optional*, defaults to `""`):
583
+ The name of the module.
584
+ skip_keys (`str` or `List[str]`, *optional*):
585
+ A list of keys to ignore when moving inputs or outputs between devices.
586
+ preload_module_classes (`List[str]`, *optional*):
587
+ A list of classes whose instances should load all their weights (even in the submodules) at the beginning
588
+ of the forward. This should only be used for classes that have submodules which are registered but not
589
+ called directly during the forward, for instance if a `dense` linear layer is registered, but at forward,
590
+ `dense.weight` and `dense.bias` are used in some operations instead of calling `dense` directly.
591
+ tied_params_map (Optional[Dict[int, Dict[torch.device, torch.Tensor]]], *optional*, defaults to `None`):
592
+ A map of data pointers to dictionaries of devices to already dispatched tied weights. For a given execution
593
+ device, this parameter is useful to reuse the first available pointer of a shared weight for all others,
594
+ instead of duplicating memory.
595
+ """
596
+ # If one device and one offload, we've got one hook.
597
+ if not isinstance(execution_device, Mapping) and not isinstance(offload, dict):
598
+ if not offload:
599
+ hook = AlignDevicesHook(
600
+ execution_device=execution_device,
601
+ io_same_device=True,
602
+ skip_keys=skip_keys,
603
+ place_submodules=True,
604
+ tied_params_map=tied_params_map,
605
+ )
606
+ add_hook_to_module(module, hook)
607
+ else:
608
+ attach_align_device_hook(
609
+ module,
610
+ execution_device=execution_device,
611
+ offload=True,
612
+ weights_map=weights_map,
613
+ offload_buffers=offload_buffers,
614
+ module_name=module_name,
615
+ skip_keys=skip_keys,
616
+ tied_params_map=tied_params_map,
617
+ )
618
+ return
619
+
620
+ if not isinstance(execution_device, Mapping):
621
+ execution_device = {key: execution_device for key in offload.keys()}
622
+ if not isinstance(offload, Mapping):
623
+ offload = {key: offload for key in execution_device.keys()}
624
+
625
+ if module_name in execution_device and module_name in offload and not offload[module_name]:
626
+ hook = AlignDevicesHook(
627
+ execution_device=execution_device[module_name],
628
+ offload_buffers=offload_buffers,
629
+ io_same_device=(module_name == ""),
630
+ place_submodules=True,
631
+ skip_keys=skip_keys,
632
+ tied_params_map=tied_params_map,
633
+ )
634
+ add_hook_to_module(module, hook)
635
+ attach_execution_device_hook(
636
+ module, execution_device[module_name], skip_keys=skip_keys, tied_params_map=tied_params_map
637
+ )
638
+ elif module_name in execution_device and module_name in offload:
639
+ attach_align_device_hook(
640
+ module,
641
+ execution_device=execution_device[module_name],
642
+ offload=True,
643
+ weights_map=weights_map,
644
+ offload_buffers=offload_buffers,
645
+ module_name=module_name,
646
+ skip_keys=skip_keys,
647
+ preload_module_classes=preload_module_classes,
648
+ tied_params_map=tied_params_map,
649
+ )
650
+ if not hasattr(module, "_hf_hook"):
651
+ hook = AlignDevicesHook(
652
+ execution_device=execution_device[module_name],
653
+ io_same_device=(module_name == ""),
654
+ skip_keys=skip_keys,
655
+ tied_params_map=tied_params_map,
656
+ )
657
+ add_hook_to_module(module, hook)
658
+ attach_execution_device_hook(
659
+ module,
660
+ execution_device[module_name],
661
+ preload_module_classes=preload_module_classes,
662
+ skip_keys=skip_keys,
663
+ tied_params_map=tied_params_map,
664
+ )
665
+ elif module_name == "":
666
+ hook = AlignDevicesHook(
667
+ execution_device=execution_device.get(""),
668
+ io_same_device=True,
669
+ skip_keys=skip_keys,
670
+ tied_params_map=tied_params_map,
671
+ )
672
+ add_hook_to_module(module, hook)
673
+
674
+ for child_name, child in module.named_children():
675
+ child_name = f"{module_name}.{child_name}" if len(module_name) > 0 else child_name
676
+ attach_align_device_hook_on_blocks(
677
+ child,
678
+ execution_device=execution_device,
679
+ offload=offload,
680
+ weights_map=weights_map,
681
+ offload_buffers=offload_buffers,
682
+ module_name=child_name,
683
+ preload_module_classes=preload_module_classes,
684
+ skip_keys=skip_keys,
685
+ tied_params_map=tied_params_map,
686
+ )
687
+
688
+
689
+ class CpuOffload(ModelHook):
690
+ """
691
+ Offloads a model on the CPU until its forward pass is called. The model will not be offloaded back to the CPU after
692
+ the forward, the user needs to call the `init_hook` method again for this.
693
+
694
+ Args:
695
+ execution_device(`str`, `int` or `torch.device`, *optional*):
696
+ The device on which the model should be executed. Will default to the MPS device if it's available, then
697
+ GPU 0 if there is a GPU, and finally to the CPU.
698
+ prev_module_hook (`UserCpuOffloadHook`, *optional*):
699
+ The hook sent back by [`cpu_offload_with_hook`] for a previous model in the pipeline you are running. If
700
+ passed, its offload method will be called just before the forward of the model to which this hook is
701
+ attached.
702
+ """
703
+
704
+ def __init__(
705
+ self,
706
+ execution_device: Optional[Union[str, int, torch.device]] = None,
707
+ prev_module_hook: Optional["UserCpuOffloadHook"] = None,
708
+ ):
709
+ self.prev_module_hook = prev_module_hook
710
+
711
+ self.execution_device = execution_device if execution_device is not None else PartialState().default_device
712
+
713
+ def init_hook(self, module):
714
+ return module.to("cpu")
715
+
716
+ def pre_forward(self, module, *args, **kwargs):
717
+ if self.prev_module_hook is not None:
718
+ self.prev_module_hook.offload()
719
+ clear_device_cache()
720
+ module.to(self.execution_device)
721
+ return send_to_device(args, self.execution_device), send_to_device(kwargs, self.execution_device)
722
+
723
+
724
+ class UserCpuOffloadHook:
725
+ """
726
+ A simple hook grouping a model and a `ModelHook`, which provides easy APIs for to call the init method of the hook
727
+ or remove it entirely.
728
+ """
729
+
730
+ def __init__(self, model, hook):
731
+ self.model = model
732
+ self.hook = hook
733
+
734
+ def offload(self):
735
+ self.hook.init_hook(self.model)
736
+
737
+ def remove(self):
738
+ remove_hook_from_module(self.model)
739
+
740
+
741
+ class LayerwiseCastingHook(ModelHook):
742
+ r"""
743
+ A hook that casts the weights of a module to a high precision dtype for computation, and to a low precision dtype
744
+ for storage. This process may lead to quality loss in the output, but can significantly reduce the memory
745
+ footprint.
746
+ """
747
+
748
+ _is_stateful = False
749
+
750
+ def __init__(self, storage_dtype: torch.dtype, compute_dtype: torch.dtype, non_blocking: bool) -> None:
751
+ self.storage_dtype = storage_dtype
752
+ self.compute_dtype = compute_dtype
753
+ self.non_blocking = non_blocking
754
+
755
+ def init_hook(self, module: torch.nn.Module):
756
+ module.to(dtype=self.storage_dtype, non_blocking=self.non_blocking)
757
+ return module
758
+
759
+ def pre_forward(self, module: torch.nn.Module, *args, **kwargs):
760
+ module.to(dtype=self.compute_dtype, non_blocking=self.non_blocking)
761
+ return args, kwargs
762
+
763
+ def post_forward(self, module: torch.nn.Module, output):
764
+ module.to(dtype=self.storage_dtype, non_blocking=self.non_blocking)
765
+ return output
venv/lib/python3.10/site-packages/accelerate/inference.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 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
+ import math
15
+ from types import MethodType
16
+ from typing import Any, Optional, Union
17
+
18
+ from .state import PartialState
19
+ from .utils import (
20
+ calculate_maximum_sizes,
21
+ convert_bytes,
22
+ copy_tensor_to_devices,
23
+ ignorant_find_batch_size,
24
+ infer_auto_device_map,
25
+ is_pippy_available,
26
+ pad_input_tensors,
27
+ send_to_device,
28
+ )
29
+
30
+
31
+ def generate_device_map(model, num_processes: int = 1, no_split_module_classes=None, max_memory: dict = None):
32
+ """
33
+ Calculates the device map for `model` with an offset for PiPPy
34
+ """
35
+ if num_processes == 1:
36
+ return infer_auto_device_map(model, no_split_module_classes=no_split_module_classes, clean_result=False)
37
+ if max_memory is None:
38
+ model_size, shared = calculate_maximum_sizes(model)
39
+
40
+ # Split into `n` chunks for each GPU
41
+ memory = (model_size + shared[0]) / num_processes
42
+ memory = convert_bytes(memory)
43
+ value, ending = memory.split(" ")
44
+
45
+ # Add a chunk to deal with potential extra shared memory instances
46
+ memory = math.ceil(float(value)) * 1.1
47
+ memory = f"{memory} {ending}"
48
+ max_memory = {i: memory for i in range(num_processes)}
49
+ device_map = infer_auto_device_map(
50
+ model,
51
+ max_memory=max_memory,
52
+ no_split_module_classes=no_split_module_classes,
53
+ clean_result=False,
54
+ )
55
+ return device_map
56
+
57
+
58
+ def find_pippy_batch_size(args, kwargs):
59
+ found_batch_size = None
60
+ if args is not None:
61
+ for arg in args:
62
+ found_batch_size = ignorant_find_batch_size(arg)
63
+ if found_batch_size is not None:
64
+ break
65
+ if kwargs is not None and found_batch_size is None:
66
+ for kwarg in kwargs.values():
67
+ found_batch_size = ignorant_find_batch_size(kwarg)
68
+ if found_batch_size is not None:
69
+ break
70
+ return found_batch_size
71
+
72
+
73
+ def build_pipeline(model, split_points, args, kwargs, num_chunks):
74
+ """
75
+ Attaches the split points to the model based on `self.device_map` and generates a `PipelineStage`. Requires passing
76
+ in needed `args` and `kwargs` as the model needs on the CPU.
77
+
78
+ Users can pass in custom `num_chunks` as an optional hyper-parameter. By default will use
79
+ `AcceleratorState.num_processes`
80
+ """
81
+ # Note: We import here to reduce import time from general modules, and isolate outside dependencies
82
+ from torch.distributed.pipelining import ScheduleGPipe, SplitPoint, pipeline
83
+
84
+ # We need to annotate the split points in the model for PiPPy
85
+ state = PartialState()
86
+ split_spec = {split_point: SplitPoint.BEGINNING for split_point in split_points}
87
+ pipe = pipeline(
88
+ model,
89
+ mb_args=args,
90
+ mb_kwargs=kwargs,
91
+ split_spec=split_spec,
92
+ )
93
+ stage = pipe.build_stage(state.local_process_index, device=state.device)
94
+ schedule = ScheduleGPipe(stage, num_chunks)
95
+
96
+ return schedule
97
+
98
+
99
+ def pippy_forward(forward, num_chunks, gather_output, *args, **kwargs):
100
+ state = PartialState()
101
+ output = None
102
+
103
+ if state.num_processes == 1:
104
+ output = forward(*args, **kwargs)
105
+ elif state.is_local_main_process:
106
+ found_batch_size = find_pippy_batch_size(args, kwargs)
107
+ if found_batch_size is None:
108
+ raise ValueError("Could not find batch size from args or kwargs")
109
+ else:
110
+ if found_batch_size != num_chunks:
111
+ args = pad_input_tensors(args, found_batch_size, num_chunks)
112
+ kwargs = pad_input_tensors(kwargs, found_batch_size, num_chunks)
113
+ forward(*args, **kwargs)
114
+ elif state.is_last_process:
115
+ output = forward()
116
+ else:
117
+ forward()
118
+ if gather_output:
119
+ # Each node will get a copy of the full output which is only on the last GPU
120
+ output = copy_tensor_to_devices(output)
121
+ return output
122
+
123
+
124
+ def prepare_pippy(
125
+ model,
126
+ split_points: Optional[Union[str, list[str]]] = "auto",
127
+ no_split_module_classes: Optional[list[str]] = None,
128
+ example_args: Optional[tuple[Any]] = (),
129
+ example_kwargs: Optional[dict[str, Any]] = None,
130
+ num_chunks: Optional[int] = None,
131
+ gather_output: Optional[bool] = False,
132
+ ):
133
+ """
134
+ Wraps `model` for pipeline parallel inference.
135
+
136
+ Args:
137
+ model (`torch.nn.Module`):
138
+ A model we want to split for pipeline-parallel inference
139
+ split_points (`str` or `List[str]`, defaults to 'auto'):
140
+ How to generate the split points and chunk the model across each GPU. 'auto' will find the best balanced
141
+ split given any model. Should be a list of layer names in the model to split by otherwise.
142
+ no_split_module_classes (`List[str]`):
143
+ A list of class names for layers we don't want to be split.
144
+ example_args (tuple of model inputs):
145
+ The expected inputs for the model that uses order-based inputs for a *single process*. Recommended to use
146
+ this method if possible.
147
+ example_kwargs (dict of model inputs)
148
+ The expected inputs for the model that uses dictionary-based inputs for a *single process*. This is a
149
+ *highly* limiting structure that requires the same keys be present at *all* inference calls. Not
150
+ recommended unless the prior condition is true for all cases.
151
+ num_chunks (`int`, defaults to the number of available GPUs):
152
+ The number of different stages the Pipeline will have. By default it will assign one chunk per GPU, but
153
+ this can be tuned and played with. In general one should have num_chunks >= num_gpus.
154
+ gather_output (`bool`, defaults to `False`):
155
+ If `True`, the output from the last GPU (which holds the true outputs) is sent across to all GPUs.
156
+ """
157
+ if not is_pippy_available():
158
+ raise ImportError("Using `torch.distributed.pipelining` requires PyTorch 2.4.0 or later.")
159
+ state = PartialState()
160
+ example_args = send_to_device(example_args, "cpu")
161
+ example_kwargs = send_to_device(example_kwargs, "cpu")
162
+ if num_chunks is None:
163
+ num_chunks = state.num_processes
164
+ if split_points == "auto":
165
+ device_map = generate_device_map(model, num_chunks, no_split_module_classes=no_split_module_classes)
166
+ split_points = []
167
+ for i in range(1, num_chunks):
168
+ split_points.append(next(k for k, v in device_map.items() if v == i))
169
+ model.hf_split_points = split_points
170
+ stage = build_pipeline(model, split_points, example_args, example_kwargs, num_chunks)
171
+ model._original_forward = model.forward
172
+ model._original_call = model.__call__
173
+ model.pippy_stage = stage
174
+ model.hf_split_points = split_points
175
+
176
+ def forward(*args, **kwargs):
177
+ return pippy_forward(stage.step, num_chunks, gather_output, *args, **kwargs)
178
+
179
+ # To act like a decorator so that it can be popped when doing `extract_model_from_parallel`
180
+ # Note: creates an infinite recursion loop with `generate`
181
+ model_forward = MethodType(forward, model)
182
+ forward.__wrapped__ = model_forward
183
+ model.forward = forward
184
+ return model
venv/lib/python3.10/site-packages/accelerate/launchers.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2021 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 os
16
+ import sys
17
+ import tempfile
18
+
19
+ import torch
20
+
21
+ from .state import AcceleratorState, PartialState
22
+ from .utils import (
23
+ PrecisionType,
24
+ PrepareForLaunch,
25
+ are_libraries_initialized,
26
+ check_cuda_p2p_ib_support,
27
+ get_gpu_info,
28
+ is_mps_available,
29
+ is_torch_version,
30
+ patch_environment,
31
+ )
32
+ from .utils.constants import ELASTIC_LOG_LINE_PREFIX_TEMPLATE_PYTORCH_VERSION
33
+
34
+
35
+ def test_launch():
36
+ "Verify a `PartialState` can be initialized."
37
+ _ = PartialState()
38
+
39
+
40
+ def notebook_launcher(
41
+ function,
42
+ args=(),
43
+ num_processes=None,
44
+ mixed_precision="no",
45
+ use_port="29500",
46
+ master_addr="127.0.0.1",
47
+ node_rank=0,
48
+ num_nodes=1,
49
+ rdzv_backend="static",
50
+ rdzv_endpoint="",
51
+ rdzv_conf=None,
52
+ rdzv_id="none",
53
+ max_restarts=0,
54
+ monitor_interval=0.1,
55
+ log_line_prefix_template=None,
56
+ ):
57
+ """
58
+ Launches a training function, using several processes or multiple nodes if it's possible in the current environment
59
+ (TPU with multiple cores for instance).
60
+
61
+ <Tip warning={true}>
62
+
63
+ To use this function absolutely zero calls to a device must be made in the notebook session before calling. If any
64
+ have been made, you will need to restart the notebook and make sure no cells use any device capability.
65
+
66
+ Setting `ACCELERATE_DEBUG_MODE="1"` in your environment will run a test before truly launching to ensure that none
67
+ of those calls have been made.
68
+
69
+ </Tip>
70
+
71
+ Args:
72
+ function (`Callable`):
73
+ The training function to execute. If it accepts arguments, the first argument should be the index of the
74
+ process run.
75
+ args (`Tuple`):
76
+ Tuple of arguments to pass to the function (it will receive `*args`).
77
+ num_processes (`int`, *optional*):
78
+ The number of processes to use for training. Will default to 8 in Colab/Kaggle if a TPU is available, to
79
+ the number of devices available otherwise.
80
+ mixed_precision (`str`, *optional*, defaults to `"no"`):
81
+ If `fp16` or `bf16`, will use mixed precision training on multi-device.
82
+ use_port (`str`, *optional*, defaults to `"29500"`):
83
+ The port to use to communicate between processes when launching a multi-device training.
84
+ master_addr (`str`, *optional*, defaults to `"127.0.0.1"`):
85
+ The address to use for communication between processes.
86
+ node_rank (`int`, *optional*, defaults to 0):
87
+ The rank of the current node.
88
+ num_nodes (`int`, *optional*, defaults to 1):
89
+ The number of nodes to use for training.
90
+ rdzv_backend (`str`, *optional*, defaults to `"static"`):
91
+ The rendezvous method to use, such as 'static' (the default) or 'c10d'
92
+ rdzv_endpoint (`str`, *optional*, defaults to `""`):
93
+ The endpoint of the rdzv sync. storage.
94
+ rdzv_conf (`Dict`, *optional*, defaults to `None`):
95
+ Additional rendezvous configuration.
96
+ rdzv_id (`str`, *optional*, defaults to `"none"`):
97
+ The unique run id of the job.
98
+ max_restarts (`int`, *optional*, defaults to 0):
99
+ The maximum amount of restarts that elastic agent will conduct on workers before failure.
100
+ monitor_interval (`float`, *optional*, defaults to 0.1):
101
+ The interval in seconds that is used by the elastic_agent as a period of monitoring workers.
102
+ log_line_prefix_template (`str`, *optional*, defaults to `None`):
103
+ The prefix template for elastic launch logging. Available from PyTorch 2.2.0.
104
+
105
+ Example:
106
+
107
+ ```python
108
+ # Assume this is defined in a Jupyter Notebook on an instance with two devices
109
+ from accelerate import notebook_launcher
110
+
111
+
112
+ def train(*args):
113
+ # Your training function here
114
+ ...
115
+
116
+
117
+ notebook_launcher(train, args=(arg1, arg2), num_processes=2, mixed_precision="fp16")
118
+ ```
119
+ """
120
+ # Are we in a google colab or a Kaggle Kernel?
121
+ in_colab = False
122
+ in_kaggle = False
123
+ if any(key.startswith("KAGGLE") for key in os.environ.keys()):
124
+ in_kaggle = True
125
+ elif "IPython" in sys.modules:
126
+ in_colab = "google.colab" in str(sys.modules["IPython"].get_ipython())
127
+
128
+ try:
129
+ mixed_precision = PrecisionType(mixed_precision.lower())
130
+ except ValueError:
131
+ raise ValueError(
132
+ f"Unknown mixed_precision mode: {args.mixed_precision.lower()}. Choose between {PrecisionType.list()}."
133
+ )
134
+
135
+ if (in_colab or in_kaggle) and (
136
+ (os.environ.get("TPU_NAME", None) is not None) or (os.environ.get("PJRT_DEVICE", "") == "TPU")
137
+ ):
138
+ # TPU launch
139
+ import torch_xla.distributed.xla_multiprocessing as xmp
140
+
141
+ if len(AcceleratorState._shared_state) > 0:
142
+ raise ValueError(
143
+ "To train on TPU in Colab or Kaggle Kernel, the `Accelerator` should only be initialized inside "
144
+ "your training function. Restart your notebook and make sure no cells initializes an "
145
+ "`Accelerator`."
146
+ )
147
+
148
+ launcher = PrepareForLaunch(function, distributed_type="XLA")
149
+ print("Launching a training on TPU cores.")
150
+ xmp.spawn(launcher, args=args, start_method="fork")
151
+ elif in_colab and get_gpu_info()[1] < 2:
152
+ # No need for a distributed launch otherwise as it's either CPU or one GPU.
153
+ if torch.cuda.is_available():
154
+ print("Launching training on one GPU.")
155
+ else:
156
+ print("Launching training on one CPU.")
157
+ function(*args)
158
+ else:
159
+ if num_processes is None:
160
+ raise ValueError(
161
+ "You have to specify the number of devices you would like to use, add `num_processes=...` to your call."
162
+ )
163
+ if node_rank >= num_nodes:
164
+ raise ValueError("The node_rank must be less than the number of nodes.")
165
+ if num_processes > 1:
166
+ # Multi-device launch
167
+ from torch.distributed.launcher.api import LaunchConfig, elastic_launch
168
+ from torch.multiprocessing import start_processes
169
+ from torch.multiprocessing.spawn import ProcessRaisedException
170
+
171
+ if len(AcceleratorState._shared_state) > 0:
172
+ raise ValueError(
173
+ "To launch a multi-device training from your notebook, the `Accelerator` should only be initialized "
174
+ "inside your training function. Restart your notebook and make sure no cells initializes an "
175
+ "`Accelerator`."
176
+ )
177
+ # Check for specific libraries known to initialize device that users constantly use
178
+ problematic_imports = are_libraries_initialized("bitsandbytes")
179
+ if len(problematic_imports) > 0:
180
+ err = (
181
+ "Could not start distributed process. Libraries known to initialize device upon import have been "
182
+ "imported already. Please keep these imports inside your training function to try and help with this:"
183
+ )
184
+ for lib_name in problematic_imports:
185
+ err += f"\n\t* `{lib_name}`"
186
+ raise RuntimeError(err)
187
+
188
+ patched_env = dict(
189
+ nproc=num_processes,
190
+ node_rank=node_rank,
191
+ world_size=num_nodes * num_processes,
192
+ master_addr=master_addr,
193
+ master_port=use_port,
194
+ mixed_precision=mixed_precision,
195
+ )
196
+
197
+ # Check for CUDA P2P and IB issues
198
+ if not check_cuda_p2p_ib_support():
199
+ patched_env["nccl_p2p_disable"] = "1"
200
+ patched_env["nccl_ib_disable"] = "1"
201
+
202
+ # torch.distributed will expect a few environment variable to be here. We set the ones common to each
203
+ # process here (the other ones will be set be the launcher).
204
+ with patch_environment(**patched_env):
205
+ # First dummy launch
206
+ device_type = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"
207
+ distributed_type = "MULTI_XPU" if device_type == "xpu" else "MULTI_GPU"
208
+ if os.environ.get("ACCELERATE_DEBUG_MODE", "false").lower() == "true":
209
+ launcher = PrepareForLaunch(test_launch, distributed_type=distributed_type)
210
+ try:
211
+ start_processes(launcher, args=(), nprocs=num_processes, start_method="fork")
212
+ except ProcessRaisedException as e:
213
+ err = "An issue was found when verifying a stable environment for the notebook launcher."
214
+ if f"Cannot re-initialize {device_type.upper()} in forked subprocess" in e.args[0]:
215
+ raise RuntimeError(
216
+ f"{err}"
217
+ "This likely stems from an outside import causing issues once the `notebook_launcher()` is called. "
218
+ "Please review your imports and test them when running the `notebook_launcher()` to identify "
219
+ f"which one is problematic and causing {device_type.upper()} to be initialized."
220
+ ) from e
221
+ else:
222
+ raise RuntimeError(f"{err} The following error was raised: {e}") from e
223
+ # Now the actual launch
224
+ launcher = PrepareForLaunch(function, distributed_type=distributed_type)
225
+ print(f"Launching training on {num_processes} {device_type.upper()}s.")
226
+ try:
227
+ if rdzv_conf is None:
228
+ rdzv_conf = {}
229
+ if rdzv_backend == "static":
230
+ rdzv_conf["rank"] = node_rank
231
+ if not rdzv_endpoint:
232
+ rdzv_endpoint = f"{master_addr}:{use_port}"
233
+ launch_config_kwargs = dict(
234
+ min_nodes=num_nodes,
235
+ max_nodes=num_nodes,
236
+ nproc_per_node=num_processes,
237
+ run_id=rdzv_id,
238
+ rdzv_endpoint=rdzv_endpoint,
239
+ rdzv_backend=rdzv_backend,
240
+ rdzv_configs=rdzv_conf,
241
+ max_restarts=max_restarts,
242
+ monitor_interval=monitor_interval,
243
+ start_method="fork",
244
+ )
245
+ if is_torch_version(">=", ELASTIC_LOG_LINE_PREFIX_TEMPLATE_PYTORCH_VERSION):
246
+ launch_config_kwargs["log_line_prefix_template"] = log_line_prefix_template
247
+ elastic_launch(config=LaunchConfig(**launch_config_kwargs), entrypoint=function)(*args)
248
+ except ProcessRaisedException as e:
249
+ if f"Cannot re-initialize {device_type.upper()} in forked subprocess" in e.args[0]:
250
+ raise RuntimeError(
251
+ f"{device_type.upper()} has been initialized before the `notebook_launcher` could create a forked subprocess. "
252
+ "This likely stems from an outside import causing issues once the `notebook_launcher()` is called. "
253
+ "Please review your imports and test them when running the `notebook_launcher()` to identify "
254
+ f"which one is problematic and causing {device_type.upper()} to be initialized."
255
+ ) from e
256
+ else:
257
+ raise RuntimeError(f"An issue was found when launching the training: {e}") from e
258
+
259
+ else:
260
+ # No need for a distributed launch otherwise as it's either CPU, GPU, XPU or MPS.
261
+ if is_mps_available():
262
+ os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
263
+ print("Launching training on MPS.")
264
+ elif torch.cuda.is_available():
265
+ print("Launching training on one GPU.")
266
+ elif torch.xpu.is_available():
267
+ print("Launching training on one XPU.")
268
+ else:
269
+ print("Launching training on CPU.")
270
+ function(*args)
271
+
272
+
273
+ def debug_launcher(function, args=(), num_processes=2):
274
+ """
275
+ Launches a training function using several processes on CPU for debugging purposes.
276
+
277
+ <Tip warning={true}>
278
+
279
+ This function is provided for internal testing and debugging, but it's not intended for real trainings. It will
280
+ only use the CPU.
281
+
282
+ </Tip>
283
+
284
+ Args:
285
+ function (`Callable`):
286
+ The training function to execute.
287
+ args (`Tuple`):
288
+ Tuple of arguments to pass to the function (it will receive `*args`).
289
+ num_processes (`int`, *optional*, defaults to 2):
290
+ The number of processes to use for training.
291
+ """
292
+ from torch.multiprocessing import start_processes
293
+
294
+ with tempfile.NamedTemporaryFile() as tmp_file:
295
+ # torch.distributed will expect a few environment variable to be here. We set the ones common to each
296
+ # process here (the other ones will be set be the launcher).
297
+ with patch_environment(
298
+ world_size=num_processes,
299
+ master_addr="127.0.0.1",
300
+ master_port="29500",
301
+ accelerate_mixed_precision="no",
302
+ accelerate_debug_rdv_file=tmp_file.name,
303
+ accelerate_use_cpu="yes",
304
+ ):
305
+ launcher = PrepareForLaunch(function, debug=True)
306
+ start_processes(launcher, args=args, nprocs=num_processes, start_method="fork")
venv/lib/python3.10/site-packages/accelerate/local_sgd.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023 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
+ import torch
15
+
16
+ from accelerate import Accelerator, DistributedType
17
+
18
+
19
+ class LocalSGD:
20
+ """
21
+ A helper class to support local SGD on top of Accelerator. It simply runs a given number of updates independently
22
+ on each device, and averages model weights every K synchronization step.
23
+
24
+ It should be used only in the multi-GPU (or multi-CPU) setup without extensions such as DeepSpeed. In particular,
25
+ this is a simple implementation that cannot support scenarios such as model parallelism.
26
+
27
+
28
+ Although we are not aware of the true origins of this simple approach, the idea of local SGD is quite old and goes
29
+ back to at least:
30
+
31
+ Zhang, J., De Sa, C., Mitliagkas, I., & Ré, C. (2016). [Parallel SGD: When does averaging help?. arXiv preprint
32
+ arXiv:1606.07365.](https://arxiv.org/abs/1606.07365)
33
+
34
+ We credit the term Local SGD to the following paper (but there might be earlier references we are not aware of).
35
+
36
+ Stich, Sebastian Urban. ["Local SGD Converges Fast and Communicates Little." ICLR 2019-International Conference on
37
+ Learning Representations. No. CONF. 2019.](https://arxiv.org/abs/1805.09767)
38
+
39
+ """
40
+
41
+ def __enter__(self):
42
+ if self.enabled:
43
+ self.model_sync_obj = self.model.no_sync()
44
+ self.model_sync_obj.__enter__()
45
+
46
+ return self
47
+
48
+ def __exit__(self, type, value, tb):
49
+ if self.enabled:
50
+ # Average all models on exit
51
+ self._sync_and_avg_model_params()
52
+ self.model_sync_obj.__exit__(type, value, tb)
53
+
54
+ def __init__(self, accelerator: Accelerator, model: torch.nn.Module, local_sgd_steps: int, enabled: bool = True):
55
+ """
56
+ Constructor.
57
+
58
+ Args:
59
+ model (`torch.nn.Module):
60
+ The model whose parameters we need to average.
61
+ accelerator (`Accelerator`):
62
+ Accelerator object.
63
+ local_sgd_steps (`int`):
64
+ A number of local SGD steps (before model parameters are synchronized).
65
+ enabled (`bool):
66
+ Local SGD is disabled if this parameter set to `False`.
67
+ """
68
+ if accelerator.distributed_type not in [
69
+ DistributedType.NO,
70
+ DistributedType.MULTI_CPU,
71
+ DistributedType.MULTI_GPU,
72
+ DistributedType.MULTI_XPU,
73
+ DistributedType.MULTI_MLU,
74
+ DistributedType.MULTI_HPU,
75
+ DistributedType.MULTI_SDAA,
76
+ DistributedType.MULTI_MUSA,
77
+ DistributedType.MULTI_NPU,
78
+ ]:
79
+ raise NotImplementedError("LocalSGD is supported only for CPUs and GPUs (no DeepSpeed or MegatronLM)")
80
+ self.enabled = enabled and accelerator.distributed_type != DistributedType.NO
81
+ self.num_steps = 0
82
+ if self.enabled:
83
+ self.accelerator = accelerator
84
+ self.model = model
85
+ self.local_sgd_steps = local_sgd_steps
86
+
87
+ def step(self):
88
+ """
89
+ This function makes a "step" and synchronizes model parameters if necessary.
90
+ """
91
+ self.num_steps += 1
92
+ if not self.enabled:
93
+ return
94
+
95
+ if self.num_steps % self.local_sgd_steps == 0:
96
+ self._sync_and_avg_model_params()
97
+
98
+ def _sync_and_avg_model_params(self):
99
+ """
100
+ Synchronize + Average model parameters across all GPUs
101
+ """
102
+
103
+ self.accelerator.wait_for_everyone()
104
+ with self.accelerator.autocast():
105
+ for param in self.model.parameters():
106
+ param.data = self.accelerator.reduce(param.data, reduction="mean")
venv/lib/python3.10/site-packages/accelerate/logging.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 functools
16
+ import logging
17
+ import os
18
+
19
+ from .state import PartialState
20
+
21
+
22
+ class MultiProcessAdapter(logging.LoggerAdapter):
23
+ """
24
+ An adapter to assist with logging in multiprocess.
25
+
26
+ `log` takes in an additional `main_process_only` kwarg, which dictates whether it should be called on all processes
27
+ or only the main executed one. Default is `main_process_only=True`.
28
+
29
+ Does not require an `Accelerator` object to be created first.
30
+ """
31
+
32
+ @staticmethod
33
+ def _should_log(main_process_only):
34
+ "Check if log should be performed"
35
+ state = PartialState()
36
+ return not main_process_only or (main_process_only and state.is_main_process)
37
+
38
+ def log(self, level, msg, *args, **kwargs):
39
+ """
40
+ Delegates logger call after checking if we should log.
41
+
42
+ Accepts a new kwarg of `main_process_only`, which will dictate whether it will be logged across all processes
43
+ or only the main executed one. Default is `True` if not passed
44
+
45
+ Also accepts "in_order", which if `True` makes the processes log one by one, in order. This is much easier to
46
+ read, but comes at the cost of sometimes needing to wait for the other processes. Default is `False` to not
47
+ break with the previous behavior.
48
+
49
+ `in_order` is ignored if `main_process_only` is passed.
50
+ """
51
+ if PartialState._shared_state == {}:
52
+ raise RuntimeError(
53
+ "You must initialize the accelerate state by calling either `PartialState()` or `Accelerator()` before using the logging utility."
54
+ )
55
+ main_process_only = kwargs.pop("main_process_only", True)
56
+ in_order = kwargs.pop("in_order", False)
57
+ # set `stacklevel` to exclude ourself in `Logger.findCaller()` while respecting user's choice
58
+ kwargs.setdefault("stacklevel", 2)
59
+
60
+ if self.isEnabledFor(level):
61
+ if self._should_log(main_process_only):
62
+ msg, kwargs = self.process(msg, kwargs)
63
+ self.logger.log(level, msg, *args, **kwargs)
64
+
65
+ elif in_order:
66
+ state = PartialState()
67
+ for i in range(state.num_processes):
68
+ if i == state.process_index:
69
+ msg, kwargs = self.process(msg, kwargs)
70
+ self.logger.log(level, msg, *args, **kwargs)
71
+ state.wait_for_everyone()
72
+
73
+ @functools.lru_cache(None)
74
+ def warning_once(self, *args, **kwargs):
75
+ """
76
+ This method is identical to `logger.warning()`, but will emit the warning with the same message only once
77
+
78
+ Note: The cache is for the function arguments, so 2 different callers using the same arguments will hit the
79
+ cache. The assumption here is that all warning messages are unique across the code. If they aren't then need to
80
+ switch to another type of cache that includes the caller frame information in the hashing function.
81
+ """
82
+ self.warning(*args, **kwargs)
83
+
84
+
85
+ def get_logger(name: str, log_level: str = None):
86
+ """
87
+ Returns a `logging.Logger` for `name` that can handle multiprocessing.
88
+
89
+ If a log should be called on all processes, pass `main_process_only=False` If a log should be called on all
90
+ processes and in order, also pass `in_order=True`
91
+
92
+ Args:
93
+ name (`str`):
94
+ The name for the logger, such as `__file__`
95
+ log_level (`str`, *optional*):
96
+ The log level to use. If not passed, will default to the `LOG_LEVEL` environment variable, or `INFO` if not
97
+
98
+ Example:
99
+
100
+ ```python
101
+ >>> from accelerate.logging import get_logger
102
+ >>> from accelerate import Accelerator
103
+
104
+ >>> logger = get_logger(__name__)
105
+
106
+ >>> accelerator = Accelerator()
107
+ >>> logger.info("My log", main_process_only=False)
108
+ >>> logger.debug("My log", main_process_only=True)
109
+
110
+ >>> logger = get_logger(__name__, log_level="DEBUG")
111
+ >>> logger.info("My log")
112
+ >>> logger.debug("My second log")
113
+
114
+ >>> array = ["a", "b", "c", "d"]
115
+ >>> letter_at_rank = array[accelerator.process_index]
116
+ >>> logger.info(letter_at_rank, in_order=True)
117
+ ```
118
+ """
119
+ if log_level is None:
120
+ log_level = os.environ.get("ACCELERATE_LOG_LEVEL", None)
121
+ logger = logging.getLogger(name)
122
+ if log_level is not None:
123
+ logger.setLevel(log_level.upper())
124
+ logger.root.setLevel(log_level.upper())
125
+ return MultiProcessAdapter(logger, {})
venv/lib/python3.10/site-packages/accelerate/memory_utils.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 warnings
16
+
17
+
18
+ warnings.warn(
19
+ "memory_utils has been reorganized to utils.memory. Import `find_executable_batchsize` from the main `__init__`: "
20
+ "`from accelerate import find_executable_batch_size` to avoid this warning.",
21
+ FutureWarning,
22
+ )
venv/lib/python3.10/site-packages/accelerate/optimizer.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2021 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 inspect
16
+
17
+ import torch
18
+
19
+ from .state import AcceleratorState, GradientState
20
+ from .utils import DistributedType, honor_type, is_lomo_available, is_torch_xla_available
21
+
22
+
23
+ if is_torch_xla_available():
24
+ import torch_xla.core.xla_model as xm
25
+ import torch_xla.runtime as xr
26
+
27
+
28
+ def move_to_device(state, device):
29
+ if isinstance(state, (list, tuple)):
30
+ return honor_type(state, (move_to_device(t, device) for t in state))
31
+ elif isinstance(state, dict):
32
+ return type(state)({k: move_to_device(v, device) for k, v in state.items()})
33
+ elif isinstance(state, torch.Tensor):
34
+ return state.to(device)
35
+ return state
36
+
37
+
38
+ class AcceleratedOptimizer(torch.optim.Optimizer):
39
+ """
40
+ Internal wrapper around a torch optimizer.
41
+
42
+ Conditionally will perform `step` and `zero_grad` if gradients should be synchronized when performing gradient
43
+ accumulation.
44
+
45
+ Args:
46
+ optimizer (`torch.optim.optimizer.Optimizer`):
47
+ The optimizer to wrap.
48
+ device_placement (`bool`, *optional*, defaults to `True`):
49
+ Whether or not the optimizer should handle device placement. If so, it will place the state dictionary of
50
+ `optimizer` on the right device.
51
+ scaler (`torch.amp.GradScaler` or `torch.cuda.amp.GradScaler`, *optional*):
52
+ The scaler to use in the step function if training with mixed precision.
53
+ """
54
+
55
+ def __init__(self, optimizer, device_placement=True, scaler=None):
56
+ self.optimizer = optimizer
57
+ self.scaler = scaler
58
+ self.accelerator_state = AcceleratorState()
59
+ self.gradient_state = GradientState()
60
+ self.device_placement = device_placement
61
+ self._is_overflow = False
62
+
63
+ if self.scaler is not None:
64
+ self._accelerate_step_called = False
65
+ self._optimizer_original_step_method = self.optimizer.step
66
+ self._optimizer_patched_step_method = patch_optimizer_step(self, self.optimizer.step)
67
+
68
+ # Handle device placement
69
+ if device_placement:
70
+ state_dict = self.optimizer.state_dict()
71
+ if self.accelerator_state.distributed_type == DistributedType.XLA:
72
+ xm.send_cpu_data_to_device(state_dict, self.accelerator_state.device)
73
+ else:
74
+ state_dict = move_to_device(state_dict, self.accelerator_state.device)
75
+ self.optimizer.load_state_dict(state_dict)
76
+
77
+ @property
78
+ def state(self):
79
+ return self.optimizer.state
80
+
81
+ @state.setter
82
+ def state(self, state):
83
+ self.optimizer.state = state
84
+
85
+ @property
86
+ def param_groups(self):
87
+ return self.optimizer.param_groups
88
+
89
+ @param_groups.setter
90
+ def param_groups(self, param_groups):
91
+ self.optimizer.param_groups = param_groups
92
+
93
+ @property
94
+ def defaults(self):
95
+ return self.optimizer.defaults
96
+
97
+ @defaults.setter
98
+ def defaults(self, defaults):
99
+ self.optimizer.defaults = defaults
100
+
101
+ def add_param_group(self, param_group):
102
+ self.optimizer.add_param_group(param_group)
103
+
104
+ def load_state_dict(self, state_dict):
105
+ if self.accelerator_state.distributed_type == DistributedType.XLA and self.device_placement:
106
+ xm.send_cpu_data_to_device(state_dict, self.accelerator_state.device)
107
+ self.optimizer.load_state_dict(state_dict)
108
+
109
+ def state_dict(self):
110
+ return self.optimizer.state_dict()
111
+
112
+ def zero_grad(self, set_to_none=None):
113
+ if self.gradient_state.sync_gradients:
114
+ accept_arg = "set_to_none" in inspect.signature(self.optimizer.zero_grad).parameters
115
+ if accept_arg:
116
+ if set_to_none is None:
117
+ set_to_none = True
118
+ self.optimizer.zero_grad(set_to_none=set_to_none)
119
+ else:
120
+ if set_to_none is not None:
121
+ raise ValueError("`set_to_none` for Optimizer.zero_grad` is not supported by this optimizer.")
122
+ self.optimizer.zero_grad()
123
+
124
+ def train(self):
125
+ """
126
+ Sets the optimizer to "train" mode. Useful for optimizers like `schedule_free`
127
+ """
128
+ if hasattr(self.optimizer, "train") and callable(self.optimizer.train):
129
+ self.optimizer.train()
130
+ elif (
131
+ hasattr(self.optimizer, "optimizer")
132
+ and hasattr(self.optimizer.optimizer, "train")
133
+ and callable(self.optimizer.optimizer.train)
134
+ ):
135
+ # the deepspeed optimizer further wraps the optimizer
136
+ self.optimizer.optimizer.train()
137
+
138
+ def eval(self):
139
+ """
140
+ Sets the optimizer to "eval" mode. Useful for optimizers like `schedule_free`
141
+ """
142
+ if hasattr(self.optimizer, "eval") and callable(self.optimizer.eval):
143
+ self.optimizer.eval()
144
+
145
+ def step(self, closure=None):
146
+ if is_lomo_available():
147
+ from lomo_optim import AdaLomo, Lomo
148
+
149
+ if (
150
+ not self.gradient_state.is_xla_gradients_synced
151
+ and self.accelerator_state.distributed_type == DistributedType.XLA
152
+ ):
153
+ gradients = xm._fetch_gradients(self.optimizer)
154
+ xm.all_reduce("sum", gradients, scale=1.0 / xr.world_size())
155
+ self.gradient_state.is_xla_gradients_synced = True
156
+
157
+ if is_lomo_available():
158
+ # `step` should be a no-op for LOMO optimizers.
159
+ if isinstance(self.optimizer, (Lomo, AdaLomo)):
160
+ return
161
+
162
+ if self.gradient_state.sync_gradients:
163
+ if self.scaler is not None:
164
+ self.optimizer.step = self._optimizer_patched_step_method
165
+
166
+ self.scaler.step(self.optimizer, closure)
167
+ self.scaler.update()
168
+
169
+ if not self._accelerate_step_called:
170
+ # If the optimizer step was skipped, gradient overflow was detected.
171
+ self._is_overflow = True
172
+ else:
173
+ self._is_overflow = False
174
+ # Reset the step method to the original one
175
+ self.optimizer.step = self._optimizer_original_step_method
176
+ # Reset the indicator
177
+ self._accelerate_step_called = False
178
+ else:
179
+ self.optimizer.step(closure)
180
+ if self.accelerator_state.distributed_type == DistributedType.XLA:
181
+ self.gradient_state.is_xla_gradients_synced = False
182
+
183
+ def _switch_parameters(self, parameters_map):
184
+ for param_group in self.optimizer.param_groups:
185
+ param_group["params"] = [parameters_map.get(p, p) for p in param_group["params"]]
186
+
187
+ @property
188
+ def step_was_skipped(self):
189
+ """Whether or not the optimizer step was skipped."""
190
+ return self._is_overflow
191
+
192
+ def __getstate__(self):
193
+ _ignored_keys = [
194
+ "_accelerate_step_called",
195
+ "_optimizer_original_step_method",
196
+ "_optimizer_patched_step_method",
197
+ ]
198
+ return {k: v for k, v in self.__dict__.items() if k not in _ignored_keys}
199
+
200
+ def __setstate__(self, state):
201
+ self.__dict__.update(state)
202
+ if self.scaler is not None:
203
+ self._accelerate_step_called = False
204
+ self._optimizer_original_step_method = self.optimizer.step
205
+ self._optimizer_patched_step_method = patch_optimizer_step(self, self.optimizer.step)
206
+
207
+
208
+ def patch_optimizer_step(accelerated_optimizer: AcceleratedOptimizer, method):
209
+ def patched_step(*args, **kwargs):
210
+ accelerated_optimizer._accelerate_step_called = True
211
+ return method(*args, **kwargs)
212
+
213
+ return patched_step
venv/lib/python3.10/site-packages/accelerate/scheduler.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # We ignore warnings about stepping the scheduler since we step it ourselves during gradient accumulation
16
+
17
+ import warnings
18
+
19
+ from .state import AcceleratorState, GradientState
20
+
21
+
22
+ warnings.filterwarnings("ignore", category=UserWarning, module="torch.optim.lr_scheduler")
23
+
24
+
25
+ class AcceleratedScheduler:
26
+ """
27
+ A wrapper around a learning rate scheduler that will only step when the optimizer(s) have a training step. Useful
28
+ to avoid making a scheduler step too fast when gradients went overflow and there was no training step (in mixed
29
+ precision training)
30
+
31
+ When performing gradient accumulation scheduler lengths should not be changed accordingly, Accelerate will always
32
+ step the scheduler to account for it.
33
+
34
+ Args:
35
+ scheduler (`torch.optim.lr_scheduler._LRScheduler`):
36
+ The scheduler to wrap.
37
+ optimizers (one or a list of `torch.optim.Optimizer`):
38
+ The optimizers used.
39
+ step_with_optimizer (`bool`, *optional*, defaults to `True`):
40
+ Whether or not the scheduler should be stepped at each optimizer step.
41
+ split_batches (`bool`, *optional*, defaults to `False`):
42
+ Whether or not the dataloaders split one batch across the different processes (so batch size is the same
43
+ regardless of the number of processes) or create batches on each process (so batch size is the original
44
+ batch size multiplied by the number of processes).
45
+ """
46
+
47
+ def __init__(self, scheduler, optimizers, step_with_optimizer: bool = True, split_batches: bool = False):
48
+ self.scheduler = scheduler
49
+ self.optimizers = optimizers if isinstance(optimizers, (list, tuple)) else [optimizers]
50
+ self.split_batches = split_batches
51
+ self.step_with_optimizer = step_with_optimizer
52
+ self.gradient_state = GradientState()
53
+
54
+ def step(self, *args, **kwargs):
55
+ if not self.step_with_optimizer:
56
+ # No link between scheduler and optimizer -> just step
57
+ self.scheduler.step(*args, **kwargs)
58
+ return
59
+
60
+ # Otherwise, first make sure the optimizer was stepped.
61
+ if not self.gradient_state.sync_gradients:
62
+ if self.gradient_state.adjust_scheduler:
63
+ self.scheduler._step_count += 1
64
+ return
65
+
66
+ for opt in self.optimizers:
67
+ if opt.step_was_skipped:
68
+ return
69
+ if self.split_batches:
70
+ # Split batches -> the training dataloader batch size is not changed so one step per training step
71
+ self.scheduler.step(*args, **kwargs)
72
+ else:
73
+ # Otherwise the training dataloader batch size was multiplied by `num_processes`, so we need to do
74
+ # num_processes steps per training step
75
+ num_processes = AcceleratorState().num_processes
76
+ for _ in range(num_processes):
77
+ # Special case when using OneCycle and `drop_last` was not used
78
+ if hasattr(self.scheduler, "total_steps"):
79
+ if self.scheduler._step_count <= self.scheduler.total_steps:
80
+ self.scheduler.step(*args, **kwargs)
81
+ else:
82
+ self.scheduler.step(*args, **kwargs)
83
+
84
+ # Passthroughs
85
+ def get_last_lr(self):
86
+ return self.scheduler.get_last_lr()
87
+
88
+ def state_dict(self):
89
+ return self.scheduler.state_dict()
90
+
91
+ def load_state_dict(self, state_dict):
92
+ self.scheduler.load_state_dict(state_dict)
93
+
94
+ def get_lr(self):
95
+ return self.scheduler.get_lr()
96
+
97
+ def print_lr(self, *args, **kwargs):
98
+ return self.scheduler.print_lr(*args, **kwargs)
venv/lib/python3.10/site-packages/accelerate/state.py ADDED
@@ -0,0 +1,1347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2021 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
+ from __future__ import annotations
16
+
17
+ import logging
18
+ import os
19
+ import threading
20
+ import warnings
21
+ import weakref
22
+ from contextlib import contextmanager
23
+ from functools import partial
24
+ from typing import Any, Callable
25
+
26
+ import torch
27
+
28
+ from .utils import (
29
+ DistributedType,
30
+ DynamoBackend,
31
+ GradientAccumulationPlugin,
32
+ check_cuda_fp8_capability,
33
+ check_cuda_p2p_ib_support,
34
+ deepspeed_required,
35
+ get_cpu_distributed_information,
36
+ get_int_from_env,
37
+ is_ccl_available,
38
+ is_datasets_available,
39
+ is_deepspeed_available,
40
+ is_fp8_available,
41
+ is_habana_gaudi1,
42
+ is_hpu_available,
43
+ is_ipex_available,
44
+ is_mlu_available,
45
+ is_mps_available,
46
+ is_musa_available,
47
+ is_npu_available,
48
+ is_sdaa_available,
49
+ is_torch_xla_available,
50
+ is_xccl_available,
51
+ is_xpu_available,
52
+ parse_choice_from_env,
53
+ parse_flag_from_env,
54
+ set_numa_affinity,
55
+ )
56
+ from .utils.dataclasses import SageMakerDistributedType
57
+
58
+
59
+ if is_torch_xla_available():
60
+ import torch_xla.core.xla_model as xm
61
+ import torch_xla.runtime as xr
62
+
63
+ if is_mlu_available(check_device=False):
64
+ import torch_mlu # noqa: F401
65
+
66
+ if is_sdaa_available(check_device=False):
67
+ import torch_sdaa # noqa: F401
68
+
69
+ if is_musa_available(check_device=False):
70
+ import torch_musa # noqa: F401
71
+
72
+ if is_npu_available(check_device=False):
73
+ import torch_npu # noqa: F401
74
+
75
+
76
+ logger = logging.getLogger(__name__)
77
+
78
+
79
+ def is_initialized() -> bool:
80
+ """
81
+ Checks if the `AcceleratorState` has been initialized from `Accelerator`. Same as `AcceleratorState.initialized`,
82
+ but works as a module method.
83
+ """
84
+ return AcceleratorState._shared_state != {}
85
+
86
+
87
+ # Lambda function that does nothing
88
+ def do_nothing(*args, **kwargs):
89
+ return None
90
+
91
+
92
+ class ThreadLocalSharedDict(threading.local):
93
+ """
94
+ Descriptor that holds a dict shared between instances of a class in the same thread.
95
+
96
+ Note: Descriptors have slightly different semantics than just a dict field on its own.
97
+ `PartialState(...)._shared_state` and `PartialState._shared_state` (instance vs class) give the same value: the
98
+ underlying _storage dict. Likewise, `PartialState(...)._shared_state = {...}` overrides the _storage dict inside
99
+ the descriptor as you would expect. However, `PartialState._shared_state = {}` actually replaces the descriptor
100
+ object with a dict instead Thus, you should modify the _storage dict in-place (e.g. `_shared_state.clear()`).
101
+
102
+ See Python documentation for an explanation of descriptors: https://docs.python.org/3/howto/descriptor.html
103
+
104
+ This is required for using PyTorch/XLA with PJRT in multithreaded mode (required for TPU v2 and v3).
105
+
106
+ See https://github.com/pytorch/xla/blob/r2.0/docs/pjrt.md#multithreading-on-tpu-v2v3
107
+ """
108
+
109
+ def __init__(self, thread_local: bool = False):
110
+ self._storage = {}
111
+
112
+ def __get__(self, obj, objtype=None):
113
+ return self._storage
114
+
115
+ def __set__(self, obj, value):
116
+ self._storage = value
117
+
118
+
119
+ # Prefer global shared dictionary, except when using TPU.
120
+ SharedDict = dict if not is_torch_xla_available() else ThreadLocalSharedDict
121
+
122
+
123
+ # Inspired by Alex Martelli's 'Borg'.
124
+ class PartialState:
125
+ """
126
+ Singleton class that has information about the current training environment and functions to help with process
127
+ control. Designed to be used when only process control and device execution states are needed. Does *not* need to
128
+ be initialized from `Accelerator`.
129
+
130
+ Args:
131
+ cpu (`bool`, *optional*):
132
+ Whether or not to force the script to execute on CPU. Will ignore any accelerators available if set to
133
+ `True` and force the execution on the CPU.
134
+ kwargs (additional keyword arguments, *optional*):
135
+ Additional keyword arguments to pass to the relevant `init_process_group` function. Valid `kwargs` can be
136
+ found in [`utils.InitProcessGroupKwargs`]. See the example section for detailed usage.
137
+
138
+ **Available attributes:**
139
+
140
+ - **device** (`torch.device`) -- The device to use.
141
+ - **distributed_type** ([`~accelerate.state.DistributedType`]) -- The type of distributed environment currently
142
+ in use.
143
+ - **local_process_index** (`int`) -- The index of the current process on the current server.
144
+ - **mixed_precision** (`str`) -- Whether or not the current script will use mixed precision, and if so the type
145
+ of mixed precision being performed. (Choose from 'no','fp16','bf16 or 'fp8').
146
+ - **num_processes** (`int`) -- The number of processes currently launched in parallel.
147
+ - **process_index** (`int`) -- The index of the current process.
148
+ - **is_last_process** (`bool`) -- Whether or not the current process is the last one.
149
+ - **is_main_process** (`bool`) -- Whether or not the current process is the main one.
150
+ - **is_local_main_process** (`bool`) -- Whether or not the current process is the main one on the local node.
151
+ - **debug** (`bool`) -- Whether or not the current script is being run in debug mode.
152
+
153
+ Example:
154
+ ```python
155
+ from accelerate.utils import InitProcessGroupKwargs
156
+
157
+ # To include `InitProcessGroupKwargs`, init then call `.to_kwargs()`
158
+ kwargs = InitProcessGroupKwargs(...).to_kwargs()
159
+ state = PartialState(**kwargs)
160
+ ```
161
+ """
162
+
163
+ _shared_state = SharedDict()
164
+ _known_attrs = [
165
+ "_cpu",
166
+ "_mixed_precision",
167
+ "_shared_state",
168
+ "backend",
169
+ "debug",
170
+ "device",
171
+ "distributed_type",
172
+ "fork_launched",
173
+ "local_process_index",
174
+ "num_processes",
175
+ "process_index",
176
+ ]
177
+
178
+ def __init__(self, cpu: bool = False, **kwargs):
179
+ self.__dict__ = self._shared_state
180
+ if not self.initialized:
181
+ self._cpu = cpu
182
+ self.backend = None
183
+ env_device = os.environ.get("ACCELERATE_TORCH_DEVICE", None)
184
+ self.device = torch.device(env_device) if env_device is not None else None
185
+ self.debug = parse_flag_from_env("ACCELERATE_DEBUG_MODE")
186
+ use_sagemaker_dp = kwargs.pop("_use_sagemaker_dp", None)
187
+ dist_information = None
188
+ if use_sagemaker_dp is None:
189
+ use_sagemaker_dp = (
190
+ os.environ.get("ACCELERATE_USE_SAGEMAKER", "false") == "true"
191
+ and os.environ.get("ACCELERATE_SAGEMAKER_DISTRIBUTED_TYPE") != SageMakerDistributedType.NO
192
+ )
193
+
194
+ # Sets up self.backend + imports
195
+ original_backend = kwargs.pop("backend", None)
196
+ backend, distributed_type = self._prepare_backend(cpu, use_sagemaker_dp, original_backend)
197
+ if original_backend is not None and backend != original_backend:
198
+ raise ValueError(f"Your assigned backend {original_backend} is not avaliable, please use {backend}")
199
+ self.backend = backend
200
+ self.distributed_type = distributed_type
201
+ use_deepspeed = False
202
+ if not cpu and self.backend != "xla":
203
+ if int(os.environ.get("LOCAL_RANK", -1)) != -1:
204
+ # Deal with spawning deepspeed
205
+ if os.environ.get("ACCELERATE_USE_DEEPSPEED", "false") == "true":
206
+ if not is_deepspeed_available():
207
+ raise ImportError(
208
+ "DeepSpeed is not available => install it using `pip3 install deepspeed` or build it from source"
209
+ )
210
+ from deepspeed import comm as dist
211
+
212
+ if not dist.is_initialized():
213
+ if self.backend == "tccl":
214
+ local_rank = os.environ.get("LOCAL_RANK", -1)
215
+ torch.sdaa.set_device(f"sdaa:{local_rank}")
216
+ dist.init_distributed(dist_backend=self.backend, auto_mpi_discovery=False, **kwargs)
217
+ # We need to flag to `use_deepspeed` to be True to override `distributed_type` later
218
+ use_deepspeed = True
219
+ # Deal with all other backends but XPU and CPU, that gets handled special later
220
+ elif (
221
+ self.distributed_type not in (DistributedType.MULTI_XPU, DistributedType.MULTI_CPU)
222
+ and not torch.distributed.is_initialized()
223
+ ):
224
+ if self.backend == "tccl":
225
+ local_rank = os.environ.get("LOCAL_RANK", -1)
226
+ torch.sdaa.set_device(f"sdaa:{local_rank}")
227
+ if (
228
+ self.backend == "nccl"
229
+ and os.environ.get("ACCELERATE_USE_FSDP", "false") == "true"
230
+ and (
231
+ os.environ.get("FSDP_OFFLOAD_PARAMS", "false") == "true"
232
+ or os.environ.get("FSDP_STATE_DICT_TYPE", "SHARDED_STATE_DICT") == "FULL_STATE_DICT"
233
+ )
234
+ ):
235
+ self.backend = "cuda:nccl,cpu:gloo"
236
+ torch.distributed.init_process_group(backend=self.backend, **kwargs)
237
+
238
+ # XPU and CPU require special env configs to be set
239
+ if self.distributed_type in (DistributedType.MULTI_XPU, DistributedType.MULTI_CPU):
240
+ dist_information = get_cpu_distributed_information()
241
+ os.environ["RANK"] = str(dist_information.rank)
242
+ os.environ["WORLD_SIZE"] = str(dist_information.world_size)
243
+ os.environ["LOCAL_RANK"] = str(dist_information.local_rank)
244
+ os.environ["LOCAL_WORLD_SIZE"] = str(dist_information.local_world_size)
245
+ if not os.environ.get("MASTER_PORT", None):
246
+ os.environ["MASTER_PORT"] = "29500"
247
+ if (
248
+ not os.environ.get("MASTER_ADDR", None)
249
+ and dist_information.local_world_size != dist_information.world_size
250
+ and self.backend != "mpi"
251
+ ):
252
+ raise ValueError(
253
+ "Tried to launch on distributed with multinode, but `MASTER_ADDR` env was not set, "
254
+ "please try exporting rank 0's hostname as `MASTER_ADDR`"
255
+ )
256
+ kwargs["rank"] = dist_information.rank
257
+ kwargs["world_size"] = dist_information.world_size
258
+
259
+ if (
260
+ self.distributed_type == DistributedType.MULTI_CPU
261
+ and get_int_from_env(["OMP_NUM_THREADS"], 0) == 0
262
+ ):
263
+ import psutil
264
+
265
+ num_cpu_threads_per_process = int(
266
+ psutil.cpu_count(logical=False) / dist_information.local_world_size
267
+ )
268
+ if num_cpu_threads_per_process == 0:
269
+ num_cpu_threads_per_process = 1
270
+ torch.set_num_threads(num_cpu_threads_per_process)
271
+ warnings.warn(
272
+ f"OMP_NUM_THREADS/MKL_NUM_THREADS unset, we set it at {num_cpu_threads_per_process} to improve oob"
273
+ " performance."
274
+ )
275
+
276
+ if not torch.distributed.is_initialized():
277
+ torch.distributed.init_process_group(backend=self.backend, **kwargs)
278
+
279
+ # No backend == no distributed training
280
+ if self.backend is None:
281
+ self.distributed_type = DistributedType.NO
282
+ self.num_processes = 1
283
+ self.process_index = 0
284
+ self.local_process_index = 0
285
+ elif self.backend == "xla":
286
+ # XLA needs device setting first for `set_replication`
287
+ self.set_device()
288
+ xm.set_replication(self.device, xm.get_xla_supported_devices())
289
+ self.num_processes = xr.world_size()
290
+ self.process_index = xr.global_ordinal()
291
+ if is_torch_xla_available(check_is_tpu=True):
292
+ self.local_process_index = xm.get_local_ordinal()
293
+ else:
294
+ self.local_process_index = int(os.environ.get("LOCAL_RANK", -1))
295
+ else:
296
+ self.num_processes = torch.distributed.get_world_size()
297
+ self.process_index = torch.distributed.get_rank()
298
+ self.local_process_index = (
299
+ int(os.environ.get("LOCAL_RANK", -1)) if dist_information is None else dist_information.local_rank
300
+ )
301
+ self.set_device()
302
+ # Now we can change to deepseed
303
+ if use_deepspeed:
304
+ self.distributed_type = DistributedType.DEEPSPEED
305
+
306
+ # Set CPU affinity if enabled
307
+ if parse_flag_from_env("ACCELERATE_CPU_AFFINITY", False):
308
+ set_numa_affinity(self.local_process_index)
309
+
310
+ # Check for old RTX 4000's that can't use P2P or IB and are on old drivers
311
+ if self.device.type == "cuda" and not check_cuda_p2p_ib_support():
312
+ if "NCCL_P2P_DISABLE" not in os.environ or "NCCL_IB_DISABLE" not in os.environ:
313
+ raise NotImplementedError(
314
+ "Using RTX 4000 series doesn't support faster communication broadband via P2P or IB. "
315
+ 'Please set `NCCL_P2P_DISABLE="1"` and `NCCL_IB_DISABLE="1" or use `accelerate launch` which '
316
+ "will do this automatically."
317
+ )
318
+
319
+ # Important: This should be the *only* code outside of `self.initialized!`
320
+ self.fork_launched = parse_flag_from_env("FORK_LAUNCHED", 0)
321
+
322
+ def __repr__(self) -> str:
323
+ return (
324
+ f"Distributed environment: {self.distributed_type}{(' Backend: ' + self.backend) if self.backend else ''}\n"
325
+ f"Num processes: {self.num_processes}\n"
326
+ f"Process index: {self.process_index}\n"
327
+ f"Local process index: {self.local_process_index}\n"
328
+ f"Device: {self.device}\n"
329
+ )
330
+
331
+ @staticmethod
332
+ def _reset_state():
333
+ "Resets `_shared_state`, is used internally and should not be called"
334
+ PartialState._shared_state.clear()
335
+
336
+ @property
337
+ def initialized(self) -> bool:
338
+ "Returns whether the `PartialState` has been initialized"
339
+ return self._shared_state != {}
340
+
341
+ @property
342
+ def use_distributed(self):
343
+ """
344
+ Whether the Accelerator is configured for distributed training
345
+ """
346
+ return self.distributed_type != DistributedType.NO and self.num_processes > 1
347
+
348
+ @property
349
+ def is_last_process(self) -> bool:
350
+ "Returns whether the current process is the last one"
351
+ return self.process_index == self.num_processes - 1
352
+
353
+ @property
354
+ def is_main_process(self) -> bool:
355
+ "Returns whether the current process is the main process"
356
+ return (
357
+ self.process_index == 0 if self.distributed_type != DistributedType.MEGATRON_LM else self.is_last_process
358
+ )
359
+
360
+ @property
361
+ def is_local_main_process(self) -> bool:
362
+ "Returns whether the current process is the main process on the local node"
363
+ return (
364
+ self.local_process_index == 0
365
+ if self.distributed_type != DistributedType.MEGATRON_LM
366
+ else self.is_last_process
367
+ )
368
+
369
+ def wait_for_everyone(self):
370
+ """
371
+ Will stop the execution of the current process until every other process has reached that point (so this does
372
+ nothing when the script is only run in one process). Useful to do before saving a model.
373
+
374
+ Example:
375
+
376
+ ```python
377
+ >>> # Assuming two GPU processes
378
+ >>> import time
379
+ >>> from accelerate.state import PartialState
380
+
381
+ >>> state = PartialState()
382
+ >>> if state.is_main_process:
383
+ ... time.sleep(2)
384
+ >>> else:
385
+ ... print("I'm waiting for the main process to finish its sleep...")
386
+ >>> state.wait_for_everyone()
387
+ >>> # Should print on every process at the same time
388
+ >>> print("Everyone is here")
389
+ ```
390
+ """
391
+ if self.distributed_type in (
392
+ DistributedType.MULTI_GPU,
393
+ DistributedType.MULTI_MLU,
394
+ DistributedType.MULTI_SDAA,
395
+ DistributedType.MULTI_MUSA,
396
+ DistributedType.MULTI_NPU,
397
+ DistributedType.MULTI_XPU,
398
+ DistributedType.MULTI_CPU,
399
+ DistributedType.MULTI_HPU,
400
+ DistributedType.DEEPSPEED,
401
+ DistributedType.FSDP,
402
+ ):
403
+ torch.distributed.barrier()
404
+ elif self.distributed_type == DistributedType.XLA:
405
+ xm.rendezvous("accelerate.utils.wait_for_everyone")
406
+
407
+ def _goes_first(self, is_main: bool):
408
+ if not is_main:
409
+ self.wait_for_everyone()
410
+
411
+ yield
412
+
413
+ if is_main:
414
+ self.wait_for_everyone()
415
+
416
+ @contextmanager
417
+ def split_between_processes(self, inputs: list | tuple | dict | torch.Tensor, apply_padding: bool = False):
418
+ """
419
+ Splits `input` between `self.num_processes` quickly and can be then used on that process. Useful when doing
420
+ distributed inference, such as with different prompts.
421
+
422
+ Note that when using a `dict`, all keys need to have the same number of elements.
423
+
424
+ Args:
425
+ inputs (`list`, `tuple`, `torch.Tensor`, `dict` of `list`/`tuple`/`torch.Tensor`, or `datasets.Dataset`):
426
+ The input to split between processes.
427
+ apply_padding (`bool`, `optional`, defaults to `False`):
428
+ Whether to apply padding by repeating the last element of the input so that all processes have the same
429
+ number of elements. Useful when trying to perform actions such as `gather()` on the outputs or passing
430
+ in less inputs than there are processes. If so, just remember to drop the padded elements afterwards.
431
+
432
+
433
+ Example:
434
+
435
+ ```python
436
+ # Assume there are two processes
437
+ from accelerate import PartialState
438
+
439
+ state = PartialState()
440
+ with state.split_between_processes(["A", "B", "C"]) as inputs:
441
+ print(inputs)
442
+ # Process 0
443
+ ["A", "B"]
444
+ # Process 1
445
+ ["C"]
446
+
447
+ with state.split_between_processes(["A", "B", "C"], apply_padding=True) as inputs:
448
+ print(inputs)
449
+ # Process 0
450
+ ["A", "B"]
451
+ # Process 1
452
+ ["C", "C"]
453
+ ```
454
+ """
455
+ if self.num_processes == 1:
456
+ yield inputs
457
+ return
458
+ length = len(inputs)
459
+ # Nested dictionary of any types
460
+ if isinstance(inputs, dict):
461
+ length = len(inputs[list(inputs.keys())[0]])
462
+ if not all(len(v) == length for v in inputs.values()):
463
+ raise ValueError("All values in the dictionary must have the same length")
464
+ num_samples_per_process, num_extras = divmod(length, self.num_processes)
465
+ start_index = self.process_index * num_samples_per_process + min(self.process_index, num_extras)
466
+ end_index = start_index + num_samples_per_process + (1 if self.process_index < num_extras else 0)
467
+
468
+ def _split_values(inputs, start_index, end_index):
469
+ if isinstance(inputs, (list, tuple, torch.Tensor)):
470
+ if start_index >= len(inputs):
471
+ result = inputs[-1:]
472
+ else:
473
+ result = inputs[start_index:end_index]
474
+ if apply_padding:
475
+ if isinstance(result, torch.Tensor):
476
+ from accelerate.utils import pad_across_processes, send_to_device
477
+
478
+ # The tensor needs to be on the device before we can pad it
479
+ tensorized_result = send_to_device(result, self.device)
480
+ result = pad_across_processes(tensorized_result, pad_index=inputs[-1])
481
+ else:
482
+ result += [result[-1]] * (num_samples_per_process + (1 if num_extras > 0 else 0) - len(result))
483
+ return result
484
+ elif isinstance(inputs, dict):
485
+ for key in inputs.keys():
486
+ inputs[key] = _split_values(inputs[key], start_index, end_index)
487
+ return inputs
488
+ else:
489
+ if is_datasets_available():
490
+ from datasets import Dataset
491
+
492
+ if isinstance(inputs, Dataset):
493
+ if start_index >= len(inputs):
494
+ start_index = len(inputs) - 1
495
+ if end_index > len(inputs):
496
+ end_index = len(inputs)
497
+ result_idcs = list(range(start_index, end_index))
498
+ if apply_padding:
499
+ result_idcs += [end_index - 1] * (
500
+ num_samples_per_process + (1 if num_extras > 0 else 0) - len(result_idcs)
501
+ )
502
+ return inputs.select(result_idcs)
503
+ return inputs
504
+
505
+ yield _split_values(inputs, start_index, end_index)
506
+
507
+ @contextmanager
508
+ def main_process_first(self):
509
+ """
510
+ Lets the main process go first inside a with block.
511
+
512
+ The other processes will enter the with block after the main process exits.
513
+
514
+ Example:
515
+
516
+ ```python
517
+ >>> from accelerate import Accelerator
518
+
519
+ >>> accelerator = Accelerator()
520
+ >>> with accelerator.main_process_first():
521
+ ... # This will be printed first by process 0 then in a seemingly
522
+ ... # random order by the other processes.
523
+ ... print(f"This will be printed by process {accelerator.process_index}")
524
+ ```
525
+ """
526
+ yield from self._goes_first(self.is_main_process)
527
+
528
+ @contextmanager
529
+ def local_main_process_first(self):
530
+ """
531
+ Lets the local main process go inside a with block.
532
+
533
+ The other processes will enter the with block after the main process exits.
534
+
535
+ Example:
536
+
537
+ ```python
538
+ >>> from accelerate.state import PartialState
539
+
540
+ >>> state = PartialState()
541
+ >>> with state.local_main_process_first():
542
+ ... # This will be printed first by local process 0 then in a seemingly
543
+ ... # random order by the other processes.
544
+ ... print(f"This will be printed by process {state.local_process_index}")
545
+ ```
546
+ """
547
+ yield from self._goes_first(self.is_local_main_process)
548
+
549
+ def on_main_process(self, function: Callable[..., Any] = None):
550
+ """
551
+ Decorator that only runs the decorated function on the main process.
552
+
553
+ Args:
554
+ function (`Callable`): The function to decorate.
555
+
556
+ Example:
557
+
558
+ ```python
559
+ >>> from accelerate.state import PartialState
560
+
561
+ >>> state = PartialState()
562
+
563
+
564
+ >>> @state.on_main_process
565
+ ... def print_something():
566
+ ... print("This will be printed by process 0 only.")
567
+
568
+
569
+ >>> print_something()
570
+ "This will be printed by process 0 only"
571
+ ```
572
+ """
573
+ if not self.initialized:
574
+ raise ValueError("The `PartialState` or `Accelerator` must be initialized before calling this function.")
575
+ if self.is_main_process or not self.use_distributed:
576
+ return function
577
+ return do_nothing
578
+
579
+ def on_local_main_process(self, function: Callable[..., Any] = None):
580
+ """
581
+ Decorator that only runs the decorated function on the local main process.
582
+
583
+ Args:
584
+ function (`Callable`): The function to decorate.
585
+
586
+ Example:
587
+ ```python
588
+ # Assume we have 2 servers with 4 processes each.
589
+ from accelerate.state import PartialState
590
+
591
+ state = PartialState()
592
+
593
+
594
+ @state.on_local_main_process
595
+ def print_something():
596
+ print("This will be printed by process 0 only on each server.")
597
+
598
+
599
+ print_something()
600
+ # On server 1:
601
+ "This will be printed by process 0 only"
602
+ # On server 2:
603
+ "This will be printed by process 0 only"
604
+ ```
605
+ """
606
+ if self.is_local_main_process or not self.use_distributed:
607
+ return function
608
+ return do_nothing
609
+
610
+ def on_last_process(self, function: Callable[..., Any]):
611
+ """
612
+ Decorator that only runs the decorated function on the last process.
613
+
614
+ Args:
615
+ function (`Callable`): The function to decorate.
616
+
617
+ Example:
618
+ ```python
619
+ # Assume we have 4 processes.
620
+ from accelerate.state import PartialState
621
+
622
+ state = PartialState()
623
+
624
+
625
+ @state.on_last_process
626
+ def print_something():
627
+ print(f"Printed on process {state.process_index}")
628
+
629
+
630
+ print_something()
631
+ "Printed on process 3"
632
+ ```
633
+ """
634
+ if self.is_last_process or not self.use_distributed:
635
+ return function
636
+ return do_nothing
637
+
638
+ def on_process(self, function: Callable[..., Any] = None, process_index: int = None):
639
+ """
640
+ Decorator that only runs the decorated function on the process with the given index.
641
+
642
+ Args:
643
+ function (`Callable`, `optional`):
644
+ The function to decorate.
645
+ process_index (`int`, `optional`):
646
+ The index of the process on which to run the function.
647
+
648
+ Example:
649
+ ```python
650
+ # Assume we have 4 processes.
651
+ from accelerate.state import PartialState
652
+
653
+ state = PartialState()
654
+
655
+
656
+ @state.on_process(process_index=2)
657
+ def print_something():
658
+ print(f"Printed on process {state.process_index}")
659
+
660
+
661
+ print_something()
662
+ "Printed on process 2"
663
+ ```
664
+ """
665
+ if function is None:
666
+ return partial(self.on_process, process_index=process_index)
667
+ if (self.process_index == process_index) or (not self.use_distributed):
668
+ return function
669
+ return do_nothing
670
+
671
+ def on_local_process(self, function: Callable[..., Any] = None, local_process_index: int = None):
672
+ """
673
+ Decorator that only runs the decorated function on the process with the given index on the current node.
674
+
675
+ Args:
676
+ function (`Callable`, *optional*):
677
+ The function to decorate.
678
+ local_process_index (`int`, *optional*):
679
+ The index of the local process on which to run the function.
680
+
681
+ Example:
682
+ ```python
683
+ # Assume we have 2 servers with 4 processes each.
684
+ from accelerate import Accelerator
685
+
686
+ accelerator = Accelerator()
687
+
688
+
689
+ @accelerator.on_local_process(local_process_index=2)
690
+ def print_something():
691
+ print(f"Printed on process {accelerator.local_process_index}")
692
+
693
+
694
+ print_something()
695
+ # On server 1:
696
+ "Printed on process 2"
697
+ # On server 2:
698
+ "Printed on process 2"
699
+ ```
700
+ """
701
+ if function is None:
702
+ return partial(self.on_local_process, local_process_index=local_process_index)
703
+ if (self.local_process_index == local_process_index) or (not self.use_distributed):
704
+ return function
705
+ return do_nothing
706
+
707
+ def print(self, *args, **kwargs):
708
+ if self.is_local_main_process:
709
+ print(*args, **kwargs)
710
+
711
+ @property
712
+ def default_device(self) -> torch.device:
713
+ """
714
+ Returns the default device which is:
715
+ - MPS if `torch.backends.mps.is_available()` and `torch.backends.mps.is_built()` both return True.
716
+ - CUDA if `torch.cuda.is_available()`
717
+ - MLU if `is_mlu_available()`
718
+ - SDAA if `is_sdaa_available()`
719
+ - MUSA if `is_musa_available()`
720
+ - NPU if `is_npu_available()`
721
+ - HPU if `is_hpu_available()`
722
+ - CPU otherwise
723
+ """
724
+ if is_mps_available():
725
+ os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
726
+ return torch.device("mps")
727
+ elif is_mlu_available():
728
+ return torch.device("mlu")
729
+ elif is_sdaa_available():
730
+ return torch.device("sdaa")
731
+ elif is_musa_available():
732
+ return torch.device("musa")
733
+ # NPU should be checked before CUDA when using `transfer_to_npu`
734
+ # See issue #3020: https://github.com/huggingface/accelerate/issues/3020
735
+ elif is_npu_available():
736
+ return torch.device("npu")
737
+ elif is_hpu_available():
738
+ return torch.device("hpu")
739
+ elif torch.cuda.is_available():
740
+ return torch.device("cuda")
741
+ elif is_xpu_available():
742
+ return torch.device("xpu")
743
+ else:
744
+ return torch.device("cpu")
745
+
746
+ def _prepare_backend(
747
+ self, cpu: bool = False, sagemaker_dp=False, backend: str = None
748
+ ) -> tuple[str, DistributedType]:
749
+ "Prepares any imports needed before initializing the distributed backend and sets `self.backend` properly"
750
+ distributed_type = None
751
+ if sagemaker_dp:
752
+ import smdistributed.dataparallel.torch.torch_smddp # noqa
753
+
754
+ backend = "smddp"
755
+ distributed_type = DistributedType.MULTI_GPU
756
+ elif is_torch_xla_available():
757
+ backend = "xla"
758
+ distributed_type = DistributedType.XLA
759
+
760
+ elif int(os.environ.get("LOCAL_RANK", -1)) != -1 and not cpu:
761
+ if is_mlu_available():
762
+ backend = "cncl"
763
+ distributed_type = DistributedType.MULTI_MLU
764
+ if is_sdaa_available():
765
+ backend = "tccl"
766
+ distributed_type = DistributedType.MULTI_SDAA
767
+ elif is_musa_available():
768
+ backend = "mccl"
769
+ distributed_type = DistributedType.MULTI_MUSA
770
+ # NPU should be checked before CUDA when using `transfer_to_npu`
771
+ # See issue #3020: https://github.com/huggingface/accelerate/issues/3020
772
+ elif is_npu_available():
773
+ backend = "hccl"
774
+ distributed_type = DistributedType.MULTI_NPU
775
+ elif is_hpu_available(init_hccl=True):
776
+ if backend is None:
777
+ backend = "hccl"
778
+ distributed_type = DistributedType.MULTI_HPU
779
+ elif torch.cuda.is_available():
780
+ if backend is None:
781
+ backend = "nccl"
782
+ distributed_type = DistributedType.MULTI_GPU
783
+ elif is_xpu_available() and is_xccl_available():
784
+ if backend is None:
785
+ backend = "xccl"
786
+ distributed_type = DistributedType.MULTI_XPU
787
+
788
+ if distributed_type is None and (
789
+ int(os.environ.get("LOCAL_RANK", -1)) != -1
790
+ or get_int_from_env(["PMI_SIZE", "OMPI_COMM_WORLD_SIZE", "MV2_COMM_WORLD_SIZE", "WORLD_SIZE"], 1) > 1
791
+ ):
792
+ if not cpu and is_xpu_available():
793
+ distributed_type = DistributedType.MULTI_XPU
794
+ else:
795
+ distributed_type = DistributedType.MULTI_CPU
796
+
797
+ if (
798
+ backend in (None, "ccl")
799
+ and is_ccl_available()
800
+ and (get_int_from_env(["CCL_WORKER_COUNT"], 0) > 0 or distributed_type == DistributedType.MULTI_XPU)
801
+ ):
802
+ import oneccl_bindings_for_pytorch # noqa: F401
803
+
804
+ backend = "ccl"
805
+ elif backend in (None, "mpi") and torch.distributed.is_mpi_available():
806
+ backend = "mpi"
807
+ else:
808
+ backend = "gloo"
809
+ if distributed_type is None:
810
+ distributed_type = DistributedType.NO
811
+
812
+ return backend, distributed_type
813
+
814
+ def set_device(self):
815
+ """
816
+ Sets the device in `self.device` to the current distributed environment.
817
+ """
818
+ if self.device is not None:
819
+ return
820
+ if self.distributed_type == DistributedType.NO:
821
+ self.device = torch.device("cpu") if self._cpu else self.default_device
822
+ return
823
+ device = str(self.distributed_type).split(".")[-1].replace("MULTI_", "").lower()
824
+ if device not in ("cpu", "gpu", "mlu", "musa", "npu", "xpu", "xla", "hpu", "sdaa"):
825
+ raise ValueError(
826
+ f"Can't set device for {self.distributed_type} ({device}), verify we should be calling `_set_device()` for it!"
827
+ )
828
+ if device == "xla":
829
+ self.device = xm.xla_device()
830
+ elif device == "hpu":
831
+ self.device = torch.device("hpu", torch.hpu.current_device())
832
+ else:
833
+ if device == "gpu":
834
+ device = "cuda"
835
+ device_module = getattr(torch, device)
836
+ device_index = self.local_process_index % device_module.device_count()
837
+ self.device = torch.device(device, device_index)
838
+ device_module.set_device(self.device)
839
+
840
+ def destroy_process_group(self, group=None):
841
+ """
842
+ Destroys the process group. If one is not specified, the default process group is destroyed.
843
+ """
844
+ if self.fork_launched and group is None:
845
+ return
846
+ # needed when using torch.distributed.init_process_group
847
+ if torch.distributed.is_initialized():
848
+ torch.distributed.destroy_process_group(group)
849
+
850
+ def __getattr__(self, name: str):
851
+ # By this point we know that no attributes of `self` contain `name`,
852
+ # so we just modify the error message
853
+ if name in self._known_attrs:
854
+ raise AttributeError(
855
+ f"`PartialState` object has no attribute `{name}`. "
856
+ "This happens if `PartialState._reset_state()` was called and "
857
+ "an `Accelerator` or `PartialState` was not reinitialized."
858
+ )
859
+ # Raise a typical AttributeError
860
+ raise AttributeError(f"'PartialState' object has no attribute '{name}'")
861
+
862
+
863
+ class AcceleratorState:
864
+ """
865
+ Singleton class that has information about the current training environment.
866
+
867
+ **Available attributes:**
868
+
869
+ - **device** (`torch.device`) -- The device to use.
870
+ - **distributed_type** ([`~accelerate.state.DistributedType`]) -- The type of distributed environment currently
871
+ in use.
872
+ - **initialized** (`bool`) -- Whether or not the `AcceleratorState` has been initialized from `Accelerator`.
873
+ - **local_process_index** (`int`) -- The index of the current process on the current server.
874
+ - **mixed_precision** (`str`) -- Whether or not the current script will use mixed precision, and if so the type
875
+ of mixed precision being performed. (Choose from 'no','fp16','bf16 or 'fp8').
876
+ - **num_processes** (`int`) -- The number of processes currently launched in parallel.
877
+ - **process_index** (`int`) -- The index of the current process.
878
+ - **is_last_process** (`bool`) -- Whether or not the current process is the last one.
879
+ - **is_main_process** (`bool`) -- Whether or not the current process is the main one.
880
+ - **is_local_main_process** (`bool`) -- Whether or not the current process is the main one on the local node.
881
+ - **debug** (`bool`) -- Whether or not the current script is being run in debug mode.
882
+ """
883
+
884
+ _shared_state = SharedDict()
885
+ _known_attrs = PartialState._known_attrs + [
886
+ "deepspeed_plugin",
887
+ "use_ipex",
888
+ "fsdp_plugin",
889
+ "megatron_lm_plugin",
890
+ "dynamo_plugin",
891
+ ]
892
+
893
+ def __init__(
894
+ self,
895
+ mixed_precision: str = None,
896
+ cpu: bool = False,
897
+ dynamo_plugin=None,
898
+ deepspeed_plugin=None,
899
+ fsdp_plugin=None,
900
+ torch_tp_plugin=None,
901
+ megatron_lm_plugin=None,
902
+ _from_accelerator: bool = False,
903
+ **kwargs,
904
+ ):
905
+ self.__dict__ = self._shared_state
906
+ if parse_flag_from_env("ACCELERATE_USE_CPU"):
907
+ cpu = True
908
+ if PartialState._shared_state == {}:
909
+ PartialState(cpu, **kwargs)
910
+ self.__dict__.update(PartialState._shared_state)
911
+ self._check_initialized(mixed_precision, cpu)
912
+ if not self.initialized:
913
+ self.deepspeed_plugins = None
914
+ self.use_ipex = None
915
+ self.torch_tp_plugin = torch_tp_plugin
916
+ mixed_precision = (
917
+ parse_choice_from_env("ACCELERATE_MIXED_PRECISION", "no")
918
+ if mixed_precision is None
919
+ else mixed_precision.lower()
920
+ )
921
+ if mixed_precision == "fp8":
922
+ # this is confusing, why is is_fp8_available only checks for library availability ?
923
+ if not is_fp8_available():
924
+ raise ValueError(
925
+ "Using `fp8` precision requires `transformer_engine` or `MS-AMP` to be installed."
926
+ )
927
+ elif torch.cuda.is_available() and not check_cuda_fp8_capability():
928
+ logger.warning(
929
+ f"The current device has compute capability of {torch.cuda.get_device_capability()} which is "
930
+ "insufficient for FP8 mixed precision training (requires a GPU Hopper/Ada Lovelace "
931
+ "or higher, compute capability of 8.9 or higher). Will use FP16 instead."
932
+ )
933
+ mixed_precision = "fp16"
934
+ elif is_habana_gaudi1():
935
+ logger.warning(
936
+ "The current HPU device is Gaudi1 which does not support FP8 mixed precision training (requires "
937
+ "Gaudi2 or higher). Will use BF16 instead."
938
+ )
939
+ mixed_precision = "bf16"
940
+
941
+ self.dynamo_plugin = dynamo_plugin
942
+ if not _from_accelerator:
943
+ raise ValueError(
944
+ "Please make sure to properly initialize your accelerator via `accelerator = Accelerator()` "
945
+ "before using any functionality from the `accelerate` library."
946
+ )
947
+ # deepspeed handles mixed_precision using deepspeed_config
948
+ self._mixed_precision = "no" if self.distributed_type == DistributedType.DEEPSPEED else mixed_precision
949
+ if self.distributed_type == DistributedType.XLA and is_torch_xla_available(check_is_tpu=True):
950
+ if mixed_precision == "bf16":
951
+ if os.environ.get("ACCELERATE_DOWNCAST_BF16"):
952
+ os.environ["XLA_USE_BF16"] = str(0)
953
+ os.environ["XLA_DOWNCAST_BF16"] = str(1)
954
+ self.downcast_bfloat = True
955
+ else:
956
+ os.environ["XLA_USE_BF16"] = str(1)
957
+ os.environ["XLA_DOWNCAST_BF16"] = str(0)
958
+ self.downcast_bfloat = False
959
+ elif os.environ.get("ACCELERATE_USE_DEEPSPEED", "false") == "true" and not cpu:
960
+ self.distributed_type = DistributedType.DEEPSPEED
961
+ if not isinstance(deepspeed_plugin, dict):
962
+ deepspeed_plugin.set_mixed_precision(mixed_precision)
963
+ deepspeed_plugin.select(_from_accelerator_state=True)
964
+ else:
965
+ for plugin in deepspeed_plugin.values():
966
+ plugin.set_mixed_precision(mixed_precision)
967
+ # The first plugin passed in is always the active one
968
+ first_plugin = next(iter(deepspeed_plugin.values()))
969
+ first_plugin.select(_from_accelerator_state=True)
970
+ self.deepspeed_plugins = deepspeed_plugin
971
+ elif self.distributed_type in [
972
+ DistributedType.MULTI_GPU,
973
+ DistributedType.MULTI_MLU,
974
+ DistributedType.MULTI_SDAA,
975
+ DistributedType.MULTI_MUSA,
976
+ DistributedType.MULTI_NPU,
977
+ DistributedType.MULTI_XPU,
978
+ DistributedType.MULTI_HPU,
979
+ ]:
980
+ if os.environ.get("ACCELERATE_USE_FSDP", "false") == "true" or fsdp_plugin is not None:
981
+ self.distributed_type = DistributedType.FSDP
982
+ if self._mixed_precision != "no":
983
+ fsdp_plugin.set_mixed_precision(self._mixed_precision)
984
+ self.fsdp_plugin = fsdp_plugin
985
+ if os.environ.get("ACCELERATE_USE_MEGATRON_LM", "false") == "true" and self.distributed_type not in [
986
+ DistributedType.MULTI_XPU,
987
+ ]:
988
+ self.distributed_type = DistributedType.MEGATRON_LM
989
+ megatron_lm_plugin.set_mixed_precision(self._mixed_precision)
990
+ self.megatron_lm_plugin = megatron_lm_plugin
991
+ if self.torch_tp_plugin is not None:
992
+ self.distributed_type = DistributedType.TP
993
+ elif self.distributed_type in [DistributedType.MULTI_CPU, DistributedType.MULTI_XPU, DistributedType.NO]:
994
+ if is_ipex_available():
995
+ # check if user disables it explicitly
996
+ self.use_ipex = parse_flag_from_env("ACCELERATE_USE_IPEX", default=True)
997
+ else:
998
+ self.use_ipex = False
999
+ if (
1000
+ self.dynamo_plugin.backend != DynamoBackend.NO
1001
+ and self._mixed_precision == "no"
1002
+ and self.device.type == "cuda"
1003
+ ):
1004
+ torch.backends.cuda.matmul.allow_tf32 = True
1005
+ if (
1006
+ self.dynamo_plugin.backend != DynamoBackend.NO
1007
+ and self._mixed_precision == "no"
1008
+ and self.device.type == "musa"
1009
+ ):
1010
+ torch.backends.musa.matmul.allow_tf32 = True
1011
+ PartialState._shared_state["distributed_type"] = self.distributed_type
1012
+
1013
+ @property
1014
+ def initialized(self) -> bool:
1015
+ return self._shared_state != PartialState._shared_state
1016
+
1017
+ def __repr__(self):
1018
+ repr = PartialState().__repr__() + f"\nMixed precision type: {self.mixed_precision}\n"
1019
+ if self.distributed_type == DistributedType.DEEPSPEED:
1020
+ repr += f"ds_config: {self.deepspeed_plugin.deepspeed_config}\n"
1021
+ return repr
1022
+
1023
+ def _check_initialized(self, mixed_precision=None, cpu=None):
1024
+ "Checks if a modification is trying to be made and the `AcceleratorState` has already been initialized"
1025
+ if self.initialized:
1026
+ err = "AcceleratorState has already been initialized and cannot be changed, restart your runtime completely and pass `{flag}` to `Accelerator()`."
1027
+ if cpu and self.device.type != "cpu":
1028
+ raise ValueError(err.format(flag="cpu=True"))
1029
+ if (
1030
+ mixed_precision is not None
1031
+ and mixed_precision != self._mixed_precision
1032
+ and self.distributed_type != DistributedType.DEEPSPEED
1033
+ ):
1034
+ raise ValueError(err.format(flag=f"mixed_precision='{mixed_precision}'"))
1035
+
1036
+ @property
1037
+ def mixed_precision(self):
1038
+ if self.distributed_type == DistributedType.DEEPSPEED:
1039
+ config = self.deepspeed_plugin.deepspeed_config
1040
+ if config.get("fp16", {}).get("enabled", False):
1041
+ mixed_precision = "fp16"
1042
+ elif config.get("bf16", {}).get("enabled", False):
1043
+ mixed_precision = "bf16"
1044
+ else:
1045
+ mixed_precision = "no"
1046
+ else:
1047
+ mixed_precision = self._mixed_precision
1048
+ return mixed_precision
1049
+
1050
+ @staticmethod
1051
+ def _reset_state(reset_partial_state: bool = False):
1052
+ "Resets `_shared_state`, is used internally and should not be called"
1053
+ AcceleratorState._shared_state.clear()
1054
+ if reset_partial_state:
1055
+ PartialState._reset_state()
1056
+
1057
+ def destroy_process_group(self, group=None):
1058
+ """
1059
+ Destroys the process group. If one is not specified, the default process group is destroyed.
1060
+
1061
+ If `self.fork_lauched` is `True` and `group` is `None`, nothing happens.
1062
+ """
1063
+ PartialState().destroy_process_group(group)
1064
+
1065
+ @property
1066
+ def fork_launched(self):
1067
+ return PartialState().fork_launched
1068
+
1069
+ @property
1070
+ def use_distributed(self):
1071
+ """
1072
+ Whether the Accelerator is configured for distributed training
1073
+ """
1074
+ return PartialState().use_distributed
1075
+
1076
+ @property
1077
+ def is_fsdp2(self) -> bool:
1078
+ return self.distributed_type == DistributedType.FSDP and self.fsdp_plugin.fsdp_version == 2
1079
+
1080
+ @property
1081
+ def is_last_process(self) -> bool:
1082
+ "Returns whether the current process is the last one"
1083
+ return PartialState().is_last_process
1084
+
1085
+ @property
1086
+ def is_main_process(self) -> bool:
1087
+ "Returns whether the current process is the main process"
1088
+ return PartialState().is_main_process
1089
+
1090
+ @property
1091
+ def is_local_main_process(self) -> bool:
1092
+ "Returns whether the current process is the main process on the local node"
1093
+ return PartialState().is_local_main_process
1094
+
1095
+ def wait_for_everyone(self):
1096
+ PartialState().wait_for_everyone()
1097
+
1098
+ @contextmanager
1099
+ def split_between_processes(self, inputs: list | tuple | dict | torch.Tensor, apply_padding: bool = False):
1100
+ """
1101
+ Splits `input` between `self.num_processes` quickly and can be then used on that process. Useful when doing
1102
+ distributed inference, such as with different prompts.
1103
+
1104
+ Note that when using a `dict`, all keys need to have the same number of elements.
1105
+
1106
+ Args:
1107
+ inputs (`list`, `tuple`, `torch.Tensor`, or `dict` of `list`/`tuple`/`torch.Tensor`):
1108
+ The input to split between processes.
1109
+ apply_padding (`bool`, `optional`, defaults to `False`):
1110
+ Whether to apply padding by repeating the last element of the input so that all processes have the same
1111
+ number of elements. Useful when trying to perform actions such as `gather()` on the outputs or passing
1112
+ in less inputs than there are processes. If so, just remember to drop the padded elements afterwards.
1113
+
1114
+
1115
+ Example:
1116
+
1117
+ ```python
1118
+ # Assume there are two processes
1119
+ from accelerate.state import AcceleratorState
1120
+
1121
+ state = AcceleratorState()
1122
+ with state.split_between_processes(["A", "B", "C"]) as inputs:
1123
+ print(inputs)
1124
+ # Process 0
1125
+ ["A", "B"]
1126
+ # Process 1
1127
+ ["C"]
1128
+
1129
+ with state.split_between_processes(["A", "B", "C"], apply_padding=True) as inputs:
1130
+ print(inputs)
1131
+ # Process 0
1132
+ ["A", "B"]
1133
+ # Process 1
1134
+ ["C", "C"]
1135
+ ```
1136
+ """
1137
+ with PartialState().split_between_processes(inputs, apply_padding=apply_padding) as inputs:
1138
+ yield inputs
1139
+
1140
+ @contextmanager
1141
+ def main_process_first(self):
1142
+ """
1143
+ Lets the main process go first inside a with block.
1144
+
1145
+ The other processes will enter the with block after the main process exits.
1146
+ """
1147
+ with PartialState().main_process_first():
1148
+ yield
1149
+
1150
+ @contextmanager
1151
+ def local_main_process_first(self):
1152
+ """
1153
+ Lets the local main process go inside a with block.
1154
+
1155
+ The other processes will enter the with block after the main process exits.
1156
+ """
1157
+ with PartialState().local_main_process_first():
1158
+ yield
1159
+
1160
+ @property
1161
+ def deepspeed_plugin(self):
1162
+ """
1163
+ Returns the currently active DeepSpeedPlugin.
1164
+
1165
+ If not using deepspeed, returns `None`.
1166
+ """
1167
+ # To maintain original behavior, return None if not using deepspeed.
1168
+ if self.distributed_type != DistributedType.DEEPSPEED:
1169
+ return None
1170
+ from accelerate.utils.deepspeed import get_active_deepspeed_plugin
1171
+
1172
+ return get_active_deepspeed_plugin(self)
1173
+
1174
+ @deepspeed_required
1175
+ def get_deepspeed_plugin(self, name: str):
1176
+ """
1177
+ Returns the DeepSpeedPlugin with the given plugin_key.
1178
+ """
1179
+ return self.deepspeed_plugins[name]
1180
+
1181
+ @deepspeed_required
1182
+ def select_deepspeed_plugin(self, name: str = None):
1183
+ """
1184
+ Activates the DeepSpeedPlugin with the given `name`, and will disable all other plugins.
1185
+ """
1186
+ for key, plugin in self.deepspeed_plugins.items():
1187
+ if key != name:
1188
+ plugin._unselect()
1189
+ self.deepspeed_plugins[name].select(_from_accelerator_state=True)
1190
+
1191
+ def print(self, *args, **kwargs):
1192
+ PartialState().print(*args, **kwargs)
1193
+
1194
+ def __getattr__(self, name: str):
1195
+ # By this point we know that no attributes of `self` contain `name`,
1196
+ # so we just modify the error message
1197
+ if name in self._known_attrs:
1198
+ raise AttributeError(
1199
+ f"`AcceleratorState` object has no attribute `{name}`. "
1200
+ "This happens if `AcceleratorState._reset_state()` was called and "
1201
+ "an `Accelerator` or `PartialState` was not reinitialized."
1202
+ )
1203
+ # Raise a typical AttributeError
1204
+ raise AttributeError(f"'AcceleratorState' object has no attribute '{name}'")
1205
+
1206
+
1207
+ class GradientState:
1208
+ """
1209
+ Singleton class that has information related to gradient synchronization for gradient accumulation
1210
+
1211
+ **Available attributes:**
1212
+
1213
+ - **end_of_dataloader** (`bool`) -- Whether we have reached the end the current dataloader
1214
+ - **remainder** (`int`) -- The number of extra samples that were added from padding the dataloader
1215
+ - **sync_gradients** (`bool`) -- Whether the gradients should be synced across all devices
1216
+ - **active_dataloader** (`Optional[DataLoader]`) -- The dataloader that is currently being iterated over
1217
+ - **dataloader_references** (`List[Optional[DataLoader]]`) -- A list of references to the dataloaders that are
1218
+ being iterated over
1219
+ - **num_steps** (`int`) -- The number of steps to accumulate over
1220
+ - **adjust_scheduler** (`bool`) -- Whether the scheduler should be adjusted to account for the gradient
1221
+ accumulation
1222
+ - **sync_with_dataloader** (`bool`) -- Whether the gradients should be synced at the end of the dataloader
1223
+ iteration and the number of total steps reset
1224
+ - **is_xla_gradients_synced** (`bool`) -- Whether the XLA gradients have been synchronized. It is initialized
1225
+ as false. Once gradients have been reduced before the optimizer step, this flag is set to true. Subsequently,
1226
+ after each step, the flag is reset to false. FSDP will always synchronize the gradients, hence
1227
+ is_xla_gradients_synced is always true.
1228
+ """
1229
+
1230
+ _shared_state = SharedDict()
1231
+
1232
+ def __init__(self, gradient_accumulation_plugin: GradientAccumulationPlugin | None = None):
1233
+ self.__dict__ = self._shared_state
1234
+ if not self.initialized:
1235
+ self.sync_gradients = True
1236
+ self._dataloader_references_ref = [None]
1237
+ self.plugin_kwargs = (
1238
+ gradient_accumulation_plugin.to_kwargs() if gradient_accumulation_plugin is not None else {}
1239
+ )
1240
+ self._is_xla_gradients_synced = False
1241
+
1242
+ # Plugin args are different and can be updated
1243
+ if gradient_accumulation_plugin is not None and self.plugin_kwargs != gradient_accumulation_plugin.to_kwargs():
1244
+ self.plugin_kwargs = gradient_accumulation_plugin.to_kwargs()
1245
+
1246
+ @property
1247
+ def num_steps(self) -> int:
1248
+ "Returns the number of steps to accumulate over"
1249
+ return self.plugin_kwargs.get("num_steps", 1)
1250
+
1251
+ @property
1252
+ def adjust_scheduler(self) -> bool:
1253
+ "Returns whether the scheduler should be adjusted"
1254
+ return self.plugin_kwargs.get("adjust_scheduler", False)
1255
+
1256
+ @property
1257
+ def sync_with_dataloader(self) -> bool:
1258
+ "Returns whether the gradients should be synced at the end of the dataloader iteration and the number of total steps reset"
1259
+ return self.plugin_kwargs.get("sync_with_dataloader", True)
1260
+
1261
+ @property
1262
+ def initialized(self) -> bool:
1263
+ "Returns whether the `GradientState` has been initialized"
1264
+ return GradientState._shared_state != {}
1265
+
1266
+ @property
1267
+ def end_of_dataloader(self) -> bool:
1268
+ "Returns whether we have reached the end of the current dataloader"
1269
+ if not self.in_dataloader:
1270
+ return False
1271
+ return self.active_dataloader.end_of_dataloader
1272
+
1273
+ @property
1274
+ def remainder(self) -> int:
1275
+ "Returns the number of extra samples that were added from padding the dataloader"
1276
+ if not self.in_dataloader:
1277
+ return -1
1278
+ return self.active_dataloader.remainder
1279
+
1280
+ def __repr__(self):
1281
+ return (
1282
+ f"Sync Gradients: {self.sync_gradients}\n"
1283
+ f"At end of current dataloader: {self.end_of_dataloader}\n"
1284
+ f"Extra samples added: {self.remainder}\n"
1285
+ f"Gradient accumulation plugin: {self.plugin_kwargs}\n"
1286
+ )
1287
+
1288
+ @property
1289
+ def is_xla_gradients_synced(self):
1290
+ "Returns the value of is_xla_gradients_synced. FSDP will always synchronize the gradients, hence is_xla_gradients_synced is always true."
1291
+ if parse_flag_from_env("ACCELERATE_USE_FSDP", default=False):
1292
+ return True
1293
+ return self._is_xla_gradients_synced
1294
+
1295
+ @is_xla_gradients_synced.setter
1296
+ def is_xla_gradients_synced(self, is_synced):
1297
+ "Set the _is_xla_gradients_synced attribute."
1298
+ self._is_xla_gradients_synced = is_synced
1299
+
1300
+ def _set_sync_gradients(self, sync_gradients):
1301
+ "Private function that sets whether gradients should be synchronized. Users should not have to call this."
1302
+ self.sync_gradients = sync_gradients
1303
+ # Allow grad-sync to automatically work on TPUs
1304
+ if (
1305
+ self.sync_gradients
1306
+ and is_torch_xla_available(check_is_tpu=True)
1307
+ and PartialState().distributed_type == DistributedType.XLA
1308
+ ):
1309
+ xm.mark_step()
1310
+
1311
+ def _add_dataloader(self, dataloader):
1312
+ "Private function that adds a dataloader to `self.dataloader_references` and sets `in_dataloader` to `True`. Users should not have to call this."
1313
+ # We explicitly use assignment to ensure that the property setter is triggered, which is required for garbage collection.
1314
+ # Avoid using self.dataloader_references.append as it will not trigger the setter.
1315
+ self.dataloader_references += [dataloader]
1316
+
1317
+ def _remove_dataloader(self, dataloader):
1318
+ "Private function that removes a dataloader from `self.dataloader_references` and sets `in_dataloader` to `False` if there are no more dataloaders. Users should not have to call this."
1319
+ # We explicitly use assignment to ensure that the property setter is triggered.
1320
+ self.dataloader_references = [
1321
+ dataloader_ref for dataloader_ref in self.dataloader_references if dataloader_ref != dataloader
1322
+ ]
1323
+
1324
+ @property
1325
+ def active_dataloader(self):
1326
+ return self.dataloader_references[-1]
1327
+
1328
+ @property
1329
+ def dataloader_references(self):
1330
+ # We use a property getter and setter with weakrefs to avoid circular references that prevent garbage collection
1331
+ return [reference() if reference is not None else reference for reference in self._dataloader_references_ref]
1332
+
1333
+ @dataloader_references.setter
1334
+ def dataloader_references(self, references):
1335
+ self._dataloader_references_ref = [
1336
+ weakref.ref(dataloader) if dataloader is not None else dataloader for dataloader in references
1337
+ ]
1338
+
1339
+ @property
1340
+ def in_dataloader(self) -> bool:
1341
+ "Returns whether the current process is in a dataloader"
1342
+ return self.active_dataloader is not None
1343
+
1344
+ @staticmethod
1345
+ def _reset_state():
1346
+ "Resets `_shared_state`, is used internally and should not be called"
1347
+ GradientState._shared_state.clear()
venv/lib/python3.10/site-packages/accelerate/test_utils/__init__.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 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
+ from .testing import (
15
+ DEFAULT_LAUNCH_COMMAND,
16
+ are_the_same_tensors,
17
+ assert_exception,
18
+ capture_call_output,
19
+ device_count,
20
+ execute_subprocess_async,
21
+ get_launch_command,
22
+ get_torch_dist_unique_port,
23
+ memory_allocated_func,
24
+ path_in_accelerate_package,
25
+ pytest_xdist_worker_id,
26
+ require_bnb,
27
+ require_cpu,
28
+ require_cuda,
29
+ require_cuda_or_hpu,
30
+ require_cuda_or_xpu,
31
+ require_fp8,
32
+ require_fp16,
33
+ require_huggingface_suite,
34
+ require_mlu,
35
+ require_mps,
36
+ require_multi_device,
37
+ require_multi_gpu,
38
+ require_multi_gpu_or_xpu,
39
+ require_multi_xpu,
40
+ require_musa,
41
+ require_non_cpu,
42
+ require_non_hpu,
43
+ require_non_torch_xla,
44
+ require_non_xpu,
45
+ require_npu,
46
+ require_pippy,
47
+ require_sdaa,
48
+ require_single_device,
49
+ require_single_gpu,
50
+ require_single_xpu,
51
+ require_torch_min_version,
52
+ require_torchao,
53
+ require_torchvision,
54
+ require_tpu,
55
+ require_transformer_engine,
56
+ require_xpu,
57
+ run_first,
58
+ skip,
59
+ slow,
60
+ torch_device,
61
+ )
62
+ from .training import RegressionDataset, RegressionModel, RegressionModel4XPU
63
+
64
+
65
+ from .scripts import test_script, test_sync, test_ops # isort: skip
venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (1.65 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/examples.cpython-310.pyc ADDED
Binary file (5.21 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/testing.cpython-310.pyc ADDED
Binary file (29.4 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/__pycache__/training.cpython-310.pyc ADDED
Binary file (5.78 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/examples.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ # Copyright 2022 The HuggingFace Team. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ A collection of utilities for comparing `examples/complete_*_example.py` scripts with the capabilities inside of each
18
+ `examples/by_feature` example. `compare_against_test` is the main function that should be used when testing, while the
19
+ others are used to either get the code that matters, or to preprocess them (such as stripping comments)
20
+ """
21
+
22
+ import os
23
+
24
+
25
+ def get_function_contents_by_name(lines: list[str], name: str):
26
+ """
27
+ Extracts a function from `lines` of segmented source code with the name `name`.
28
+
29
+ Args:
30
+ lines (`List[str]`):
31
+ Source code of a script separated by line.
32
+ name (`str`):
33
+ The name of the function to extract. Should be either `training_function` or `main`
34
+ """
35
+ if name != "training_function" and name != "main":
36
+ raise ValueError(f"Incorrect function name passed: {name}, choose either 'main' or 'training_function'")
37
+ good_lines, found_start = [], False
38
+ for line in lines:
39
+ if not found_start and f"def {name}" in line:
40
+ found_start = True
41
+ good_lines.append(line)
42
+ continue
43
+ if found_start:
44
+ if name == "training_function" and "def main" in line:
45
+ return good_lines
46
+ if name == "main" and "if __name__" in line:
47
+ return good_lines
48
+ good_lines.append(line)
49
+
50
+
51
+ def clean_lines(lines: list[str]):
52
+ """
53
+ Filters `lines` and removes any entries that start with a comment ('#') or is just a newline ('\n')
54
+
55
+ Args:
56
+ lines (`List[str]`):
57
+ Source code of a script separated by line.
58
+ """
59
+ return [line for line in lines if not line.lstrip().startswith("#") and line != "\n"]
60
+
61
+
62
+ def compare_against_test(base_filename: str, feature_filename: str, parser_only: bool, secondary_filename: str = None):
63
+ """
64
+ Tests whether the additional code inside of `feature_filename` was implemented in `base_filename`. This should be
65
+ used when testing to see if `complete_*_.py` examples have all of the implementations from each of the
66
+ `examples/by_feature/*` scripts.
67
+
68
+ It utilizes `nlp_example.py` to extract out all of the repeated training code, so that only the new additional code
69
+ is examined and checked. If something *other* than `nlp_example.py` should be used, such as `cv_example.py` for the
70
+ `complete_cv_example.py` script, it should be passed in for the `secondary_filename` parameter.
71
+
72
+ Args:
73
+ base_filename (`str` or `os.PathLike`):
74
+ The filepath of a single "complete" example script to test, such as `examples/complete_cv_example.py`
75
+ feature_filename (`str` or `os.PathLike`):
76
+ The filepath of a single feature example script. The contents of this script are checked to see if they
77
+ exist in `base_filename`
78
+ parser_only (`bool`):
79
+ Whether to compare only the `main()` sections in both files, or to compare the contents of
80
+ `training_loop()`
81
+ secondary_filename (`str`, *optional*):
82
+ A potential secondary filepath that should be included in the check. This function extracts the base
83
+ functionalities off of "examples/nlp_example.py", so if `base_filename` is a script other than
84
+ `complete_nlp_example.py`, the template script should be included here. Such as `examples/cv_example.py`
85
+ """
86
+ with open(base_filename) as f:
87
+ base_file_contents = f.readlines()
88
+ with open(os.path.abspath(os.path.join("examples", "nlp_example.py"))) as f:
89
+ full_file_contents = f.readlines()
90
+ with open(feature_filename) as f:
91
+ feature_file_contents = f.readlines()
92
+ if secondary_filename is not None:
93
+ with open(secondary_filename) as f:
94
+ secondary_file_contents = f.readlines()
95
+
96
+ # This is our base, we remove all the code from here in our `full_filename` and `feature_filename` to find the new content
97
+ if parser_only:
98
+ base_file_func = clean_lines(get_function_contents_by_name(base_file_contents, "main"))
99
+ full_file_func = clean_lines(get_function_contents_by_name(full_file_contents, "main"))
100
+ feature_file_func = clean_lines(get_function_contents_by_name(feature_file_contents, "main"))
101
+ if secondary_filename is not None:
102
+ secondary_file_func = clean_lines(get_function_contents_by_name(secondary_file_contents, "main"))
103
+ else:
104
+ base_file_func = clean_lines(get_function_contents_by_name(base_file_contents, "training_function"))
105
+ full_file_func = clean_lines(get_function_contents_by_name(full_file_contents, "training_function"))
106
+ feature_file_func = clean_lines(get_function_contents_by_name(feature_file_contents, "training_function"))
107
+ if secondary_filename is not None:
108
+ secondary_file_func = clean_lines(
109
+ get_function_contents_by_name(secondary_file_contents, "training_function")
110
+ )
111
+
112
+ _dl_line = "train_dataloader, eval_dataloader = get_dataloaders(accelerator, batch_size)\n"
113
+
114
+ # Specific code in our script that differs from the full version, aka what is new
115
+ new_feature_code = []
116
+ passed_idxs = [] # We keep track of the idxs just in case it's a repeated statement
117
+ it = iter(feature_file_func)
118
+ for i in range(len(feature_file_func) - 1):
119
+ if i not in passed_idxs:
120
+ line = next(it)
121
+ if (line not in full_file_func) and (line.lstrip() != _dl_line):
122
+ if "TESTING_MOCKED_DATALOADERS" not in line:
123
+ new_feature_code.append(line)
124
+ passed_idxs.append(i)
125
+ else:
126
+ # Skip over the `config['num_epochs'] = 2` statement
127
+ _ = next(it)
128
+
129
+ # Extract out just the new parts from the full_file_training_func
130
+ new_full_example_parts = []
131
+ passed_idxs = [] # We keep track of the idxs just in case it's a repeated statement
132
+ for i, line in enumerate(base_file_func):
133
+ if i not in passed_idxs:
134
+ if (line not in full_file_func) and (line.lstrip() != _dl_line):
135
+ if "TESTING_MOCKED_DATALOADERS" not in line:
136
+ new_full_example_parts.append(line)
137
+ passed_idxs.append(i)
138
+
139
+ # Finally, get the overall diff
140
+ diff_from_example = [line for line in new_feature_code if line not in new_full_example_parts]
141
+ if secondary_filename is not None:
142
+ diff_from_two = [line for line in full_file_contents if line not in secondary_file_func]
143
+ diff_from_example = [line for line in diff_from_example if line not in diff_from_two]
144
+
145
+ return diff_from_example
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 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.
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_merge_weights.cpython-310.pyc ADDED
Binary file (4.96 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_notebook.cpython-310.pyc ADDED
Binary file (3.73 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_ops.cpython-310.pyc ADDED
Binary file (4.63 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_script.cpython-310.pyc ADDED
Binary file (23.5 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/__pycache__/test_sync.cpython-310.pyc ADDED
Binary file (9.23 kB). View file
 
venv/lib/python3.10/site-packages/accelerate/test_utils/scripts/test_cli.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ import torch
15
+
16
+ from accelerate.utils import is_xpu_available
17
+
18
+
19
+ def main():
20
+ accelerator_type = "GPU"
21
+ num_accelerators = 0
22
+ if torch.cuda.is_available():
23
+ num_accelerators = torch.cuda.device_count()
24
+ accelerator_type = "GPU"
25
+ elif is_xpu_available():
26
+ num_accelerators = torch.xpu.device_count()
27
+ accelerator_type = "XPU"
28
+ print(f"Successfully ran on {num_accelerators} {accelerator_type}s")
29
+
30
+
31
+ if __name__ == "__main__":
32
+ main()