lowvram.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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. sd_model.lowvram = True
  12. parents = {}
  13. def send_me_to_gpu(module, _):
  14. """send this module to GPU; send whatever tracked module was previous in GPU to CPU;
  15. we add this as forward_pre_hook to a lot of modules and this way all but one of them will
  16. be in CPU
  17. """
  18. global module_in_gpu
  19. module = parents.get(module, module)
  20. if module_in_gpu == module:
  21. return
  22. if module_in_gpu is not None:
  23. module_in_gpu.to(cpu)
  24. module.to(devices.device)
  25. module_in_gpu = module
  26. # see below for register_forward_pre_hook;
  27. # first_stage_model does not use forward(), it uses encode/decode, so register_forward_pre_hook is
  28. # useless here, and we just replace those methods
  29. first_stage_model = sd_model.first_stage_model
  30. first_stage_model_encode = sd_model.first_stage_model.encode
  31. first_stage_model_decode = sd_model.first_stage_model.decode
  32. def first_stage_model_encode_wrap(x):
  33. send_me_to_gpu(first_stage_model, None)
  34. return first_stage_model_encode(x)
  35. def first_stage_model_decode_wrap(z):
  36. send_me_to_gpu(first_stage_model, None)
  37. return first_stage_model_decode(z)
  38. to_remain_in_cpu = [
  39. (sd_model, 'first_stage_model'),
  40. (sd_model, 'depth_model'),
  41. (sd_model, 'embedder'),
  42. (sd_model, 'model'),
  43. (sd_model, 'embedder'),
  44. ]
  45. is_sdxl = hasattr(sd_model, 'conditioner')
  46. is_sd2 = not is_sdxl and hasattr(sd_model.cond_stage_model, 'model')
  47. if is_sdxl:
  48. to_remain_in_cpu.append((sd_model, 'conditioner'))
  49. elif is_sd2:
  50. to_remain_in_cpu.append((sd_model.cond_stage_model, 'model'))
  51. else:
  52. to_remain_in_cpu.append((sd_model.cond_stage_model, 'transformer'))
  53. # remove several big modules: cond, first_stage, depth/embedder (if applicable), and unet from the model
  54. stored = []
  55. for obj, field in to_remain_in_cpu:
  56. module = getattr(obj, field, None)
  57. stored.append(module)
  58. setattr(obj, field, None)
  59. # send the model to GPU.
  60. sd_model.to(devices.device)
  61. # put modules back. the modules will be in CPU.
  62. for (obj, field), module in zip(to_remain_in_cpu, stored):
  63. setattr(obj, field, module)
  64. # register hooks for those the first three models
  65. if is_sdxl:
  66. sd_model.conditioner.register_forward_pre_hook(send_me_to_gpu)
  67. elif is_sd2:
  68. sd_model.cond_stage_model.model.register_forward_pre_hook(send_me_to_gpu)
  69. sd_model.cond_stage_model.model.token_embedding.register_forward_pre_hook(send_me_to_gpu)
  70. parents[sd_model.cond_stage_model.model] = sd_model.cond_stage_model
  71. parents[sd_model.cond_stage_model.model.token_embedding] = sd_model.cond_stage_model
  72. else:
  73. sd_model.cond_stage_model.transformer.register_forward_pre_hook(send_me_to_gpu)
  74. parents[sd_model.cond_stage_model.transformer] = sd_model.cond_stage_model
  75. sd_model.first_stage_model.register_forward_pre_hook(send_me_to_gpu)
  76. sd_model.first_stage_model.encode = first_stage_model_encode_wrap
  77. sd_model.first_stage_model.decode = first_stage_model_decode_wrap
  78. if sd_model.depth_model:
  79. sd_model.depth_model.register_forward_pre_hook(send_me_to_gpu)
  80. if sd_model.embedder:
  81. sd_model.embedder.register_forward_pre_hook(send_me_to_gpu)
  82. if use_medvram:
  83. sd_model.model.register_forward_pre_hook(send_me_to_gpu)
  84. else:
  85. diff_model = sd_model.model.diffusion_model
  86. # the third remaining model is still too big for 4 GB, so we also do the same for its submodules
  87. # so that only one of them is in GPU at a time
  88. stored = diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed
  89. diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed = None, None, None, None
  90. sd_model.model.to(devices.device)
  91. diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed = stored
  92. # install hooks for bits of third model
  93. diff_model.time_embed.register_forward_pre_hook(send_me_to_gpu)
  94. for block in diff_model.input_blocks:
  95. block.register_forward_pre_hook(send_me_to_gpu)
  96. diff_model.middle_block.register_forward_pre_hook(send_me_to_gpu)
  97. for block in diff_model.output_blocks:
  98. block.register_forward_pre_hook(send_me_to_gpu)
  99. def is_enabled(sd_model):
  100. return getattr(sd_model, 'lowvram', False)