Skip to content

Commit e24d960

Browse files
committed
add clean_memory_on_device and use it from training
1 parent 75ecb04 commit e24d960

13 files changed

Lines changed: 55 additions & 38 deletions

fine_tune.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from tqdm import tqdm
1111

1212
import torch
13-
from library.device_utils import init_ipex, clean_memory
13+
from library.device_utils import init_ipex, clean_memory_on_device
1414
init_ipex()
1515

1616
from accelerate.utils import set_seed
@@ -156,7 +156,7 @@ def fn_recursive_set_mem_eff(module: torch.nn.Module):
156156
with torch.no_grad():
157157
train_dataset_group.cache_latents(vae, args.vae_batch_size, args.cache_latents_to_disk, accelerator.is_main_process)
158158
vae.to("cpu")
159-
clean_memory()
159+
clean_memory_on_device(accelerator.device)
160160

161161
accelerator.wait_for_everyone()
162162

library/device_utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ def clean_memory():
3131
torch.mps.empty_cache()
3232

3333

34+
def clean_memory_on_device(device: torch.device):
35+
r"""
36+
Clean memory on the specified device, will be called from training scripts.
37+
"""
38+
gc.collect()
39+
40+
# device may "cuda" or "cuda:0", so we need to check the type of device
41+
if device.type == "cuda":
42+
torch.cuda.empty_cache()
43+
if device.type == "xpu":
44+
torch.xpu.empty_cache()
45+
if device.type == "mps":
46+
torch.mps.empty_cache()
47+
48+
3449
@functools.lru_cache(maxsize=None)
3550
def get_preferred_device() -> torch.device:
3651
r"""

library/sdxl_train_util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import Optional
55

66
import torch
7-
from library.device_utils import init_ipex, clean_memory
7+
from library.device_utils import init_ipex, clean_memory_on_device
88
init_ipex()
99

1010
from accelerate import init_empty_weights
@@ -50,7 +50,7 @@ def load_target_model(args, accelerator, model_version: str, weight_dtype):
5050
unet.to(accelerator.device)
5151
vae.to(accelerator.device)
5252

53-
clean_memory()
53+
clean_memory_on_device(accelerator.device)
5454
accelerator.wait_for_everyone()
5555

5656
return load_stable_diffusion_format, text_encoder1, text_encoder2, vae, unet, logit_scale, ckpt_info

library/train_util.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from tqdm import tqdm
3333

3434
import torch
35-
from library.device_utils import init_ipex, clean_memory
35+
from library.device_utils import init_ipex, clean_memory_on_device
3636

3737
init_ipex()
3838

@@ -2285,7 +2285,7 @@ def cache_batch_latents(
22852285
info.latents_flipped = flipped_latent
22862286

22872287
if not HIGH_VRAM:
2288-
clean_memory()
2288+
clean_memory_on_device(vae.device)
22892289

22902290

22912291
def cache_batch_text_encoder_outputs(
@@ -4026,7 +4026,7 @@ def load_target_model(args, weight_dtype, accelerator, unet_use_linear_projectio
40264026
unet.to(accelerator.device)
40274027
vae.to(accelerator.device)
40284028

4029-
clean_memory()
4029+
clean_memory_on_device(accelerator.device)
40304030
accelerator.wait_for_everyone()
40314031

40324032
return text_encoder, vae, unet, load_stable_diffusion_format
@@ -4695,7 +4695,7 @@ def sample_images_common(
46954695
distributed_state = PartialState() # for multi gpu distributed inference. this is a singleton, so it's safe to use it here
46964696

46974697
org_vae_device = vae.device # CPUにいるはず
4698-
vae.to(distributed_state.device)
4698+
vae.to(distributed_state.device) # distributed_state.device is same as accelerator.device
46994699

47004700
# unwrap unet and text_encoder(s)
47014701
unet = accelerator.unwrap_model(unet)
@@ -4752,7 +4752,11 @@ def sample_images_common(
47524752

47534753
# save random state to restore later
47544754
rng_state = torch.get_rng_state()
4755-
cuda_rng_state = torch.cuda.get_rng_state() if torch.cuda.is_available() else None # TODO mps etc. support
4755+
cuda_rng_state = None
4756+
try:
4757+
cuda_rng_state = torch.cuda.get_rng_state() if torch.cuda.is_available() else None
4758+
except Exception:
4759+
pass
47564760

47574761
if distributed_state.num_processes <= 1:
47584762
# If only one device is available, just use the original prompt list. We don't need to care about the distribution of prompts.
@@ -4774,8 +4778,10 @@ def sample_images_common(
47744778
# clear pipeline and cache to reduce vram usage
47754779
del pipeline
47764780

4777-
with torch.cuda.device(torch.cuda.current_device()):
4778-
torch.cuda.empty_cache()
4781+
# I'm not sure which of these is the correct way to clear the memory, but accelerator's device is used in the pipeline, so I'm using it here.
4782+
# with torch.cuda.device(torch.cuda.current_device()):
4783+
# torch.cuda.empty_cache()
4784+
clean_memory_on_device(accelerator.device)
47794785

47804786
torch.set_rng_state(rng_state)
47814787
if cuda_rng_state is not None:
@@ -4870,10 +4876,6 @@ def sample_image_inference(accelerator: Accelerator, args: argparse.Namespace, p
48704876
pass
48714877
# endregion
48724878

4873-
# # clear pipeline and cache to reduce vram usage
4874-
# del pipeline
4875-
# torch.cuda.empty_cache()
4876-
48774879

48784880

48794881
# region 前処理用

sdxl_train.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from tqdm import tqdm
1111

1212
import torch
13-
from library.device_utils import init_ipex, clean_memory
13+
from library.device_utils import init_ipex, clean_memory_on_device
1414
init_ipex()
1515

1616
from accelerate.utils import set_seed
@@ -250,7 +250,7 @@ def fn_recursive_set_mem_eff(module: torch.nn.Module):
250250
with torch.no_grad():
251251
train_dataset_group.cache_latents(vae, args.vae_batch_size, args.cache_latents_to_disk, accelerator.is_main_process)
252252
vae.to("cpu")
253-
clean_memory()
253+
clean_memory_on_device(accelerator.device)
254254

255255
accelerator.wait_for_everyone()
256256

@@ -403,7 +403,7 @@ def fn_recursive_set_mem_eff(module: torch.nn.Module):
403403
# move Text Encoders for sampling images. Text Encoder doesn't work on CPU with fp16
404404
text_encoder1.to("cpu", dtype=torch.float32)
405405
text_encoder2.to("cpu", dtype=torch.float32)
406-
clean_memory()
406+
clean_memory_on_device(accelerator.device)
407407
else:
408408
# make sure Text Encoders are on GPU
409409
text_encoder1.to(accelerator.device)

sdxl_train_control_net_lllite.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from tqdm import tqdm
1515

1616
import torch
17-
from library.device_utils import init_ipex, clean_memory
17+
from library.device_utils import init_ipex, clean_memory_on_device
1818
init_ipex()
1919

2020
from torch.nn.parallel import DistributedDataParallel as DDP
@@ -162,7 +162,7 @@ def train(args):
162162
accelerator.is_main_process,
163163
)
164164
vae.to("cpu")
165-
clean_memory()
165+
clean_memory_on_device(accelerator.device)
166166

167167
accelerator.wait_for_everyone()
168168

@@ -287,7 +287,7 @@ def train(args):
287287
# move Text Encoders for sampling images. Text Encoder doesn't work on CPU with fp16
288288
text_encoder1.to("cpu", dtype=torch.float32)
289289
text_encoder2.to("cpu", dtype=torch.float32)
290-
clean_memory()
290+
clean_memory_on_device(accelerator.device)
291291
else:
292292
# make sure Text Encoders are on GPU
293293
text_encoder1.to(accelerator.device)

sdxl_train_control_net_lllite_old.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from tqdm import tqdm
1212

1313
import torch
14-
from library.device_utils import init_ipex, clean_memory
14+
from library.device_utils import init_ipex, clean_memory_on_device
1515
init_ipex()
1616

1717
from torch.nn.parallel import DistributedDataParallel as DDP
@@ -161,7 +161,7 @@ def train(args):
161161
accelerator.is_main_process,
162162
)
163163
vae.to("cpu")
164-
clean_memory()
164+
clean_memory_on_device(accelerator.device)
165165

166166
accelerator.wait_for_everyone()
167167

@@ -260,7 +260,7 @@ def train(args):
260260
# move Text Encoders for sampling images. Text Encoder doesn't work on CPU with fp16
261261
text_encoder1.to("cpu", dtype=torch.float32)
262262
text_encoder2.to("cpu", dtype=torch.float32)
263-
clean_memory()
263+
clean_memory_on_device(accelerator.device)
264264
else:
265265
# make sure Text Encoders are on GPU
266266
text_encoder1.to(accelerator.device)

sdxl_train_network.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import argparse
22

33
import torch
4-
from library.device_utils import init_ipex, clean_memory
4+
from library.device_utils import init_ipex, clean_memory_on_device
55
init_ipex()
66

77
from library import sdxl_model_util, sdxl_train_util, train_util
@@ -64,7 +64,7 @@ def cache_text_encoder_outputs_if_needed(
6464
org_unet_device = unet.device
6565
vae.to("cpu")
6666
unet.to("cpu")
67-
clean_memory()
67+
clean_memory_on_device(accelerator.device)
6868

6969
# When TE is not be trained, it will not be prepared so we need to use explicit autocast
7070
with accelerator.autocast():
@@ -79,7 +79,7 @@ def cache_text_encoder_outputs_if_needed(
7979

8080
text_encoders[0].to("cpu", dtype=torch.float32) # Text Encoder doesn't work with fp16 on CPU
8181
text_encoders[1].to("cpu", dtype=torch.float32)
82-
clean_memory()
82+
clean_memory_on_device(accelerator.device)
8383

8484
if not args.lowram:
8585
print("move vae and unet back to original device")

train_controlnet.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from tqdm import tqdm
1212

1313
import torch
14-
from library.device_utils import init_ipex, clean_memory
14+
from library.device_utils import init_ipex, clean_memory_on_device
1515
init_ipex()
1616

1717
from torch.nn.parallel import DistributedDataParallel as DDP
@@ -217,8 +217,8 @@ def train(args):
217217
accelerator.is_main_process,
218218
)
219219
vae.to("cpu")
220-
clean_memory()
221-
220+
clean_memory_on_device(accelerator.device)
221+
222222
accelerator.wait_for_everyone()
223223

224224
if args.gradient_checkpointing:

train_db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from tqdm import tqdm
1212

1313
import torch
14-
from library.device_utils import init_ipex, clean_memory
14+
from library.device_utils import init_ipex, clean_memory_on_device
1515
init_ipex()
1616

1717
from accelerate.utils import set_seed
@@ -136,7 +136,7 @@ def train(args):
136136
with torch.no_grad():
137137
train_dataset_group.cache_latents(vae, args.vae_batch_size, args.cache_latents_to_disk, accelerator.is_main_process)
138138
vae.to("cpu")
139-
clean_memory()
139+
clean_memory_on_device(accelerator.device)
140140

141141
accelerator.wait_for_everyone()
142142

0 commit comments

Comments
 (0)