Enabling gradient checkpointing for VAE (#2536) · huamichaelchen/diffusers@116f70c · GitHub
Skip to content

Commit 116f70c

Browse files
aandywpatrickvonplatenwilliamberman
authored
Enabling gradient checkpointing for VAE (huggingface#2536)
* updated black format * update black format * make style format * updated line endings * update code formatting * Update examples/research_projects/onnxruntime/text_to_image/train_text_to_image.py Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com> * Update src/diffusers/models/vae.py Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com> * Update src/diffusers/models/vae.py Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com> * added vae gradient checkpointing test * make style --------- Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com> Co-authored-by: Will Berman <wlbberman@gmail.com>
1 parent a169571 commit 116f70c

5 files changed

Lines changed: 108 additions & 15 deletions

File tree

‎examples/research_projects/onnxruntime/text_to_image/train_text_to_image.py‎

Lines changed: 1 addition & 0 deletions

‎src/diffusers/models/autoencoder_kl.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class AutoencoderKL(ModelMixin, ConfigMixin):
6565
Synthesis with Latent Diffusion Models](https://arxiv.org/abs/2112.10752) paper.
6666
"""
6767

68+
_supports_gradient_checkpointing = True
69+
6870
@register_to_config
6971
def __init__(
7072
self,
@@ -121,6 +123,10 @@ def __init__(
121123
self.tile_latent_min_size = int(sample_size / (2 ** (len(self.block_out_channels) - 1)))
122124
self.tile_overlap_factor = 0.25
123125

126+
def _set_gradient_checkpointing(self, module, value=False):
127+
if isinstance(module, (Encoder, Decoder)):
128+
module.gradient_checkpointing = value
129+
124130
def enable_tiling(self, use_tiling: bool = True):
125131
r"""
126132
Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to

‎src/diffusers/models/cross_attention.py‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
SlicedAttnProcessor,
2525
XFormersAttnProcessor,
2626
)
27-
from .attention_processor import ( # noqa: F401
28-
AttnProcessor as AttnProcessorRename,
29-
)
27+
from .attention_processor import AttnProcessor as AttnProcessorRename # noqa: F401
3028

3129

3230
deprecate(

‎src/diffusers/models/vae.py‎

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ def __init__(
5050
super().__init__()
5151
self.layers_per_block = layers_per_block
5252

53-
self.conv_in = torch.nn.Conv2d(in_channels, block_out_channels[0], kernel_size=3, stride=1, padding=1)
53+
self.conv_in = torch.nn.Conv2d(
54+
in_channels,
55+
block_out_channels[0],
56+
kernel_size=3,
57+
stride=1,
58+
padding=1,
59+
)
5460

5561
self.mid_block = None
5662
self.down_blocks = nn.ModuleList([])
@@ -96,16 +102,34 @@ def __init__(
96102
conv_out_channels = 2 * out_channels if double_z else out_channels
97103
self.conv_out = nn.Conv2d(block_out_channels[-1], conv_out_channels, 3, padding=1)
98104

105+
self.gradient_checkpointing = False
106+
99107
def forward(self, x):
100108
sample = x
101109
sample = self.conv_in(sample)
102110

103-
# down
104-
for down_block in self.down_blocks:
105-
sample = down_block(sample)
111+
if self.training and self.gradient_checkpointing:
112+
113+
def create_custom_forward(module):
114+
def custom_forward(*inputs):
115+
return module(*inputs)
116+
117+
return custom_forward
118+
119+
# down
120+
for down_block in self.down_blocks:
121+
sample = torch.utils.checkpoint.checkpoint(create_custom_forward(down_block), sample)
122+
123+
# middle
124+
sample = torch.utils.checkpoint.checkpoint(create_custom_forward(self.mid_block), sample)
125+
126+
else:
127+
# down
128+
for down_block in self.down_blocks:
129+
sample = down_block(sample)
106130

107-
# middle
108-
sample = self.mid_block(sample)
131+
# middle
132+
sample = self.mid_block(sample)
109133

110134
# post-process
111135
sample = self.conv_norm_out(sample)
@@ -129,7 +153,13 @@ def __init__(
129153
super().__init__()
130154
self.layers_per_block = layers_per_block
131155

132-
self.conv_in = nn.Conv2d(in_channels, block_out_channels[-1], kernel_size=3, stride=1, padding=1)
156+
self.conv_in = nn.Conv2d(
157+
in_channels,
158+
block_out_channels[-1],
159+
kernel_size=3,
160+
stride=1,
161+
padding=1,
162+
)
133163

134164
self.mid_block = None
135165
self.up_blocks = nn.ModuleList([])
@@ -176,16 +206,33 @@ def __init__(
176206
self.conv_act = nn.SiLU()
177207
self.conv_out = nn.Conv2d(block_out_channels[0], out_channels, 3, padding=1)
178208

209+
self.gradient_checkpointing = False
210+
179211
def forward(self, z):
180212
sample = z
181213
sample = self.conv_in(sample)
182214

183-
# middle
184-
sample = self.mid_block(sample)
215+
if self.training and self.gradient_checkpointing:
185216

186-
# up
187-
for up_block in self.up_blocks:
188-
sample = up_block(sample)
217+
def create_custom_forward(module):
218+
def custom_forward(*inputs):
219+
return module(*inputs)
220+
221+
return custom_forward
222+
223+
# middle
224+
sample = torch.utils.checkpoint.checkpoint(create_custom_forward(self.mid_block), sample)
225+
226+
# up
227+
for up_block in self.up_blocks:
228+
sample = torch.utils.checkpoint.checkpoint(create_custom_forward(up_block), sample)
229+
else:
230+
# middle
231+
sample = self.mid_block(sample)
232+
233+
# up
234+
for up_block in self.up_blocks:
235+
sample = up_block(sample)
189236

190237
# post-process
191238
sample = self.conv_norm_out(sample)

‎tests/models/test_models_vae.py‎

Lines changed: 41 additions & 0 deletions

0 commit comments

Comments
 (0)