BiliSakura commited on
Commit
cec62b3
·
verified ·
1 Parent(s): 3765616

Update JiT-B-16-SIM/transformer/jit_transformer_2d.py

Browse files
JiT-B-16-SIM/transformer/jit_transformer_2d.py ADDED
@@ -0,0 +1,559 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2026 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import math
16
+
17
+ import numpy as np
18
+ import torch
19
+ import torch.nn as nn
20
+ import torch.nn.functional as F
21
+
22
+ from diffusers.configuration_utils import ConfigMixin, register_to_config
23
+ from diffusers.models.modeling_outputs import Transformer2DModelOutput
24
+ from diffusers.models.modeling_utils import ModelMixin
25
+ from diffusers.models.normalization import RMSNorm
26
+ from diffusers.utils import logging
27
+
28
+ logger = logging.get_logger(__name__)
29
+
30
+
31
+
32
+ def broadcat(tensors, dim=-1):
33
+ num_tensors = len(tensors)
34
+ shape_lens = {len(t.shape) for t in tensors}
35
+ if len(shape_lens) != 1:
36
+ raise ValueError("tensors must all have the same number of dimensions")
37
+ shape_len = list(shape_lens)[0]
38
+ dim = (dim + shape_len) if dim < 0 else dim
39
+ dims = list(zip(*(list(t.shape) for t in tensors)))
40
+ expandable_dims = [(i, val) for i, val in enumerate(dims) if i != dim]
41
+
42
+ if not all(len(set(t[1])) <= 2 for t in expandable_dims):
43
+ raise ValueError("invalid dimensions for broadcastable concatenation")
44
+
45
+ max_dims = [(t[0], max(t[1])) for t in expandable_dims]
46
+ expanded_dims = [(t[0], (t[1],) * num_tensors) for t in max_dims]
47
+ expanded_dims.insert(dim, (dim, dims[dim]))
48
+ expandable_shapes = list(zip(*(t[1] for t in expanded_dims)))
49
+ tensors = [t[0].expand(*t[1]) for t in zip(tensors, expandable_shapes)]
50
+ return torch.cat(tensors, dim=dim)
51
+
52
+
53
+ def rotate_half(x):
54
+ x = x.view(*x.shape[:-1], x.shape[-1] // 2, 2)
55
+ x1, x2 = x.unbind(dim=-1)
56
+ x = torch.stack((-x2, x1), dim=-1)
57
+ return x.view(*x.shape[:-2], -1)
58
+
59
+
60
+ class JiTRotaryEmbedding(nn.Module):
61
+ def __init__(
62
+ self,
63
+ dim,
64
+ pt_seq_len=16,
65
+ ft_seq_len=None,
66
+ custom_freqs=None,
67
+ theta=10000,
68
+ num_cls_token=0,
69
+ ):
70
+ super().__init__()
71
+ self.dim = dim
72
+ self.pt_seq_len = pt_seq_len
73
+ self.theta = theta
74
+ self.num_cls_token = num_cls_token
75
+ self.custom_freqs = custom_freqs
76
+ if ft_seq_len is None:
77
+ ft_seq_len = pt_seq_len
78
+ self._cached_hw = None
79
+ cos, sin = self._build_freqs(ft_seq_len, ft_seq_len, device=torch.device("cpu"))
80
+ self.register_buffer("freqs_cos", cos, persistent=False)
81
+ self.register_buffer("freqs_sin", sin, persistent=False)
82
+ self._cached_hw = (ft_seq_len, ft_seq_len)
83
+
84
+ def _build_freqs(self, height, width, device):
85
+ if self.custom_freqs is not None:
86
+ freqs = self.custom_freqs.to(device=device, dtype=torch.float32)
87
+ else:
88
+ freqs = 1.0 / (
89
+ self.theta ** (torch.arange(0, self.dim, 2, device=device, dtype=torch.float32)[: (self.dim // 2)] / self.dim)
90
+ )
91
+
92
+ t_h = torch.arange(height, device=device, dtype=torch.float32) / height * self.pt_seq_len
93
+ t_w = torch.arange(width, device=device, dtype=torch.float32) / width * self.pt_seq_len
94
+ freqs_h = torch.einsum("..., f -> ... f", t_h, freqs).repeat_interleave(2, dim=-1)
95
+ freqs_w = torch.einsum("..., f -> ... f", t_w, freqs).repeat_interleave(2, dim=-1)
96
+ freqs_2d = broadcat((freqs_h[:, None, :], freqs_w[None, :, :]), dim=-1)
97
+ freqs_flat = freqs_2d.view(-1, freqs_2d.shape[-1])
98
+ cos_img = freqs_flat.cos()
99
+ sin_img = freqs_flat.sin()
100
+ if self.num_cls_token > 0:
101
+ _, dim_freq = cos_img.shape
102
+ cos_pad = torch.ones(self.num_cls_token, dim_freq, dtype=cos_img.dtype, device=device)
103
+ sin_pad = torch.zeros(self.num_cls_token, dim_freq, dtype=sin_img.dtype, device=device)
104
+ cos_img = torch.cat([cos_pad, cos_img], dim=0)
105
+ sin_img = torch.cat([sin_pad, sin_img], dim=0)
106
+ return cos_img, sin_img
107
+
108
+ def forward(self, t, height=None, width=None):
109
+ # Applied on (batch, seq_len, heads, head_dim) tensors from attention.
110
+ seq_len = t.shape[1]
111
+ if height is None or width is None:
112
+ image_tokens = seq_len - self.num_cls_token
113
+ size = int(image_tokens**0.5)
114
+ if size * size != image_tokens:
115
+ raise ValueError(
116
+ f"Cannot infer square token grid from sequence length {seq_len} with {self.num_cls_token} class tokens."
117
+ )
118
+ height = size
119
+ width = size
120
+ if self._cached_hw != (height, width) or self.freqs_cos.device != t.device:
121
+ self.freqs_cos, self.freqs_sin = self._build_freqs(height, width, device=t.device)
122
+ self._cached_hw = (height, width)
123
+ freqs_cos = self.freqs_cos[:seq_len].to(t.dtype)
124
+ freqs_sin = self.freqs_sin[:seq_len].to(t.dtype)
125
+
126
+ return t * freqs_cos[:, None, :] + rotate_half(t) * freqs_sin[:, None, :]
127
+
128
+
129
+ def modulate(x, shift, scale):
130
+ return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
131
+
132
+
133
+ class JiTPatchEmbed(nn.Module):
134
+ """Image to Patch Embedding with Bottleneck"""
135
+
136
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, pca_dim=768, embed_dim=768, bias=True):
137
+ super().__init__()
138
+ img_size = (img_size, img_size)
139
+ patch_size = (patch_size, patch_size)
140
+ self.img_size = img_size
141
+ self.patch_size = patch_size
142
+ self.num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0])
143
+
144
+ self.proj1 = nn.Conv2d(in_chans, pca_dim, kernel_size=patch_size, stride=patch_size, bias=False)
145
+ self.proj2 = nn.Conv2d(pca_dim, embed_dim, kernel_size=1, stride=1, bias=bias)
146
+
147
+ def forward(self, x):
148
+ x = self.proj2(self.proj1(x)).flatten(2).transpose(1, 2)
149
+ return x
150
+
151
+
152
+ class JiTTimestepEmbedder(nn.Module):
153
+ """
154
+ Embeds scalar timesteps into vector representations.
155
+ """
156
+
157
+ def __init__(self, hidden_size, frequency_embedding_size=256):
158
+ super().__init__()
159
+ self.mlp = nn.Sequential(
160
+ nn.Linear(frequency_embedding_size, hidden_size, bias=True),
161
+ nn.SiLU(),
162
+ nn.Linear(hidden_size, hidden_size, bias=True),
163
+ )
164
+ self.frequency_embedding_size = frequency_embedding_size
165
+
166
+ @staticmethod
167
+ def timestep_embedding(t, dim, max_period=10000):
168
+ """
169
+ Create sinusoidal timestep embeddings.
170
+ """
171
+ half = dim // 2
172
+ freqs = torch.exp(
173
+ -math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half
174
+ ).to(device=t.device)
175
+ args = t[:, None].float() * freqs[None]
176
+ embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
177
+ if dim % 2:
178
+ embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1)
179
+ return embedding
180
+
181
+ def forward(self, t, dtype=None):
182
+ t_freq = self.timestep_embedding(t, self.frequency_embedding_size)
183
+ if dtype is not None:
184
+ t_freq = t_freq.to(dtype=dtype)
185
+ t_emb = self.mlp(t_freq)
186
+ return t_emb
187
+
188
+
189
+ class JiTLabelEmbedder(nn.Module):
190
+ """
191
+ Embeds class labels into vector representations.
192
+ """
193
+
194
+ def __init__(self, num_classes, hidden_size):
195
+ super().__init__()
196
+ self.embedding_table = nn.Embedding(num_classes + 1, hidden_size)
197
+ self.num_classes = num_classes
198
+
199
+ def forward(self, labels):
200
+ embeddings = self.embedding_table(labels)
201
+ return embeddings
202
+
203
+
204
+ class JiTAttention(nn.Module):
205
+ def __init__(self, dim, num_heads=8, qkv_bias=True, qk_norm=True, attn_drop=0.0, proj_drop=0.0, eps=1e-6):
206
+ super().__init__()
207
+ self.num_heads = num_heads
208
+ head_dim = dim // num_heads
209
+
210
+ self.q_norm = RMSNorm(head_dim, eps=eps) if qk_norm else nn.Identity()
211
+ self.k_norm = RMSNorm(head_dim, eps=eps) if qk_norm else nn.Identity()
212
+
213
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
214
+ self.attn_drop = attn_drop
215
+ self.proj = nn.Linear(dim, dim)
216
+ self.proj_drop = nn.Dropout(proj_drop)
217
+
218
+ def forward(self, x, rope=None, grid_height=None, grid_width=None):
219
+ B, N, C = x.shape
220
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
221
+ q, k, v = qkv[0], qkv[1], qkv[2]
222
+
223
+ q = self.q_norm(q)
224
+ k = self.k_norm(k)
225
+
226
+ if rope is not None:
227
+ q = q.transpose(1, 2)
228
+ k = k.transpose(1, 2)
229
+ q = rope(q, height=grid_height, width=grid_width)
230
+ k = rope(k, height=grid_height, width=grid_width)
231
+ q = q.transpose(1, 2)
232
+ k = k.transpose(1, 2)
233
+
234
+ dropout_p = self.attn_drop if self.training else 0.0
235
+ x = F.scaled_dot_product_attention(q, k, v, dropout_p=dropout_p)
236
+ x = x.transpose(1, 2).reshape(B, N, C)
237
+ x = self.proj(x)
238
+ x = self.proj_drop(x)
239
+ return x
240
+
241
+
242
+ class JiTSwiGLUFFN(nn.Module):
243
+ def __init__(self, dim: int, hidden_dim: int, drop=0.0, bias=True) -> None:
244
+ super().__init__()
245
+ hidden_dim = int(hidden_dim * 2 / 3)
246
+ self.w12 = nn.Linear(dim, 2 * hidden_dim, bias=bias)
247
+ self.w3 = nn.Linear(hidden_dim, dim, bias=bias)
248
+ self.ffn_dropout = nn.Dropout(drop)
249
+
250
+ def forward(self, x):
251
+ x12 = self.w12(x)
252
+ x1, x2 = x12.chunk(2, dim=-1)
253
+ hidden = F.silu(x1) * x2
254
+ return self.w3(self.ffn_dropout(hidden))
255
+
256
+
257
+ class JiTBlock(nn.Module):
258
+ def __init__(self, hidden_size, num_heads, mlp_ratio=4.0, attn_drop=0.0, proj_drop=0.0, eps=1e-6):
259
+ super().__init__()
260
+ self.norm1 = RMSNorm(hidden_size, eps=eps)
261
+ self.attn = JiTAttention(
262
+ hidden_size,
263
+ num_heads=num_heads,
264
+ qkv_bias=True,
265
+ qk_norm=True,
266
+ attn_drop=attn_drop,
267
+ proj_drop=proj_drop,
268
+ eps=eps,
269
+ )
270
+ self.norm2 = RMSNorm(hidden_size, eps=eps)
271
+ mlp_hidden_dim = int(hidden_size * mlp_ratio)
272
+ self.mlp = JiTSwiGLUFFN(hidden_size, mlp_hidden_dim, drop=proj_drop)
273
+
274
+ self.act = nn.SiLU()
275
+ self.adaLN_modulation = nn.Linear(hidden_size, 6 * hidden_size, bias=True)
276
+
277
+ def forward(self, x, c, feat_rope=None, grid_height=None, grid_width=None):
278
+ # Apply activation
279
+ c = self.act(c)
280
+
281
+ shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.adaLN_modulation(c).chunk(6, dim=-1)
282
+
283
+ # Attention block
284
+ norm_x = self.norm1(x)
285
+ modulated_x = modulate(norm_x, shift_msa, scale_msa)
286
+ attn_out = self.attn(modulated_x, rope=feat_rope, grid_height=grid_height, grid_width=grid_width)
287
+ x = x + gate_msa.unsqueeze(1) * attn_out
288
+
289
+ # MLP block
290
+ norm_x = self.norm2(x)
291
+ modulated_x = modulate(norm_x, shift_mlp, scale_mlp)
292
+ mlp_out = self.mlp(modulated_x)
293
+ x = x + gate_mlp.unsqueeze(1) * mlp_out
294
+
295
+ return x
296
+
297
+
298
+ def get_2d_sincos_pos_embed(embed_dim, grid_size, cls_token=False, extra_tokens=0):
299
+ grid_h = np.arange(grid_size, dtype=np.float32)
300
+ grid_w = np.arange(grid_size, dtype=np.float32)
301
+ grid = np.meshgrid(grid_w, grid_h)
302
+ grid = np.stack(grid, axis=0)
303
+ grid = grid.reshape([2, 1, grid_size, grid_size])
304
+ pos_embed = get_2d_sincos_pos_embed_from_grid(embed_dim, grid)
305
+ if cls_token and extra_tokens > 0:
306
+ pos_embed = np.concatenate([np.zeros([extra_tokens, embed_dim]), pos_embed], axis=0)
307
+ return pos_embed
308
+
309
+
310
+ def get_2d_sincos_pos_embed_from_grid(embed_dim, grid):
311
+ if embed_dim % 2 != 0:
312
+ raise ValueError(f"embed_dim must be divisible by 2, but got {embed_dim}")
313
+
314
+ emb_h = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[0])
315
+ emb_w = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[1])
316
+ emb = np.concatenate([emb_h, emb_w], axis=1)
317
+ return emb
318
+
319
+
320
+ def get_1d_sincos_pos_embed_from_grid(embed_dim, pos):
321
+ if embed_dim % 2 != 0:
322
+ raise ValueError(f"embed_dim must be divisible by 2, but got {embed_dim}")
323
+
324
+ omega = np.arange(embed_dim // 2, dtype=np.float64)
325
+ omega /= embed_dim / 2.0
326
+ omega = 1.0 / 10000**omega
327
+
328
+ pos = pos.reshape(-1)
329
+ out = np.einsum("m,d->md", pos, omega)
330
+
331
+ emb_sin = np.sin(out)
332
+ emb_cos = np.cos(out)
333
+
334
+ emb = np.concatenate([emb_sin, emb_cos], axis=1)
335
+ return emb
336
+
337
+
338
+ class JiTTransformer2DModel(ModelMixin, ConfigMixin):
339
+ r"""
340
+ A 2D Transformer for pixel-space class-conditional generation with JiT
341
+ ([Back to Basics: Let Denoising Generative Models Denoise](https://arxiv.org/abs/2511.13720)).
342
+
343
+ Parameters:
344
+ sample_size (`int`, defaults to `256`):
345
+ Input image resolution (height and width).
346
+ patch_size (`int`, defaults to `16`):
347
+ Patch size for the bottleneck patch embedder.
348
+ in_channels (`int`, defaults to `3`):
349
+ Number of input image channels.
350
+ hidden_size (`int`, defaults to `768`):
351
+ Transformer hidden dimension.
352
+ num_layers (`int`, defaults to `12`):
353
+ Number of JiT transformer blocks.
354
+ num_attention_heads (`int`, defaults to `12`):
355
+ Number of attention heads per block.
356
+ mlp_ratio (`float`, defaults to `4.0`):
357
+ MLP hidden dimension multiplier.
358
+ attention_dropout (`float`, defaults to `0.0`):
359
+ Attention dropout in the middle quarter of blocks.
360
+ dropout (`float`, defaults to `0.0`):
361
+ Projection dropout in the middle quarter of blocks.
362
+ num_classes (`int`, defaults to `1000`):
363
+ Number of class labels (null label uses index `num_classes` for CFG).
364
+ bottleneck_dim (`int`, defaults to `128`):
365
+ PCA bottleneck dimension in the patch embedder.
366
+ in_context_len (`int`, defaults to `32`):
367
+ Number of in-context class tokens prepended mid-network.
368
+ in_context_start (`int`, defaults to `4`):
369
+ Block index at which in-context tokens are inserted.
370
+ norm_eps (`float`, defaults to `1e-6`):
371
+ Epsilon for RMSNorm layers.
372
+ """
373
+
374
+ _supports_gradient_checkpointing = True
375
+ _skip_layerwise_casting_patterns = ["pos_embed", "norm"]
376
+
377
+ @register_to_config
378
+ def __init__(
379
+ self,
380
+ sample_size: int = 256,
381
+ patch_size: int = 16,
382
+ in_channels: int = 3,
383
+ hidden_size: int = 768,
384
+ num_layers: int = 12,
385
+ num_attention_heads: int = 12,
386
+ mlp_ratio: float = 4.0,
387
+ attention_dropout: float = 0.0,
388
+ dropout: float = 0.0,
389
+ num_classes: int = 1000,
390
+ bottleneck_dim: int = 128,
391
+ in_context_len: int = 32,
392
+ in_context_start: int = 4,
393
+ norm_eps: float = 1e-6,
394
+ ):
395
+ super().__init__()
396
+ self.sample_size = sample_size
397
+ self.patch_size = patch_size
398
+ self.in_channels = in_channels
399
+ self.out_channels = in_channels
400
+ self.hidden_size = hidden_size
401
+ self.num_layers = num_layers
402
+ self.num_attention_heads = num_attention_heads
403
+ self.in_context_len = in_context_len
404
+ self.in_context_start = in_context_start
405
+ self.norm_eps = norm_eps
406
+ self.gradient_checkpointing = False
407
+
408
+ # Time and Class Embedding
409
+ self.t_embedder = JiTTimestepEmbedder(hidden_size)
410
+ self.y_embedder = JiTLabelEmbedder(num_classes, hidden_size)
411
+
412
+ # Patch Embedding
413
+ self.x_embedder = JiTPatchEmbed(
414
+ img_size=sample_size,
415
+ patch_size=patch_size,
416
+ in_chans=in_channels,
417
+ pca_dim=bottleneck_dim,
418
+ embed_dim=hidden_size,
419
+ bias=True,
420
+ )
421
+
422
+ # Positional Embedding (Fixed Sin-Cos)
423
+ num_patches = self.x_embedder.num_patches
424
+ pos_embed = get_2d_sincos_pos_embed(hidden_size, int(num_patches**0.5))
425
+ self.register_buffer("pos_embed", torch.from_numpy(pos_embed).float().unsqueeze(0), persistent=True)
426
+
427
+ # In-context Embedding
428
+ if self.in_context_len > 0:
429
+ self.in_context_posemb = nn.Parameter(torch.zeros(1, self.in_context_len, hidden_size))
430
+
431
+ # RoPE
432
+ half_head_dim = hidden_size // num_attention_heads // 2
433
+ hw_seq_len = sample_size // patch_size
434
+ self.feat_rope = JiTRotaryEmbedding(dim=half_head_dim, pt_seq_len=hw_seq_len, num_cls_token=0)
435
+ self.feat_rope_incontext = JiTRotaryEmbedding(
436
+ dim=half_head_dim, pt_seq_len=hw_seq_len, num_cls_token=self.in_context_len
437
+ )
438
+
439
+ # Blocks
440
+ self.blocks = nn.ModuleList(
441
+ [
442
+ JiTBlock(
443
+ hidden_size,
444
+ num_attention_heads,
445
+ mlp_ratio=mlp_ratio,
446
+ attn_drop=attention_dropout if (num_layers // 4 * 3 > i >= num_layers // 4) else 0.0,
447
+ proj_drop=dropout if (num_layers // 4 * 3 > i >= num_layers // 4) else 0.0,
448
+ eps=norm_eps,
449
+ )
450
+ for i in range(num_layers)
451
+ ]
452
+ )
453
+
454
+ # Final Layer
455
+ self.norm_final = RMSNorm(hidden_size, eps=norm_eps)
456
+ self.linear_final = nn.Linear(hidden_size, patch_size * patch_size * self.out_channels, bias=True)
457
+ self.act_final = nn.SiLU()
458
+ self.adaLN_modulation_final = nn.Linear(hidden_size, 2 * hidden_size, bias=True)
459
+
460
+ def _get_patch_grid(self, hidden_states):
461
+ height, width = hidden_states.shape[-2:]
462
+ if height % self.patch_size != 0 or width % self.patch_size != 0:
463
+ raise ValueError(
464
+ f"Input size {(height, width)} must be divisible by patch_size={self.patch_size}."
465
+ )
466
+ return height // self.patch_size, width // self.patch_size
467
+
468
+ def _interpolate_pos_encoding(self, tokens, grid_height, grid_width):
469
+ num_tokens = grid_height * grid_width
470
+ if self.pos_embed.shape[1] == num_tokens:
471
+ return self.pos_embed.to(device=tokens.device, dtype=tokens.dtype)
472
+ base_size = int(self.pos_embed.shape[1] ** 0.5)
473
+ pos_embed = self.pos_embed.reshape(1, base_size, base_size, self.hidden_size).permute(0, 3, 1, 2)
474
+ pos_embed = F.interpolate(pos_embed, size=(grid_height, grid_width), mode="bicubic", align_corners=False)
475
+ pos_embed = pos_embed.permute(0, 2, 3, 1).reshape(1, num_tokens, self.hidden_size)
476
+ return pos_embed.to(device=tokens.device, dtype=tokens.dtype)
477
+
478
+ def forward(
479
+ self,
480
+ hidden_states: torch.Tensor,
481
+ timestep: torch.LongTensor,
482
+ class_labels: torch.LongTensor,
483
+ interpolate_pos_encoding: bool = True,
484
+ return_dict: bool = True,
485
+ ):
486
+
487
+ t_emb = self.t_embedder(timestep, dtype=hidden_states.dtype)
488
+ y_emb = self.y_embedder(class_labels)
489
+
490
+ # Ensure embeddings match hidden_states dtype
491
+ y_emb = y_emb.to(dtype=hidden_states.dtype)
492
+
493
+ c = t_emb + y_emb
494
+
495
+ # Patch Embed
496
+ grid_height, grid_width = self._get_patch_grid(hidden_states)
497
+ x = self.x_embedder(hidden_states)
498
+ if interpolate_pos_encoding:
499
+ pos_embed = self._interpolate_pos_encoding(x, grid_height, grid_width)
500
+ else:
501
+ expected_tokens = grid_height * grid_width
502
+ if self.pos_embed.shape[1] != expected_tokens:
503
+ raise ValueError(
504
+ f"pos_embed token count {self.pos_embed.shape[1]} does not match input token count {expected_tokens}. "
505
+ "Enable interpolate_pos_encoding for dynamic resolutions."
506
+ )
507
+ pos_embed = self.pos_embed.to(device=x.device, dtype=x.dtype)
508
+ x = x + pos_embed
509
+
510
+ # Blocks
511
+ for i, block in enumerate(self.blocks):
512
+ if self.in_context_len > 0 and i == self.in_context_start:
513
+ in_context_tokens = y_emb.unsqueeze(1).repeat(1, self.in_context_len, 1)
514
+ in_context_tokens = in_context_tokens + self.in_context_posemb.to(in_context_tokens.dtype)
515
+ x = torch.cat([in_context_tokens, x], dim=1)
516
+
517
+ rope = self.feat_rope if i < self.in_context_start else self.feat_rope_incontext
518
+
519
+ if self.training and self.gradient_checkpointing:
520
+ def custom_forward(current_x, current_c):
521
+ return block(
522
+ current_x,
523
+ current_c,
524
+ feat_rope=rope,
525
+ grid_height=grid_height,
526
+ grid_width=grid_width,
527
+ )
528
+
529
+ x = torch.utils.checkpoint.checkpoint(
530
+ custom_forward,
531
+ x,
532
+ c,
533
+ use_reentrant=False,
534
+ )
535
+ else:
536
+ x = block(x, c, feat_rope=rope, grid_height=grid_height, grid_width=grid_width)
537
+
538
+ # Slice off in-context tokens
539
+ if self.in_context_len > 0:
540
+ x = x[:, self.in_context_len :]
541
+
542
+ # Final Layer
543
+ c = self.act_final(c)
544
+ shift, scale = self.adaLN_modulation_final(c).chunk(2, dim=1)
545
+
546
+ x = modulate(self.norm_final(x), shift, scale)
547
+ x = self.linear_final(x)
548
+
549
+ # Unpatchify
550
+ x = x.reshape(shape=(x.shape[0], grid_height, grid_width, self.patch_size, self.patch_size, self.out_channels))
551
+ x = torch.einsum("nhwpqc->nchpwq", x)
552
+ output = x.reshape(
553
+ shape=(x.shape[0], self.out_channels, grid_height * self.patch_size, grid_width * self.patch_size)
554
+ )
555
+
556
+ if not return_dict:
557
+ return (output,)
558
+
559
+ return Transformer2DModelOutput(sample=output)