ostris commited on
Commit
5dcf26e
·
verified ·
1 Parent(s): 1f441a8

Add gradient checkpointing to the vae

Browse files
README.md CHANGED
@@ -66,6 +66,9 @@ shapes, so `weights_name="my_finetune.safetensors"` loads any Primal VAE checkpo
66
  `pixel_shuffle` by `compression / 2`, so `compression=8` is a 4x4 patch. `vae.token_channels(8)` and
67
  `vae.image_multiple` give you the numbers above.
68
 
 
 
 
69
  ## Architecture
70
 
71
  Both models are the same network, they only differ in output channels.
 
66
  `pixel_shuffle` by `compression / 2`, so `compression=8` is a 4x4 patch. `vae.token_channels(8)` and
67
  `vae.image_multiple` give you the numbers above.
68
 
69
+ To backprop through `decode` (a pixel-space loss on a diffusion model's prediction), `vae.enable_gradient_checkpointing()`
70
+ checkpoints every residual block of both U-Nets; inference under `torch.no_grad()` is unaffected.
71
+
72
  ## Architecture
73
 
74
  Both models are the same network, they only differ in output channels.
__pycache__/modeling_primal_vae.cpython-312.pyc ADDED
Binary file (18.9 kB). View file
 
modeling_primal_vae.py CHANGED
@@ -15,6 +15,7 @@ from typing import List, Optional
15
  import torch
16
  import torch.nn as nn
17
  import torch.nn.functional as F
 
18
  from diffusers.configuration_utils import ConfigMixin, register_to_config
19
  from diffusers.models.modeling_utils import ModelMixin
20
  from huggingface_hub import hf_hub_download
@@ -66,6 +67,14 @@ class UStack(nn.Module):
66
  self.up_blocks = nn.ModuleList([nn.ModuleList([ResBlock(widths[i], DILATION_CYCLE[j % len(DILATION_CYCLE)]) for j in range(up_depths[i])]) for i in range(L - 1)])
67
  self.norm_out = ChannelRMSNorm(widths[0])
68
  self.conv_out = nn.Conv2d(widths[0], out_ch, 3, padding=1)
 
 
 
 
 
 
 
 
69
 
70
  def forward(self, x: torch.Tensor) -> torch.Tensor:
71
  x = self.conv_in(x)
@@ -73,14 +82,14 @@ class UStack(nn.Module):
73
  L = len(self.down_blocks)
74
  for i in range(L):
75
  for blk in self.down_blocks[i]:
76
- x = blk(x)
77
  if i < L - 1:
78
  skips.append(x)
79
  x = self.downs[i](F.pixel_unshuffle(x, 2))
80
  for i in reversed(range(L - 1)):
81
  x = F.pixel_shuffle(self.ups[i](x), 2) + skips[i]
82
  for blk in self.up_blocks[i]:
83
- x = blk(x)
84
  return self.conv_out(F.silu(self.norm_out(x)))
85
 
86
 
@@ -88,6 +97,8 @@ class PrimalVAE(ModelMixin, ConfigMixin):
88
  """Primal VAE: `encode` -> [B, latent_channels, H/compression, W/compression] (~N(0,1)), `decode` back to
89
  [B, 3, H, W] in [-1, 1]. No posterior, no scaling/shift factor."""
90
 
 
 
91
  @register_to_config
92
  def __init__(
93
  self,
 
15
  import torch
16
  import torch.nn as nn
17
  import torch.nn.functional as F
18
+ import torch.utils.checkpoint
19
  from diffusers.configuration_utils import ConfigMixin, register_to_config
20
  from diffusers.models.modeling_utils import ModelMixin
21
  from huggingface_hub import hf_hub_download
 
67
  self.up_blocks = nn.ModuleList([nn.ModuleList([ResBlock(widths[i], DILATION_CYCLE[j % len(DILATION_CYCLE)]) for j in range(up_depths[i])]) for i in range(L - 1)])
68
  self.norm_out = ChannelRMSNorm(widths[0])
69
  self.conv_out = nn.Conv2d(widths[0], out_ch, 3, padding=1)
70
+ # set by ModelMixin.enable_gradient_checkpointing(); per ResBlock, only while grad is enabled
71
+ self.gradient_checkpointing = False
72
+ self._gradient_checkpointing_func = lambda blk, x: torch.utils.checkpoint.checkpoint(blk, x, use_reentrant=False)
73
+
74
+ def _block(self, blk: ResBlock, x: torch.Tensor) -> torch.Tensor:
75
+ if self.gradient_checkpointing and torch.is_grad_enabled():
76
+ return self._gradient_checkpointing_func(blk, x)
77
+ return blk(x)
78
 
79
  def forward(self, x: torch.Tensor) -> torch.Tensor:
80
  x = self.conv_in(x)
 
82
  L = len(self.down_blocks)
83
  for i in range(L):
84
  for blk in self.down_blocks[i]:
85
+ x = self._block(blk, x)
86
  if i < L - 1:
87
  skips.append(x)
88
  x = self.downs[i](F.pixel_unshuffle(x, 2))
89
  for i in reversed(range(L - 1)):
90
  x = F.pixel_shuffle(self.ups[i](x), 2) + skips[i]
91
  for blk in self.up_blocks[i]:
92
+ x = self._block(blk, x)
93
  return self.conv_out(F.silu(self.norm_out(x)))
94
 
95
 
 
97
  """Primal VAE: `encode` -> [B, latent_channels, H/compression, W/compression] (~N(0,1)), `decode` back to
98
  [B, 3, H, W] in [-1, 1]. No posterior, no scaling/shift factor."""
99
 
100
+ _supports_gradient_checkpointing = True
101
+
102
  @register_to_config
103
  def __init__(
104
  self,