lowvram.py 4.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import torch
  2. from modules import devices
  3. module_in_gpu = None
  4. cpu = torch.device("cpu")
  5. def send_everything_to_cpu():
  6. global module_in_gpu
  7. if module_in_gpu is not None:
  8. module_in_gpu.to(cpu)
  9. module_in_gpu = None
  10. def setup_for_low_vram(sd_model, use_medvram):
  11. parents = {}
  12. def send_me_to_gpu(module, _):
  13. """send this module to GPU; send whatever tracked module was previous in GPU to CPU;
  14. we add this as forward_pre_hook to a lot of modules and this way all but one of them will
  15. be in CPU
  16. """
  17. global module_in_gpu
  18. module = parents.get(module, module)
  19. if module_in_gpu == module:
  20. return
  21. if module_in_gpu is not None:
  22. module_in_gpu.to(cpu)
  23. module.to(devices.device)
  24. module_in_gpu = module
  25. # see below for register_forward_pre_hook;
  26. # first_stage_model does not use forward(), it uses encode/decode, so register_forward_pre_hook is
  27. # useless here, and we just replace those methods
  28. first_stage_model = sd_model.first_stage_model
  29. first_stage_model_encode = sd_model.first_stage_model.encode
  30. first_stage_model_decode = sd_model.first_stage_model.decode
  31. def first_stage_model_encode_wrap(x):
  32. send_me_to_gpu(first_stage_model, None)
  33. return first_stage_model_encode(x)
  34. def first_stage_model_decode_wrap(z):
  35. send_me_to_gpu(first_stage_model, None)
  36. return first_stage_model_decode(z)
  37. # for SD1, cond_stage_model is CLIP and its NN is in the tranformer frield, but for SD2, it's open clip, and it's in model field
  38. if hasattr(sd_model.cond_stage_model, 'model'):
  39. sd_model.cond_stage_model.transformer = sd_model.cond_stage_model.model
  40. # remove several big modules: cond, first_stage, depth/embedder (if applicable), and unet from the model and then
  41. # send the model to GPU. Then put modules back. the modules will be in CPU.
  42. stored = sd_model.cond_stage_model.transformer, sd_model.first_stage_model, getattr(sd_model, 'depth_model', None), getattr(sd_model, 'embedder', None), sd_model.model
  43. sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.depth_model, sd_model.embedder, sd_model.model = None, None, None, None, None
  44. sd_model.to(devices.device)
  45. sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.depth_model, sd_model.embedder, sd_model.model = stored
  46. # register hooks for those the first three models
  47. sd_model.cond_stage_model.transformer.register_forward_pre_hook(send_me_to_gpu)
  48. sd_model.first_stage_model.register_forward_pre_hook(send_me_to_gpu)
  49. sd_model.first_stage_model.encode = first_stage_model_encode_wrap
  50. sd_model.first_stage_model.decode = first_stage_model_decode_wrap
  51. if sd_model.depth_model:
  52. sd_model.depth_model.register_forward_pre_hook(send_me_to_gpu)
  53. if sd_model.embedder:
  54. sd_model.embedder.register_forward_pre_hook(send_me_to_gpu)
  55. parents[sd_model.cond_stage_model.transformer] = sd_model.cond_stage_model
  56. if hasattr(sd_model.cond_stage_model, 'model'):
  57. sd_model.cond_stage_model.model = sd_model.cond_stage_model.transformer
  58. del sd_model.cond_stage_model.transformer
  59. if use_medvram:
  60. sd_model.model.register_forward_pre_hook(send_me_to_gpu)
  61. else:
  62. diff_model = sd_model.model.diffusion_model
  63. # the third remaining model is still too big for 4 GB, so we also do the same for its submodules
  64. # so that only one of them is in GPU at a time
  65. stored = diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed
  66. diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed = None, None, None, None
  67. sd_model.model.to(devices.device)
  68. diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed = stored
  69. # install hooks for bits of third model
  70. diff_model.time_embed.register_forward_pre_hook(send_me_to_gpu)
  71. for block in diff_model.input_blocks:
  72. block.register_forward_pre_hook(send_me_to_gpu)
  73. diff_model.middle_block.register_forward_pre_hook(send_me_to_gpu)
  74. for block in diff_model.output_blocks:
  75. block.register_forward_pre_hook(send_me_to_gpu)