r""" Applies group offloading to the internal layers of a torch.nn.Module. To understand what group offloading is, and where it is beneficial, we need to first provide some context on how other supported offloading methods work. Typically, offloading is done at two levels: - Module-
(
module: torch.nn.Module,
onload_device: str | torch.device,
offload_device: str | torch.device = torch.device("cpu"),
offload_type: str | GroupOffloadingType = "block_level",
num_blocks_per_group: int | None = None,
non_blocking: bool = False,
use_stream: bool = False,
record_stream: bool = False,
low_cpu_mem_usage: bool = False,
offload_to_disk_path: str | None = None,
block_modules: list[str] | None = None,
exclude_kwargs: list[str] | None = None,
)
| 564 | |
| 565 | |
| 566 | def apply_group_offloading( |
| 567 | module: torch.nn.Module, |
| 568 | onload_device: str | torch.device, |
| 569 | offload_device: str | torch.device = torch.device("cpu"), |
| 570 | offload_type: str | GroupOffloadingType = "block_level", |
| 571 | num_blocks_per_group: int | None = None, |
| 572 | non_blocking: bool = False, |
| 573 | use_stream: bool = False, |
| 574 | record_stream: bool = False, |
| 575 | low_cpu_mem_usage: bool = False, |
| 576 | offload_to_disk_path: str | None = None, |
| 577 | block_modules: list[str] | None = None, |
| 578 | exclude_kwargs: list[str] | None = None, |
| 579 | ) -> None: |
| 580 | r""" |
| 581 | Applies group offloading to the internal layers of a torch.nn.Module. To understand what group offloading is, and |
| 582 | where it is beneficial, we need to first provide some context on how other supported offloading methods work. |
| 583 | |
| 584 | Typically, offloading is done at two levels: |
| 585 | - Module-level: In Diffusers, this can be enabled using the `ModelMixin::enable_model_cpu_offload()` method. It |
| 586 | works by offloading each component of a pipeline to the CPU for storage, and onloading to the accelerator device |
| 587 | when needed for computation. This method is more memory-efficient than keeping all components on the accelerator, |
| 588 | but the memory requirements are still quite high. For this method to work, one needs memory equivalent to size of |
| 589 | the model in runtime dtype + size of largest intermediate activation tensors to be able to complete the forward |
| 590 | pass. |
| 591 | - Leaf-level: In Diffusers, this can be enabled using the `ModelMixin::enable_sequential_cpu_offload()` method. It |
| 592 | works by offloading the lowest leaf-level parameters of the computation graph to the CPU for storage, and |
| 593 | onloading only the leafs to the accelerator device for computation. This uses the lowest amount of accelerator |
| 594 | memory, but can be slower due to the excessive number of device synchronizations. |
| 595 | |
| 596 | Group offloading is a middle ground between the two methods. It works by offloading groups of internal layers, |
| 597 | (either `torch.nn.ModuleList` or `torch.nn.Sequential`). This method uses lower memory than module-level |
| 598 | offloading. It is also faster than leaf-level/sequential offloading, as the number of device synchronizations is |
| 599 | reduced. |
| 600 | |
| 601 | Another supported feature (for CUDA devices with support for asynchronous data transfer streams) is the ability to |
| 602 | overlap data transfer and computation to reduce the overall execution time compared to sequential offloading. This |
| 603 | is enabled using layer prefetching with streams, i.e., the layer that is to be executed next starts onloading to |
| 604 | the accelerator device while the current layer is being executed - this increases the memory requirements slightly. |
| 605 | Note that this implementation also supports leaf-level offloading but can be made much faster when using streams. |
| 606 | |
| 607 | Args: |
| 608 | module (`torch.nn.Module`): |
| 609 | The module to which group offloading is applied. |
| 610 | onload_device (`torch.device`): |
| 611 | The device to which the group of modules are onloaded. |
| 612 | offload_device (`torch.device`, defaults to `torch.device("cpu")`): |
| 613 | The device to which the group of modules are offloaded. This should typically be the CPU. Default is CPU. |
| 614 | offload_type (`str` or `GroupOffloadingType`, defaults to "block_level"): |
| 615 | The type of offloading to be applied. Can be one of "block_level" or "leaf_level". Default is |
| 616 | "block_level". |
| 617 | offload_to_disk_path (`str`, *optional*, defaults to `None`): |
| 618 | The path to the directory where parameters will be offloaded. Setting this option can be useful in limited |
| 619 | RAM environment settings where a reasonable speed-memory trade-off is desired. |
| 620 | num_blocks_per_group (`int`, *optional*): |
| 621 | The number of blocks per group when using offload_type="block_level". This is required when using |
| 622 | offload_type="block_level". |
| 623 | non_blocking (`bool`, defaults to `False`): |
searching dependent graphs…