comdoleger commited on
Commit
1951d8b
·
verified ·
1 Parent(s): c832837

Upload extensions_built_in/diffusion_models/chroma/src/layers.py with huggingface_hub

Browse files
extensions_built_in/diffusion_models/chroma/src/layers.py ADDED
@@ -0,0 +1,719 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from dataclasses import dataclass
3
+
4
+ import torch
5
+ from einops import rearrange
6
+ from torch import Tensor, nn
7
+ import torch.nn.functional as F
8
+
9
+ from .math import attention, rope
10
+ from functools import lru_cache
11
+
12
+
13
+ class EmbedND(nn.Module):
14
+ def __init__(self, dim: int, theta: int, axes_dim: list[int]):
15
+ super().__init__()
16
+ self.dim = dim
17
+ self.theta = theta
18
+ self.axes_dim = axes_dim
19
+
20
+ def forward(self, ids: Tensor) -> Tensor:
21
+ n_axes = ids.shape[-1]
22
+ emb = torch.cat(
23
+ [rope(ids[..., i], self.axes_dim[i], self.theta) for i in range(n_axes)],
24
+ dim=-3,
25
+ )
26
+
27
+ return emb.unsqueeze(1)
28
+
29
+
30
+ def timestep_embedding(t: Tensor, dim, max_period=10000, time_factor: float = 1000.0):
31
+ """
32
+ Create sinusoidal timestep embeddings.
33
+ :param t: a 1-D Tensor of N indices, one per batch element.
34
+ These may be fractional.
35
+ :param dim: the dimension of the output.
36
+ :param max_period: controls the minimum frequency of the embeddings.
37
+ :return: an (N, D) Tensor of positional embeddings.
38
+ """
39
+ t = time_factor * t
40
+ half = dim // 2
41
+ freqs = torch.exp(
42
+ -math.log(max_period)
43
+ * torch.arange(start=0, end=half, dtype=torch.float32)
44
+ / half
45
+ ).to(t.device)
46
+
47
+ args = t[:, None].float() * freqs[None]
48
+ embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
49
+ if dim % 2:
50
+ embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1)
51
+ if torch.is_floating_point(t):
52
+ embedding = embedding.to(t)
53
+ return embedding
54
+
55
+
56
+ class MLPEmbedder(nn.Module):
57
+ def __init__(self, in_dim: int, hidden_dim: int):
58
+ super().__init__()
59
+ self.in_layer = nn.Linear(in_dim, hidden_dim, bias=True)
60
+ self.silu = nn.SiLU()
61
+ self.out_layer = nn.Linear(hidden_dim, hidden_dim, bias=True)
62
+
63
+ @property
64
+ def device(self):
65
+ # Get the device of the module (assumes all parameters are on the same device)
66
+ return next(self.parameters()).device
67
+
68
+ def forward(self, x: Tensor) -> Tensor:
69
+ return self.out_layer(self.silu(self.in_layer(x)))
70
+
71
+
72
+ class RMSNorm(torch.nn.Module):
73
+ def __init__(self, dim: int, use_compiled: bool = False):
74
+ super().__init__()
75
+ self.scale = nn.Parameter(torch.ones(dim))
76
+ self.use_compiled = use_compiled
77
+
78
+ def _forward(self, x: Tensor):
79
+ x_dtype = x.dtype
80
+ x = x.float()
81
+ rrms = torch.rsqrt(torch.mean(x**2, dim=-1, keepdim=True) + 1e-6)
82
+ return (x * rrms).to(dtype=x_dtype) * self.scale
83
+
84
+ def forward(self, x: Tensor):
85
+ return F.rms_norm(x, self.scale.shape, weight=self.scale, eps=1e-6)
86
+ # if self.use_compiled:
87
+ # return torch.compile(self._forward)(x)
88
+ # else:
89
+ # return self._forward(x)
90
+
91
+
92
+ def distribute_modulations(tensor: torch.Tensor, depth_single_blocks, depth_double_blocks):
93
+ """
94
+ Distributes slices of the tensor into the block_dict as ModulationOut objects.
95
+
96
+ Args:
97
+ tensor (torch.Tensor): Input tensor with shape [batch_size, vectors, dim].
98
+ """
99
+ batch_size, vectors, dim = tensor.shape
100
+
101
+ block_dict = {}
102
+
103
+ # HARD CODED VALUES! lookup table for the generated vectors
104
+ # TODO: move this into chroma config!
105
+ # Add 38 single mod blocks
106
+ for i in range(depth_single_blocks):
107
+ key = f"single_blocks.{i}.modulation.lin"
108
+ block_dict[key] = None
109
+
110
+ # Add 19 image double blocks
111
+ for i in range(depth_double_blocks):
112
+ key = f"double_blocks.{i}.img_mod.lin"
113
+ block_dict[key] = None
114
+
115
+ # Add 19 text double blocks
116
+ for i in range(depth_double_blocks):
117
+ key = f"double_blocks.{i}.txt_mod.lin"
118
+ block_dict[key] = None
119
+
120
+ # Add the final layer
121
+ block_dict["final_layer.adaLN_modulation.1"] = None
122
+ # 6.2b version
123
+ # block_dict["lite_double_blocks.4.img_mod.lin"] = None
124
+ # block_dict["lite_double_blocks.4.txt_mod.lin"] = None
125
+
126
+ idx = 0 # Index to keep track of the vector slices
127
+
128
+ for key in block_dict.keys():
129
+ if "single_blocks" in key:
130
+ # Single block: 1 ModulationOut
131
+ block_dict[key] = ModulationOut(
132
+ shift=tensor[:, idx : idx + 1, :],
133
+ scale=tensor[:, idx + 1 : idx + 2, :],
134
+ gate=tensor[:, idx + 2 : idx + 3, :],
135
+ )
136
+ idx += 3 # Advance by 3 vectors
137
+
138
+ elif "img_mod" in key:
139
+ # Double block: List of 2 ModulationOut
140
+ double_block = []
141
+ for _ in range(2): # Create 2 ModulationOut objects
142
+ double_block.append(
143
+ ModulationOut(
144
+ shift=tensor[:, idx : idx + 1, :],
145
+ scale=tensor[:, idx + 1 : idx + 2, :],
146
+ gate=tensor[:, idx + 2 : idx + 3, :],
147
+ )
148
+ )
149
+ idx += 3 # Advance by 3 vectors per ModulationOut
150
+ block_dict[key] = double_block
151
+
152
+ elif "txt_mod" in key:
153
+ # Double block: List of 2 ModulationOut
154
+ double_block = []
155
+ for _ in range(2): # Create 2 ModulationOut objects
156
+ double_block.append(
157
+ ModulationOut(
158
+ shift=tensor[:, idx : idx + 1, :],
159
+ scale=tensor[:, idx + 1 : idx + 2, :],
160
+ gate=tensor[:, idx + 2 : idx + 3, :],
161
+ )
162
+ )
163
+ idx += 3 # Advance by 3 vectors per ModulationOut
164
+ block_dict[key] = double_block
165
+
166
+ elif "final_layer" in key:
167
+ # Final layer: 1 ModulationOut
168
+ block_dict[key] = [
169
+ tensor[:, idx : idx + 1, :],
170
+ tensor[:, idx + 1 : idx + 2, :],
171
+ ]
172
+ idx += 2 # Advance by 3 vectors
173
+
174
+ return block_dict
175
+
176
+
177
+
178
+ class NerfEmbedder(nn.Module):
179
+ """
180
+ An embedder module that combines input features with a 2D positional
181
+ encoding that mimics the Discrete Cosine Transform (DCT).
182
+
183
+ This module takes an input tensor of shape (B, P^2, C), where P is the
184
+ patch size, and enriches it with positional information before projecting
185
+ it to a new hidden size.
186
+ """
187
+ def __init__(self, in_channels, hidden_size_input, max_freqs):
188
+ """
189
+ Initializes the NerfEmbedder.
190
+
191
+ Args:
192
+ in_channels (int): The number of channels in the input tensor.
193
+ hidden_size_input (int): The desired dimension of the output embedding.
194
+ max_freqs (int): The number of frequency components to use for both
195
+ the x and y dimensions of the positional encoding.
196
+ The total number of positional features will be max_freqs^2.
197
+ """
198
+ super().__init__()
199
+ self.max_freqs = max_freqs
200
+ self.hidden_size_input = hidden_size_input
201
+
202
+ # A linear layer to project the concatenated input features and
203
+ # positional encodings to the final output dimension.
204
+ self.embedder = nn.Sequential(
205
+ nn.Linear(in_channels + max_freqs**2, hidden_size_input)
206
+ )
207
+
208
+ @lru_cache(maxsize=4)
209
+ def fetch_pos(self, patch_size, device, dtype):
210
+ """
211
+ Generates and caches 2D DCT-like positional embeddings for a given patch size.
212
+
213
+ The LRU cache is a performance optimization that avoids recomputing the
214
+ same positional grid on every forward pass.
215
+
216
+ Args:
217
+ patch_size (int): The side length of the square input patch.
218
+ device: The torch device to create the tensors on.
219
+ dtype: The torch dtype for the tensors.
220
+
221
+ Returns:
222
+ A tensor of shape (1, patch_size^2, max_freqs^2) containing the
223
+ positional embeddings.
224
+ """
225
+ # Create normalized 1D coordinate grids from 0 to 1.
226
+ pos_x = torch.linspace(0, 1, patch_size, device=device, dtype=dtype)
227
+ pos_y = torch.linspace(0, 1, patch_size, device=device, dtype=dtype)
228
+
229
+ # Create a 2D meshgrid of coordinates.
230
+ pos_y, pos_x = torch.meshgrid(pos_y, pos_x, indexing="ij")
231
+
232
+ # Reshape positions to be broadcastable with frequencies.
233
+ # Shape becomes (patch_size^2, 1, 1).
234
+ pos_x = pos_x.reshape(-1, 1, 1)
235
+ pos_y = pos_y.reshape(-1, 1, 1)
236
+
237
+ # Create a 1D tensor of frequency values from 0 to max_freqs-1.
238
+ freqs = torch.linspace(0, self.max_freqs - 1, self.max_freqs, dtype=dtype, device=device)
239
+
240
+ # Reshape frequencies to be broadcastable for creating 2D basis functions.
241
+ # freqs_x shape: (1, max_freqs, 1)
242
+ # freqs_y shape: (1, 1, max_freqs)
243
+ freqs_x = freqs[None, :, None]
244
+ freqs_y = freqs[None, None, :]
245
+
246
+ # A custom weighting coefficient, not part of standard DCT.
247
+ # This seems to down-weight the contribution of higher-frequency interactions.
248
+ coeffs = (1 + freqs_x * freqs_y) ** -1
249
+
250
+ # Calculate the 1D cosine basis functions for x and y coordinates.
251
+ # This is the core of the DCT formulation.
252
+ dct_x = torch.cos(pos_x * freqs_x * torch.pi)
253
+ dct_y = torch.cos(pos_y * freqs_y * torch.pi)
254
+
255
+ # Combine the 1D basis functions to create 2D basis functions by element-wise
256
+ # multiplication, and apply the custom coefficients. Broadcasting handles the
257
+ # combination of all (pos_x, freqs_x) with all (pos_y, freqs_y).
258
+ # The result is flattened into a feature vector for each position.
259
+ dct = (dct_x * dct_y * coeffs).view(1, -1, self.max_freqs ** 2)
260
+
261
+ return dct
262
+
263
+ def forward(self, inputs):
264
+ """
265
+ Forward pass for the embedder.
266
+
267
+ Args:
268
+ inputs (Tensor): The input tensor of shape (B, P^2, C).
269
+
270
+ Returns:
271
+ Tensor: The output tensor of shape (B, P^2, hidden_size_input).
272
+ """
273
+ # Get the batch size, number of pixels, and number of channels.
274
+ B, P2, C = inputs.shape
275
+ # Store the original dtype to cast back to at the end.
276
+ original_dtype = inputs.dtype
277
+ # Force all operations within this module to run in fp32.
278
+ with torch.autocast("cuda", enabled=False):
279
+ # Infer the patch side length from the number of pixels (P^2).
280
+ patch_size = int(P2 ** 0.5)
281
+
282
+ inputs = inputs.float()
283
+ # Fetch the pre-computed or cached positional embeddings.
284
+ dct = self.fetch_pos(patch_size, inputs.device, torch.float32)
285
+
286
+ # Repeat the positional embeddings for each item in the batch.
287
+ dct = dct.repeat(B, 1, 1)
288
+
289
+ # Concatenate the original input features with the positional embeddings
290
+ # along the feature dimension.
291
+ inputs = torch.cat([inputs, dct], dim=-1)
292
+
293
+ # Project the combined tensor to the target hidden size.
294
+ inputs = self.embedder.float()(inputs)
295
+
296
+ return inputs.to(original_dtype)
297
+
298
+
299
+
300
+ class NerfGLUBlock(nn.Module):
301
+ """
302
+ A NerfBlock using a Gated Linear Unit (GLU) like MLP.
303
+ """
304
+ def __init__(self, hidden_size_s, hidden_size_x, mlp_ratio, use_compiled):
305
+ super().__init__()
306
+ # The total number of parameters for the MLP is increased to accommodate
307
+ # the gate, value, and output projection matrices.
308
+ # We now need to generate parameters for 3 matrices.
309
+ total_params = 3 * hidden_size_x**2 * mlp_ratio
310
+ self.param_generator = nn.Linear(hidden_size_s, total_params)
311
+ self.norm = RMSNorm(hidden_size_x, use_compiled)
312
+ self.mlp_ratio = mlp_ratio
313
+ # nn.init.zeros_(self.param_generator.weight)
314
+ # nn.init.zeros_(self.param_generator.bias)
315
+
316
+
317
+ def forward(self, x, s):
318
+ batch_size, num_x, hidden_size_x = x.shape
319
+ mlp_params = self.param_generator(s)
320
+
321
+ # Split the generated parameters into three parts for the gate, value, and output projection.
322
+ fc1_gate_params, fc1_value_params, fc2_params = mlp_params.chunk(3, dim=-1)
323
+
324
+ # Reshape the parameters into matrices for batch matrix multiplication.
325
+ fc1_gate = fc1_gate_params.view(batch_size, hidden_size_x, hidden_size_x * self.mlp_ratio)
326
+ fc1_value = fc1_value_params.view(batch_size, hidden_size_x, hidden_size_x * self.mlp_ratio)
327
+ fc2 = fc2_params.view(batch_size, hidden_size_x * self.mlp_ratio, hidden_size_x)
328
+
329
+ # Normalize the generated weight matrices as in the original implementation.
330
+ fc1_gate = torch.nn.functional.normalize(fc1_gate, dim=-2)
331
+ fc1_value = torch.nn.functional.normalize(fc1_value, dim=-2)
332
+ fc2 = torch.nn.functional.normalize(fc2, dim=-2)
333
+
334
+ res_x = x
335
+ x = self.norm(x)
336
+
337
+ # Apply the final output projection.
338
+ x = torch.bmm(torch.nn.functional.silu(torch.bmm(x, fc1_gate)) * torch.bmm(x, fc1_value), fc2)
339
+
340
+ x = x + res_x
341
+ return x
342
+
343
+
344
+ class NerfFinalLayer(nn.Module):
345
+ def __init__(self, hidden_size, out_channels, use_compiled):
346
+ super().__init__()
347
+ self.norm = RMSNorm(hidden_size, use_compiled=use_compiled)
348
+ self.linear = nn.Linear(hidden_size, out_channels)
349
+ nn.init.zeros_(self.linear.weight)
350
+ nn.init.zeros_(self.linear.bias)
351
+
352
+ def forward(self, x):
353
+ x = self.norm(x)
354
+ x = self.linear(x)
355
+ return x
356
+
357
+
358
+ class NerfFinalLayerConv(nn.Module):
359
+ def __init__(self, hidden_size, out_channels, use_compiled):
360
+ super().__init__()
361
+ self.norm = RMSNorm(hidden_size, use_compiled=use_compiled)
362
+
363
+ # replace nn.Linear with nn.Conv2d since linear is just pointwise conv
364
+ self.conv = nn.Conv2d(
365
+ in_channels=hidden_size,
366
+ out_channels=out_channels,
367
+ kernel_size=3,
368
+ padding=1
369
+ )
370
+ nn.init.zeros_(self.conv.weight)
371
+ nn.init.zeros_(self.conv.bias)
372
+
373
+ def forward(self, x):
374
+ # shape: [N, C, H, W] !
375
+ # RMSNorm normalizes over the last dimension, but our channel dim (C) is at dim=1.
376
+ # So, we permute the dimensions to make the channel dimension the last one.
377
+ x_permuted = x.permute(0, 2, 3, 1) # Shape becomes [N, H, W, C]
378
+
379
+ # Apply normalization on the feature/channel dimension
380
+ x_norm = self.norm(x_permuted)
381
+
382
+ # Permute back to the original dimension order for the convolution
383
+ x_norm_permuted = x_norm.permute(0, 3, 1, 2) # Shape becomes [N, C, H, W]
384
+
385
+ # Apply the 3x3 convolution
386
+ x = self.conv(x_norm_permuted)
387
+ return x
388
+
389
+
390
+ class Approximator(nn.Module):
391
+ def __init__(self, in_dim: int, out_dim: int, hidden_dim: int, n_layers=4):
392
+ super().__init__()
393
+ self.in_proj = nn.Linear(in_dim, hidden_dim, bias=True)
394
+ self.layers = nn.ModuleList(
395
+ [MLPEmbedder(hidden_dim, hidden_dim) for x in range(n_layers)]
396
+ )
397
+ self.norms = nn.ModuleList([RMSNorm(hidden_dim) for x in range(n_layers)])
398
+ self.out_proj = nn.Linear(hidden_dim, out_dim)
399
+
400
+ @property
401
+ def device(self):
402
+ # Get the device of the module (assumes all parameters are on the same device)
403
+ return next(self.parameters()).device
404
+
405
+ def forward(self, x: Tensor) -> Tensor:
406
+ x = self.in_proj(x)
407
+
408
+ for layer, norms in zip(self.layers, self.norms):
409
+ x = x + layer(norms(x))
410
+
411
+ x = self.out_proj(x)
412
+
413
+ return x
414
+
415
+
416
+ class QKNorm(torch.nn.Module):
417
+ def __init__(self, dim: int, use_compiled: bool = False):
418
+ super().__init__()
419
+ self.query_norm = RMSNorm(dim, use_compiled=use_compiled)
420
+ self.key_norm = RMSNorm(dim, use_compiled=use_compiled)
421
+ self.use_compiled = use_compiled
422
+
423
+ def forward(self, q: Tensor, k: Tensor, v: Tensor) -> tuple[Tensor, Tensor]:
424
+ q = self.query_norm(q)
425
+ k = self.key_norm(k)
426
+ return q.to(v), k.to(v)
427
+
428
+
429
+ class SelfAttention(nn.Module):
430
+ def __init__(
431
+ self,
432
+ dim: int,
433
+ num_heads: int = 8,
434
+ qkv_bias: bool = False,
435
+ use_compiled: bool = False,
436
+ ):
437
+ super().__init__()
438
+ self.num_heads = num_heads
439
+ head_dim = dim // num_heads
440
+
441
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
442
+ self.norm = QKNorm(head_dim, use_compiled=use_compiled)
443
+ self.proj = nn.Linear(dim, dim)
444
+ self.use_compiled = use_compiled
445
+
446
+ def forward(self, x: Tensor, pe: Tensor) -> Tensor:
447
+ qkv = self.qkv(x)
448
+ q, k, v = rearrange(qkv, "B L (K H D) -> K B H L D", K=3, H=self.num_heads)
449
+ q, k = self.norm(q, k, v)
450
+ x = attention(q, k, v, pe=pe)
451
+ x = self.proj(x)
452
+ return x
453
+
454
+
455
+ @dataclass
456
+ class ModulationOut:
457
+ shift: Tensor
458
+ scale: Tensor
459
+ gate: Tensor
460
+
461
+
462
+ def _modulation_shift_scale_fn(x, scale, shift):
463
+ return (1 + scale) * x + shift
464
+
465
+
466
+ def _modulation_gate_fn(x, gate, gate_params):
467
+ return x + gate * gate_params
468
+
469
+
470
+ class DoubleStreamBlock(nn.Module):
471
+ def __init__(
472
+ self,
473
+ hidden_size: int,
474
+ num_heads: int,
475
+ mlp_ratio: float,
476
+ qkv_bias: bool = False,
477
+ use_compiled: bool = False,
478
+ ):
479
+ super().__init__()
480
+
481
+ mlp_hidden_dim = int(hidden_size * mlp_ratio)
482
+ self.num_heads = num_heads
483
+ self.hidden_size = hidden_size
484
+ self.img_norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
485
+ self.img_attn = SelfAttention(
486
+ dim=hidden_size,
487
+ num_heads=num_heads,
488
+ qkv_bias=qkv_bias,
489
+ use_compiled=use_compiled,
490
+ )
491
+
492
+ self.img_norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
493
+ self.img_mlp = nn.Sequential(
494
+ nn.Linear(hidden_size, mlp_hidden_dim, bias=True),
495
+ nn.GELU(approximate="tanh"),
496
+ nn.Linear(mlp_hidden_dim, hidden_size, bias=True),
497
+ )
498
+
499
+ self.txt_norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
500
+ self.txt_attn = SelfAttention(
501
+ dim=hidden_size,
502
+ num_heads=num_heads,
503
+ qkv_bias=qkv_bias,
504
+ use_compiled=use_compiled,
505
+ )
506
+
507
+ self.txt_norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
508
+ self.txt_mlp = nn.Sequential(
509
+ nn.Linear(hidden_size, mlp_hidden_dim, bias=True),
510
+ nn.GELU(approximate="tanh"),
511
+ nn.Linear(mlp_hidden_dim, hidden_size, bias=True),
512
+ )
513
+ self.use_compiled = use_compiled
514
+
515
+ @property
516
+ def device(self):
517
+ # Get the device of the module (assumes all parameters are on the same device)
518
+ return next(self.parameters()).device
519
+
520
+ def modulation_shift_scale_fn(self, x, scale, shift):
521
+ if self.use_compiled:
522
+ return torch.compile(_modulation_shift_scale_fn)(x, scale, shift)
523
+ else:
524
+ return _modulation_shift_scale_fn(x, scale, shift)
525
+
526
+ def modulation_gate_fn(self, x, gate, gate_params):
527
+ if self.use_compiled:
528
+ return torch.compile(_modulation_gate_fn)(x, gate, gate_params)
529
+ else:
530
+ return _modulation_gate_fn(x, gate, gate_params)
531
+
532
+ def forward(
533
+ self,
534
+ img: Tensor,
535
+ txt: Tensor,
536
+ pe: Tensor,
537
+ distill_vec: list[ModulationOut],
538
+ mask: Tensor,
539
+ ) -> tuple[Tensor, Tensor]:
540
+ (img_mod1, img_mod2), (txt_mod1, txt_mod2) = distill_vec
541
+
542
+ # prepare image for attention
543
+ img_modulated = self.img_norm1(img)
544
+ # replaced with compiled fn
545
+ # img_modulated = (1 + img_mod1.scale) * img_modulated + img_mod1.shift
546
+ img_modulated = self.modulation_shift_scale_fn(
547
+ img_modulated, img_mod1.scale, img_mod1.shift
548
+ )
549
+ img_qkv = self.img_attn.qkv(img_modulated)
550
+ img_q, img_k, img_v = rearrange(
551
+ img_qkv, "B L (K H D) -> K B H L D", K=3, H=self.num_heads
552
+ )
553
+ img_q, img_k = self.img_attn.norm(img_q, img_k, img_v)
554
+
555
+ # prepare txt for attention
556
+ txt_modulated = self.txt_norm1(txt)
557
+ # replaced with compiled fn
558
+ # txt_modulated = (1 + txt_mod1.scale) * txt_modulated + txt_mod1.shift
559
+ txt_modulated = self.modulation_shift_scale_fn(
560
+ txt_modulated, txt_mod1.scale, txt_mod1.shift
561
+ )
562
+ txt_qkv = self.txt_attn.qkv(txt_modulated)
563
+ txt_q, txt_k, txt_v = rearrange(
564
+ txt_qkv, "B L (K H D) -> K B H L D", K=3, H=self.num_heads
565
+ )
566
+ txt_q, txt_k = self.txt_attn.norm(txt_q, txt_k, txt_v)
567
+
568
+ # run actual attention
569
+ q = torch.cat((txt_q, img_q), dim=2)
570
+ k = torch.cat((txt_k, img_k), dim=2)
571
+ v = torch.cat((txt_v, img_v), dim=2)
572
+
573
+ attn = attention(q, k, v, pe=pe, mask=mask)
574
+ txt_attn, img_attn = attn[:, : txt.shape[1]], attn[:, txt.shape[1] :]
575
+
576
+ # calculate the img bloks
577
+ # replaced with compiled fn
578
+ # img = img + img_mod1.gate * self.img_attn.proj(img_attn)
579
+ # img = img + img_mod2.gate * self.img_mlp((1 + img_mod2.scale) * self.img_norm2(img) + img_mod2.shift)
580
+ img = self.modulation_gate_fn(img, img_mod1.gate, self.img_attn.proj(img_attn))
581
+ img = self.modulation_gate_fn(
582
+ img,
583
+ img_mod2.gate,
584
+ self.img_mlp(
585
+ self.modulation_shift_scale_fn(
586
+ self.img_norm2(img), img_mod2.scale, img_mod2.shift
587
+ )
588
+ ),
589
+ )
590
+
591
+ # calculate the txt bloks
592
+ # replaced with compiled fn
593
+ # txt = txt + txt_mod1.gate * self.txt_attn.proj(txt_attn)
594
+ # txt = txt + txt_mod2.gate * self.txt_mlp((1 + txt_mod2.scale) * self.txt_norm2(txt) + txt_mod2.shift)
595
+ txt = self.modulation_gate_fn(txt, txt_mod1.gate, self.txt_attn.proj(txt_attn))
596
+ txt = self.modulation_gate_fn(
597
+ txt,
598
+ txt_mod2.gate,
599
+ self.txt_mlp(
600
+ self.modulation_shift_scale_fn(
601
+ self.txt_norm2(txt), txt_mod2.scale, txt_mod2.shift
602
+ )
603
+ ),
604
+ )
605
+
606
+ return img, txt
607
+
608
+
609
+ class SingleStreamBlock(nn.Module):
610
+ """
611
+ A DiT block with parallel linear layers as described in
612
+ https://arxiv.org/abs/2302.05442 and adapted modulation interface.
613
+ """
614
+
615
+ def __init__(
616
+ self,
617
+ hidden_size: int,
618
+ num_heads: int,
619
+ mlp_ratio: float = 4.0,
620
+ qk_scale: float | None = None,
621
+ use_compiled: bool = False,
622
+ ):
623
+ super().__init__()
624
+ self.hidden_dim = hidden_size
625
+ self.num_heads = num_heads
626
+ head_dim = hidden_size // num_heads
627
+ self.scale = qk_scale or head_dim**-0.5
628
+
629
+ self.mlp_hidden_dim = int(hidden_size * mlp_ratio)
630
+ # qkv and mlp_in
631
+ self.linear1 = nn.Linear(hidden_size, hidden_size * 3 + self.mlp_hidden_dim)
632
+ # proj and mlp_out
633
+ self.linear2 = nn.Linear(hidden_size + self.mlp_hidden_dim, hidden_size)
634
+
635
+ self.norm = QKNorm(head_dim, use_compiled=use_compiled)
636
+
637
+ self.hidden_size = hidden_size
638
+ self.pre_norm = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
639
+
640
+ self.mlp_act = nn.GELU(approximate="tanh")
641
+ self.use_compiled = use_compiled
642
+
643
+ @property
644
+ def device(self):
645
+ # Get the device of the module (assumes all parameters are on the same device)
646
+ return next(self.parameters()).device
647
+
648
+ def modulation_shift_scale_fn(self, x, scale, shift):
649
+ if self.use_compiled:
650
+ return torch.compile(_modulation_shift_scale_fn)(x, scale, shift)
651
+ else:
652
+ return _modulation_shift_scale_fn(x, scale, shift)
653
+
654
+ def modulation_gate_fn(self, x, gate, gate_params):
655
+ if self.use_compiled:
656
+ return torch.compile(_modulation_gate_fn)(x, gate, gate_params)
657
+ else:
658
+ return _modulation_gate_fn(x, gate, gate_params)
659
+
660
+ def forward(
661
+ self, x: Tensor, pe: Tensor, distill_vec: list[ModulationOut], mask: Tensor
662
+ ) -> Tensor:
663
+ mod = distill_vec
664
+ # replaced with compiled fn
665
+ # x_mod = (1 + mod.scale) * self.pre_norm(x) + mod.shift
666
+ x_mod = self.modulation_shift_scale_fn(self.pre_norm(x), mod.scale, mod.shift)
667
+ qkv, mlp = torch.split(
668
+ self.linear1(x_mod), [3 * self.hidden_size, self.mlp_hidden_dim], dim=-1
669
+ )
670
+
671
+ q, k, v = rearrange(qkv, "B L (K H D) -> K B H L D", K=3, H=self.num_heads)
672
+ q, k = self.norm(q, k, v)
673
+
674
+ # compute attention
675
+ attn = attention(q, k, v, pe=pe, mask=mask)
676
+ # compute activation in mlp stream, cat again and run second linear layer
677
+ output = self.linear2(torch.cat((attn, self.mlp_act(mlp)), 2))
678
+ # replaced with compiled fn
679
+ # return x + mod.gate * output
680
+ return self.modulation_gate_fn(x, mod.gate, output)
681
+
682
+
683
+ class LastLayer(nn.Module):
684
+ def __init__(
685
+ self,
686
+ hidden_size: int,
687
+ patch_size: int,
688
+ out_channels: int,
689
+ use_compiled: bool = False,
690
+ ):
691
+ super().__init__()
692
+ self.norm_final = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
693
+ self.linear = nn.Linear(
694
+ hidden_size, patch_size * patch_size * out_channels, bias=True
695
+ )
696
+ self.use_compiled = use_compiled
697
+
698
+ @property
699
+ def device(self):
700
+ # Get the device of the module (assumes all parameters are on the same device)
701
+ return next(self.parameters()).device
702
+
703
+ def modulation_shift_scale_fn(self, x, scale, shift):
704
+ if self.use_compiled:
705
+ return torch.compile(_modulation_shift_scale_fn)(x, scale, shift)
706
+ else:
707
+ return _modulation_shift_scale_fn(x, scale, shift)
708
+
709
+ def forward(self, x: Tensor, distill_vec: list[Tensor]) -> Tensor:
710
+ shift, scale = distill_vec
711
+ shift = shift.squeeze(1)
712
+ scale = scale.squeeze(1)
713
+ # replaced with compiled fn
714
+ # x = (1 + scale[:, None, :]) * self.norm_final(x) + shift[:, None, :]
715
+ x = self.modulation_shift_scale_fn(
716
+ self.norm_final(x), scale[:, None, :], shift[:, None, :]
717
+ )
718
+ x = self.linear(x)
719
+ return x