vidfom commited on
Commit
a48bc74
·
verified ·
1 Parent(s): ed27b9c

Upload folder using huggingface_hub (part 3)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. ComfyUI/comfy/ldm/flux/__pycache__/redux.cpython-312.pyc +0 -0
  3. ComfyUI/comfy/ldm/flux/controlnet.py +208 -0
  4. ComfyUI/comfy/ldm/flux/layers.py +372 -0
  5. ComfyUI/comfy/ldm/flux/math.py +58 -0
  6. ComfyUI/comfy/ldm/flux/model.py +408 -0
  7. ComfyUI/comfy/ldm/flux/redux.py +25 -0
  8. ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/asymm_models_joint.cpython-312.pyc +0 -0
  9. ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/layers.cpython-312.pyc +0 -0
  10. ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/rope_mixed.cpython-312.pyc +0 -0
  11. ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/temporal_rope.cpython-312.pyc +0 -0
  12. ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/utils.cpython-312.pyc +0 -0
  13. ComfyUI/comfy/ldm/genmo/joint_model/asymm_models_joint.py +561 -0
  14. ComfyUI/comfy/ldm/genmo/joint_model/layers.py +153 -0
  15. ComfyUI/comfy/ldm/genmo/joint_model/rope_mixed.py +88 -0
  16. ComfyUI/comfy/ldm/genmo/joint_model/temporal_rope.py +34 -0
  17. ComfyUI/comfy/ldm/genmo/joint_model/utils.py +102 -0
  18. ComfyUI/comfy/ldm/genmo/vae/__pycache__/model.cpython-312.pyc +0 -0
  19. ComfyUI/comfy/ldm/genmo/vae/model.py +711 -0
  20. ComfyUI/comfy/ldm/hidream/__pycache__/model.cpython-312.pyc +0 -0
  21. ComfyUI/comfy/ldm/hidream/model.py +829 -0
  22. ComfyUI/comfy/ldm/hidream_o1/__pycache__/attention.cpython-312.pyc +0 -0
  23. ComfyUI/comfy/ldm/hidream_o1/__pycache__/conditioning.cpython-312.pyc +0 -0
  24. ComfyUI/comfy/ldm/hidream_o1/__pycache__/model.cpython-312.pyc +0 -0
  25. ComfyUI/comfy/ldm/hidream_o1/__pycache__/utils.cpython-312.pyc +0 -0
  26. ComfyUI/comfy/ldm/hidream_o1/attention.py +41 -0
  27. ComfyUI/comfy/ldm/hidream_o1/conditioning.py +230 -0
  28. ComfyUI/comfy/ldm/hidream_o1/model.py +306 -0
  29. ComfyUI/comfy/ldm/hidream_o1/utils.py +173 -0
  30. ComfyUI/comfy/ldm/hunyuan3d/__pycache__/model.cpython-312.pyc +0 -0
  31. ComfyUI/comfy/ldm/hunyuan3d/__pycache__/vae.cpython-312.pyc +0 -0
  32. ComfyUI/comfy/ldm/hunyuan3d/model.py +148 -0
  33. ComfyUI/comfy/ldm/hunyuan3d/vae.py +988 -0
  34. ComfyUI/comfy/ldm/hunyuan3dv2_1/__pycache__/hunyuandit.cpython-312.pyc +0 -0
  35. ComfyUI/comfy/ldm/hunyuan3dv2_1/hunyuandit.py +668 -0
  36. ComfyUI/comfy/ldm/hunyuan_video/__pycache__/model.cpython-312.pyc +0 -0
  37. ComfyUI/comfy/ldm/hunyuan_video/__pycache__/upsampler.cpython-312.pyc +0 -0
  38. ComfyUI/comfy/ldm/hunyuan_video/__pycache__/vae.cpython-312.pyc +0 -0
  39. ComfyUI/comfy/ldm/hunyuan_video/__pycache__/vae_refiner.cpython-312.pyc +0 -0
  40. ComfyUI/comfy/ldm/hunyuan_video/model.py +497 -0
  41. ComfyUI/comfy/ldm/hunyuan_video/upsampler.py +122 -0
  42. ComfyUI/comfy/ldm/hunyuan_video/vae.py +136 -0
  43. ComfyUI/comfy/ldm/hunyuan_video/vae_refiner.py +313 -0
  44. ComfyUI/comfy/ldm/hydit/__pycache__/attn_layers.cpython-312.pyc +0 -0
  45. ComfyUI/comfy/ldm/hydit/__pycache__/controlnet.cpython-312.pyc +0 -0
  46. ComfyUI/comfy/ldm/hydit/__pycache__/models.cpython-312.pyc +0 -0
  47. ComfyUI/comfy/ldm/hydit/__pycache__/poolers.cpython-312.pyc +0 -0
  48. ComfyUI/comfy/ldm/hydit/__pycache__/posemb_layers.cpython-312.pyc +0 -0
  49. ComfyUI/comfy/ldm/hydit/attn_layers.py +218 -0
  50. ComfyUI/comfy/ldm/hydit/controlnet.py +311 -0
.gitattributes CHANGED
@@ -39,3 +39,4 @@ ComfyUI/comfy/__pycache__/model_patcher.cpython-312.pyc filter=lfs diff=lfs merg
39
  ComfyUI/comfy/__pycache__/sd.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
40
  ComfyUI/comfy/__pycache__/supported_models.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
41
  ComfyUI/comfy/k_diffusion/__pycache__/sampling.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
 
 
39
  ComfyUI/comfy/__pycache__/sd.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
40
  ComfyUI/comfy/__pycache__/supported_models.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
41
  ComfyUI/comfy/k_diffusion/__pycache__/sampling.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
42
+ ComfyUI/comfy/ldm/sam3/__pycache__/tracker.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
ComfyUI/comfy/ldm/flux/__pycache__/redux.cpython-312.pyc ADDED
Binary file (1.63 kB). View file
 
ComfyUI/comfy/ldm/flux/controlnet.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #Original code can be found on: https://github.com/XLabs-AI/x-flux/blob/main/src/flux/controlnet.py
2
+ #modified to support different types of flux controlnets
3
+
4
+ import torch
5
+ import math
6
+ from torch import Tensor, nn
7
+ from einops import rearrange, repeat
8
+
9
+ from .layers import (timestep_embedding)
10
+
11
+ from .model import Flux
12
+ import comfy.ldm.common_dit
13
+
14
+ class MistolineCondDownsamplBlock(nn.Module):
15
+ def __init__(self, dtype=None, device=None, operations=None):
16
+ super().__init__()
17
+ self.encoder = nn.Sequential(
18
+ operations.Conv2d(3, 16, 3, padding=1, dtype=dtype, device=device),
19
+ nn.SiLU(),
20
+ operations.Conv2d(16, 16, 1, dtype=dtype, device=device),
21
+ nn.SiLU(),
22
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
23
+ nn.SiLU(),
24
+ operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
25
+ nn.SiLU(),
26
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
27
+ nn.SiLU(),
28
+ operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
29
+ nn.SiLU(),
30
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
31
+ nn.SiLU(),
32
+ operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
33
+ nn.SiLU(),
34
+ operations.Conv2d(16, 16, 1, dtype=dtype, device=device),
35
+ nn.SiLU(),
36
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device)
37
+ )
38
+
39
+ def forward(self, x):
40
+ return self.encoder(x)
41
+
42
+ class MistolineControlnetBlock(nn.Module):
43
+ def __init__(self, hidden_size, dtype=None, device=None, operations=None):
44
+ super().__init__()
45
+ self.linear = operations.Linear(hidden_size, hidden_size, dtype=dtype, device=device)
46
+ self.act = nn.SiLU()
47
+
48
+ def forward(self, x):
49
+ return self.act(self.linear(x))
50
+
51
+
52
+ class ControlNetFlux(Flux):
53
+ def __init__(self, latent_input=False, num_union_modes=0, mistoline=False, control_latent_channels=None, image_model=None, dtype=None, device=None, operations=None, **kwargs):
54
+ super().__init__(final_layer=False, dtype=dtype, device=device, operations=operations, **kwargs)
55
+
56
+ self.main_model_double = 19
57
+ self.main_model_single = 38
58
+
59
+ self.mistoline = mistoline
60
+ # add ControlNet blocks
61
+ if self.mistoline:
62
+ control_block = lambda : MistolineControlnetBlock(self.hidden_size, dtype=dtype, device=device, operations=operations)
63
+ else:
64
+ control_block = lambda : operations.Linear(self.hidden_size, self.hidden_size, dtype=dtype, device=device)
65
+
66
+ self.controlnet_blocks = nn.ModuleList([])
67
+ for _ in range(self.params.depth):
68
+ self.controlnet_blocks.append(control_block())
69
+
70
+ self.controlnet_single_blocks = nn.ModuleList([])
71
+ for _ in range(self.params.depth_single_blocks):
72
+ self.controlnet_single_blocks.append(control_block())
73
+
74
+ self.num_union_modes = num_union_modes
75
+ self.controlnet_mode_embedder = None
76
+ if self.num_union_modes > 0:
77
+ self.controlnet_mode_embedder = operations.Embedding(self.num_union_modes, self.hidden_size, dtype=dtype, device=device)
78
+
79
+ self.gradient_checkpointing = False
80
+ self.latent_input = latent_input
81
+ if control_latent_channels is None:
82
+ control_latent_channels = self.in_channels
83
+ else:
84
+ control_latent_channels *= 2 * 2 #patch size
85
+
86
+ self.pos_embed_input = operations.Linear(control_latent_channels, self.hidden_size, bias=True, dtype=dtype, device=device)
87
+ if not self.latent_input:
88
+ if self.mistoline:
89
+ self.input_cond_block = MistolineCondDownsamplBlock(dtype=dtype, device=device, operations=operations)
90
+ else:
91
+ self.input_hint_block = nn.Sequential(
92
+ operations.Conv2d(3, 16, 3, padding=1, dtype=dtype, device=device),
93
+ nn.SiLU(),
94
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
95
+ nn.SiLU(),
96
+ operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
97
+ nn.SiLU(),
98
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
99
+ nn.SiLU(),
100
+ operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
101
+ nn.SiLU(),
102
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
103
+ nn.SiLU(),
104
+ operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
105
+ nn.SiLU(),
106
+ operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device)
107
+ )
108
+
109
+ def forward_orig(
110
+ self,
111
+ img: Tensor,
112
+ img_ids: Tensor,
113
+ controlnet_cond: Tensor,
114
+ txt: Tensor,
115
+ txt_ids: Tensor,
116
+ timesteps: Tensor,
117
+ y: Tensor,
118
+ guidance: Tensor = None,
119
+ control_type: Tensor = None,
120
+ ) -> Tensor:
121
+ if img.ndim != 3 or txt.ndim != 3:
122
+ raise ValueError("Input img and txt tensors must have 3 dimensions.")
123
+
124
+ if y is None:
125
+ y = torch.zeros((img.shape[0], self.params.vec_in_dim), device=img.device, dtype=img.dtype)
126
+ else:
127
+ y = y[:, :self.params.vec_in_dim]
128
+
129
+ # running on sequences img
130
+ img = self.img_in(img)
131
+
132
+ controlnet_cond = self.pos_embed_input(controlnet_cond)
133
+ img = img + controlnet_cond
134
+ vec = self.time_in(timestep_embedding(timesteps, 256))
135
+ if self.params.guidance_embed:
136
+ vec = vec + self.guidance_in(timestep_embedding(guidance, 256))
137
+ vec = vec + self.vector_in(y)
138
+ txt = self.txt_in(txt)
139
+
140
+ if self.controlnet_mode_embedder is not None and len(control_type) > 0:
141
+ control_cond = self.controlnet_mode_embedder(torch.tensor(control_type, device=img.device), out_dtype=img.dtype).unsqueeze(0).repeat((txt.shape[0], 1, 1))
142
+ txt = torch.cat([control_cond, txt], dim=1)
143
+ txt_ids = torch.cat([txt_ids[:,:1], txt_ids], dim=1)
144
+
145
+ ids = torch.cat((txt_ids, img_ids), dim=1)
146
+ pe = self.pe_embedder(ids)
147
+
148
+ controlnet_double = ()
149
+
150
+ for i in range(len(self.double_blocks)):
151
+ img, txt = self.double_blocks[i](img=img, txt=txt, vec=vec, pe=pe)
152
+ controlnet_double = controlnet_double + (self.controlnet_blocks[i](img),)
153
+
154
+ img = torch.cat((txt, img), 1)
155
+
156
+ controlnet_single = ()
157
+
158
+ for i in range(len(self.single_blocks)):
159
+ img = self.single_blocks[i](img, vec=vec, pe=pe)
160
+ controlnet_single = controlnet_single + (self.controlnet_single_blocks[i](img[:, txt.shape[1] :, ...]),)
161
+
162
+ repeat = math.ceil(self.main_model_double / len(controlnet_double))
163
+ if self.latent_input:
164
+ out_input = ()
165
+ for x in controlnet_double:
166
+ out_input += (x,) * repeat
167
+ else:
168
+ out_input = (controlnet_double * repeat)
169
+
170
+ out = {"input": out_input[:self.main_model_double]}
171
+ if len(controlnet_single) > 0:
172
+ repeat = math.ceil(self.main_model_single / len(controlnet_single))
173
+ out_output = ()
174
+ if self.latent_input:
175
+ for x in controlnet_single:
176
+ out_output += (x,) * repeat
177
+ else:
178
+ out_output = (controlnet_single * repeat)
179
+ out["output"] = out_output[:self.main_model_single]
180
+ return out
181
+
182
+ def forward(self, x, timesteps, context, y=None, guidance=None, hint=None, **kwargs):
183
+ patch_size = 2
184
+ if self.latent_input:
185
+ hint = comfy.ldm.common_dit.pad_to_patch_size(hint, (patch_size, patch_size))
186
+ elif self.mistoline:
187
+ hint = hint * 2.0 - 1.0
188
+ hint = self.input_cond_block(hint)
189
+ else:
190
+ hint = hint * 2.0 - 1.0
191
+ hint = self.input_hint_block(hint)
192
+
193
+ hint = rearrange(hint, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=patch_size, pw=patch_size)
194
+
195
+ bs, c, h, w = x.shape
196
+ x = comfy.ldm.common_dit.pad_to_patch_size(x, (patch_size, patch_size))
197
+
198
+ img = rearrange(x, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=patch_size, pw=patch_size)
199
+
200
+ h_len = ((h + (patch_size // 2)) // patch_size)
201
+ w_len = ((w + (patch_size // 2)) // patch_size)
202
+ img_ids = torch.zeros((h_len, w_len, 3), device=x.device, dtype=x.dtype)
203
+ img_ids[..., 1] = img_ids[..., 1] + torch.linspace(0, h_len - 1, steps=h_len, device=x.device, dtype=x.dtype)[:, None]
204
+ img_ids[..., 2] = img_ids[..., 2] + torch.linspace(0, w_len - 1, steps=w_len, device=x.device, dtype=x.dtype)[None, :]
205
+ img_ids = repeat(img_ids, "h w c -> b (h w) c", b=bs)
206
+
207
+ txt_ids = torch.zeros((bs, context.shape[1], 3), device=x.device, dtype=x.dtype)
208
+ return self.forward_orig(img, img_ids, hint, context, txt_ids, timesteps, y, guidance, control_type=kwargs.get("control_type", []))
ComfyUI/comfy/ldm/flux/layers.py ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from dataclasses import dataclass
3
+
4
+ import torch
5
+ from torch import Tensor, nn
6
+
7
+ from .math import attention, rope
8
+
9
+ # Fix import for some custom nodes, TODO: delete eventually.
10
+ RMSNorm = None
11
+
12
+ class EmbedND(nn.Module):
13
+ def __init__(self, dim: int, theta: int, axes_dim: list):
14
+ super().__init__()
15
+ self.dim = dim
16
+ self.theta = theta
17
+ self.axes_dim = axes_dim
18
+
19
+ def forward(self, ids: Tensor) -> Tensor:
20
+ n_axes = ids.shape[-1]
21
+ emb = torch.cat(
22
+ [rope(ids[..., i], self.axes_dim[i], self.theta) for i in range(n_axes)],
23
+ dim=-3,
24
+ )
25
+
26
+ return emb.unsqueeze(1)
27
+
28
+
29
+ def timestep_embedding(t: Tensor, dim, max_period=10000, time_factor: float = 1000.0):
30
+ """
31
+ Create sinusoidal timestep embeddings.
32
+ :param t: a 1-D Tensor of N indices, one per batch element.
33
+ These may be fractional.
34
+ :param dim: the dimension of the output.
35
+ :param max_period: controls the minimum frequency of the embeddings.
36
+ :return: an (N, D) Tensor of positional embeddings.
37
+ """
38
+ t = time_factor * t
39
+ half = dim // 2
40
+ freqs = torch.exp(-math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32, device=t.device) / half)
41
+
42
+ args = t[:, None].float() * freqs[None]
43
+ embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
44
+ if dim % 2:
45
+ embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1)
46
+ if torch.is_floating_point(t):
47
+ embedding = embedding.to(t)
48
+ return embedding
49
+
50
+ class MLPEmbedder(nn.Module):
51
+ def __init__(self, in_dim: int, hidden_dim: int, bias=True, dtype=None, device=None, operations=None):
52
+ super().__init__()
53
+ self.in_layer = operations.Linear(in_dim, hidden_dim, bias=bias, dtype=dtype, device=device)
54
+ self.silu = nn.SiLU()
55
+ self.out_layer = operations.Linear(hidden_dim, hidden_dim, bias=bias, dtype=dtype, device=device)
56
+
57
+ def forward(self, x: Tensor) -> Tensor:
58
+ return self.out_layer(self.silu(self.in_layer(x)))
59
+
60
+ class YakMLP(nn.Module):
61
+ def __init__(self, hidden_size: int, intermediate_size: int, dtype=None, device=None, operations=None):
62
+ super().__init__()
63
+ self.hidden_size = hidden_size
64
+ self.intermediate_size = intermediate_size
65
+ self.gate_proj = operations.Linear(self.hidden_size, self.intermediate_size, bias=True, dtype=dtype, device=device)
66
+ self.up_proj = operations.Linear(self.hidden_size, self.intermediate_size, bias=True, dtype=dtype, device=device)
67
+ self.down_proj = operations.Linear(self.intermediate_size, self.hidden_size, bias=True, dtype=dtype, device=device)
68
+ self.act_fn = nn.SiLU()
69
+
70
+ def forward(self, x: Tensor) -> Tensor:
71
+ down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
72
+ return down_proj
73
+
74
+ def build_mlp(hidden_size, mlp_hidden_dim, mlp_silu_act=False, yak_mlp=False, dtype=None, device=None, operations=None):
75
+ if yak_mlp:
76
+ return YakMLP(hidden_size, mlp_hidden_dim, dtype=dtype, device=device, operations=operations)
77
+ if mlp_silu_act:
78
+ return nn.Sequential(
79
+ operations.Linear(hidden_size, mlp_hidden_dim * 2, bias=False, dtype=dtype, device=device),
80
+ SiLUActivation(),
81
+ operations.Linear(mlp_hidden_dim, hidden_size, bias=False, dtype=dtype, device=device),
82
+ )
83
+ else:
84
+ return nn.Sequential(
85
+ operations.Linear(hidden_size, mlp_hidden_dim, bias=True, dtype=dtype, device=device),
86
+ nn.GELU(approximate="tanh"),
87
+ operations.Linear(mlp_hidden_dim, hidden_size, bias=True, dtype=dtype, device=device),
88
+ )
89
+
90
+
91
+ class QKNorm(torch.nn.Module):
92
+ def __init__(self, dim: int, dtype=None, device=None, operations=None):
93
+ super().__init__()
94
+ self.query_norm = operations.RMSNorm(dim, dtype=dtype, device=device)
95
+ self.key_norm = operations.RMSNorm(dim, dtype=dtype, device=device)
96
+
97
+ def forward(self, q: Tensor, k: Tensor, v: Tensor) -> tuple:
98
+ q = self.query_norm(q)
99
+ k = self.key_norm(k)
100
+ return q.to(v), k.to(v)
101
+
102
+
103
+ class SelfAttention(nn.Module):
104
+ def __init__(self, dim: int, num_heads: int = 8, qkv_bias: bool = False, proj_bias: bool = True, dtype=None, device=None, operations=None):
105
+ super().__init__()
106
+ self.num_heads = num_heads
107
+ head_dim = dim // num_heads
108
+
109
+ self.qkv = operations.Linear(dim, dim * 3, bias=qkv_bias, dtype=dtype, device=device)
110
+ self.norm = QKNorm(head_dim, dtype=dtype, device=device, operations=operations)
111
+ self.proj = operations.Linear(dim, dim, bias=proj_bias, dtype=dtype, device=device)
112
+
113
+
114
+ @dataclass
115
+ class ModulationOut:
116
+ shift: Tensor
117
+ scale: Tensor
118
+ gate: Tensor
119
+
120
+
121
+ class Modulation(nn.Module):
122
+ def __init__(self, dim: int, double: bool, bias=True, dtype=None, device=None, operations=None):
123
+ super().__init__()
124
+ self.is_double = double
125
+ self.multiplier = 6 if double else 3
126
+ self.lin = operations.Linear(dim, self.multiplier * dim, bias=bias, dtype=dtype, device=device)
127
+
128
+ def forward(self, vec: Tensor) -> tuple:
129
+ if vec.ndim == 2:
130
+ vec = vec[:, None, :]
131
+ out = self.lin(nn.functional.silu(vec)).chunk(self.multiplier, dim=-1)
132
+
133
+ return (
134
+ ModulationOut(*out[:3]),
135
+ ModulationOut(*out[3:]) if self.is_double else None,
136
+ )
137
+
138
+
139
+ def apply_mod(tensor, m_mult, m_add=None, modulation_dims=None):
140
+ if modulation_dims is None:
141
+ if m_add is not None:
142
+ return torch.addcmul(m_add, tensor, m_mult)
143
+ else:
144
+ return tensor * m_mult
145
+ else:
146
+ for d in modulation_dims:
147
+ tensor[:, d[0]:d[1]] *= m_mult[:, d[2]:d[2] + 1]
148
+ if m_add is not None:
149
+ tensor[:, d[0]:d[1]] += m_add[:, d[2]:d[2] + 1]
150
+ return tensor
151
+
152
+
153
+ class SiLUActivation(nn.Module):
154
+ def __init__(self):
155
+ super().__init__()
156
+ self.gate_fn = nn.SiLU()
157
+
158
+ def forward(self, x: Tensor) -> Tensor:
159
+ x1, x2 = x.chunk(2, dim=-1)
160
+ return self.gate_fn(x1) * x2
161
+
162
+
163
+ class DoubleStreamBlock(nn.Module):
164
+ def __init__(self, hidden_size: int, num_heads: int, mlp_ratio: float, qkv_bias: bool = False, modulation=True, mlp_silu_act=False, proj_bias=True, yak_mlp=False, dtype=None, device=None, operations=None):
165
+ super().__init__()
166
+
167
+ mlp_hidden_dim = int(hidden_size * mlp_ratio)
168
+ self.num_heads = num_heads
169
+ self.hidden_size = hidden_size
170
+ self.modulation = modulation
171
+
172
+ if self.modulation:
173
+ self.img_mod = Modulation(hidden_size, double=True, dtype=dtype, device=device, operations=operations)
174
+
175
+ self.img_norm1 = operations.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device)
176
+ self.img_attn = SelfAttention(dim=hidden_size, num_heads=num_heads, qkv_bias=qkv_bias, proj_bias=proj_bias, dtype=dtype, device=device, operations=operations)
177
+
178
+ self.img_norm2 = operations.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device)
179
+
180
+ self.img_mlp = build_mlp(hidden_size, mlp_hidden_dim, mlp_silu_act=mlp_silu_act, yak_mlp=yak_mlp, dtype=dtype, device=device, operations=operations)
181
+
182
+ if self.modulation:
183
+ self.txt_mod = Modulation(hidden_size, double=True, dtype=dtype, device=device, operations=operations)
184
+
185
+ self.txt_norm1 = operations.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device)
186
+ self.txt_attn = SelfAttention(dim=hidden_size, num_heads=num_heads, qkv_bias=qkv_bias, proj_bias=proj_bias, dtype=dtype, device=device, operations=operations)
187
+
188
+ self.txt_norm2 = operations.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device)
189
+
190
+ self.txt_mlp = build_mlp(hidden_size, mlp_hidden_dim, mlp_silu_act=mlp_silu_act, yak_mlp=yak_mlp, dtype=dtype, device=device, operations=operations)
191
+
192
+ def forward(self, img: Tensor, txt: Tensor, vec: Tensor, pe: Tensor, attn_mask=None, modulation_dims_img=None, modulation_dims_txt=None, transformer_options={}):
193
+ if self.modulation:
194
+ img_mod1, img_mod2 = self.img_mod(vec)
195
+ txt_mod1, txt_mod2 = self.txt_mod(vec)
196
+ else:
197
+ (img_mod1, img_mod2), (txt_mod1, txt_mod2) = vec
198
+
199
+ transformer_patches = transformer_options.get("patches", {})
200
+ extra_options = transformer_options.copy()
201
+
202
+ # prepare image for attention
203
+ img_modulated = self.img_norm1(img)
204
+ img_modulated = apply_mod(img_modulated, (1 + img_mod1.scale), img_mod1.shift, modulation_dims_img)
205
+ img_qkv = self.img_attn.qkv(img_modulated)
206
+ del img_modulated
207
+ img_q, img_k, img_v = img_qkv.view(img_qkv.shape[0], img_qkv.shape[1], 3, self.num_heads, -1).permute(2, 0, 3, 1, 4)
208
+ del img_qkv
209
+ img_q, img_k = self.img_attn.norm(img_q, img_k, img_v)
210
+
211
+ # prepare txt for attention
212
+ txt_modulated = self.txt_norm1(txt)
213
+ txt_modulated = apply_mod(txt_modulated, (1 + txt_mod1.scale), txt_mod1.shift, modulation_dims_txt)
214
+ txt_qkv = self.txt_attn.qkv(txt_modulated)
215
+ del txt_modulated
216
+ txt_q, txt_k, txt_v = txt_qkv.view(txt_qkv.shape[0], txt_qkv.shape[1], 3, self.num_heads, -1).permute(2, 0, 3, 1, 4)
217
+ del txt_qkv
218
+ txt_q, txt_k = self.txt_attn.norm(txt_q, txt_k, txt_v)
219
+
220
+ q = torch.cat((txt_q, img_q), dim=2)
221
+ del txt_q, img_q
222
+ k = torch.cat((txt_k, img_k), dim=2)
223
+ del txt_k, img_k
224
+ v = torch.cat((txt_v, img_v), dim=2)
225
+ del txt_v, img_v
226
+
227
+ extra_options["img_slice"] = [txt.shape[1], q.shape[2]]
228
+ if "attn1_patch" in transformer_patches:
229
+ patch = transformer_patches["attn1_patch"]
230
+ for p in patch:
231
+ out = p(q, k, v, pe=pe, attn_mask=attn_mask, extra_options=extra_options)
232
+ q, k, v, pe, attn_mask = out.get("q", q), out.get("k", k), out.get("v", v), out.get("pe", pe), out.get("attn_mask", attn_mask)
233
+
234
+ # run actual attention
235
+ attn = attention(q, k, v, pe=pe, mask=attn_mask, transformer_options=transformer_options)
236
+ del q, k, v
237
+
238
+ if "attn1_output_patch" in transformer_patches:
239
+ patch = transformer_patches["attn1_output_patch"]
240
+ for p in patch:
241
+ attn = p(attn, extra_options)
242
+
243
+ txt_attn, img_attn = attn[:, : txt.shape[1]], attn[:, txt.shape[1]:]
244
+
245
+ # calculate the img bloks
246
+ img += apply_mod(self.img_attn.proj(img_attn), img_mod1.gate, None, modulation_dims_img)
247
+ del img_attn
248
+ img += apply_mod(self.img_mlp(apply_mod(self.img_norm2(img), (1 + img_mod2.scale), img_mod2.shift, modulation_dims_img)), img_mod2.gate, None, modulation_dims_img)
249
+
250
+ # calculate the txt bloks
251
+ txt += apply_mod(self.txt_attn.proj(txt_attn), txt_mod1.gate, None, modulation_dims_txt)
252
+ del txt_attn
253
+ txt += apply_mod(self.txt_mlp(apply_mod(self.txt_norm2(txt), (1 + txt_mod2.scale), txt_mod2.shift, modulation_dims_txt)), txt_mod2.gate, None, modulation_dims_txt)
254
+
255
+ if txt.dtype == torch.float16:
256
+ txt = torch.nan_to_num(txt, nan=0.0, posinf=65504, neginf=-65504)
257
+
258
+ return img, txt
259
+
260
+
261
+ class SingleStreamBlock(nn.Module):
262
+ """
263
+ A DiT block with parallel linear layers as described in
264
+ https://arxiv.org/abs/2302.05442 and adapted modulation interface.
265
+ """
266
+
267
+ def __init__(
268
+ self,
269
+ hidden_size: int,
270
+ num_heads: int,
271
+ mlp_ratio: float = 4.0,
272
+ qk_scale: float = None,
273
+ modulation=True,
274
+ mlp_silu_act=False,
275
+ bias=True,
276
+ yak_mlp=False,
277
+ dtype=None,
278
+ device=None,
279
+ operations=None
280
+ ):
281
+ super().__init__()
282
+ self.hidden_dim = hidden_size
283
+ self.num_heads = num_heads
284
+ head_dim = hidden_size // num_heads
285
+ self.scale = qk_scale or head_dim**-0.5
286
+
287
+ self.mlp_hidden_dim = int(hidden_size * mlp_ratio)
288
+
289
+ self.mlp_hidden_dim_first = self.mlp_hidden_dim
290
+ self.yak_mlp = yak_mlp
291
+ if mlp_silu_act:
292
+ self.mlp_hidden_dim_first = int(hidden_size * mlp_ratio * 2)
293
+ self.mlp_act = SiLUActivation()
294
+ else:
295
+ self.mlp_act = nn.GELU(approximate="tanh")
296
+
297
+ if self.yak_mlp:
298
+ self.mlp_hidden_dim_first *= 2
299
+ self.mlp_act = nn.SiLU()
300
+
301
+ # qkv and mlp_in
302
+ self.linear1 = operations.Linear(hidden_size, hidden_size * 3 + self.mlp_hidden_dim_first, bias=bias, dtype=dtype, device=device)
303
+ # proj and mlp_out
304
+ self.linear2 = operations.Linear(hidden_size + self.mlp_hidden_dim, hidden_size, bias=bias, dtype=dtype, device=device)
305
+
306
+ self.norm = QKNorm(head_dim, dtype=dtype, device=device, operations=operations)
307
+
308
+ self.hidden_size = hidden_size
309
+ self.pre_norm = operations.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device)
310
+
311
+ if modulation:
312
+ self.modulation = Modulation(hidden_size, double=False, dtype=dtype, device=device, operations=operations)
313
+ else:
314
+ self.modulation = None
315
+
316
+ def forward(self, x: Tensor, vec: Tensor, pe: Tensor, attn_mask=None, modulation_dims=None, transformer_options={}) -> Tensor:
317
+ if self.modulation:
318
+ mod, _ = self.modulation(vec)
319
+ else:
320
+ mod = vec
321
+
322
+ transformer_patches = transformer_options.get("patches", {})
323
+ extra_options = transformer_options.copy()
324
+
325
+ qkv, mlp = torch.split(self.linear1(apply_mod(self.pre_norm(x), (1 + mod.scale), mod.shift, modulation_dims)), [3 * self.hidden_size, self.mlp_hidden_dim_first], dim=-1)
326
+
327
+ q, k, v = qkv.view(qkv.shape[0], qkv.shape[1], 3, self.num_heads, -1).permute(2, 0, 3, 1, 4)
328
+ del qkv
329
+ q, k = self.norm(q, k, v)
330
+
331
+ if "attn1_patch" in transformer_patches:
332
+ patch = transformer_patches["attn1_patch"]
333
+ for p in patch:
334
+ out = p(q, k, v, pe=pe, attn_mask=attn_mask, extra_options=extra_options)
335
+ q, k, v, pe, attn_mask = out.get("q", q), out.get("k", k), out.get("v", v), out.get("pe", pe), out.get("attn_mask", attn_mask)
336
+
337
+ # compute attention
338
+ attn = attention(q, k, v, pe=pe, mask=attn_mask, transformer_options=transformer_options)
339
+ del q, k, v
340
+
341
+ if "attn1_output_patch" in transformer_patches:
342
+ patch = transformer_patches["attn1_output_patch"]
343
+ for p in patch:
344
+ attn = p(attn, extra_options)
345
+
346
+ # compute activation in mlp stream, cat again and run second linear layer
347
+ if self.yak_mlp:
348
+ mlp = self.mlp_act(mlp[..., self.mlp_hidden_dim_first // 2:]) * mlp[..., :self.mlp_hidden_dim_first // 2]
349
+ else:
350
+ mlp = self.mlp_act(mlp)
351
+ output = self.linear2(torch.cat((attn, mlp), 2))
352
+ x += apply_mod(output, mod.gate, None, modulation_dims)
353
+ if x.dtype == torch.float16:
354
+ x = torch.nan_to_num(x, nan=0.0, posinf=65504, neginf=-65504)
355
+ return x
356
+
357
+
358
+ class LastLayer(nn.Module):
359
+ def __init__(self, hidden_size: int, patch_size: int, out_channels: int, bias=True, dtype=None, device=None, operations=None):
360
+ super().__init__()
361
+ self.norm_final = operations.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device)
362
+ self.linear = operations.Linear(hidden_size, patch_size * patch_size * out_channels, bias=bias, dtype=dtype, device=device)
363
+ self.adaLN_modulation = nn.Sequential(nn.SiLU(), operations.Linear(hidden_size, 2 * hidden_size, bias=bias, dtype=dtype, device=device))
364
+
365
+ def forward(self, x: Tensor, vec: Tensor, modulation_dims=None) -> Tensor:
366
+ if vec.ndim == 2:
367
+ vec = vec[:, None, :]
368
+
369
+ shift, scale = self.adaLN_modulation(vec).chunk(2, dim=-1)
370
+ x = apply_mod(self.norm_final(x), (1 + scale), shift, modulation_dims)
371
+ x = self.linear(x)
372
+ return x
ComfyUI/comfy/ldm/flux/math.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from einops import rearrange
3
+ from torch import Tensor
4
+
5
+ from comfy.ldm.modules.attention import optimized_attention
6
+ import comfy.model_management
7
+ import comfy.quant_ops
8
+
9
+
10
+ def attention(q: Tensor, k: Tensor, v: Tensor, pe: Tensor, mask=None, transformer_options={}) -> Tensor:
11
+ if pe is not None:
12
+ q, k = apply_rope(q, k, pe)
13
+ heads = q.shape[1]
14
+ x = optimized_attention(q, k, v, heads, skip_reshape=True, mask=mask, transformer_options=transformer_options)
15
+ return x
16
+
17
+ def rope(pos: Tensor, dim: int, theta: int) -> Tensor:
18
+ assert dim % 2 == 0
19
+ if not comfy.model_management.supports_fp64(pos.device):
20
+ device = torch.device("cpu")
21
+ else:
22
+ device = pos.device
23
+
24
+ scale = torch.linspace(0, (dim - 2) / dim, steps=dim//2, dtype=torch.float64, device=device)
25
+ omega = 1.0 / (theta**scale)
26
+ out = torch.einsum("...n,d->...nd", pos.to(dtype=torch.float32, device=device), omega)
27
+ out = torch.stack([torch.cos(out), -torch.sin(out), torch.sin(out), torch.cos(out)], dim=-1)
28
+ out = rearrange(out, "b n d (i j) -> b n d i j", i=2, j=2)
29
+ return out.to(dtype=torch.float32, device=pos.device)
30
+
31
+
32
+ def _apply_rope1(x: Tensor, freqs_cis: Tensor):
33
+ x_ = x.to(dtype=freqs_cis.dtype).reshape(*x.shape[:-1], -1, 1, 2)
34
+ if x_.shape[2] != 1 and freqs_cis.shape[2] != 1 and x_.shape[2] != freqs_cis.shape[2]:
35
+ freqs_cis = freqs_cis[:, :, :x_.shape[2]]
36
+
37
+ x_out = freqs_cis[..., 0] * x_[..., 0]
38
+ x_out.addcmul_(freqs_cis[..., 1], x_[..., 1])
39
+
40
+ return x_out.reshape(*x.shape).type_as(x)
41
+
42
+
43
+ def _apply_rope(xq: Tensor, xk: Tensor, freqs_cis: Tensor):
44
+ return apply_rope1(xq, freqs_cis), apply_rope1(xk, freqs_cis)
45
+
46
+
47
+ def apply_rope(xq, xk, freqs_cis):
48
+ if comfy.model_management.in_training:
49
+ return _apply_rope(xq, xk, freqs_cis)
50
+ else:
51
+ return comfy.quant_ops.ck.apply_rope(xq, xk, freqs_cis)
52
+
53
+
54
+ def apply_rope1(x, freqs_cis):
55
+ if comfy.model_management.in_training:
56
+ return _apply_rope1(x, freqs_cis)
57
+ else:
58
+ return comfy.quant_ops.ck.apply_rope1(x, freqs_cis)
ComfyUI/comfy/ldm/flux/model.py ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #Original code can be found on: https://github.com/black-forest-labs/flux
2
+
3
+ from dataclasses import dataclass
4
+
5
+ import torch
6
+ from torch import Tensor, nn
7
+ from einops import rearrange, repeat
8
+ import comfy.ldm.common_dit
9
+ import comfy.patcher_extension
10
+
11
+ from .layers import (
12
+ DoubleStreamBlock,
13
+ EmbedND,
14
+ LastLayer,
15
+ MLPEmbedder,
16
+ SingleStreamBlock,
17
+ timestep_embedding,
18
+ Modulation,
19
+ )
20
+
21
+ @dataclass
22
+ class FluxParams:
23
+ in_channels: int
24
+ out_channels: int
25
+ vec_in_dim: int
26
+ context_in_dim: int
27
+ hidden_size: int
28
+ mlp_ratio: float
29
+ num_heads: int
30
+ depth: int
31
+ depth_single_blocks: int
32
+ axes_dim: list
33
+ theta: int
34
+ patch_size: int
35
+ qkv_bias: bool
36
+ guidance_embed: bool
37
+ txt_ids_dims: list
38
+ global_modulation: bool = False
39
+ mlp_silu_act: bool = False
40
+ ops_bias: bool = True
41
+ default_ref_method: str = "offset"
42
+ ref_index_scale: float = 1.0
43
+ yak_mlp: bool = False
44
+ txt_norm: bool = False
45
+
46
+
47
+ def invert_slices(slices, length):
48
+ sorted_slices = sorted(slices)
49
+ result = []
50
+ current = 0
51
+
52
+ for start, end in sorted_slices:
53
+ if current < start:
54
+ result.append((current, start))
55
+ current = max(current, end)
56
+
57
+ if current < length:
58
+ result.append((current, length))
59
+
60
+ return result
61
+
62
+
63
+ class Flux(nn.Module):
64
+ """
65
+ Transformer model for flow matching on sequences.
66
+ """
67
+
68
+ def __init__(self, image_model=None, final_layer=True, dtype=None, device=None, operations=None, **kwargs):
69
+ super().__init__()
70
+ self.dtype = dtype
71
+ params = FluxParams(**kwargs)
72
+ self.params = params
73
+ self.patch_size = params.patch_size
74
+ self.in_channels = params.in_channels * params.patch_size * params.patch_size
75
+ self.out_channels = params.out_channels * params.patch_size * params.patch_size
76
+ if params.hidden_size % params.num_heads != 0:
77
+ raise ValueError(
78
+ f"Hidden size {params.hidden_size} must be divisible by num_heads {params.num_heads}"
79
+ )
80
+ pe_dim = params.hidden_size // params.num_heads
81
+ if sum(params.axes_dim) != pe_dim:
82
+ raise ValueError(f"Got {params.axes_dim} but expected positional dim {pe_dim}")
83
+ self.hidden_size = params.hidden_size
84
+ self.num_heads = params.num_heads
85
+ self.pe_embedder = EmbedND(dim=pe_dim, theta=params.theta, axes_dim=params.axes_dim)
86
+ self.img_in = operations.Linear(self.in_channels, self.hidden_size, bias=params.ops_bias, dtype=dtype, device=device)
87
+ self.time_in = MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size, bias=params.ops_bias, dtype=dtype, device=device, operations=operations)
88
+ if params.vec_in_dim is not None:
89
+ self.vector_in = MLPEmbedder(params.vec_in_dim, self.hidden_size, dtype=dtype, device=device, operations=operations)
90
+ else:
91
+ self.vector_in = None
92
+
93
+ self.guidance_in = (
94
+ MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size, bias=params.ops_bias, dtype=dtype, device=device, operations=operations) if params.guidance_embed else nn.Identity()
95
+ )
96
+ self.txt_in = operations.Linear(params.context_in_dim, self.hidden_size, bias=params.ops_bias, dtype=dtype, device=device)
97
+
98
+ if params.txt_norm:
99
+ self.txt_norm = operations.RMSNorm(params.context_in_dim, dtype=dtype, device=device)
100
+ else:
101
+ self.txt_norm = None
102
+
103
+ self.double_blocks = nn.ModuleList(
104
+ [
105
+ DoubleStreamBlock(
106
+ self.hidden_size,
107
+ self.num_heads,
108
+ mlp_ratio=params.mlp_ratio,
109
+ qkv_bias=params.qkv_bias,
110
+ modulation=params.global_modulation is False,
111
+ mlp_silu_act=params.mlp_silu_act,
112
+ proj_bias=params.ops_bias,
113
+ yak_mlp=params.yak_mlp,
114
+ dtype=dtype, device=device, operations=operations
115
+ )
116
+ for _ in range(params.depth)
117
+ ]
118
+ )
119
+
120
+ self.single_blocks = nn.ModuleList(
121
+ [
122
+ SingleStreamBlock(self.hidden_size, self.num_heads, mlp_ratio=params.mlp_ratio, modulation=params.global_modulation is False, mlp_silu_act=params.mlp_silu_act, bias=params.ops_bias, yak_mlp=params.yak_mlp, dtype=dtype, device=device, operations=operations)
123
+ for _ in range(params.depth_single_blocks)
124
+ ]
125
+ )
126
+
127
+ if final_layer:
128
+ self.final_layer = LastLayer(self.hidden_size, 1, self.out_channels, bias=params.ops_bias, dtype=dtype, device=device, operations=operations)
129
+
130
+ if params.global_modulation:
131
+ self.double_stream_modulation_img = Modulation(
132
+ self.hidden_size,
133
+ double=True,
134
+ bias=False,
135
+ dtype=dtype, device=device, operations=operations
136
+ )
137
+ self.double_stream_modulation_txt = Modulation(
138
+ self.hidden_size,
139
+ double=True,
140
+ bias=False,
141
+ dtype=dtype, device=device, operations=operations
142
+ )
143
+ self.single_stream_modulation = Modulation(
144
+ self.hidden_size, double=False, bias=False, dtype=dtype, device=device, operations=operations
145
+ )
146
+
147
+ def forward_orig(
148
+ self,
149
+ img: Tensor,
150
+ img_ids: Tensor,
151
+ txt: Tensor,
152
+ txt_ids: Tensor,
153
+ timesteps: Tensor,
154
+ y: Tensor,
155
+ guidance: Tensor = None,
156
+ control = None,
157
+ timestep_zero_index=None,
158
+ transformer_options={},
159
+ attn_mask: Tensor = None,
160
+ ) -> Tensor:
161
+
162
+ transformer_options = transformer_options.copy()
163
+ patches = transformer_options.get("patches", {})
164
+ patches_replace = transformer_options.get("patches_replace", {})
165
+ if img.ndim != 3 or txt.ndim != 3:
166
+ raise ValueError("Input img and txt tensors must have 3 dimensions.")
167
+
168
+ # running on sequences img
169
+ img = self.img_in(img)
170
+ vec = self.time_in(timestep_embedding(timesteps, 256).to(img.dtype))
171
+ if self.params.guidance_embed:
172
+ if guidance is not None:
173
+ vec = vec + self.guidance_in(timestep_embedding(guidance, 256).to(img.dtype))
174
+
175
+ if self.vector_in is not None:
176
+ if y is None:
177
+ y = torch.zeros((img.shape[0], self.params.vec_in_dim), device=img.device, dtype=img.dtype)
178
+ vec = vec + self.vector_in(y[:, :self.params.vec_in_dim])
179
+
180
+ if self.txt_norm is not None:
181
+ txt = self.txt_norm(txt)
182
+ txt = self.txt_in(txt)
183
+
184
+ if "post_input" in patches:
185
+ for p in patches["post_input"]:
186
+ out = p({"img": img, "txt": txt, "img_ids": img_ids, "txt_ids": txt_ids, "transformer_options": transformer_options})
187
+ img = out["img"]
188
+ txt = out["txt"]
189
+ img_ids = out["img_ids"]
190
+ txt_ids = out["txt_ids"]
191
+
192
+ if img_ids is not None:
193
+ ids = torch.cat((txt_ids, img_ids), dim=1)
194
+ pe = self.pe_embedder(ids)
195
+ else:
196
+ pe = None
197
+
198
+ vec_orig = vec
199
+ txt_vec = vec
200
+ extra_kwargs = {}
201
+ if timestep_zero_index is not None:
202
+ modulation_dims = []
203
+ batch = vec.shape[0] // 2
204
+ vec_orig = vec_orig.reshape(2, batch, vec.shape[1]).movedim(0, 1)
205
+ invert = invert_slices(timestep_zero_index, img.shape[1])
206
+ for s in invert:
207
+ modulation_dims.append((s[0], s[1], 0))
208
+ for s in timestep_zero_index:
209
+ modulation_dims.append((s[0], s[1], 1))
210
+ extra_kwargs["modulation_dims_img"] = modulation_dims
211
+ txt_vec = vec[:batch]
212
+
213
+ if self.params.global_modulation:
214
+ vec = (self.double_stream_modulation_img(vec_orig), self.double_stream_modulation_txt(txt_vec))
215
+
216
+ blocks_replace = patches_replace.get("dit", {})
217
+ transformer_options["total_blocks"] = len(self.double_blocks)
218
+ transformer_options["block_type"] = "double"
219
+ for i, block in enumerate(self.double_blocks):
220
+ transformer_options["block_index"] = i
221
+ if ("double_block", i) in blocks_replace:
222
+ def block_wrap(args):
223
+ out = {}
224
+ out["img"], out["txt"] = block(img=args["img"],
225
+ txt=args["txt"],
226
+ vec=args["vec"],
227
+ pe=args["pe"],
228
+ attn_mask=args.get("attn_mask"),
229
+ transformer_options=args.get("transformer_options"),
230
+ **extra_kwargs)
231
+ return out
232
+
233
+ out = blocks_replace[("double_block", i)]({"img": img,
234
+ "txt": txt,
235
+ "vec": vec,
236
+ "pe": pe,
237
+ "attn_mask": attn_mask,
238
+ "transformer_options": transformer_options},
239
+ {"original_block": block_wrap})
240
+ txt = out["txt"]
241
+ img = out["img"]
242
+ else:
243
+ img, txt = block(img=img,
244
+ txt=txt,
245
+ vec=vec,
246
+ pe=pe,
247
+ attn_mask=attn_mask,
248
+ transformer_options=transformer_options,
249
+ **extra_kwargs)
250
+
251
+ if control is not None: # Controlnet
252
+ control_i = control.get("input")
253
+ if i < len(control_i):
254
+ add = control_i[i]
255
+ if add is not None:
256
+ img[:, :add.shape[1]] += add
257
+
258
+ if img.dtype == torch.float16:
259
+ img = torch.nan_to_num(img, nan=0.0, posinf=65504, neginf=-65504)
260
+
261
+ img = torch.cat((txt, img), 1)
262
+
263
+ if self.params.global_modulation:
264
+ vec, _ = self.single_stream_modulation(vec_orig)
265
+
266
+ extra_kwargs = {}
267
+ if timestep_zero_index is not None:
268
+ lambda a: 0 if a == 0 else a + txt.shape[1]
269
+ modulation_dims_combined = list(map(lambda x: (0 if x[0] == 0 else x[0] + txt.shape[1], x[1] + txt.shape[1], x[2]), modulation_dims))
270
+ extra_kwargs["modulation_dims"] = modulation_dims_combined
271
+
272
+ transformer_options["total_blocks"] = len(self.single_blocks)
273
+ transformer_options["block_type"] = "single"
274
+ transformer_options["img_slice"] = [txt.shape[1], img.shape[1]]
275
+ for i, block in enumerate(self.single_blocks):
276
+ transformer_options["block_index"] = i
277
+ if ("single_block", i) in blocks_replace:
278
+ def block_wrap(args):
279
+ out = {}
280
+ out["img"] = block(args["img"],
281
+ vec=args["vec"],
282
+ pe=args["pe"],
283
+ attn_mask=args.get("attn_mask"),
284
+ transformer_options=args.get("transformer_options"),
285
+ **extra_kwargs)
286
+ return out
287
+
288
+ out = blocks_replace[("single_block", i)]({"img": img,
289
+ "vec": vec,
290
+ "pe": pe,
291
+ "attn_mask": attn_mask,
292
+ "transformer_options": transformer_options},
293
+ {"original_block": block_wrap})
294
+ img = out["img"]
295
+ else:
296
+ img = block(img, vec=vec, pe=pe, attn_mask=attn_mask, transformer_options=transformer_options, **extra_kwargs)
297
+
298
+ if control is not None: # Controlnet
299
+ control_o = control.get("output")
300
+ if i < len(control_o):
301
+ add = control_o[i]
302
+ if add is not None:
303
+ img[:, txt.shape[1] : txt.shape[1] + add.shape[1], ...] += add
304
+
305
+ img = img[:, txt.shape[1] :, ...]
306
+
307
+ extra_kwargs = {}
308
+ if timestep_zero_index is not None:
309
+ extra_kwargs["modulation_dims"] = modulation_dims
310
+
311
+ img = self.final_layer(img, vec_orig, **extra_kwargs) # (N, T, patch_size ** 2 * out_channels)
312
+ return img
313
+
314
+ def process_img(self, x, index=0, h_offset=0, w_offset=0, transformer_options={}):
315
+ bs, c, h, w = x.shape
316
+ patch_size = self.patch_size
317
+ x = comfy.ldm.common_dit.pad_to_patch_size(x, (patch_size, patch_size))
318
+
319
+ img = rearrange(x, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=patch_size, pw=patch_size)
320
+ h_len = ((h + (patch_size // 2)) // patch_size)
321
+ w_len = ((w + (patch_size // 2)) // patch_size)
322
+
323
+ h_offset = ((h_offset + (patch_size // 2)) // patch_size)
324
+ w_offset = ((w_offset + (patch_size // 2)) // patch_size)
325
+
326
+ steps_h = h_len
327
+ steps_w = w_len
328
+
329
+ rope_options = transformer_options.get("rope_options", None)
330
+ if rope_options is not None:
331
+ h_len = (h_len - 1.0) * rope_options.get("scale_y", 1.0) + 1.0
332
+ w_len = (w_len - 1.0) * rope_options.get("scale_x", 1.0) + 1.0
333
+
334
+ index += rope_options.get("shift_t", 0.0)
335
+ h_offset += rope_options.get("shift_y", 0.0)
336
+ w_offset += rope_options.get("shift_x", 0.0)
337
+
338
+ img_ids = torch.zeros((steps_h, steps_w, len(self.params.axes_dim)), device=x.device, dtype=torch.float32)
339
+ img_ids[:, :, 0] = img_ids[:, :, 1] + index
340
+ img_ids[:, :, 1] = img_ids[:, :, 1] + torch.linspace(h_offset, h_len - 1 + h_offset, steps=steps_h, device=x.device, dtype=torch.float32).unsqueeze(1)
341
+ img_ids[:, :, 2] = img_ids[:, :, 2] + torch.linspace(w_offset, w_len - 1 + w_offset, steps=steps_w, device=x.device, dtype=torch.float32).unsqueeze(0)
342
+ return img, repeat(img_ids, "h w c -> b (h w) c", b=bs)
343
+
344
+ def forward(self, x, timestep, context, y=None, guidance=None, ref_latents=None, control=None, transformer_options={}, **kwargs):
345
+ return comfy.patcher_extension.WrapperExecutor.new_class_executor(
346
+ self._forward,
347
+ self,
348
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.DIFFUSION_MODEL, transformer_options)
349
+ ).execute(x, timestep, context, y, guidance, ref_latents, control, transformer_options, **kwargs)
350
+
351
+ def _forward(self, x, timestep, context, y=None, guidance=None, ref_latents=None, control=None, transformer_options={}, **kwargs):
352
+ bs, c, h_orig, w_orig = x.shape
353
+ patch_size = self.patch_size
354
+
355
+ h_len = ((h_orig + (patch_size // 2)) // patch_size)
356
+ w_len = ((w_orig + (patch_size // 2)) // patch_size)
357
+ img, img_ids = self.process_img(x, transformer_options=transformer_options)
358
+ img_tokens = img.shape[1]
359
+ timestep_zero_index = None
360
+ if ref_latents is not None:
361
+ ref_num_tokens = []
362
+ h = 0
363
+ w = 0
364
+ index = 0
365
+ ref_latents_method = kwargs.get("ref_latents_method", self.params.default_ref_method)
366
+ timestep_zero = ref_latents_method == "index_timestep_zero"
367
+ for ref in ref_latents:
368
+ if ref_latents_method in ("index", "index_timestep_zero"):
369
+ index += self.params.ref_index_scale
370
+ h_offset = 0
371
+ w_offset = 0
372
+ elif ref_latents_method == "uxo":
373
+ index = 0
374
+ h_offset = h_len * patch_size + h
375
+ w_offset = w_len * patch_size + w
376
+ h += ref.shape[-2]
377
+ w += ref.shape[-1]
378
+ else:
379
+ index = 1
380
+ h_offset = 0
381
+ w_offset = 0
382
+ if ref.shape[-2] + h > ref.shape[-1] + w:
383
+ w_offset = w
384
+ else:
385
+ h_offset = h
386
+ h = max(h, ref.shape[-2] + h_offset)
387
+ w = max(w, ref.shape[-1] + w_offset)
388
+
389
+ kontext, kontext_ids = self.process_img(ref, index=index, h_offset=h_offset, w_offset=w_offset, transformer_options=transformer_options)
390
+ img = torch.cat([img, kontext], dim=1)
391
+ img_ids = torch.cat([img_ids, kontext_ids], dim=1)
392
+ ref_num_tokens.append(kontext.shape[1])
393
+ if timestep_zero:
394
+ if index > 0:
395
+ timestep = torch.cat([timestep, timestep * 0], dim=0)
396
+ timestep_zero_index = [[img_tokens, img_ids.shape[1]]]
397
+ transformer_options = transformer_options.copy()
398
+ transformer_options["reference_image_num_tokens"] = ref_num_tokens
399
+
400
+ txt_ids = torch.zeros((bs, context.shape[1], len(self.params.axes_dim)), device=x.device, dtype=torch.float32)
401
+
402
+ if len(self.params.txt_ids_dims) > 0:
403
+ for i in self.params.txt_ids_dims:
404
+ txt_ids[:, :, i] = torch.linspace(0, context.shape[1] - 1, steps=context.shape[1], device=x.device, dtype=torch.float32)
405
+
406
+ out = self.forward_orig(img, img_ids, context, txt_ids, timestep, y, guidance, control, timestep_zero_index=timestep_zero_index, transformer_options=transformer_options, attn_mask=kwargs.get("attention_mask", None))
407
+ out = out[:, :img_tokens]
408
+ return rearrange(out, "b (h w) (c ph pw) -> b c (h ph) (w pw)", h=h_len, w=w_len, ph=self.patch_size, pw=self.patch_size)[:,:,:h_orig,:w_orig]
ComfyUI/comfy/ldm/flux/redux.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import comfy.ops
3
+
4
+ ops = comfy.ops.manual_cast
5
+
6
+ class ReduxImageEncoder(torch.nn.Module):
7
+ def __init__(
8
+ self,
9
+ redux_dim: int = 1152,
10
+ txt_in_features: int = 4096,
11
+ device=None,
12
+ dtype=None,
13
+ ) -> None:
14
+ super().__init__()
15
+
16
+ self.redux_dim = redux_dim
17
+ self.device = device
18
+ self.dtype = dtype
19
+
20
+ self.redux_up = ops.Linear(redux_dim, txt_in_features * 3, dtype=dtype)
21
+ self.redux_down = ops.Linear(txt_in_features * 3, txt_in_features, dtype=dtype)
22
+
23
+ def forward(self, sigclip_embeds) -> torch.Tensor:
24
+ projected_x = self.redux_down(torch.nn.functional.silu(self.redux_up(sigclip_embeds)))
25
+ return projected_x
ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/asymm_models_joint.cpython-312.pyc ADDED
Binary file (20.1 kB). View file
 
ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/layers.cpython-312.pyc ADDED
Binary file (7.92 kB). View file
 
ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/rope_mixed.cpython-312.pyc ADDED
Binary file (3.21 kB). View file
 
ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/temporal_rope.cpython-312.pyc ADDED
Binary file (1.55 kB). View file
 
ComfyUI/comfy/ldm/genmo/joint_model/__pycache__/utils.cpython-312.pyc ADDED
Binary file (4.75 kB). View file
 
ComfyUI/comfy/ldm/genmo/joint_model/asymm_models_joint.py ADDED
@@ -0,0 +1,561 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #original code from https://github.com/genmoai/models under apache 2.0 license
2
+ #adapted to ComfyUI
3
+
4
+ from typing import Dict, List, Optional, Tuple
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+ from einops import rearrange
10
+ # from flash_attn import flash_attn_varlen_qkvpacked_func
11
+ from comfy.ldm.modules.attention import optimized_attention
12
+
13
+ from .layers import (
14
+ FeedForward,
15
+ PatchEmbed,
16
+ TimestepEmbedder,
17
+ )
18
+
19
+ from .rope_mixed import (
20
+ compute_mixed_rotation,
21
+ create_position_matrix,
22
+ )
23
+ from .temporal_rope import apply_rotary_emb_qk_real
24
+ from .utils import (
25
+ AttentionPool,
26
+ modulate,
27
+ )
28
+
29
+ import comfy.ldm.common_dit
30
+ import comfy.ops
31
+
32
+
33
+ def modulated_rmsnorm(x, scale, eps=1e-6):
34
+ # Normalize and modulate
35
+ x_normed = comfy.ldm.common_dit.rms_norm(x, eps=eps)
36
+ x_modulated = x_normed * (1 + scale.unsqueeze(1))
37
+
38
+ return x_modulated
39
+
40
+
41
+ def residual_tanh_gated_rmsnorm(x, x_res, gate, eps=1e-6):
42
+ # Apply tanh to gate
43
+ tanh_gate = torch.tanh(gate).unsqueeze(1)
44
+
45
+ # Normalize and apply gated scaling
46
+ x_normed = comfy.ldm.common_dit.rms_norm(x_res, eps=eps) * tanh_gate
47
+
48
+ # Apply residual connection
49
+ output = x + x_normed
50
+
51
+ return output
52
+
53
+ class AsymmetricAttention(nn.Module):
54
+ def __init__(
55
+ self,
56
+ dim_x: int,
57
+ dim_y: int,
58
+ num_heads: int = 8,
59
+ qkv_bias: bool = True,
60
+ qk_norm: bool = False,
61
+ attn_drop: float = 0.0,
62
+ update_y: bool = True,
63
+ out_bias: bool = True,
64
+ attend_to_padding: bool = False,
65
+ softmax_scale: Optional[float] = None,
66
+ device: Optional[torch.device] = None,
67
+ dtype=None,
68
+ operations=None,
69
+ ):
70
+ super().__init__()
71
+ self.dim_x = dim_x
72
+ self.dim_y = dim_y
73
+ self.num_heads = num_heads
74
+ self.head_dim = dim_x // num_heads
75
+ self.attn_drop = attn_drop
76
+ self.update_y = update_y
77
+ self.attend_to_padding = attend_to_padding
78
+ self.softmax_scale = softmax_scale
79
+ if dim_x % num_heads != 0:
80
+ raise ValueError(
81
+ f"dim_x={dim_x} should be divisible by num_heads={num_heads}"
82
+ )
83
+
84
+ # Input layers.
85
+ self.qkv_bias = qkv_bias
86
+ self.qkv_x = operations.Linear(dim_x, 3 * dim_x, bias=qkv_bias, device=device, dtype=dtype)
87
+ # Project text features to match visual features (dim_y -> dim_x)
88
+ self.qkv_y = operations.Linear(dim_y, 3 * dim_x, bias=qkv_bias, device=device, dtype=dtype)
89
+
90
+ # Query and key normalization for stability.
91
+ assert qk_norm
92
+ self.q_norm_x = operations.RMSNorm(self.head_dim, eps=1e-5, device=device, dtype=dtype)
93
+ self.k_norm_x = operations.RMSNorm(self.head_dim, eps=1e-5, device=device, dtype=dtype)
94
+ self.q_norm_y = operations.RMSNorm(self.head_dim, eps=1e-5, device=device, dtype=dtype)
95
+ self.k_norm_y = operations.RMSNorm(self.head_dim, eps=1e-5, device=device, dtype=dtype)
96
+
97
+ # Output layers. y features go back down from dim_x -> dim_y.
98
+ self.proj_x = operations.Linear(dim_x, dim_x, bias=out_bias, device=device, dtype=dtype)
99
+ self.proj_y = (
100
+ operations.Linear(dim_x, dim_y, bias=out_bias, device=device, dtype=dtype)
101
+ if update_y
102
+ else nn.Identity()
103
+ )
104
+
105
+ def forward(
106
+ self,
107
+ x: torch.Tensor, # (B, N, dim_x)
108
+ y: torch.Tensor, # (B, L, dim_y)
109
+ scale_x: torch.Tensor, # (B, dim_x), modulation for pre-RMSNorm.
110
+ scale_y: torch.Tensor, # (B, dim_y), modulation for pre-RMSNorm.
111
+ crop_y,
112
+ transformer_options={},
113
+ **rope_rotation,
114
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
115
+ rope_cos = rope_rotation.get("rope_cos")
116
+ rope_sin = rope_rotation.get("rope_sin")
117
+ # Pre-norm for visual features
118
+ x = modulated_rmsnorm(x, scale_x) # (B, M, dim_x) where M = N / cp_group_size
119
+
120
+ # Process visual features
121
+ # qkv_x = self.qkv_x(x) # (B, M, 3 * dim_x)
122
+ # assert qkv_x.dtype == torch.bfloat16
123
+ # qkv_x = all_to_all_collect_tokens(
124
+ # qkv_x, self.num_heads
125
+ # ) # (3, B, N, local_h, head_dim)
126
+
127
+ # Process text features
128
+ y = modulated_rmsnorm(y, scale_y) # (B, L, dim_y)
129
+ q_y, k_y, v_y = self.qkv_y(y).view(y.shape[0], y.shape[1], 3, self.num_heads, -1).unbind(2) # (B, N, local_h, head_dim)
130
+
131
+ q_y = self.q_norm_y(q_y)
132
+ k_y = self.k_norm_y(k_y)
133
+
134
+ # Split qkv_x into q, k, v
135
+ q_x, k_x, v_x = self.qkv_x(x).view(x.shape[0], x.shape[1], 3, self.num_heads, -1).unbind(2) # (B, N, local_h, head_dim)
136
+ q_x = self.q_norm_x(q_x)
137
+ q_x = apply_rotary_emb_qk_real(q_x, rope_cos, rope_sin)
138
+ k_x = self.k_norm_x(k_x)
139
+ k_x = apply_rotary_emb_qk_real(k_x, rope_cos, rope_sin)
140
+
141
+ q = torch.cat([q_x, q_y[:, :crop_y]], dim=1).transpose(1, 2)
142
+ k = torch.cat([k_x, k_y[:, :crop_y]], dim=1).transpose(1, 2)
143
+ v = torch.cat([v_x, v_y[:, :crop_y]], dim=1).transpose(1, 2)
144
+
145
+ xy = optimized_attention(q,
146
+ k,
147
+ v, self.num_heads, skip_reshape=True, transformer_options=transformer_options)
148
+
149
+ x, y = torch.tensor_split(xy, (q_x.shape[1],), dim=1)
150
+ x = self.proj_x(x)
151
+ o = torch.zeros(y.shape[0], q_y.shape[1], y.shape[-1], device=y.device, dtype=y.dtype)
152
+ o[:, :y.shape[1]] = y
153
+
154
+ y = self.proj_y(o)
155
+ # print("ox", x)
156
+ # print("oy", y)
157
+ return x, y
158
+
159
+
160
+ class AsymmetricJointBlock(nn.Module):
161
+ def __init__(
162
+ self,
163
+ hidden_size_x: int,
164
+ hidden_size_y: int,
165
+ num_heads: int,
166
+ *,
167
+ mlp_ratio_x: float = 8.0, # Ratio of hidden size to d_model for MLP for visual tokens.
168
+ mlp_ratio_y: float = 4.0, # Ratio of hidden size to d_model for MLP for text tokens.
169
+ update_y: bool = True, # Whether to update text tokens in this block.
170
+ device: Optional[torch.device] = None,
171
+ dtype=None,
172
+ operations=None,
173
+ **block_kwargs,
174
+ ):
175
+ super().__init__()
176
+ self.update_y = update_y
177
+ self.hidden_size_x = hidden_size_x
178
+ self.hidden_size_y = hidden_size_y
179
+ self.mod_x = operations.Linear(hidden_size_x, 4 * hidden_size_x, device=device, dtype=dtype)
180
+ if self.update_y:
181
+ self.mod_y = operations.Linear(hidden_size_x, 4 * hidden_size_y, device=device, dtype=dtype)
182
+ else:
183
+ self.mod_y = operations.Linear(hidden_size_x, hidden_size_y, device=device, dtype=dtype)
184
+
185
+ # Self-attention:
186
+ self.attn = AsymmetricAttention(
187
+ hidden_size_x,
188
+ hidden_size_y,
189
+ num_heads=num_heads,
190
+ update_y=update_y,
191
+ device=device,
192
+ dtype=dtype,
193
+ operations=operations,
194
+ **block_kwargs,
195
+ )
196
+
197
+ # MLP.
198
+ mlp_hidden_dim_x = int(hidden_size_x * mlp_ratio_x)
199
+ assert mlp_hidden_dim_x == int(1536 * 8)
200
+ self.mlp_x = FeedForward(
201
+ in_features=hidden_size_x,
202
+ hidden_size=mlp_hidden_dim_x,
203
+ multiple_of=256,
204
+ ffn_dim_multiplier=None,
205
+ device=device,
206
+ dtype=dtype,
207
+ operations=operations,
208
+ )
209
+
210
+ # MLP for text not needed in last block.
211
+ if self.update_y:
212
+ mlp_hidden_dim_y = int(hidden_size_y * mlp_ratio_y)
213
+ self.mlp_y = FeedForward(
214
+ in_features=hidden_size_y,
215
+ hidden_size=mlp_hidden_dim_y,
216
+ multiple_of=256,
217
+ ffn_dim_multiplier=None,
218
+ device=device,
219
+ dtype=dtype,
220
+ operations=operations,
221
+ )
222
+
223
+ def forward(
224
+ self,
225
+ x: torch.Tensor,
226
+ c: torch.Tensor,
227
+ y: torch.Tensor,
228
+ transformer_options={},
229
+ **attn_kwargs,
230
+ ):
231
+ """Forward pass of a block.
232
+
233
+ Args:
234
+ x: (B, N, dim) tensor of visual tokens
235
+ c: (B, dim) tensor of conditioned features
236
+ y: (B, L, dim) tensor of text tokens
237
+ num_frames: Number of frames in the video. N = num_frames * num_spatial_tokens
238
+
239
+ Returns:
240
+ x: (B, N, dim) tensor of visual tokens after block
241
+ y: (B, L, dim) tensor of text tokens after block
242
+ """
243
+ N = x.size(1)
244
+
245
+ c = F.silu(c)
246
+ mod_x = self.mod_x(c)
247
+ scale_msa_x, gate_msa_x, scale_mlp_x, gate_mlp_x = mod_x.chunk(4, dim=1)
248
+
249
+ mod_y = self.mod_y(c)
250
+ if self.update_y:
251
+ scale_msa_y, gate_msa_y, scale_mlp_y, gate_mlp_y = mod_y.chunk(4, dim=1)
252
+ else:
253
+ scale_msa_y = mod_y
254
+
255
+ # Self-attention block.
256
+ x_attn, y_attn = self.attn(
257
+ x,
258
+ y,
259
+ scale_x=scale_msa_x,
260
+ scale_y=scale_msa_y,
261
+ transformer_options=transformer_options,
262
+ **attn_kwargs,
263
+ )
264
+
265
+ assert x_attn.size(1) == N
266
+ x = residual_tanh_gated_rmsnorm(x, x_attn, gate_msa_x)
267
+ if self.update_y:
268
+ y = residual_tanh_gated_rmsnorm(y, y_attn, gate_msa_y)
269
+
270
+ # MLP block.
271
+ x = self.ff_block_x(x, scale_mlp_x, gate_mlp_x)
272
+ if self.update_y:
273
+ y = self.ff_block_y(y, scale_mlp_y, gate_mlp_y)
274
+
275
+ return x, y
276
+
277
+ def ff_block_x(self, x, scale_x, gate_x):
278
+ x_mod = modulated_rmsnorm(x, scale_x)
279
+ x_res = self.mlp_x(x_mod)
280
+ x = residual_tanh_gated_rmsnorm(x, x_res, gate_x) # Sandwich norm
281
+ return x
282
+
283
+ def ff_block_y(self, y, scale_y, gate_y):
284
+ y_mod = modulated_rmsnorm(y, scale_y)
285
+ y_res = self.mlp_y(y_mod)
286
+ y = residual_tanh_gated_rmsnorm(y, y_res, gate_y) # Sandwich norm
287
+ return y
288
+
289
+
290
+ class FinalLayer(nn.Module):
291
+ """
292
+ The final layer of DiT.
293
+ """
294
+
295
+ def __init__(
296
+ self,
297
+ hidden_size,
298
+ patch_size,
299
+ out_channels,
300
+ device: Optional[torch.device] = None,
301
+ dtype=None,
302
+ operations=None,
303
+ ):
304
+ super().__init__()
305
+ self.norm_final = operations.LayerNorm(
306
+ hidden_size, elementwise_affine=False, eps=1e-6, device=device, dtype=dtype
307
+ )
308
+ self.mod = operations.Linear(hidden_size, 2 * hidden_size, device=device, dtype=dtype)
309
+ self.linear = operations.Linear(
310
+ hidden_size, patch_size * patch_size * out_channels, device=device, dtype=dtype
311
+ )
312
+
313
+ def forward(self, x, c):
314
+ c = F.silu(c)
315
+ shift, scale = self.mod(c).chunk(2, dim=1)
316
+ x = modulate(self.norm_final(x), shift, scale)
317
+ x = self.linear(x)
318
+ return x
319
+
320
+
321
+ class AsymmDiTJoint(nn.Module):
322
+ """
323
+ Diffusion model with a Transformer backbone.
324
+
325
+ Ingests text embeddings instead of a label.
326
+ """
327
+
328
+ def __init__(
329
+ self,
330
+ *,
331
+ patch_size=2,
332
+ in_channels=4,
333
+ hidden_size_x=1152,
334
+ hidden_size_y=1152,
335
+ depth=48,
336
+ num_heads=16,
337
+ mlp_ratio_x=8.0,
338
+ mlp_ratio_y=4.0,
339
+ use_t5: bool = False,
340
+ t5_feat_dim: int = 4096,
341
+ t5_token_length: int = 256,
342
+ learn_sigma=True,
343
+ patch_embed_bias: bool = True,
344
+ timestep_mlp_bias: bool = True,
345
+ attend_to_padding: bool = False,
346
+ timestep_scale: Optional[float] = None,
347
+ use_extended_posenc: bool = False,
348
+ posenc_preserve_area: bool = False,
349
+ rope_theta: float = 10000.0,
350
+ image_model=None,
351
+ device: Optional[torch.device] = None,
352
+ dtype=None,
353
+ operations=None,
354
+ **block_kwargs,
355
+ ):
356
+ super().__init__()
357
+
358
+ self.dtype = dtype
359
+ self.learn_sigma = learn_sigma
360
+ self.in_channels = in_channels
361
+ self.out_channels = in_channels * 2 if learn_sigma else in_channels
362
+ self.patch_size = patch_size
363
+ self.num_heads = num_heads
364
+ self.hidden_size_x = hidden_size_x
365
+ self.hidden_size_y = hidden_size_y
366
+ self.head_dim = (
367
+ hidden_size_x // num_heads
368
+ ) # Head dimension and count is determined by visual.
369
+ self.attend_to_padding = attend_to_padding
370
+ self.use_extended_posenc = use_extended_posenc
371
+ self.posenc_preserve_area = posenc_preserve_area
372
+ self.use_t5 = use_t5
373
+ self.t5_token_length = t5_token_length
374
+ self.t5_feat_dim = t5_feat_dim
375
+ self.rope_theta = (
376
+ rope_theta # Scaling factor for frequency computation for temporal RoPE.
377
+ )
378
+
379
+ self.x_embedder = PatchEmbed(
380
+ patch_size=patch_size,
381
+ in_chans=in_channels,
382
+ embed_dim=hidden_size_x,
383
+ bias=patch_embed_bias,
384
+ dtype=dtype,
385
+ device=device,
386
+ operations=operations
387
+ )
388
+ # Conditionings
389
+ # Timestep
390
+ self.t_embedder = TimestepEmbedder(
391
+ hidden_size_x, bias=timestep_mlp_bias, timestep_scale=timestep_scale, dtype=dtype, device=device, operations=operations
392
+ )
393
+
394
+ if self.use_t5:
395
+ # Caption Pooling (T5)
396
+ self.t5_y_embedder = AttentionPool(
397
+ t5_feat_dim, num_heads=8, output_dim=hidden_size_x, dtype=dtype, device=device, operations=operations
398
+ )
399
+
400
+ # Dense Embedding Projection (T5)
401
+ self.t5_yproj = operations.Linear(
402
+ t5_feat_dim, hidden_size_y, bias=True, dtype=dtype, device=device
403
+ )
404
+
405
+ # Initialize pos_frequencies as an empty parameter.
406
+ self.pos_frequencies = nn.Parameter(
407
+ torch.empty(3, self.num_heads, self.head_dim // 2, dtype=dtype, device=device)
408
+ )
409
+
410
+ assert not self.attend_to_padding
411
+
412
+ # for depth 48:
413
+ # b = 0: AsymmetricJointBlock, update_y=True
414
+ # b = 1: AsymmetricJointBlock, update_y=True
415
+ # ...
416
+ # b = 46: AsymmetricJointBlock, update_y=True
417
+ # b = 47: AsymmetricJointBlock, update_y=False. No need to update text features.
418
+ blocks = []
419
+ for b in range(depth):
420
+ # Joint multi-modal block
421
+ update_y = b < depth - 1
422
+ block = AsymmetricJointBlock(
423
+ hidden_size_x,
424
+ hidden_size_y,
425
+ num_heads,
426
+ mlp_ratio_x=mlp_ratio_x,
427
+ mlp_ratio_y=mlp_ratio_y,
428
+ update_y=update_y,
429
+ attend_to_padding=attend_to_padding,
430
+ device=device,
431
+ dtype=dtype,
432
+ operations=operations,
433
+ **block_kwargs,
434
+ )
435
+
436
+ blocks.append(block)
437
+ self.blocks = nn.ModuleList(blocks)
438
+
439
+ self.final_layer = FinalLayer(
440
+ hidden_size_x, patch_size, self.out_channels, dtype=dtype, device=device, operations=operations
441
+ )
442
+
443
+ def embed_x(self, x: torch.Tensor) -> torch.Tensor:
444
+ """
445
+ Args:
446
+ x: (B, C=12, T, H, W) tensor of visual tokens
447
+
448
+ Returns:
449
+ x: (B, C=3072, N) tensor of visual tokens with positional embedding.
450
+ """
451
+ return self.x_embedder(x) # Convert BcTHW to BCN
452
+
453
+ def prepare(
454
+ self,
455
+ x: torch.Tensor,
456
+ sigma: torch.Tensor,
457
+ t5_feat: torch.Tensor,
458
+ t5_mask: torch.Tensor,
459
+ ):
460
+ """Prepare input and conditioning embeddings."""
461
+ # Visual patch embeddings with positional encoding.
462
+ T, H, W = x.shape[-3:]
463
+ pH, pW = H // self.patch_size, W // self.patch_size
464
+ x = self.embed_x(x) # (B, N, D), where N = T * H * W / patch_size ** 2
465
+ assert x.ndim == 3
466
+
467
+ pH, pW = H // self.patch_size, W // self.patch_size
468
+ N = T * pH * pW
469
+ assert x.size(1) == N
470
+ pos = create_position_matrix(
471
+ T, pH=pH, pW=pW, device=x.device, dtype=torch.float32
472
+ ) # (N, 3)
473
+ rope_cos, rope_sin = compute_mixed_rotation(
474
+ freqs=comfy.ops.cast_to(self.pos_frequencies, dtype=x.dtype, device=x.device), pos=pos
475
+ ) # Each are (N, num_heads, dim // 2)
476
+
477
+ c_t = self.t_embedder(1 - sigma, out_dtype=x.dtype) # (B, D)
478
+
479
+ t5_y_pool = self.t5_y_embedder(t5_feat, t5_mask) # (B, D)
480
+
481
+ c = c_t + t5_y_pool
482
+
483
+ y_feat = self.t5_yproj(t5_feat) # (B, L, t5_feat_dim) --> (B, L, D)
484
+
485
+ return x, c, y_feat, rope_cos, rope_sin
486
+
487
+ def forward(
488
+ self,
489
+ x: torch.Tensor,
490
+ timestep: torch.Tensor,
491
+ context: List[torch.Tensor],
492
+ attention_mask: List[torch.Tensor],
493
+ num_tokens=256,
494
+ packed_indices: Dict[str, torch.Tensor] = None,
495
+ rope_cos: torch.Tensor = None,
496
+ rope_sin: torch.Tensor = None,
497
+ control=None, transformer_options={}, **kwargs
498
+ ):
499
+ patches_replace = transformer_options.get("patches_replace", {})
500
+ y_feat = context
501
+ y_mask = attention_mask
502
+ sigma = timestep
503
+ """Forward pass of DiT.
504
+
505
+ Args:
506
+ x: (B, C, T, H, W) tensor of spatial inputs (images or latent representations of images)
507
+ sigma: (B,) tensor of noise standard deviations
508
+ y_feat: List((B, L, y_feat_dim) tensor of caption token features. For SDXL text encoders: L=77, y_feat_dim=2048)
509
+ y_mask: List((B, L) boolean tensor indicating which tokens are not padding)
510
+ packed_indices: Dict with keys for Flash Attention. Result of compute_packed_indices.
511
+ """
512
+ B, _, T, H, W = x.shape
513
+
514
+ x, c, y_feat, rope_cos, rope_sin = self.prepare(
515
+ x, sigma, y_feat, y_mask
516
+ )
517
+ del y_mask
518
+
519
+ blocks_replace = patches_replace.get("dit", {})
520
+ for i, block in enumerate(self.blocks):
521
+ if ("double_block", i) in blocks_replace:
522
+ def block_wrap(args):
523
+ out = {}
524
+ out["img"], out["txt"] = block(
525
+ args["img"],
526
+ args["vec"],
527
+ args["txt"],
528
+ rope_cos=args["rope_cos"],
529
+ rope_sin=args["rope_sin"],
530
+ crop_y=args["num_tokens"],
531
+ transformer_options=args["transformer_options"]
532
+ )
533
+ return out
534
+ out = blocks_replace[("double_block", i)]({"img": x, "txt": y_feat, "vec": c, "rope_cos": rope_cos, "rope_sin": rope_sin, "num_tokens": num_tokens, "transformer_options": transformer_options}, {"original_block": block_wrap})
535
+ y_feat = out["txt"]
536
+ x = out["img"]
537
+ else:
538
+ x, y_feat = block(
539
+ x,
540
+ c,
541
+ y_feat,
542
+ rope_cos=rope_cos,
543
+ rope_sin=rope_sin,
544
+ crop_y=num_tokens,
545
+ transformer_options=transformer_options,
546
+ ) # (B, M, D), (B, L, D)
547
+ del y_feat # Final layers don't use dense text features.
548
+
549
+ x = self.final_layer(x, c) # (B, M, patch_size ** 2 * out_channels)
550
+ x = rearrange(
551
+ x,
552
+ "B (T hp wp) (p1 p2 c) -> B c T (hp p1) (wp p2)",
553
+ T=T,
554
+ hp=H // self.patch_size,
555
+ wp=W // self.patch_size,
556
+ p1=self.patch_size,
557
+ p2=self.patch_size,
558
+ c=self.out_channels,
559
+ )
560
+
561
+ return -x
ComfyUI/comfy/ldm/genmo/joint_model/layers.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #original code from https://github.com/genmoai/models under apache 2.0 license
2
+ #adapted to ComfyUI
3
+
4
+ import collections.abc
5
+ import math
6
+ from itertools import repeat
7
+ from typing import Callable, Optional
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from einops import rearrange
13
+ import comfy.ldm.common_dit
14
+
15
+
16
+ # From PyTorch internals
17
+ def _ntuple(n):
18
+ def parse(x):
19
+ if isinstance(x, collections.abc.Iterable) and not isinstance(x, str):
20
+ return tuple(x)
21
+ return tuple(repeat(x, n))
22
+
23
+ return parse
24
+
25
+
26
+ to_2tuple = _ntuple(2)
27
+
28
+
29
+ class TimestepEmbedder(nn.Module):
30
+ def __init__(
31
+ self,
32
+ hidden_size: int,
33
+ frequency_embedding_size: int = 256,
34
+ *,
35
+ bias: bool = True,
36
+ timestep_scale: Optional[float] = None,
37
+ dtype=None,
38
+ device=None,
39
+ operations=None,
40
+ ):
41
+ super().__init__()
42
+ self.mlp = nn.Sequential(
43
+ operations.Linear(frequency_embedding_size, hidden_size, bias=bias, dtype=dtype, device=device),
44
+ nn.SiLU(),
45
+ operations.Linear(hidden_size, hidden_size, bias=bias, dtype=dtype, device=device),
46
+ )
47
+ self.frequency_embedding_size = frequency_embedding_size
48
+ self.timestep_scale = timestep_scale
49
+
50
+ @staticmethod
51
+ def timestep_embedding(t, dim, max_period=10000):
52
+ half = dim // 2
53
+ freqs = torch.arange(start=0, end=half, dtype=torch.float32, device=t.device)
54
+ freqs.mul_(-math.log(max_period) / half).exp_()
55
+ args = t[:, None].float() * freqs[None]
56
+ embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
57
+ if dim % 2:
58
+ embedding = torch.cat(
59
+ [embedding, torch.zeros_like(embedding[:, :1])], dim=-1
60
+ )
61
+ return embedding
62
+
63
+ def forward(self, t, out_dtype):
64
+ if self.timestep_scale is not None:
65
+ t = t * self.timestep_scale
66
+ t_freq = self.timestep_embedding(t, self.frequency_embedding_size).to(dtype=out_dtype)
67
+ t_emb = self.mlp(t_freq)
68
+ return t_emb
69
+
70
+
71
+ class FeedForward(nn.Module):
72
+ def __init__(
73
+ self,
74
+ in_features: int,
75
+ hidden_size: int,
76
+ multiple_of: int,
77
+ ffn_dim_multiplier: Optional[float],
78
+ device: Optional[torch.device] = None,
79
+ dtype=None,
80
+ operations=None,
81
+ ):
82
+ super().__init__()
83
+ # keep parameter count and computation constant compared to standard FFN
84
+ hidden_size = int(2 * hidden_size / 3)
85
+ # custom dim factor multiplier
86
+ if ffn_dim_multiplier is not None:
87
+ hidden_size = int(ffn_dim_multiplier * hidden_size)
88
+ hidden_size = multiple_of * ((hidden_size + multiple_of - 1) // multiple_of)
89
+
90
+ self.hidden_dim = hidden_size
91
+ self.w1 = operations.Linear(in_features, 2 * hidden_size, bias=False, device=device, dtype=dtype)
92
+ self.w2 = operations.Linear(hidden_size, in_features, bias=False, device=device, dtype=dtype)
93
+
94
+ def forward(self, x):
95
+ x, gate = self.w1(x).chunk(2, dim=-1)
96
+ x = self.w2(F.silu(x) * gate)
97
+ return x
98
+
99
+
100
+ class PatchEmbed(nn.Module):
101
+ def __init__(
102
+ self,
103
+ patch_size: int = 16,
104
+ in_chans: int = 3,
105
+ embed_dim: int = 768,
106
+ norm_layer: Optional[Callable] = None,
107
+ flatten: bool = True,
108
+ bias: bool = True,
109
+ dynamic_img_pad: bool = False,
110
+ dtype=None,
111
+ device=None,
112
+ operations=None,
113
+ ):
114
+ super().__init__()
115
+ self.patch_size = to_2tuple(patch_size)
116
+ self.flatten = flatten
117
+ self.dynamic_img_pad = dynamic_img_pad
118
+
119
+ self.proj = operations.Conv2d(
120
+ in_chans,
121
+ embed_dim,
122
+ kernel_size=patch_size,
123
+ stride=patch_size,
124
+ bias=bias,
125
+ device=device,
126
+ dtype=dtype,
127
+ )
128
+ assert norm_layer is None
129
+ self.norm = (
130
+ norm_layer(embed_dim, device=device) if norm_layer else nn.Identity()
131
+ )
132
+
133
+ def forward(self, x):
134
+ B, _C, T, H, W = x.shape
135
+ if not self.dynamic_img_pad:
136
+ assert H % self.patch_size[0] == 0, f"Input height ({H}) should be divisible by patch size ({self.patch_size[0]})."
137
+ assert W % self.patch_size[1] == 0, f"Input width ({W}) should be divisible by patch size ({self.patch_size[1]})."
138
+ else:
139
+ pad_h = (self.patch_size[0] - H % self.patch_size[0]) % self.patch_size[0]
140
+ pad_w = (self.patch_size[1] - W % self.patch_size[1]) % self.patch_size[1]
141
+ x = F.pad(x, (0, pad_w, 0, pad_h))
142
+
143
+ x = rearrange(x, "B C T H W -> (B T) C H W", B=B, T=T)
144
+ x = comfy.ldm.common_dit.pad_to_patch_size(x, self.patch_size, padding_mode='circular')
145
+ x = self.proj(x)
146
+
147
+ # Flatten temporal and spatial dimensions.
148
+ if not self.flatten:
149
+ raise NotImplementedError("Must flatten output.")
150
+ x = rearrange(x, "(B T) C H W -> B (T H W) C", B=B, T=T)
151
+
152
+ x = self.norm(x)
153
+ return x
ComfyUI/comfy/ldm/genmo/joint_model/rope_mixed.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #original code from https://github.com/genmoai/models under apache 2.0 license
2
+
3
+ # import functools
4
+ import math
5
+
6
+ import torch
7
+
8
+
9
+ def centers(start: float, stop, num, dtype=None, device=None):
10
+ """linspace through bin centers.
11
+
12
+ Args:
13
+ start (float): Start of the range.
14
+ stop (float): End of the range.
15
+ num (int): Number of points.
16
+ dtype (torch.dtype): Data type of the points.
17
+ device (torch.device): Device of the points.
18
+
19
+ Returns:
20
+ centers (Tensor): Centers of the bins. Shape: (num,).
21
+ """
22
+ edges = torch.linspace(start, stop, num + 1, dtype=dtype, device=device)
23
+ return (edges[:-1] + edges[1:]) / 2
24
+
25
+
26
+ # @functools.lru_cache(maxsize=1)
27
+ def create_position_matrix(
28
+ T: int,
29
+ pH: int,
30
+ pW: int,
31
+ device: torch.device,
32
+ dtype: torch.dtype,
33
+ *,
34
+ target_area: float = 36864,
35
+ ):
36
+ """
37
+ Args:
38
+ T: int - Temporal dimension
39
+ pH: int - Height dimension after patchify
40
+ pW: int - Width dimension after patchify
41
+
42
+ Returns:
43
+ pos: [T * pH * pW, 3] - position matrix
44
+ """
45
+ # Create 1D tensors for each dimension
46
+ t = torch.arange(T, dtype=dtype)
47
+
48
+ # Positionally interpolate to area 36864.
49
+ # (3072x3072 frame with 16x16 patches = 192x192 latents).
50
+ # This automatically scales rope positions when the resolution changes.
51
+ # We use a large target area so the model is more sensitive
52
+ # to changes in the learned pos_frequencies matrix.
53
+ scale = math.sqrt(target_area / (pW * pH))
54
+ w = centers(-pW * scale / 2, pW * scale / 2, pW)
55
+ h = centers(-pH * scale / 2, pH * scale / 2, pH)
56
+
57
+ # Use meshgrid to create 3D grids
58
+ grid_t, grid_h, grid_w = torch.meshgrid(t, h, w, indexing="ij")
59
+
60
+ # Stack and reshape the grids.
61
+ pos = torch.stack([grid_t, grid_h, grid_w], dim=-1) # [T, pH, pW, 3]
62
+ pos = pos.view(-1, 3) # [T * pH * pW, 3]
63
+ pos = pos.to(dtype=dtype, device=device)
64
+
65
+ return pos
66
+
67
+
68
+ def compute_mixed_rotation(
69
+ freqs: torch.Tensor,
70
+ pos: torch.Tensor,
71
+ ):
72
+ """
73
+ Project each 3-dim position into per-head, per-head-dim 1D frequencies.
74
+
75
+ Args:
76
+ freqs: [3, num_heads, num_freqs] - learned rotation frequency (for t, row, col) for each head position
77
+ pos: [N, 3] - position of each token
78
+ num_heads: int
79
+
80
+ Returns:
81
+ freqs_cos: [N, num_heads, num_freqs] - cosine components
82
+ freqs_sin: [N, num_heads, num_freqs] - sine components
83
+ """
84
+ assert freqs.ndim == 3
85
+ freqs_sum = torch.einsum("Nd,dhf->Nhf", pos.to(freqs), freqs)
86
+ freqs_cos = torch.cos(freqs_sum)
87
+ freqs_sin = torch.sin(freqs_sum)
88
+ return freqs_cos, freqs_sin
ComfyUI/comfy/ldm/genmo/joint_model/temporal_rope.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #original code from https://github.com/genmoai/models under apache 2.0 license
2
+
3
+ # Based on Llama3 Implementation.
4
+ import torch
5
+
6
+
7
+ def apply_rotary_emb_qk_real(
8
+ xqk: torch.Tensor,
9
+ freqs_cos: torch.Tensor,
10
+ freqs_sin: torch.Tensor,
11
+ ) -> torch.Tensor:
12
+ """
13
+ Apply rotary embeddings to input tensors using the given frequency tensor without complex numbers.
14
+
15
+ Args:
16
+ xqk (torch.Tensor): Query and/or Key tensors to apply rotary embeddings. Shape: (B, S, *, num_heads, D)
17
+ Can be either just query or just key, or both stacked along some batch or * dim.
18
+ freqs_cos (torch.Tensor): Precomputed cosine frequency tensor.
19
+ freqs_sin (torch.Tensor): Precomputed sine frequency tensor.
20
+
21
+ Returns:
22
+ torch.Tensor: The input tensor with rotary embeddings applied.
23
+ """
24
+ # Split the last dimension into even and odd parts
25
+ xqk_even = xqk[..., 0::2]
26
+ xqk_odd = xqk[..., 1::2]
27
+
28
+ # Apply rotation
29
+ cos_part = (xqk_even * freqs_cos - xqk_odd * freqs_sin).type_as(xqk)
30
+ sin_part = (xqk_even * freqs_sin + xqk_odd * freqs_cos).type_as(xqk)
31
+
32
+ # Interleave the results back into the original shape
33
+ out = torch.stack([cos_part, sin_part], dim=-1).flatten(-2)
34
+ return out
ComfyUI/comfy/ldm/genmo/joint_model/utils.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #original code from https://github.com/genmoai/models under apache 2.0 license
2
+ #adapted to ComfyUI
3
+
4
+ from typing import Optional
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+
10
+
11
+ def modulate(x, shift, scale):
12
+ return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
13
+
14
+
15
+ def pool_tokens(x: torch.Tensor, mask: torch.Tensor, *, keepdim=False) -> torch.Tensor:
16
+ """
17
+ Pool tokens in x using mask.
18
+
19
+ NOTE: We assume x does not require gradients.
20
+
21
+ Args:
22
+ x: (B, L, D) tensor of tokens.
23
+ mask: (B, L) boolean tensor indicating which tokens are not padding.
24
+
25
+ Returns:
26
+ pooled: (B, D) tensor of pooled tokens.
27
+ """
28
+ assert x.size(1) == mask.size(1) # Expected mask to have same length as tokens.
29
+ assert x.size(0) == mask.size(0) # Expected mask to have same batch size as tokens.
30
+ mask = mask[:, :, None].to(dtype=x.dtype)
31
+ mask = mask / mask.sum(dim=1, keepdim=True).clamp(min=1)
32
+ pooled = (x * mask).sum(dim=1, keepdim=keepdim)
33
+ return pooled
34
+
35
+
36
+ class AttentionPool(nn.Module):
37
+ def __init__(
38
+ self,
39
+ embed_dim: int,
40
+ num_heads: int,
41
+ output_dim: int = None,
42
+ device: Optional[torch.device] = None,
43
+ dtype=None,
44
+ operations=None,
45
+ ):
46
+ """
47
+ Args:
48
+ spatial_dim (int): Number of tokens in sequence length.
49
+ embed_dim (int): Dimensionality of input tokens.
50
+ num_heads (int): Number of attention heads.
51
+ output_dim (int): Dimensionality of output tokens. Defaults to embed_dim.
52
+ """
53
+ super().__init__()
54
+ self.num_heads = num_heads
55
+ self.to_kv = operations.Linear(embed_dim, 2 * embed_dim, device=device, dtype=dtype)
56
+ self.to_q = operations.Linear(embed_dim, embed_dim, device=device, dtype=dtype)
57
+ self.to_out = operations.Linear(embed_dim, output_dim or embed_dim, device=device, dtype=dtype)
58
+
59
+ def forward(self, x, mask):
60
+ """
61
+ Args:
62
+ x (torch.Tensor): (B, L, D) tensor of input tokens.
63
+ mask (torch.Tensor): (B, L) boolean tensor indicating which tokens are not padding.
64
+
65
+ NOTE: We assume x does not require gradients.
66
+
67
+ Returns:
68
+ x (torch.Tensor): (B, D) tensor of pooled tokens.
69
+ """
70
+ D = x.size(2)
71
+
72
+ # Construct attention mask, shape: (B, 1, num_queries=1, num_keys=1+L).
73
+ attn_mask = mask[:, None, None, :].bool() # (B, 1, 1, L).
74
+ attn_mask = F.pad(attn_mask, (1, 0), value=True) # (B, 1, 1, 1+L).
75
+
76
+ # Average non-padding token features. These will be used as the query.
77
+ x_pool = pool_tokens(x, mask, keepdim=True) # (B, 1, D)
78
+
79
+ # Concat pooled features to input sequence.
80
+ x = torch.cat([x_pool, x], dim=1) # (B, L+1, D)
81
+
82
+ # Compute queries, keys, values. Only the mean token is used to create a query.
83
+ kv = self.to_kv(x) # (B, L+1, 2 * D)
84
+ q = self.to_q(x[:, 0]) # (B, D)
85
+
86
+ # Extract heads.
87
+ head_dim = D // self.num_heads
88
+ kv = kv.unflatten(2, (2, self.num_heads, head_dim)) # (B, 1+L, 2, H, head_dim)
89
+ kv = kv.transpose(1, 3) # (B, H, 2, 1+L, head_dim)
90
+ k, v = kv.unbind(2) # (B, H, 1+L, head_dim)
91
+ q = q.unflatten(1, (self.num_heads, head_dim)) # (B, H, head_dim)
92
+ q = q.unsqueeze(2) # (B, H, 1, head_dim)
93
+
94
+ # Compute attention.
95
+ x = F.scaled_dot_product_attention(
96
+ q, k, v, attn_mask=attn_mask, dropout_p=0.0
97
+ ) # (B, H, 1, head_dim)
98
+
99
+ # Concatenate heads and run output.
100
+ x = x.squeeze(2).flatten(1, 2) # (B, D = H * head_dim)
101
+ x = self.to_out(x)
102
+ return x
ComfyUI/comfy/ldm/genmo/vae/__pycache__/model.cpython-312.pyc ADDED
Binary file (29.2 kB). View file
 
ComfyUI/comfy/ldm/genmo/vae/model.py ADDED
@@ -0,0 +1,711 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #original code from https://github.com/genmoai/models under apache 2.0 license
2
+ #adapted to ComfyUI
3
+
4
+ from typing import List, Optional, Tuple, Union
5
+ from functools import partial
6
+ import math
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torch.nn.functional as F
11
+ from einops import rearrange
12
+
13
+ from comfy.ldm.modules.attention import optimized_attention
14
+
15
+ import comfy.ops
16
+ ops = comfy.ops.disable_weight_init
17
+
18
+ # import mochi_preview.dit.joint_model.context_parallel as cp
19
+ # from mochi_preview.vae.cp_conv import cp_pass_frames, gather_all_frames
20
+
21
+
22
+ def cast_tuple(t, length=1):
23
+ return t if isinstance(t, tuple) else ((t,) * length)
24
+
25
+
26
+ class GroupNormSpatial(ops.GroupNorm):
27
+ """
28
+ GroupNorm applied per-frame.
29
+ """
30
+
31
+ def forward(self, x: torch.Tensor, *, chunk_size: int = 8):
32
+ B, C, T, H, W = x.shape
33
+ x = rearrange(x, "B C T H W -> (B T) C H W")
34
+ # Run group norm in chunks.
35
+ output = torch.empty_like(x)
36
+ for b in range(0, B * T, chunk_size):
37
+ output[b : b + chunk_size] = super().forward(x[b : b + chunk_size])
38
+ return rearrange(output, "(B T) C H W -> B C T H W", B=B, T=T)
39
+
40
+ class PConv3d(ops.Conv3d):
41
+ def __init__(
42
+ self,
43
+ in_channels,
44
+ out_channels,
45
+ kernel_size: Union[int, Tuple[int, int, int]],
46
+ stride: Union[int, Tuple[int, int, int]],
47
+ causal: bool = True,
48
+ context_parallel: bool = True,
49
+ **kwargs,
50
+ ):
51
+ self.causal = causal
52
+ self.context_parallel = context_parallel
53
+ kernel_size = cast_tuple(kernel_size, 3)
54
+ stride = cast_tuple(stride, 3)
55
+ height_pad = (kernel_size[1] - 1) // 2
56
+ width_pad = (kernel_size[2] - 1) // 2
57
+
58
+ super().__init__(
59
+ in_channels=in_channels,
60
+ out_channels=out_channels,
61
+ kernel_size=kernel_size,
62
+ stride=stride,
63
+ dilation=(1, 1, 1),
64
+ padding=(0, height_pad, width_pad),
65
+ **kwargs,
66
+ )
67
+
68
+ def forward(self, x: torch.Tensor):
69
+ # Compute padding amounts.
70
+ context_size = self.kernel_size[0] - 1
71
+ if self.causal:
72
+ pad_front = context_size
73
+ pad_back = 0
74
+ else:
75
+ pad_front = context_size // 2
76
+ pad_back = context_size - pad_front
77
+
78
+ # Apply padding.
79
+ assert self.padding_mode == "replicate" # DEBUG
80
+ mode = "constant" if self.padding_mode == "zeros" else self.padding_mode
81
+ x = F.pad(x, (0, 0, 0, 0, pad_front, pad_back), mode=mode)
82
+ return super().forward(x)
83
+
84
+
85
+ class Conv1x1(ops.Linear):
86
+ """*1x1 Conv implemented with a linear layer."""
87
+
88
+ def __init__(self, in_features: int, out_features: int, *args, **kwargs):
89
+ super().__init__(in_features, out_features, *args, **kwargs)
90
+
91
+ def forward(self, x: torch.Tensor):
92
+ """Forward pass.
93
+
94
+ Args:
95
+ x: Input tensor. Shape: [B, C, *] or [B, *, C].
96
+
97
+ Returns:
98
+ x: Output tensor. Shape: [B, C', *] or [B, *, C'].
99
+ """
100
+ x = x.movedim(1, -1)
101
+ x = super().forward(x)
102
+ x = x.movedim(-1, 1)
103
+ return x
104
+
105
+
106
+ class DepthToSpaceTime(nn.Module):
107
+ def __init__(
108
+ self,
109
+ temporal_expansion: int,
110
+ spatial_expansion: int,
111
+ ):
112
+ super().__init__()
113
+ self.temporal_expansion = temporal_expansion
114
+ self.spatial_expansion = spatial_expansion
115
+
116
+ # When printed, this module should show the temporal and spatial expansion factors.
117
+ def extra_repr(self):
118
+ return f"texp={self.temporal_expansion}, sexp={self.spatial_expansion}"
119
+
120
+ def forward(self, x: torch.Tensor):
121
+ """Forward pass.
122
+
123
+ Args:
124
+ x: Input tensor. Shape: [B, C, T, H, W].
125
+
126
+ Returns:
127
+ x: Rearranged tensor. Shape: [B, C/(st*s*s), T*st, H*s, W*s].
128
+ """
129
+ x = rearrange(
130
+ x,
131
+ "B (C st sh sw) T H W -> B C (T st) (H sh) (W sw)",
132
+ st=self.temporal_expansion,
133
+ sh=self.spatial_expansion,
134
+ sw=self.spatial_expansion,
135
+ )
136
+
137
+ # cp_rank, _ = cp.get_cp_rank_size()
138
+ if self.temporal_expansion > 1: # and cp_rank == 0:
139
+ # Drop the first self.temporal_expansion - 1 frames.
140
+ # This is because we always want the 3x3x3 conv filter to only apply
141
+ # to the first frame, and the first frame doesn't need to be repeated.
142
+ assert all(x.shape)
143
+ x = x[:, :, self.temporal_expansion - 1 :]
144
+ assert all(x.shape)
145
+
146
+ return x
147
+
148
+
149
+ def norm_fn(
150
+ in_channels: int,
151
+ affine: bool = True,
152
+ ):
153
+ return GroupNormSpatial(affine=affine, num_groups=32, num_channels=in_channels)
154
+
155
+
156
+ class ResBlock(nn.Module):
157
+ """Residual block that preserves the spatial dimensions."""
158
+
159
+ def __init__(
160
+ self,
161
+ channels: int,
162
+ *,
163
+ affine: bool = True,
164
+ attn_block: Optional[nn.Module] = None,
165
+ causal: bool = True,
166
+ prune_bottleneck: bool = False,
167
+ padding_mode: str,
168
+ bias: bool = True,
169
+ ):
170
+ super().__init__()
171
+ self.channels = channels
172
+
173
+ assert causal
174
+ self.stack = nn.Sequential(
175
+ norm_fn(channels, affine=affine),
176
+ nn.SiLU(inplace=True),
177
+ PConv3d(
178
+ in_channels=channels,
179
+ out_channels=channels // 2 if prune_bottleneck else channels,
180
+ kernel_size=(3, 3, 3),
181
+ stride=(1, 1, 1),
182
+ padding_mode=padding_mode,
183
+ bias=bias,
184
+ causal=causal,
185
+ ),
186
+ norm_fn(channels, affine=affine),
187
+ nn.SiLU(inplace=True),
188
+ PConv3d(
189
+ in_channels=channels // 2 if prune_bottleneck else channels,
190
+ out_channels=channels,
191
+ kernel_size=(3, 3, 3),
192
+ stride=(1, 1, 1),
193
+ padding_mode=padding_mode,
194
+ bias=bias,
195
+ causal=causal,
196
+ ),
197
+ )
198
+
199
+ self.attn_block = attn_block if attn_block else nn.Identity()
200
+
201
+ def forward(self, x: torch.Tensor):
202
+ """Forward pass.
203
+
204
+ Args:
205
+ x: Input tensor. Shape: [B, C, T, H, W].
206
+ """
207
+ residual = x
208
+ x = self.stack(x)
209
+ x = x + residual
210
+ del residual
211
+
212
+ return self.attn_block(x)
213
+
214
+
215
+ class Attention(nn.Module):
216
+ def __init__(
217
+ self,
218
+ dim: int,
219
+ head_dim: int = 32,
220
+ qkv_bias: bool = False,
221
+ out_bias: bool = True,
222
+ qk_norm: bool = True,
223
+ ) -> None:
224
+ super().__init__()
225
+ self.head_dim = head_dim
226
+ self.num_heads = dim // head_dim
227
+ self.qk_norm = qk_norm
228
+
229
+ self.qkv = nn.Linear(dim, 3 * dim, bias=qkv_bias)
230
+ self.out = nn.Linear(dim, dim, bias=out_bias)
231
+
232
+ def forward(
233
+ self,
234
+ x: torch.Tensor,
235
+ ) -> torch.Tensor:
236
+ """Compute temporal self-attention.
237
+
238
+ Args:
239
+ x: Input tensor. Shape: [B, C, T, H, W].
240
+ chunk_size: Chunk size for large tensors.
241
+
242
+ Returns:
243
+ x: Output tensor. Shape: [B, C, T, H, W].
244
+ """
245
+ B, _, T, H, W = x.shape
246
+
247
+ if T == 1:
248
+ # No attention for single frame.
249
+ x = x.movedim(1, -1) # [B, C, T, H, W] -> [B, T, H, W, C]
250
+ qkv = self.qkv(x)
251
+ _, _, x = qkv.chunk(3, dim=-1) # Throw away queries and keys.
252
+ x = self.out(x)
253
+ return x.movedim(-1, 1) # [B, T, H, W, C] -> [B, C, T, H, W]
254
+
255
+ # 1D temporal attention.
256
+ x = rearrange(x, "B C t h w -> (B h w) t C")
257
+ qkv = self.qkv(x)
258
+
259
+ # Input: qkv with shape [B, t, 3 * num_heads * head_dim]
260
+ # Output: x with shape [B, num_heads, t, head_dim]
261
+ q, k, v = qkv.view(qkv.shape[0], qkv.shape[1], 3, self.num_heads, self.head_dim).transpose(1, 3).unbind(2)
262
+
263
+ if self.qk_norm:
264
+ q = F.normalize(q, p=2, dim=-1)
265
+ k = F.normalize(k, p=2, dim=-1)
266
+
267
+ x = optimized_attention(q, k, v, self.num_heads, skip_reshape=True)
268
+
269
+ assert x.size(0) == q.size(0)
270
+
271
+ x = self.out(x)
272
+ x = rearrange(x, "(B h w) t C -> B C t h w", B=B, h=H, w=W)
273
+ return x
274
+
275
+
276
+ class AttentionBlock(nn.Module):
277
+ def __init__(
278
+ self,
279
+ dim: int,
280
+ **attn_kwargs,
281
+ ) -> None:
282
+ super().__init__()
283
+ self.norm = norm_fn(dim)
284
+ self.attn = Attention(dim, **attn_kwargs)
285
+
286
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
287
+ return x + self.attn(self.norm(x))
288
+
289
+
290
+ class CausalUpsampleBlock(nn.Module):
291
+ def __init__(
292
+ self,
293
+ in_channels: int,
294
+ out_channels: int,
295
+ num_res_blocks: int,
296
+ *,
297
+ temporal_expansion: int = 2,
298
+ spatial_expansion: int = 2,
299
+ **block_kwargs,
300
+ ):
301
+ super().__init__()
302
+
303
+ blocks = []
304
+ for _ in range(num_res_blocks):
305
+ blocks.append(block_fn(in_channels, **block_kwargs))
306
+ self.blocks = nn.Sequential(*blocks)
307
+
308
+ self.temporal_expansion = temporal_expansion
309
+ self.spatial_expansion = spatial_expansion
310
+
311
+ # Change channels in the final convolution layer.
312
+ self.proj = Conv1x1(
313
+ in_channels,
314
+ out_channels * temporal_expansion * (spatial_expansion**2),
315
+ )
316
+
317
+ self.d2st = DepthToSpaceTime(
318
+ temporal_expansion=temporal_expansion, spatial_expansion=spatial_expansion
319
+ )
320
+
321
+ def forward(self, x):
322
+ x = self.blocks(x)
323
+ x = self.proj(x)
324
+ x = self.d2st(x)
325
+ return x
326
+
327
+
328
+ def block_fn(channels, *, affine: bool = True, has_attention: bool = False, **block_kwargs):
329
+ attn_block = AttentionBlock(channels) if has_attention else None
330
+ return ResBlock(channels, affine=affine, attn_block=attn_block, **block_kwargs)
331
+
332
+
333
+ class DownsampleBlock(nn.Module):
334
+ def __init__(
335
+ self,
336
+ in_channels: int,
337
+ out_channels: int,
338
+ num_res_blocks,
339
+ *,
340
+ temporal_reduction=2,
341
+ spatial_reduction=2,
342
+ **block_kwargs,
343
+ ):
344
+ """
345
+ Downsample block for the VAE encoder.
346
+
347
+ Args:
348
+ in_channels: Number of input channels.
349
+ out_channels: Number of output channels.
350
+ num_res_blocks: Number of residual blocks.
351
+ temporal_reduction: Temporal reduction factor.
352
+ spatial_reduction: Spatial reduction factor.
353
+ """
354
+ super().__init__()
355
+ layers = []
356
+
357
+ # Change the channel count in the strided convolution.
358
+ # This lets the ResBlock have uniform channel count,
359
+ # as in ConvNeXt.
360
+ assert in_channels != out_channels
361
+ layers.append(
362
+ PConv3d(
363
+ in_channels=in_channels,
364
+ out_channels=out_channels,
365
+ kernel_size=(temporal_reduction, spatial_reduction, spatial_reduction),
366
+ stride=(temporal_reduction, spatial_reduction, spatial_reduction),
367
+ # First layer in each block always uses replicate padding
368
+ padding_mode="replicate",
369
+ bias=block_kwargs["bias"],
370
+ )
371
+ )
372
+
373
+ for _ in range(num_res_blocks):
374
+ layers.append(block_fn(out_channels, **block_kwargs))
375
+
376
+ self.layers = nn.Sequential(*layers)
377
+
378
+ def forward(self, x):
379
+ return self.layers(x)
380
+
381
+
382
+ def add_fourier_features(inputs: torch.Tensor, start=6, stop=8, step=1):
383
+ num_freqs = (stop - start) // step
384
+ assert inputs.ndim == 5
385
+ C = inputs.size(1)
386
+
387
+ # Create Base 2 Fourier features.
388
+ freqs = torch.arange(start, stop, step, dtype=inputs.dtype, device=inputs.device)
389
+ assert num_freqs == len(freqs)
390
+ w = torch.pow(2.0, freqs) * (2 * torch.pi) # [num_freqs]
391
+ C = inputs.shape[1]
392
+ w = w.repeat(C)[None, :, None, None, None] # [1, C * num_freqs, 1, 1, 1]
393
+
394
+ # Interleaved repeat of input channels to match w.
395
+ h = inputs.repeat_interleave(num_freqs, dim=1) # [B, C * num_freqs, T, H, W]
396
+ # Scale channels by frequency.
397
+ h = w * h
398
+
399
+ return torch.cat(
400
+ [
401
+ inputs,
402
+ torch.sin(h),
403
+ torch.cos(h),
404
+ ],
405
+ dim=1,
406
+ )
407
+
408
+
409
+ class FourierFeatures(nn.Module):
410
+ def __init__(self, start: int = 6, stop: int = 8, step: int = 1):
411
+ super().__init__()
412
+ self.start = start
413
+ self.stop = stop
414
+ self.step = step
415
+
416
+ def forward(self, inputs):
417
+ """Add Fourier features to inputs.
418
+
419
+ Args:
420
+ inputs: Input tensor. Shape: [B, C, T, H, W]
421
+
422
+ Returns:
423
+ h: Output tensor. Shape: [B, (1 + 2 * num_freqs) * C, T, H, W]
424
+ """
425
+ return add_fourier_features(inputs, self.start, self.stop, self.step)
426
+
427
+
428
+ class Decoder(nn.Module):
429
+ def __init__(
430
+ self,
431
+ *,
432
+ out_channels: int = 3,
433
+ latent_dim: int,
434
+ base_channels: int,
435
+ channel_multipliers: List[int],
436
+ num_res_blocks: List[int],
437
+ temporal_expansions: Optional[List[int]] = None,
438
+ spatial_expansions: Optional[List[int]] = None,
439
+ has_attention: List[bool],
440
+ output_norm: bool = True,
441
+ nonlinearity: str = "silu",
442
+ output_nonlinearity: str = "silu",
443
+ causal: bool = True,
444
+ **block_kwargs,
445
+ ):
446
+ super().__init__()
447
+ self.input_channels = latent_dim
448
+ self.base_channels = base_channels
449
+ self.channel_multipliers = channel_multipliers
450
+ self.num_res_blocks = num_res_blocks
451
+ self.output_nonlinearity = output_nonlinearity
452
+ assert nonlinearity == "silu"
453
+ assert causal
454
+
455
+ ch = [mult * base_channels for mult in channel_multipliers]
456
+ self.num_up_blocks = len(ch) - 1
457
+ assert len(num_res_blocks) == self.num_up_blocks + 2
458
+
459
+ blocks = []
460
+
461
+ first_block = [
462
+ ops.Conv3d(latent_dim, ch[-1], kernel_size=(1, 1, 1))
463
+ ] # Input layer.
464
+ # First set of blocks preserve channel count.
465
+ for _ in range(num_res_blocks[-1]):
466
+ first_block.append(
467
+ block_fn(
468
+ ch[-1],
469
+ has_attention=has_attention[-1],
470
+ causal=causal,
471
+ **block_kwargs,
472
+ )
473
+ )
474
+ blocks.append(nn.Sequential(*first_block))
475
+
476
+ assert len(temporal_expansions) == len(spatial_expansions) == self.num_up_blocks
477
+ assert len(num_res_blocks) == len(has_attention) == self.num_up_blocks + 2
478
+
479
+ upsample_block_fn = CausalUpsampleBlock
480
+
481
+ for i in range(self.num_up_blocks):
482
+ block = upsample_block_fn(
483
+ ch[-i - 1],
484
+ ch[-i - 2],
485
+ num_res_blocks=num_res_blocks[-i - 2],
486
+ has_attention=has_attention[-i - 2],
487
+ temporal_expansion=temporal_expansions[-i - 1],
488
+ spatial_expansion=spatial_expansions[-i - 1],
489
+ causal=causal,
490
+ **block_kwargs,
491
+ )
492
+ blocks.append(block)
493
+
494
+ assert not output_norm
495
+
496
+ # Last block. Preserve channel count.
497
+ last_block = []
498
+ for _ in range(num_res_blocks[0]):
499
+ last_block.append(
500
+ block_fn(
501
+ ch[0], has_attention=has_attention[0], causal=causal, **block_kwargs
502
+ )
503
+ )
504
+ blocks.append(nn.Sequential(*last_block))
505
+
506
+ self.blocks = nn.ModuleList(blocks)
507
+ self.output_proj = Conv1x1(ch[0], out_channels)
508
+
509
+ def forward(self, x):
510
+ """Forward pass.
511
+
512
+ Args:
513
+ x: Latent tensor. Shape: [B, input_channels, t, h, w]. Scaled [-1, 1].
514
+
515
+ Returns:
516
+ x: Reconstructed video tensor. Shape: [B, C, T, H, W]. Scaled to [-1, 1].
517
+ T + 1 = (t - 1) * 4.
518
+ H = h * 16, W = w * 16.
519
+ """
520
+ for block in self.blocks:
521
+ x = block(x)
522
+
523
+ if self.output_nonlinearity == "silu":
524
+ x = F.silu(x, inplace=not self.training)
525
+ else:
526
+ assert (
527
+ not self.output_nonlinearity
528
+ ) # StyleGAN3 omits the to-RGB nonlinearity.
529
+
530
+ return self.output_proj(x).contiguous()
531
+
532
+ class LatentDistribution:
533
+ def __init__(self, mean: torch.Tensor, logvar: torch.Tensor):
534
+ """Initialize latent distribution.
535
+
536
+ Args:
537
+ mean: Mean of the distribution. Shape: [B, C, T, H, W].
538
+ logvar: Logarithm of variance of the distribution. Shape: [B, C, T, H, W].
539
+ """
540
+ assert mean.shape == logvar.shape
541
+ self.mean = mean
542
+ self.logvar = logvar
543
+
544
+ def sample(self, temperature=1.0, generator: torch.Generator = None, noise=None):
545
+ if temperature == 0.0:
546
+ return self.mean
547
+
548
+ if noise is None:
549
+ noise = torch.randn(self.mean.shape, device=self.mean.device, dtype=self.mean.dtype, generator=generator)
550
+ else:
551
+ assert noise.device == self.mean.device
552
+ noise = noise.to(self.mean.dtype)
553
+
554
+ if temperature != 1.0:
555
+ raise NotImplementedError(f"Temperature {temperature} is not supported.")
556
+
557
+ # Just Gaussian sample with no scaling of variance.
558
+ return noise * torch.exp(self.logvar * 0.5) + self.mean
559
+
560
+ def mode(self):
561
+ return self.mean
562
+
563
+ class Encoder(nn.Module):
564
+ def __init__(
565
+ self,
566
+ *,
567
+ in_channels: int,
568
+ base_channels: int,
569
+ channel_multipliers: List[int],
570
+ num_res_blocks: List[int],
571
+ latent_dim: int,
572
+ temporal_reductions: List[int],
573
+ spatial_reductions: List[int],
574
+ prune_bottlenecks: List[bool],
575
+ has_attentions: List[bool],
576
+ affine: bool = True,
577
+ bias: bool = True,
578
+ input_is_conv_1x1: bool = False,
579
+ padding_mode: str,
580
+ ):
581
+ super().__init__()
582
+ self.temporal_reductions = temporal_reductions
583
+ self.spatial_reductions = spatial_reductions
584
+ self.base_channels = base_channels
585
+ self.channel_multipliers = channel_multipliers
586
+ self.num_res_blocks = num_res_blocks
587
+ self.latent_dim = latent_dim
588
+
589
+ self.fourier_features = FourierFeatures()
590
+ ch = [mult * base_channels for mult in channel_multipliers]
591
+ num_down_blocks = len(ch) - 1
592
+ assert len(num_res_blocks) == num_down_blocks + 2
593
+
594
+ layers = (
595
+ [ops.Conv3d(in_channels, ch[0], kernel_size=(1, 1, 1), bias=True)]
596
+ if not input_is_conv_1x1
597
+ else [Conv1x1(in_channels, ch[0])]
598
+ )
599
+
600
+ assert len(prune_bottlenecks) == num_down_blocks + 2
601
+ assert len(has_attentions) == num_down_blocks + 2
602
+ block = partial(block_fn, padding_mode=padding_mode, affine=affine, bias=bias)
603
+
604
+ for _ in range(num_res_blocks[0]):
605
+ layers.append(block(ch[0], has_attention=has_attentions[0], prune_bottleneck=prune_bottlenecks[0]))
606
+ prune_bottlenecks = prune_bottlenecks[1:]
607
+ has_attentions = has_attentions[1:]
608
+
609
+ assert len(temporal_reductions) == len(spatial_reductions) == len(ch) - 1
610
+ for i in range(num_down_blocks):
611
+ layer = DownsampleBlock(
612
+ ch[i],
613
+ ch[i + 1],
614
+ num_res_blocks=num_res_blocks[i + 1],
615
+ temporal_reduction=temporal_reductions[i],
616
+ spatial_reduction=spatial_reductions[i],
617
+ prune_bottleneck=prune_bottlenecks[i],
618
+ has_attention=has_attentions[i],
619
+ affine=affine,
620
+ bias=bias,
621
+ padding_mode=padding_mode,
622
+ )
623
+
624
+ layers.append(layer)
625
+
626
+ # Additional blocks.
627
+ for _ in range(num_res_blocks[-1]):
628
+ layers.append(block(ch[-1], has_attention=has_attentions[-1], prune_bottleneck=prune_bottlenecks[-1]))
629
+
630
+ self.layers = nn.Sequential(*layers)
631
+
632
+ # Output layers.
633
+ self.output_norm = norm_fn(ch[-1])
634
+ self.output_proj = Conv1x1(ch[-1], 2 * latent_dim, bias=False)
635
+
636
+ @property
637
+ def temporal_downsample(self):
638
+ return math.prod(self.temporal_reductions)
639
+
640
+ @property
641
+ def spatial_downsample(self):
642
+ return math.prod(self.spatial_reductions)
643
+
644
+ def forward(self, x) -> LatentDistribution:
645
+ """Forward pass.
646
+
647
+ Args:
648
+ x: Input video tensor. Shape: [B, C, T, H, W]. Scaled to [-1, 1]
649
+
650
+ Returns:
651
+ means: Latent tensor. Shape: [B, latent_dim, t, h, w]. Scaled [-1, 1].
652
+ h = H // 8, w = W // 8, t - 1 = (T - 1) // 6
653
+ logvar: Shape: [B, latent_dim, t, h, w].
654
+ """
655
+ assert x.ndim == 5, f"Expected 5D input, got {x.shape}"
656
+ x = self.fourier_features(x)
657
+
658
+ x = self.layers(x)
659
+
660
+ x = self.output_norm(x)
661
+ x = F.silu(x, inplace=True)
662
+ x = self.output_proj(x)
663
+
664
+ means, logvar = torch.chunk(x, 2, dim=1)
665
+
666
+ assert means.ndim == 5
667
+ assert logvar.shape == means.shape
668
+ assert means.size(1) == self.latent_dim
669
+
670
+ return LatentDistribution(means, logvar)
671
+
672
+
673
+ class VideoVAE(nn.Module):
674
+ def __init__(self):
675
+ super().__init__()
676
+ self.encoder = Encoder(
677
+ in_channels=15,
678
+ base_channels=64,
679
+ channel_multipliers=[1, 2, 4, 6],
680
+ num_res_blocks=[3, 3, 4, 6, 3],
681
+ latent_dim=12,
682
+ temporal_reductions=[1, 2, 3],
683
+ spatial_reductions=[2, 2, 2],
684
+ prune_bottlenecks=[False, False, False, False, False],
685
+ has_attentions=[False, True, True, True, True],
686
+ affine=True,
687
+ bias=True,
688
+ input_is_conv_1x1=True,
689
+ padding_mode="replicate"
690
+ )
691
+ self.decoder = Decoder(
692
+ out_channels=3,
693
+ base_channels=128,
694
+ channel_multipliers=[1, 2, 4, 6],
695
+ temporal_expansions=[1, 2, 3],
696
+ spatial_expansions=[2, 2, 2],
697
+ num_res_blocks=[3, 3, 4, 6, 3],
698
+ latent_dim=12,
699
+ has_attention=[False, False, False, False, False],
700
+ padding_mode="replicate",
701
+ output_norm=False,
702
+ nonlinearity="silu",
703
+ output_nonlinearity="silu",
704
+ causal=True,
705
+ )
706
+
707
+ def encode(self, x):
708
+ return self.encoder(x).mode()
709
+
710
+ def decode(self, x):
711
+ return self.decoder(x)
ComfyUI/comfy/ldm/hidream/__pycache__/model.cpython-312.pyc ADDED
Binary file (41.9 kB). View file
 
ComfyUI/comfy/ldm/hidream/model.py ADDED
@@ -0,0 +1,829 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional, Tuple, List
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import einops
6
+ from einops import repeat
7
+
8
+ from comfy.ldm.lightricks.model import TimestepEmbedding, Timesteps
9
+ import torch.nn.functional as F
10
+
11
+ from comfy.ldm.flux.math import apply_rope, rope
12
+ from comfy.ldm.flux.layers import LastLayer
13
+
14
+ from comfy.ldm.modules.attention import optimized_attention
15
+ import comfy.model_management
16
+ import comfy.patcher_extension
17
+ import comfy.ldm.common_dit
18
+
19
+
20
+ # Copied from https://github.com/black-forest-labs/flux/blob/main/src/flux/modules/layers.py
21
+ class EmbedND(nn.Module):
22
+ def __init__(self, theta: int, axes_dim: List[int]):
23
+ super().__init__()
24
+ self.theta = theta
25
+ self.axes_dim = axes_dim
26
+
27
+ def forward(self, ids: torch.Tensor) -> torch.Tensor:
28
+ n_axes = ids.shape[-1]
29
+ emb = torch.cat(
30
+ [rope(ids[..., i], self.axes_dim[i], self.theta) for i in range(n_axes)],
31
+ dim=-3,
32
+ )
33
+ return emb.unsqueeze(2)
34
+
35
+
36
+ class PatchEmbed(nn.Module):
37
+ def __init__(
38
+ self,
39
+ patch_size=2,
40
+ in_channels=4,
41
+ out_channels=1024,
42
+ dtype=None, device=None, operations=None
43
+ ):
44
+ super().__init__()
45
+ self.patch_size = patch_size
46
+ self.out_channels = out_channels
47
+ self.proj = operations.Linear(in_channels * patch_size * patch_size, out_channels, bias=True, dtype=dtype, device=device)
48
+
49
+ def forward(self, latent):
50
+ latent = self.proj(latent)
51
+ return latent
52
+
53
+
54
+ class PooledEmbed(nn.Module):
55
+ def __init__(self, text_emb_dim, hidden_size, dtype=None, device=None, operations=None):
56
+ super().__init__()
57
+ self.pooled_embedder = TimestepEmbedding(in_channels=text_emb_dim, time_embed_dim=hidden_size, dtype=dtype, device=device, operations=operations)
58
+
59
+ def forward(self, pooled_embed):
60
+ return self.pooled_embedder(pooled_embed)
61
+
62
+
63
+ class TimestepEmbed(nn.Module):
64
+ def __init__(self, hidden_size, frequency_embedding_size=256, dtype=None, device=None, operations=None):
65
+ super().__init__()
66
+ self.time_proj = Timesteps(num_channels=frequency_embedding_size, flip_sin_to_cos=True, downscale_freq_shift=0)
67
+ self.timestep_embedder = TimestepEmbedding(in_channels=frequency_embedding_size, time_embed_dim=hidden_size, dtype=dtype, device=device, operations=operations)
68
+
69
+ def forward(self, timesteps, wdtype):
70
+ t_emb = self.time_proj(timesteps).to(dtype=wdtype)
71
+ t_emb = self.timestep_embedder(t_emb)
72
+ return t_emb
73
+
74
+
75
+ def attention(query: torch.Tensor, key: torch.Tensor, value: torch.Tensor, transformer_options={}):
76
+ return optimized_attention(query.view(query.shape[0], -1, query.shape[-1] * query.shape[-2]), key.view(key.shape[0], -1, key.shape[-1] * key.shape[-2]), value.view(value.shape[0], -1, value.shape[-1] * value.shape[-2]), query.shape[2], transformer_options=transformer_options)
77
+
78
+
79
+ class HiDreamAttnProcessor_flashattn:
80
+ """Attention processor used typically in processing the SD3-like self-attention projections."""
81
+
82
+ def __call__(
83
+ self,
84
+ attn,
85
+ image_tokens: torch.FloatTensor,
86
+ image_tokens_masks: Optional[torch.FloatTensor] = None,
87
+ text_tokens: Optional[torch.FloatTensor] = None,
88
+ rope: torch.FloatTensor = None,
89
+ transformer_options={},
90
+ *args,
91
+ **kwargs,
92
+ ) -> torch.FloatTensor:
93
+ dtype = image_tokens.dtype
94
+ batch_size = image_tokens.shape[0]
95
+
96
+ query_i = attn.q_rms_norm(attn.to_q(image_tokens)).to(dtype=dtype)
97
+ key_i = attn.k_rms_norm(attn.to_k(image_tokens)).to(dtype=dtype)
98
+ value_i = attn.to_v(image_tokens)
99
+
100
+ inner_dim = key_i.shape[-1]
101
+ head_dim = inner_dim // attn.heads
102
+
103
+ query_i = query_i.view(batch_size, -1, attn.heads, head_dim)
104
+ key_i = key_i.view(batch_size, -1, attn.heads, head_dim)
105
+ value_i = value_i.view(batch_size, -1, attn.heads, head_dim)
106
+ if image_tokens_masks is not None:
107
+ key_i = key_i * image_tokens_masks.view(batch_size, -1, 1, 1)
108
+
109
+ if not attn.single:
110
+ query_t = attn.q_rms_norm_t(attn.to_q_t(text_tokens)).to(dtype=dtype)
111
+ key_t = attn.k_rms_norm_t(attn.to_k_t(text_tokens)).to(dtype=dtype)
112
+ value_t = attn.to_v_t(text_tokens)
113
+
114
+ query_t = query_t.view(batch_size, -1, attn.heads, head_dim)
115
+ key_t = key_t.view(batch_size, -1, attn.heads, head_dim)
116
+ value_t = value_t.view(batch_size, -1, attn.heads, head_dim)
117
+
118
+ num_image_tokens = query_i.shape[1]
119
+ num_text_tokens = query_t.shape[1]
120
+ query = torch.cat([query_i, query_t], dim=1)
121
+ key = torch.cat([key_i, key_t], dim=1)
122
+ value = torch.cat([value_i, value_t], dim=1)
123
+ else:
124
+ query = query_i
125
+ key = key_i
126
+ value = value_i
127
+
128
+ if query.shape[-1] == rope.shape[-3] * 2:
129
+ query, key = apply_rope(query, key, rope)
130
+ else:
131
+ query_1, query_2 = query.chunk(2, dim=-1)
132
+ key_1, key_2 = key.chunk(2, dim=-1)
133
+ query_1, key_1 = apply_rope(query_1, key_1, rope)
134
+ query = torch.cat([query_1, query_2], dim=-1)
135
+ key = torch.cat([key_1, key_2], dim=-1)
136
+
137
+ hidden_states = attention(query, key, value, transformer_options=transformer_options)
138
+
139
+ if not attn.single:
140
+ hidden_states_i, hidden_states_t = torch.split(hidden_states, [num_image_tokens, num_text_tokens], dim=1)
141
+ hidden_states_i = attn.to_out(hidden_states_i)
142
+ hidden_states_t = attn.to_out_t(hidden_states_t)
143
+ return hidden_states_i, hidden_states_t
144
+ else:
145
+ hidden_states = attn.to_out(hidden_states)
146
+ return hidden_states
147
+
148
+ class HiDreamAttention(nn.Module):
149
+ def __init__(
150
+ self,
151
+ query_dim: int,
152
+ heads: int = 8,
153
+ dim_head: int = 64,
154
+ upcast_attention: bool = False,
155
+ upcast_softmax: bool = False,
156
+ scale_qk: bool = True,
157
+ eps: float = 1e-5,
158
+ processor = None,
159
+ out_dim: int = None,
160
+ single: bool = False,
161
+ dtype=None, device=None, operations=None
162
+ ):
163
+ # super(Attention, self).__init__()
164
+ super().__init__()
165
+ self.inner_dim = out_dim if out_dim is not None else dim_head * heads
166
+ self.query_dim = query_dim
167
+ self.upcast_attention = upcast_attention
168
+ self.upcast_softmax = upcast_softmax
169
+ self.out_dim = out_dim if out_dim is not None else query_dim
170
+
171
+ self.scale_qk = scale_qk
172
+ self.scale = dim_head**-0.5 if self.scale_qk else 1.0
173
+
174
+ self.heads = out_dim // dim_head if out_dim is not None else heads
175
+ self.sliceable_head_dim = heads
176
+ self.single = single
177
+
178
+ linear_cls = operations.Linear
179
+ self.linear_cls = linear_cls
180
+ self.to_q = linear_cls(query_dim, self.inner_dim, dtype=dtype, device=device)
181
+ self.to_k = linear_cls(self.inner_dim, self.inner_dim, dtype=dtype, device=device)
182
+ self.to_v = linear_cls(self.inner_dim, self.inner_dim, dtype=dtype, device=device)
183
+ self.to_out = linear_cls(self.inner_dim, self.out_dim, dtype=dtype, device=device)
184
+ self.q_rms_norm = operations.RMSNorm(self.inner_dim, eps, dtype=dtype, device=device)
185
+ self.k_rms_norm = operations.RMSNorm(self.inner_dim, eps, dtype=dtype, device=device)
186
+
187
+ if not single:
188
+ self.to_q_t = linear_cls(query_dim, self.inner_dim, dtype=dtype, device=device)
189
+ self.to_k_t = linear_cls(self.inner_dim, self.inner_dim, dtype=dtype, device=device)
190
+ self.to_v_t = linear_cls(self.inner_dim, self.inner_dim, dtype=dtype, device=device)
191
+ self.to_out_t = linear_cls(self.inner_dim, self.out_dim, dtype=dtype, device=device)
192
+ self.q_rms_norm_t = operations.RMSNorm(self.inner_dim, eps, dtype=dtype, device=device)
193
+ self.k_rms_norm_t = operations.RMSNorm(self.inner_dim, eps, dtype=dtype, device=device)
194
+
195
+ self.processor = processor
196
+
197
+ def forward(
198
+ self,
199
+ norm_image_tokens: torch.FloatTensor,
200
+ image_tokens_masks: torch.FloatTensor = None,
201
+ norm_text_tokens: torch.FloatTensor = None,
202
+ rope: torch.FloatTensor = None,
203
+ transformer_options={},
204
+ ) -> torch.Tensor:
205
+ return self.processor(
206
+ self,
207
+ image_tokens = norm_image_tokens,
208
+ image_tokens_masks = image_tokens_masks,
209
+ text_tokens = norm_text_tokens,
210
+ rope = rope,
211
+ transformer_options=transformer_options,
212
+ )
213
+
214
+
215
+ class FeedForwardSwiGLU(nn.Module):
216
+ def __init__(
217
+ self,
218
+ dim: int,
219
+ hidden_dim: int,
220
+ multiple_of: int = 256,
221
+ ffn_dim_multiplier: Optional[float] = None,
222
+ dtype=None, device=None, operations=None
223
+ ):
224
+ super().__init__()
225
+ hidden_dim = int(2 * hidden_dim / 3)
226
+ # custom dim factor multiplier
227
+ if ffn_dim_multiplier is not None:
228
+ hidden_dim = int(ffn_dim_multiplier * hidden_dim)
229
+ hidden_dim = multiple_of * (
230
+ (hidden_dim + multiple_of - 1) // multiple_of
231
+ )
232
+
233
+ self.w1 = operations.Linear(dim, hidden_dim, bias=False, dtype=dtype, device=device)
234
+ self.w2 = operations.Linear(hidden_dim, dim, bias=False, dtype=dtype, device=device)
235
+ self.w3 = operations.Linear(dim, hidden_dim, bias=False, dtype=dtype, device=device)
236
+
237
+ def forward(self, x):
238
+ return self.w2(torch.nn.functional.silu(self.w1(x)) * self.w3(x))
239
+
240
+
241
+ # Modified from https://github.com/deepseek-ai/DeepSeek-V3/blob/main/inference/model.py
242
+ class MoEGate(nn.Module):
243
+ def __init__(self, embed_dim, num_routed_experts=4, num_activated_experts=2, aux_loss_alpha=0.01, dtype=None, device=None, operations=None):
244
+ super().__init__()
245
+ self.top_k = num_activated_experts
246
+ self.n_routed_experts = num_routed_experts
247
+
248
+ self.scoring_func = 'softmax'
249
+ self.alpha = aux_loss_alpha
250
+ self.seq_aux = False
251
+
252
+ # topk selection algorithm
253
+ self.norm_topk_prob = False
254
+ self.gating_dim = embed_dim
255
+ self.weight = nn.Parameter(torch.empty((self.n_routed_experts, self.gating_dim), dtype=dtype, device=device))
256
+ self.reset_parameters()
257
+
258
+ def reset_parameters(self) -> None:
259
+ pass
260
+ # import torch.nn.init as init
261
+ # init.kaiming_uniform_(self.weight, a=math.sqrt(5))
262
+
263
+ def forward(self, hidden_states):
264
+ bsz, seq_len, h = hidden_states.shape
265
+
266
+ ### compute gating score
267
+ hidden_states = hidden_states.view(-1, h)
268
+ logits = F.linear(hidden_states, comfy.model_management.cast_to(self.weight, dtype=hidden_states.dtype, device=hidden_states.device), None)
269
+ if self.scoring_func == 'softmax':
270
+ scores = logits.softmax(dim=-1)
271
+ else:
272
+ raise NotImplementedError(f'insupportable scoring function for MoE gating: {self.scoring_func}')
273
+
274
+ ### select top-k experts
275
+ topk_weight, topk_idx = torch.topk(scores, k=self.top_k, dim=-1, sorted=False)
276
+
277
+ ### norm gate to sum 1
278
+ if self.top_k > 1 and self.norm_topk_prob:
279
+ denominator = topk_weight.sum(dim=-1, keepdim=True) + 1e-20
280
+ topk_weight = topk_weight / denominator
281
+
282
+ aux_loss = None
283
+ return topk_idx, topk_weight, aux_loss
284
+
285
+
286
+ # Modified from https://github.com/deepseek-ai/DeepSeek-V3/blob/main/inference/model.py
287
+ class MOEFeedForwardSwiGLU(nn.Module):
288
+ def __init__(
289
+ self,
290
+ dim: int,
291
+ hidden_dim: int,
292
+ num_routed_experts: int,
293
+ num_activated_experts: int,
294
+ dtype=None, device=None, operations=None
295
+ ):
296
+ super().__init__()
297
+ self.shared_experts = FeedForwardSwiGLU(dim, hidden_dim // 2, dtype=dtype, device=device, operations=operations)
298
+ self.experts = nn.ModuleList([FeedForwardSwiGLU(dim, hidden_dim, dtype=dtype, device=device, operations=operations) for i in range(num_routed_experts)])
299
+ self.gate = MoEGate(
300
+ embed_dim = dim,
301
+ num_routed_experts = num_routed_experts,
302
+ num_activated_experts = num_activated_experts,
303
+ dtype=dtype, device=device, operations=operations
304
+ )
305
+ self.num_activated_experts = num_activated_experts
306
+
307
+ def forward(self, x):
308
+ wtype = x.dtype
309
+ identity = x
310
+ orig_shape = x.shape
311
+ topk_idx, topk_weight, aux_loss = self.gate(x)
312
+ x = x.view(-1, x.shape[-1])
313
+ flat_topk_idx = topk_idx.view(-1)
314
+ if True: # self.training: # TODO: check which branch performs faster
315
+ x = x.repeat_interleave(self.num_activated_experts, dim=0)
316
+ y = torch.empty_like(x, dtype=wtype)
317
+ for i, expert in enumerate(self.experts):
318
+ y[flat_topk_idx == i] = expert(x[flat_topk_idx == i]).to(dtype=wtype)
319
+ y = (y.view(*topk_weight.shape, -1) * topk_weight.unsqueeze(-1)).sum(dim=1)
320
+ y = y.view(*orig_shape).to(dtype=wtype)
321
+ #y = AddAuxiliaryLoss.apply(y, aux_loss)
322
+ else:
323
+ y = self.moe_infer(x, flat_topk_idx, topk_weight.view(-1, 1)).view(*orig_shape)
324
+ y = y + self.shared_experts(identity)
325
+ return y
326
+
327
+ @torch.no_grad()
328
+ def moe_infer(self, x, flat_expert_indices, flat_expert_weights):
329
+ expert_cache = torch.zeros_like(x)
330
+ idxs = flat_expert_indices.argsort()
331
+ tokens_per_expert = flat_expert_indices.bincount().cpu().numpy().cumsum(0)
332
+ token_idxs = idxs // self.num_activated_experts
333
+ for i, end_idx in enumerate(tokens_per_expert):
334
+ start_idx = 0 if i == 0 else tokens_per_expert[i-1]
335
+ if start_idx == end_idx:
336
+ continue
337
+ expert = self.experts[i]
338
+ exp_token_idx = token_idxs[start_idx:end_idx]
339
+ expert_tokens = x[exp_token_idx]
340
+ expert_out = expert(expert_tokens)
341
+ expert_out.mul_(flat_expert_weights[idxs[start_idx:end_idx]])
342
+
343
+ # for fp16 and other dtype
344
+ expert_cache = expert_cache.to(expert_out.dtype)
345
+ expert_cache.scatter_reduce_(0, exp_token_idx.view(-1, 1).repeat(1, x.shape[-1]), expert_out, reduce='sum')
346
+ return expert_cache
347
+
348
+
349
+ class TextProjection(nn.Module):
350
+ def __init__(self, in_features, hidden_size, dtype=None, device=None, operations=None):
351
+ super().__init__()
352
+ self.linear = operations.Linear(in_features=in_features, out_features=hidden_size, bias=False, dtype=dtype, device=device)
353
+
354
+ def forward(self, caption):
355
+ hidden_states = self.linear(caption)
356
+ return hidden_states
357
+
358
+
359
+ class BlockType:
360
+ TransformerBlock = 1
361
+ SingleTransformerBlock = 2
362
+
363
+
364
+ class HiDreamImageSingleTransformerBlock(nn.Module):
365
+ def __init__(
366
+ self,
367
+ dim: int,
368
+ num_attention_heads: int,
369
+ attention_head_dim: int,
370
+ num_routed_experts: int = 4,
371
+ num_activated_experts: int = 2,
372
+ dtype=None, device=None, operations=None
373
+ ):
374
+ super().__init__()
375
+ self.num_attention_heads = num_attention_heads
376
+ self.adaLN_modulation = nn.Sequential(
377
+ nn.SiLU(),
378
+ operations.Linear(dim, 6 * dim, bias=True, dtype=dtype, device=device)
379
+ )
380
+
381
+ # 1. Attention
382
+ self.norm1_i = operations.LayerNorm(dim, eps = 1e-06, elementwise_affine = False, dtype=dtype, device=device)
383
+ self.attn1 = HiDreamAttention(
384
+ query_dim=dim,
385
+ heads=num_attention_heads,
386
+ dim_head=attention_head_dim,
387
+ processor = HiDreamAttnProcessor_flashattn(),
388
+ single = True,
389
+ dtype=dtype, device=device, operations=operations
390
+ )
391
+
392
+ # 3. Feed-forward
393
+ self.norm3_i = operations.LayerNorm(dim, eps = 1e-06, elementwise_affine = False, dtype=dtype, device=device)
394
+ if num_routed_experts > 0:
395
+ self.ff_i = MOEFeedForwardSwiGLU(
396
+ dim = dim,
397
+ hidden_dim = 4 * dim,
398
+ num_routed_experts = num_routed_experts,
399
+ num_activated_experts = num_activated_experts,
400
+ dtype=dtype, device=device, operations=operations
401
+ )
402
+ else:
403
+ self.ff_i = FeedForwardSwiGLU(dim = dim, hidden_dim = 4 * dim, dtype=dtype, device=device, operations=operations)
404
+
405
+ def forward(
406
+ self,
407
+ image_tokens: torch.FloatTensor,
408
+ image_tokens_masks: Optional[torch.FloatTensor] = None,
409
+ text_tokens: Optional[torch.FloatTensor] = None,
410
+ adaln_input: Optional[torch.FloatTensor] = None,
411
+ rope: torch.FloatTensor = None,
412
+ transformer_options={},
413
+ ) -> torch.FloatTensor:
414
+ wtype = image_tokens.dtype
415
+ shift_msa_i, scale_msa_i, gate_msa_i, shift_mlp_i, scale_mlp_i, gate_mlp_i = \
416
+ self.adaLN_modulation(adaln_input)[:,None].chunk(6, dim=-1)
417
+
418
+ # 1. MM-Attention
419
+ norm_image_tokens = self.norm1_i(image_tokens).to(dtype=wtype)
420
+ norm_image_tokens = norm_image_tokens * (1 + scale_msa_i) + shift_msa_i
421
+ attn_output_i = self.attn1(
422
+ norm_image_tokens,
423
+ image_tokens_masks,
424
+ rope = rope,
425
+ transformer_options=transformer_options,
426
+ )
427
+ image_tokens = gate_msa_i * attn_output_i + image_tokens
428
+
429
+ # 2. Feed-forward
430
+ norm_image_tokens = self.norm3_i(image_tokens).to(dtype=wtype)
431
+ norm_image_tokens = norm_image_tokens * (1 + scale_mlp_i) + shift_mlp_i
432
+ ff_output_i = gate_mlp_i * self.ff_i(norm_image_tokens.to(dtype=wtype))
433
+ image_tokens = ff_output_i + image_tokens
434
+ return image_tokens
435
+
436
+
437
+ class HiDreamImageTransformerBlock(nn.Module):
438
+ def __init__(
439
+ self,
440
+ dim: int,
441
+ num_attention_heads: int,
442
+ attention_head_dim: int,
443
+ num_routed_experts: int = 4,
444
+ num_activated_experts: int = 2,
445
+ dtype=None, device=None, operations=None
446
+ ):
447
+ super().__init__()
448
+ self.num_attention_heads = num_attention_heads
449
+ self.adaLN_modulation = nn.Sequential(
450
+ nn.SiLU(),
451
+ operations.Linear(dim, 12 * dim, bias=True, dtype=dtype, device=device)
452
+ )
453
+ # nn.init.zeros_(self.adaLN_modulation[1].weight)
454
+ # nn.init.zeros_(self.adaLN_modulation[1].bias)
455
+
456
+ # 1. Attention
457
+ self.norm1_i = operations.LayerNorm(dim, eps = 1e-06, elementwise_affine = False, dtype=dtype, device=device)
458
+ self.norm1_t = operations.LayerNorm(dim, eps = 1e-06, elementwise_affine = False, dtype=dtype, device=device)
459
+ self.attn1 = HiDreamAttention(
460
+ query_dim=dim,
461
+ heads=num_attention_heads,
462
+ dim_head=attention_head_dim,
463
+ processor = HiDreamAttnProcessor_flashattn(),
464
+ single = False,
465
+ dtype=dtype, device=device, operations=operations
466
+ )
467
+
468
+ # 3. Feed-forward
469
+ self.norm3_i = operations.LayerNorm(dim, eps = 1e-06, elementwise_affine = False, dtype=dtype, device=device)
470
+ if num_routed_experts > 0:
471
+ self.ff_i = MOEFeedForwardSwiGLU(
472
+ dim = dim,
473
+ hidden_dim = 4 * dim,
474
+ num_routed_experts = num_routed_experts,
475
+ num_activated_experts = num_activated_experts,
476
+ dtype=dtype, device=device, operations=operations
477
+ )
478
+ else:
479
+ self.ff_i = FeedForwardSwiGLU(dim = dim, hidden_dim = 4 * dim, dtype=dtype, device=device, operations=operations)
480
+ self.norm3_t = operations.LayerNorm(dim, eps = 1e-06, elementwise_affine = False)
481
+ self.ff_t = FeedForwardSwiGLU(dim = dim, hidden_dim = 4 * dim, dtype=dtype, device=device, operations=operations)
482
+
483
+ def forward(
484
+ self,
485
+ image_tokens: torch.FloatTensor,
486
+ image_tokens_masks: Optional[torch.FloatTensor] = None,
487
+ text_tokens: Optional[torch.FloatTensor] = None,
488
+ adaln_input: Optional[torch.FloatTensor] = None,
489
+ rope: torch.FloatTensor = None,
490
+ transformer_options={},
491
+ ) -> torch.FloatTensor:
492
+ wtype = image_tokens.dtype
493
+ shift_msa_i, scale_msa_i, gate_msa_i, shift_mlp_i, scale_mlp_i, gate_mlp_i, \
494
+ shift_msa_t, scale_msa_t, gate_msa_t, shift_mlp_t, scale_mlp_t, gate_mlp_t = \
495
+ self.adaLN_modulation(adaln_input)[:,None].chunk(12, dim=-1)
496
+
497
+ # 1. MM-Attention
498
+ norm_image_tokens = self.norm1_i(image_tokens).to(dtype=wtype)
499
+ norm_image_tokens = norm_image_tokens * (1 + scale_msa_i) + shift_msa_i
500
+ norm_text_tokens = self.norm1_t(text_tokens).to(dtype=wtype)
501
+ norm_text_tokens = norm_text_tokens * (1 + scale_msa_t) + shift_msa_t
502
+
503
+ attn_output_i, attn_output_t = self.attn1(
504
+ norm_image_tokens,
505
+ image_tokens_masks,
506
+ norm_text_tokens,
507
+ rope = rope,
508
+ transformer_options=transformer_options,
509
+ )
510
+
511
+ image_tokens = gate_msa_i * attn_output_i + image_tokens
512
+ text_tokens = gate_msa_t * attn_output_t + text_tokens
513
+
514
+ # 2. Feed-forward
515
+ norm_image_tokens = self.norm3_i(image_tokens).to(dtype=wtype)
516
+ norm_image_tokens = norm_image_tokens * (1 + scale_mlp_i) + shift_mlp_i
517
+ norm_text_tokens = self.norm3_t(text_tokens).to(dtype=wtype)
518
+ norm_text_tokens = norm_text_tokens * (1 + scale_mlp_t) + shift_mlp_t
519
+
520
+ ff_output_i = gate_mlp_i * self.ff_i(norm_image_tokens)
521
+ ff_output_t = gate_mlp_t * self.ff_t(norm_text_tokens)
522
+ image_tokens = ff_output_i + image_tokens
523
+ text_tokens = ff_output_t + text_tokens
524
+ return image_tokens, text_tokens
525
+
526
+
527
+ class HiDreamImageBlock(nn.Module):
528
+ def __init__(
529
+ self,
530
+ dim: int,
531
+ num_attention_heads: int,
532
+ attention_head_dim: int,
533
+ num_routed_experts: int = 4,
534
+ num_activated_experts: int = 2,
535
+ block_type: BlockType = BlockType.TransformerBlock,
536
+ dtype=None, device=None, operations=None
537
+ ):
538
+ super().__init__()
539
+ block_classes = {
540
+ BlockType.TransformerBlock: HiDreamImageTransformerBlock,
541
+ BlockType.SingleTransformerBlock: HiDreamImageSingleTransformerBlock,
542
+ }
543
+ self.block = block_classes[block_type](
544
+ dim,
545
+ num_attention_heads,
546
+ attention_head_dim,
547
+ num_routed_experts,
548
+ num_activated_experts,
549
+ dtype=dtype, device=device, operations=operations
550
+ )
551
+
552
+ def forward(
553
+ self,
554
+ image_tokens: torch.FloatTensor,
555
+ image_tokens_masks: Optional[torch.FloatTensor] = None,
556
+ text_tokens: Optional[torch.FloatTensor] = None,
557
+ adaln_input: torch.FloatTensor = None,
558
+ rope: torch.FloatTensor = None,
559
+ transformer_options={},
560
+ ) -> torch.FloatTensor:
561
+ return self.block(
562
+ image_tokens,
563
+ image_tokens_masks,
564
+ text_tokens,
565
+ adaln_input,
566
+ rope,
567
+ transformer_options=transformer_options,
568
+ )
569
+
570
+
571
+ class HiDreamImageTransformer2DModel(nn.Module):
572
+ def __init__(
573
+ self,
574
+ patch_size: Optional[int] = None,
575
+ in_channels: int = 64,
576
+ out_channels: Optional[int] = None,
577
+ num_layers: int = 16,
578
+ num_single_layers: int = 32,
579
+ attention_head_dim: int = 128,
580
+ num_attention_heads: int = 20,
581
+ caption_channels: List[int] = None,
582
+ text_emb_dim: int = 2048,
583
+ num_routed_experts: int = 4,
584
+ num_activated_experts: int = 2,
585
+ axes_dims_rope: Tuple[int, int] = (32, 32),
586
+ max_resolution: Tuple[int, int] = (128, 128),
587
+ llama_layers: List[int] = None,
588
+ image_model=None,
589
+ dtype=None, device=None, operations=None
590
+ ):
591
+ self.patch_size = patch_size
592
+ self.num_attention_heads = num_attention_heads
593
+ self.attention_head_dim = attention_head_dim
594
+ self.num_layers = num_layers
595
+ self.num_single_layers = num_single_layers
596
+
597
+ self.gradient_checkpointing = False
598
+
599
+ super().__init__()
600
+ self.dtype = dtype
601
+ self.out_channels = out_channels or in_channels
602
+ self.inner_dim = self.num_attention_heads * self.attention_head_dim
603
+ self.llama_layers = llama_layers
604
+
605
+ self.t_embedder = TimestepEmbed(self.inner_dim, dtype=dtype, device=device, operations=operations)
606
+ self.p_embedder = PooledEmbed(text_emb_dim, self.inner_dim, dtype=dtype, device=device, operations=operations)
607
+ self.x_embedder = PatchEmbed(
608
+ patch_size = patch_size,
609
+ in_channels = in_channels,
610
+ out_channels = self.inner_dim,
611
+ dtype=dtype, device=device, operations=operations
612
+ )
613
+ self.pe_embedder = EmbedND(theta=10000, axes_dim=axes_dims_rope)
614
+
615
+ self.double_stream_blocks = nn.ModuleList(
616
+ [
617
+ HiDreamImageBlock(
618
+ dim = self.inner_dim,
619
+ num_attention_heads = self.num_attention_heads,
620
+ attention_head_dim = self.attention_head_dim,
621
+ num_routed_experts = num_routed_experts,
622
+ num_activated_experts = num_activated_experts,
623
+ block_type = BlockType.TransformerBlock,
624
+ dtype=dtype, device=device, operations=operations
625
+ )
626
+ for i in range(self.num_layers)
627
+ ]
628
+ )
629
+
630
+ self.single_stream_blocks = nn.ModuleList(
631
+ [
632
+ HiDreamImageBlock(
633
+ dim = self.inner_dim,
634
+ num_attention_heads = self.num_attention_heads,
635
+ attention_head_dim = self.attention_head_dim,
636
+ num_routed_experts = num_routed_experts,
637
+ num_activated_experts = num_activated_experts,
638
+ block_type = BlockType.SingleTransformerBlock,
639
+ dtype=dtype, device=device, operations=operations
640
+ )
641
+ for i in range(self.num_single_layers)
642
+ ]
643
+ )
644
+
645
+ self.final_layer = LastLayer(self.inner_dim, patch_size, self.out_channels, dtype=dtype, device=device, operations=operations)
646
+
647
+ caption_channels = [caption_channels[1], ] * (num_layers + num_single_layers) + [caption_channels[0], ]
648
+ caption_projection = []
649
+ for caption_channel in caption_channels:
650
+ caption_projection.append(TextProjection(in_features=caption_channel, hidden_size=self.inner_dim, dtype=dtype, device=device, operations=operations))
651
+ self.caption_projection = nn.ModuleList(caption_projection)
652
+ self.max_seq = max_resolution[0] * max_resolution[1] // (patch_size * patch_size)
653
+
654
+ def expand_timesteps(self, timesteps, batch_size, device):
655
+ if not torch.is_tensor(timesteps):
656
+ is_mps = device.type == "mps"
657
+ if isinstance(timesteps, float):
658
+ dtype = torch.float32 if is_mps else torch.float64
659
+ else:
660
+ dtype = torch.int32 if is_mps else torch.int64
661
+ timesteps = torch.tensor([timesteps], dtype=dtype, device=device)
662
+ elif len(timesteps.shape) == 0:
663
+ timesteps = timesteps[None].to(device)
664
+ # broadcast to batch dimension in a way that's compatible with ONNX/Core ML
665
+ timesteps = timesteps.expand(batch_size)
666
+ return timesteps
667
+
668
+ def unpatchify(self, x: torch.Tensor, img_sizes: List[Tuple[int, int]]) -> List[torch.Tensor]:
669
+ x_arr = []
670
+ for i, img_size in enumerate(img_sizes):
671
+ pH, pW = img_size
672
+ x_arr.append(
673
+ einops.rearrange(x[i, :pH*pW].reshape(1, pH, pW, -1), 'B H W (p1 p2 C) -> B C (H p1) (W p2)',
674
+ p1=self.patch_size, p2=self.patch_size)
675
+ )
676
+ x = torch.cat(x_arr, dim=0)
677
+ return x
678
+
679
+ def patchify(self, x, max_seq, img_sizes=None):
680
+ pz2 = self.patch_size * self.patch_size
681
+ if isinstance(x, torch.Tensor):
682
+ B = x.shape[0]
683
+ device = x.device
684
+ dtype = x.dtype
685
+ else:
686
+ B = len(x)
687
+ device = x[0].device
688
+ dtype = x[0].dtype
689
+ x_masks = torch.zeros((B, max_seq), dtype=dtype, device=device)
690
+
691
+ if img_sizes is not None:
692
+ for i, img_size in enumerate(img_sizes):
693
+ x_masks[i, 0:img_size[0] * img_size[1]] = 1
694
+ x = einops.rearrange(x, 'B C S p -> B S (p C)', p=pz2)
695
+ elif isinstance(x, torch.Tensor):
696
+ pH, pW = x.shape[-2] // self.patch_size, x.shape[-1] // self.patch_size
697
+ x = einops.rearrange(x, 'B C (H p1) (W p2) -> B (H W) (p1 p2 C)', p1=self.patch_size, p2=self.patch_size)
698
+ img_sizes = [[pH, pW]] * B
699
+ x_masks = None
700
+ else:
701
+ raise NotImplementedError
702
+ return x, x_masks, img_sizes
703
+
704
+ def forward(self,
705
+ x: torch.Tensor,
706
+ t: torch.Tensor,
707
+ y: Optional[torch.Tensor] = None,
708
+ context: Optional[torch.Tensor] = None,
709
+ encoder_hidden_states_llama3=None,
710
+ image_cond=None,
711
+ control = None,
712
+ transformer_options = {},
713
+ ):
714
+ return comfy.patcher_extension.WrapperExecutor.new_class_executor(
715
+ self._forward,
716
+ self,
717
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.DIFFUSION_MODEL, transformer_options)
718
+ ).execute(x, t, y, context, encoder_hidden_states_llama3, image_cond, control, transformer_options)
719
+
720
+ def _forward(
721
+ self,
722
+ x: torch.Tensor,
723
+ t: torch.Tensor,
724
+ y: Optional[torch.Tensor] = None,
725
+ context: Optional[torch.Tensor] = None,
726
+ encoder_hidden_states_llama3=None,
727
+ image_cond=None,
728
+ control = None,
729
+ transformer_options = {},
730
+ ) -> torch.Tensor:
731
+ bs, c, h, w = x.shape
732
+ if image_cond is not None:
733
+ x = torch.cat([x, image_cond], dim=-1)
734
+ hidden_states = comfy.ldm.common_dit.pad_to_patch_size(x, (self.patch_size, self.patch_size))
735
+ timesteps = t
736
+ pooled_embeds = y
737
+ T5_encoder_hidden_states = context
738
+
739
+ img_sizes = None
740
+
741
+ # spatial forward
742
+ batch_size = hidden_states.shape[0]
743
+ hidden_states_type = hidden_states.dtype
744
+
745
+ # 0. time
746
+ timesteps = self.expand_timesteps(timesteps, batch_size, hidden_states.device)
747
+ timesteps = self.t_embedder(timesteps, hidden_states_type)
748
+ p_embedder = self.p_embedder(pooled_embeds)
749
+ adaln_input = timesteps + p_embedder
750
+
751
+ hidden_states, image_tokens_masks, img_sizes = self.patchify(hidden_states, self.max_seq, img_sizes)
752
+ if image_tokens_masks is None:
753
+ pH, pW = img_sizes[0]
754
+ img_ids = torch.zeros(pH, pW, 3, device=hidden_states.device)
755
+ img_ids[..., 1] = img_ids[..., 1] + torch.arange(pH, device=hidden_states.device)[:, None]
756
+ img_ids[..., 2] = img_ids[..., 2] + torch.arange(pW, device=hidden_states.device)[None, :]
757
+ img_ids = repeat(img_ids, "h w c -> b (h w) c", b=batch_size)
758
+ hidden_states = self.x_embedder(hidden_states)
759
+
760
+ # T5_encoder_hidden_states = encoder_hidden_states[0]
761
+ encoder_hidden_states = encoder_hidden_states_llama3.movedim(1, 0)
762
+ encoder_hidden_states = [encoder_hidden_states[k] for k in self.llama_layers]
763
+
764
+ if self.caption_projection is not None:
765
+ new_encoder_hidden_states = []
766
+ for i, enc_hidden_state in enumerate(encoder_hidden_states):
767
+ enc_hidden_state = self.caption_projection[i](enc_hidden_state)
768
+ enc_hidden_state = enc_hidden_state.view(batch_size, -1, hidden_states.shape[-1])
769
+ new_encoder_hidden_states.append(enc_hidden_state)
770
+ encoder_hidden_states = new_encoder_hidden_states
771
+ T5_encoder_hidden_states = self.caption_projection[-1](T5_encoder_hidden_states)
772
+ T5_encoder_hidden_states = T5_encoder_hidden_states.view(batch_size, -1, hidden_states.shape[-1])
773
+ encoder_hidden_states.append(T5_encoder_hidden_states)
774
+
775
+ txt_ids = torch.zeros(
776
+ batch_size,
777
+ encoder_hidden_states[-1].shape[1] + encoder_hidden_states[-2].shape[1] + encoder_hidden_states[0].shape[1],
778
+ 3,
779
+ device=img_ids.device, dtype=img_ids.dtype
780
+ )
781
+ ids = torch.cat((img_ids, txt_ids), dim=1)
782
+ rope = self.pe_embedder(ids)
783
+
784
+ # 2. Blocks
785
+ block_id = 0
786
+ initial_encoder_hidden_states = torch.cat([encoder_hidden_states[-1], encoder_hidden_states[-2]], dim=1)
787
+ initial_encoder_hidden_states_seq_len = initial_encoder_hidden_states.shape[1]
788
+ for bid, block in enumerate(self.double_stream_blocks):
789
+ cur_llama31_encoder_hidden_states = encoder_hidden_states[block_id]
790
+ cur_encoder_hidden_states = torch.cat([initial_encoder_hidden_states, cur_llama31_encoder_hidden_states], dim=1)
791
+ hidden_states, initial_encoder_hidden_states = block(
792
+ image_tokens = hidden_states,
793
+ image_tokens_masks = image_tokens_masks,
794
+ text_tokens = cur_encoder_hidden_states,
795
+ adaln_input = adaln_input,
796
+ rope = rope,
797
+ transformer_options=transformer_options,
798
+ )
799
+ initial_encoder_hidden_states = initial_encoder_hidden_states[:, :initial_encoder_hidden_states_seq_len]
800
+ block_id += 1
801
+
802
+ image_tokens_seq_len = hidden_states.shape[1]
803
+ hidden_states = torch.cat([hidden_states, initial_encoder_hidden_states], dim=1)
804
+ hidden_states_seq_len = hidden_states.shape[1]
805
+ if image_tokens_masks is not None:
806
+ encoder_attention_mask_ones = torch.ones(
807
+ (batch_size, initial_encoder_hidden_states.shape[1] + cur_llama31_encoder_hidden_states.shape[1]),
808
+ device=image_tokens_masks.device, dtype=image_tokens_masks.dtype
809
+ )
810
+ image_tokens_masks = torch.cat([image_tokens_masks, encoder_attention_mask_ones], dim=1)
811
+
812
+ for bid, block in enumerate(self.single_stream_blocks):
813
+ cur_llama31_encoder_hidden_states = encoder_hidden_states[block_id]
814
+ hidden_states = torch.cat([hidden_states, cur_llama31_encoder_hidden_states], dim=1)
815
+ hidden_states = block(
816
+ image_tokens=hidden_states,
817
+ image_tokens_masks=image_tokens_masks,
818
+ text_tokens=None,
819
+ adaln_input=adaln_input,
820
+ rope=rope,
821
+ transformer_options=transformer_options,
822
+ )
823
+ hidden_states = hidden_states[:, :hidden_states_seq_len]
824
+ block_id += 1
825
+
826
+ hidden_states = hidden_states[:, :image_tokens_seq_len, ...]
827
+ output = self.final_layer(hidden_states, adaln_input)
828
+ output = self.unpatchify(output, img_sizes)
829
+ return -output[:, :, :h, :w]
ComfyUI/comfy/ldm/hidream_o1/__pycache__/attention.cpython-312.pyc ADDED
Binary file (2.42 kB). View file
 
ComfyUI/comfy/ldm/hidream_o1/__pycache__/conditioning.cpython-312.pyc ADDED
Binary file (10.9 kB). View file
 
ComfyUI/comfy/ldm/hidream_o1/__pycache__/model.cpython-312.pyc ADDED
Binary file (16.1 kB). View file
 
ComfyUI/comfy/ldm/hidream_o1/__pycache__/utils.cpython-312.pyc ADDED
Binary file (9.95 kB). View file
 
ComfyUI/comfy/ldm/hidream_o1/attention.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HiDream-O1 two-pass attention: tokens [0, ar_len) are causal, [ar_len, T)
2
+ attend full K/V. Splitting Q at the boundary avoids the (B, 1, T, T) additive
3
+ mask the general-purpose path would build (~500 MB at T~16K) and lets the
4
+ gen half hit the user's preferred backend via optimized_attention.
5
+ """
6
+
7
+ import torch
8
+
9
+ import comfy.ops
10
+ from comfy.ldm.modules.attention import optimized_attention
11
+
12
+
13
+ def make_two_pass_attention(ar_len: int, transformer_options=None):
14
+ """Build a two-pass attention callable. AR pass uses SDPA-causal directly, gen pass routes through optimized_attention.
15
+ The AR pass goes through SDPA directand bypasses wrappers, it is only ~1% of T at typical edit sizes.
16
+ """
17
+
18
+ def two_pass_attention(q, k, v, heads, enable_gqa=False, **kwargs):
19
+ B, H, T, D = q.shape
20
+
21
+ if T < k.shape[2]: # KV-cache hot path: Q is shorter than K/V (cached AR prefix is in K/V only), all fresh Q positions are in the gen region, single full-attention call
22
+ out = optimized_attention(q, k, v, heads, mask=None, skip_reshape=True, skip_output_reshape=True, transformer_options=transformer_options, enable_gqa=enable_gqa)
23
+ elif ar_len >= T:
24
+ out = comfy.ops.scaled_dot_product_attention(q, k, v, attn_mask=None, dropout_p=0.0, is_causal=True, enable_gqa=enable_gqa)
25
+ elif ar_len <= 0:
26
+ out = optimized_attention(q, k, v, heads, mask=None, skip_reshape=True, skip_output_reshape=True, transformer_options=transformer_options, enable_gqa=enable_gqa)
27
+ else:
28
+ out_ar = comfy.ops.scaled_dot_product_attention(
29
+ q[:, :, :ar_len], k[:, :, :ar_len], v[:, :, :ar_len],
30
+ attn_mask=None, dropout_p=0.0, is_causal=True, enable_gqa=enable_gqa,
31
+ )
32
+ out_gen = optimized_attention(
33
+ q[:, :, ar_len:], k, v, heads,
34
+ mask=None, skip_reshape=True, skip_output_reshape=True,
35
+ transformer_options=transformer_options, enable_gqa=enable_gqa,
36
+ )
37
+ out = torch.cat([out_ar, out_gen], dim=2)
38
+
39
+ return out.transpose(1, 2).reshape(B, T, H * D)
40
+
41
+ return two_pass_attention
ComfyUI/comfy/ldm/hidream_o1/conditioning.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HiDream-O1 conditioning prep — ref-image dual path + extra_conds assembly.
2
+
3
+ Each ref image goes through two paths: a 32x32 patchified stream concatenated
4
+ to the noised target, and a Qwen3-VL ViT path producing tokens that scatter
5
+ into input_ids at <|image_pad|> positions.
6
+ """
7
+
8
+ from typing import List
9
+
10
+ import torch
11
+
12
+ import comfy.utils
13
+ from comfy.text_encoders.qwen_vl import process_qwen2vl_images
14
+
15
+ from .utils import (PATCH_SIZE, calculate_dimensions, cond_image_size, ref_max_size, resize_tensor)
16
+
17
+ # Qwen3-VL ViT preprocessing constants (preprocessor_config.json).
18
+ VIT_PATCH = 16
19
+ VIT_MERGE = 2
20
+ VIT_IMAGE_MEAN = [0.5, 0.5, 0.5]
21
+ VIT_IMAGE_STD = [0.5, 0.5, 0.5]
22
+
23
+
24
+ def prepare_ref_images(
25
+ ref_images: List[torch.Tensor],
26
+ target_h: int,
27
+ target_w: int,
28
+ device: torch.device,
29
+ dtype: torch.dtype,
30
+ ):
31
+ """Build the dual-path tensors for K reference images at (target_h, target_w).
32
+
33
+ Returns None for K=0, else a dict with ref_patches, ref_pixel_values,
34
+ ref_image_grid_thw, per_ref_vit_tokens, per_ref_patch_grids.
35
+ """
36
+ K = len(ref_images)
37
+ if K == 0:
38
+ return None
39
+ max_size = ref_max_size(max(target_h, target_w), K)
40
+ cis = cond_image_size(K)
41
+
42
+ refs_t = [img[0].clamp(0, 1).permute(2, 0, 1).unsqueeze(0).contiguous().float() for img in ref_images]
43
+ refs_t = [resize_tensor(t, max_size, PATCH_SIZE) for t in refs_t]
44
+
45
+ # 32-patch path.
46
+ ref_patches_per = []
47
+ per_ref_patch_grids = []
48
+ for t in refs_t:
49
+ t_norm = (t.squeeze(0) - 0.5) / 0.5 # (3, H, W) in [-1, 1]
50
+ h_p, w_p = t_norm.shape[-2] // PATCH_SIZE, t_norm.shape[-1] // PATCH_SIZE
51
+ per_ref_patch_grids.append((h_p, w_p))
52
+ patches = (
53
+ t_norm.reshape(3, h_p, PATCH_SIZE, w_p, PATCH_SIZE)
54
+ .permute(1, 3, 0, 2, 4)
55
+ .reshape(h_p * w_p, 3 * PATCH_SIZE * PATCH_SIZE)
56
+ )
57
+ ref_patches_per.append(patches)
58
+ ref_patches = torch.cat(ref_patches_per, dim=0).unsqueeze(0).to(device=device, dtype=dtype)
59
+
60
+ # ViT path.
61
+ refs_vlm_t = []
62
+ for t in refs_t:
63
+ _, _, h, w = t.shape
64
+ cond_w, cond_h = calculate_dimensions(cis, w / h)
65
+ cond_w = max(cond_w, VIT_PATCH * VIT_MERGE)
66
+ cond_h = max(cond_h, VIT_PATCH * VIT_MERGE)
67
+ refs_vlm_t.append(comfy.utils.common_upscale(t, cond_w, cond_h, "lanczos", "disabled"))
68
+
69
+ pv_list, grid_list, per_ref_vit_tokens = [], [], []
70
+ for t_v in refs_vlm_t:
71
+ pv, grid_thw = process_qwen2vl_images(
72
+ t_v.permute(0, 2, 3, 1),
73
+ min_pixels=0, max_pixels=10**12,
74
+ patch_size=VIT_PATCH, merge_size=VIT_MERGE,
75
+ image_mean=VIT_IMAGE_MEAN, image_std=VIT_IMAGE_STD,
76
+ )
77
+ grid_thw = grid_thw[0]
78
+ pv_list.append(pv.to(device=device, dtype=dtype))
79
+ grid_list.append(grid_thw.to(device=device))
80
+ # Post-merge token count = number of <|image_pad|> tokens this image expands to in input_ids.
81
+ gh, gw = int(grid_thw[1].item()), int(grid_thw[2].item())
82
+ per_ref_vit_tokens.append((gh // VIT_MERGE) * (gw // VIT_MERGE))
83
+
84
+ return {
85
+ "ref_patches": ref_patches,
86
+ "ref_pixel_values": torch.cat(pv_list, dim=0),
87
+ "ref_image_grid_thw": torch.stack(grid_list, dim=0),
88
+ "per_ref_vit_tokens": per_ref_vit_tokens,
89
+ "per_ref_patch_grids": per_ref_patch_grids,
90
+ }
91
+
92
+
93
+ def build_ref_input_ids(
94
+ text_input_ids: torch.Tensor,
95
+ per_ref_vit_tokens: List[int],
96
+ image_token_id: int,
97
+ vision_start_id: int,
98
+ vision_end_id: int,
99
+ ):
100
+ """Splice [vision_start, image_pad*N, vision_end] blocks into input_ids
101
+ after the [im_start, user, \\n] prefix (matches original chat template).
102
+ """
103
+ ids = text_input_ids[0].tolist()
104
+ inserted = []
105
+ for n_pad in per_ref_vit_tokens:
106
+ inserted.extend([vision_start_id] + [image_token_id] * n_pad + [vision_end_id])
107
+ new_ids = ids[:3] + inserted + ids[3:] # 3 = len([im_start, user, \n])
108
+ return torch.tensor([new_ids], dtype=text_input_ids.dtype, device=text_input_ids.device)
109
+
110
+
111
+ def build_extra_conds(
112
+ text_input_ids: torch.Tensor,
113
+ noise: torch.Tensor,
114
+ ref_images: List[torch.Tensor] = None,
115
+ target_patch_size: int = 32,
116
+ ):
117
+ """Assemble all conditioning tensors for HiDreamO1Transformer.forward:
118
+ input_ids (with ref-vision tokens spliced in for the edit/IP path),
119
+ position_ids (MRoPE), token_types, vinput_mask, plus the ref
120
+ dual-path tensors when refs are provided.
121
+ """
122
+ from .utils import get_rope_index_fix_point
123
+ from comfy.text_encoders.hidream_o1 import (
124
+ IMAGE_TOKEN_ID, VISION_START_ID, VISION_END_ID,
125
+ )
126
+
127
+ if text_input_ids.dim() == 1:
128
+ text_input_ids = text_input_ids.unsqueeze(0)
129
+ text_input_ids = text_input_ids.long().to(noise.device)
130
+ B = noise.shape[0]
131
+ if text_input_ids.shape[0] == 1 and B > 1:
132
+ text_input_ids = text_input_ids.expand(B, -1)
133
+
134
+ H, W = noise.shape[-2], noise.shape[-1]
135
+ h_p, w_p = H // target_patch_size, W // target_patch_size
136
+ image_len = h_p * w_p
137
+ image_grid_thw_tgt = torch.tensor(
138
+ [[1, h_p, w_p]], dtype=torch.long, device=text_input_ids.device,
139
+ )
140
+
141
+ out = {}
142
+ if ref_images:
143
+ ref = prepare_ref_images(ref_images, H, W, device=noise.device, dtype=noise.dtype)
144
+ text_input_ids = build_ref_input_ids(
145
+ text_input_ids, ref["per_ref_vit_tokens"],
146
+ IMAGE_TOKEN_ID, VISION_START_ID, VISION_END_ID,
147
+ )
148
+ new_txt_len = text_input_ids.shape[1]
149
+
150
+ # Each ref's patchified stream gets a [vision_start, image_pad*N-1]
151
+ # block in the position-id stream after the noised target.
152
+ ref_grid_lengths = [hp * wp for (hp, wp) in ref["per_ref_patch_grids"]]
153
+ tgt_vision = torch.full((1, image_len), IMAGE_TOKEN_ID,
154
+ dtype=text_input_ids.dtype, device=text_input_ids.device)
155
+ tgt_vision[:, 0] = VISION_START_ID
156
+ ref_vision_blocks = []
157
+ for rl in ref_grid_lengths:
158
+ blk = torch.full((1, rl), IMAGE_TOKEN_ID,
159
+ dtype=text_input_ids.dtype, device=text_input_ids.device)
160
+ blk[:, 0] = VISION_START_ID
161
+ ref_vision_blocks.append(blk)
162
+ ref_vision_cat = torch.cat([tgt_vision] + ref_vision_blocks, dim=1)
163
+ input_ids_pad = torch.cat([text_input_ids, ref_vision_cat], dim=-1)
164
+ total_ref_patches_len = sum(ref_grid_lengths)
165
+ total_len = new_txt_len + image_len + total_ref_patches_len
166
+
167
+ # K (ViT, post-merge) + 1 (target) + K (ref-patches) image grids.
168
+ K = len(ref_images)
169
+ igthw_cond = ref["ref_image_grid_thw"].clone()
170
+ igthw_cond[:, 1] //= 2
171
+ igthw_cond[:, 2] //= 2
172
+ image_grid_thw_ref = torch.tensor(
173
+ [[1, hp, wp] for (hp, wp) in ref["per_ref_patch_grids"]],
174
+ dtype=torch.long, device=text_input_ids.device,
175
+ )
176
+ igthw_all = torch.cat([
177
+ igthw_cond.to(text_input_ids.device),
178
+ image_grid_thw_tgt,
179
+ image_grid_thw_ref,
180
+ ], dim=0)
181
+ position_ids, _ = get_rope_index_fix_point(
182
+ spatial_merge_size=1,
183
+ image_token_id=IMAGE_TOKEN_ID,
184
+ vision_start_token_id=VISION_START_ID,
185
+ input_ids=input_ids_pad, image_grid_thw=igthw_all,
186
+ attention_mask=None,
187
+ skip_vision_start_token=[0] * K + [1] + [1] * K,
188
+ fix_point=4096,
189
+ )
190
+
191
+ # tms + target_image + ref_patches are all gen.
192
+ tms_pos = new_txt_len - 1
193
+ ar_len = tms_pos
194
+ token_types = torch.zeros(B, total_len, dtype=torch.long, device=noise.device)
195
+ token_types[:, tms_pos:] = 1
196
+ vinput_mask = torch.zeros(B, total_len, dtype=torch.bool, device=noise.device)
197
+ vinput_mask[:, new_txt_len:] = True
198
+
199
+ # Leading batch dim sidesteps CONDRegular.process_cond's repeat_to_batch_size truncation
200
+ out["ref_pixel_values"] = ref["ref_pixel_values"].unsqueeze(0)
201
+ out["ref_image_grid_thw"] = ref["ref_image_grid_thw"].unsqueeze(0)
202
+ out["ref_patches"] = ref["ref_patches"]
203
+ else:
204
+ # T2I: text + noised target only, vision_start replaces the first image token
205
+ txt_len = text_input_ids.shape[1]
206
+ total_len = txt_len + image_len
207
+ vision_tokens = torch.full((B, image_len), IMAGE_TOKEN_ID,
208
+ dtype=text_input_ids.dtype, device=text_input_ids.device)
209
+ vision_tokens[:, 0] = VISION_START_ID
210
+ input_ids_pad = torch.cat([text_input_ids, vision_tokens], dim=-1)
211
+ position_ids, _ = get_rope_index_fix_point(
212
+ spatial_merge_size=1,
213
+ image_token_id=IMAGE_TOKEN_ID,
214
+ vision_start_token_id=VISION_START_ID,
215
+ input_ids=input_ids_pad, image_grid_thw=image_grid_thw_tgt,
216
+ attention_mask=None,
217
+ skip_vision_start_token=[1],
218
+ )
219
+ ar_len = txt_len - 1
220
+ token_types = torch.zeros(B, total_len, dtype=torch.long, device=noise.device)
221
+ token_types[:, ar_len:] = 1
222
+ vinput_mask = torch.zeros(B, total_len, dtype=torch.bool, device=noise.device)
223
+ vinput_mask[:, txt_len:] = True
224
+
225
+ out["input_ids"] = text_input_ids
226
+ out["position_ids"] = position_ids[:, 0].unsqueeze(0) # Collapse position_ids batch and add a leading dim so CONDRegular's batch-resize doesn't truncate the 3-axis MRoPE dim
227
+ out["token_types"] = token_types
228
+ out["vinput_mask"] = vinput_mask
229
+ out["ar_len"] = ar_len
230
+ return out
ComfyUI/comfy/ldm/hidream_o1/model.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HiDream-O1-Image transformer.
2
+
3
+ Pixel-space DiT built on Qwen3-VL: the vision tower (Qwen35VisionModel)
4
+ encodes ref images, the Qwen3-VL-8B decoder (Llama2_ with interleaved MRoPE)
5
+ processes a unified text+image sequence, and 32x32 patch embed/unembed
6
+ shims map raw RGB in and out of LLM hidden space. The Qwen3-VL deepstack
7
+ mergers go unused — their weights are dropped at load.
8
+ """
9
+
10
+ from dataclasses import dataclass, field
11
+ from typing import List, Optional
12
+
13
+ import einops
14
+ import torch
15
+ import torch.nn as nn
16
+
17
+ import comfy.patcher_extension
18
+ from comfy.ldm.modules.diffusionmodules.mmdit import TimestepEmbedder
19
+ from comfy.text_encoders.llama import Llama2_
20
+ from comfy.text_encoders.qwen35 import Qwen35VisionModel
21
+
22
+ from .attention import make_two_pass_attention
23
+
24
+
25
+ IMAGE_TOKEN_ID = 151655 # Qwen3-VL <|image_pad|>
26
+ TMS_TOKEN_ID = 151673 # HiDream-O1 <|tms_token|>
27
+ PATCH_SIZE = 32
28
+
29
+
30
+ @dataclass
31
+ class HiDreamO1TextConfig:
32
+ """Qwen3-VL-8B text-decoder dims (matches public Qwen3-VL-8B-Instruct)."""
33
+ vocab_size: int = 151936
34
+ hidden_size: int = 4096
35
+ intermediate_size: int = 12288
36
+ num_hidden_layers: int = 36
37
+ num_attention_heads: int = 32
38
+ num_key_value_heads: int = 8
39
+ head_dim: int = 128
40
+ max_position_embeddings: int = 128000
41
+ rms_norm_eps: float = 1e-6
42
+ rope_theta: float = 5000000.0
43
+ rope_scale: Optional[float] = None
44
+ rope_dims: List[int] = field(default_factory=lambda: [24, 20, 20])
45
+ interleaved_mrope: bool = True
46
+ transformer_type: str = "llama"
47
+ rms_norm_add: bool = False
48
+ mlp_activation: str = "silu"
49
+ qkv_bias: bool = False
50
+ q_norm: str = "gemma3"
51
+ k_norm: str = "gemma3"
52
+ final_norm: bool = True
53
+ lm_head: bool = False
54
+ stop_tokens: List[int] = field(default_factory=lambda: [151643, 151645])
55
+
56
+
57
+ QWEN3VL_VISION_DEFAULTS = dict(
58
+ hidden_size=1152,
59
+ num_heads=16,
60
+ intermediate_size=4304,
61
+ depth=27,
62
+ patch_size=16,
63
+ temporal_patch_size=2,
64
+ in_channels=3,
65
+ spatial_merge_size=2,
66
+ num_position_embeddings=2304,
67
+ deepstack_visual_indexes=(8, 16, 24),
68
+ out_hidden_size=4096, # final merger projects directly into LLM hidden
69
+ )
70
+
71
+
72
+ class BottleneckPatchEmbed(nn.Module):
73
+ # 3072 -> 1024 -> 4096 (raw 32x32 RGB patch -> bottleneck -> LLM hidden).
74
+ def __init__(self, patch_size=32, in_chans=3, pca_dim=1024, embed_dim=4096, bias=True, device=None, dtype=None, ops=None):
75
+ super().__init__()
76
+ self.proj1 = ops.Linear(patch_size * patch_size * in_chans, pca_dim, bias=False, device=device, dtype=dtype)
77
+ self.proj2 = ops.Linear(pca_dim, embed_dim, bias=bias, device=device, dtype=dtype)
78
+
79
+ def forward(self, x):
80
+ return self.proj2(self.proj1(x))
81
+
82
+
83
+ class FinalLayer(nn.Module):
84
+ # 4096 -> 3072 (LLM hidden -> flat pixel patch).
85
+ def __init__(self, hidden_size, patch_size=32, out_channels=3, device=None, dtype=None, ops=None):
86
+ super().__init__()
87
+ self.linear = ops.Linear(hidden_size, patch_size * patch_size * out_channels, bias=True, device=device, dtype=dtype)
88
+
89
+ def forward(self, x):
90
+ return self.linear(x)
91
+
92
+
93
+ class HiDreamO1Transformer(nn.Module):
94
+ """HiDream-O1 unified pixel-level transformer."""
95
+
96
+ def __init__(self, image_model=None, dtype=None, device=None, operations=None,
97
+ text_config_overrides=None, vision_config_overrides=None, **kwargs):
98
+ super().__init__()
99
+ self.dtype = dtype
100
+
101
+ text_cfg = HiDreamO1TextConfig(**(text_config_overrides or {}))
102
+ vision_cfg = dict(QWEN3VL_VISION_DEFAULTS)
103
+ if vision_config_overrides:
104
+ vision_cfg.update(vision_config_overrides)
105
+ vision_cfg["out_hidden_size"] = text_cfg.hidden_size
106
+
107
+ self.text_config = text_cfg
108
+ self.vision_config = vision_cfg
109
+ self.hidden_size = text_cfg.hidden_size
110
+ self.patch_size = PATCH_SIZE
111
+ self.in_channels = 3
112
+ self.tms_token_id = TMS_TOKEN_ID
113
+
114
+ self.visual = Qwen35VisionModel(vision_cfg, device=device, dtype=dtype, ops=operations)
115
+ self.language_model = Llama2_(text_cfg, device=device, dtype=dtype, ops=operations)
116
+ self.t_embedder1 = TimestepEmbedder(
117
+ text_cfg.hidden_size, device=device, dtype=dtype, operations=operations,
118
+ )
119
+ self.x_embedder = BottleneckPatchEmbed(
120
+ patch_size=self.patch_size, in_chans=self.in_channels,
121
+ pca_dim=text_cfg.hidden_size // 4, embed_dim=text_cfg.hidden_size,
122
+ bias=True, device=device, dtype=dtype, ops=operations,
123
+ )
124
+ self.final_layer2 = FinalLayer(
125
+ text_cfg.hidden_size, patch_size=self.patch_size,
126
+ out_channels=self.in_channels, device=device, dtype=dtype, ops=operations,
127
+ )
128
+
129
+ self._visual_cache = None
130
+ self._kv_cache_entries = []
131
+
132
+ def clear_kv_cache(self):
133
+ self._kv_cache_entries = []
134
+ self._visual_cache = None
135
+
136
+ def forward(self, x, timesteps, context=None, transformer_options={}, **kwargs):
137
+ return comfy.patcher_extension.WrapperExecutor.new_class_executor(
138
+ self._forward,
139
+ self,
140
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.DIFFUSION_MODEL, transformer_options)
141
+ ).execute(x, timesteps, context, transformer_options, **kwargs)
142
+
143
+ def _forward(self, x, timesteps, context=None, transformer_options={}, input_ids=None, attention_mask=None, position_ids=None,
144
+ vinput_mask=None, ar_len=None, ref_pixel_values=None, ref_image_grid_thw=None, ref_patches=None, **kwargs):
145
+ """Returns flow-match velocity (x - x_pred) / sigma"""
146
+
147
+ if input_ids is None or position_ids is None:
148
+ raise ValueError("HiDreamO1Transformer requires input_ids and position_ids in conditioning")
149
+
150
+ B, _, H, W = x.shape
151
+ h_p, w_p = H // self.patch_size, W // self.patch_size
152
+ tgt_image_len = h_p * w_p
153
+
154
+ z = einops.rearrange(
155
+ x, 'B C (H p1) (W p2) -> B (H W) (C p1 p2)',
156
+ p1=self.patch_size, p2=self.patch_size,
157
+ )
158
+ vinputs = torch.cat([z, ref_patches.to(z.dtype)], dim=1) if ref_patches is not None else z
159
+
160
+ inputs_embeds = self.language_model.embed_tokens(input_ids).to(x.dtype)
161
+
162
+ if ref_pixel_values is not None and ref_image_grid_thw is not None:
163
+ # ViT output is constant across sampling steps within a generation
164
+ # identity-key by the input tensor so refs don't recompute every step.
165
+ cached = self._visual_cache
166
+ if cached is not None and cached[0] is ref_pixel_values:
167
+ image_embeds = cached[1]
168
+ else:
169
+ ref_pv = ref_pixel_values.to(inputs_embeds.device)
170
+ ref_grid = ref_image_grid_thw.to(inputs_embeds.device).long()
171
+ # extra_conds wraps with a leading batch dim; refs are model-level so [0] always recovers them.
172
+ if ref_pv.dim() == 3:
173
+ ref_pv = ref_pv[0]
174
+ if ref_grid.dim() == 3:
175
+ ref_grid = ref_grid[0]
176
+ image_embeds = self.visual(ref_pv, ref_grid).to(inputs_embeds.dtype)
177
+ self._visual_cache = (ref_pixel_values, image_embeds)
178
+ # image_pad positions identical across batch (input_ids shared cond/uncond).
179
+ image_idx = (input_ids[0] == IMAGE_TOKEN_ID).nonzero(as_tuple=True)[0]
180
+ if image_idx.shape[0] != image_embeds.shape[0]:
181
+ raise ValueError(
182
+ f"Image-token count {image_idx.shape[0]} != ViT output count "
183
+ f"{image_embeds.shape[0]}; check tokenizer/processor alignment."
184
+ )
185
+ inputs_embeds[:, image_idx] = image_embeds.unsqueeze(0).expand(B, -1, -1)
186
+
187
+ sigma = timesteps.float() / 1000.0
188
+ t_pixeldit = 1.0 - sigma
189
+ t_emb = self.t_embedder1(t_pixeldit * 1000, inputs_embeds.dtype)
190
+ tms_mask_3d = (input_ids == self.tms_token_id).unsqueeze(-1).expand_as(inputs_embeds)
191
+ inputs_embeds = torch.where(tms_mask_3d, t_emb.unsqueeze(1).expand_as(inputs_embeds), inputs_embeds)
192
+
193
+ vinputs_embedded = self.x_embedder(vinputs.to(inputs_embeds.dtype))
194
+ inputs_embeds = torch.cat([inputs_embeds, vinputs_embedded], dim=1)
195
+
196
+ # extra_conds stores position_ids as (1, 3, T); process_cond repeats dim 0 to B. Take row 0.
197
+ freqs_cis = self.language_model.compute_freqs_cis(position_ids[0].to(x.device), x.device)
198
+ freqs_cis = tuple(t.to(x.dtype) for t in freqs_cis)
199
+
200
+ two_pass_attn = make_two_pass_attention(ar_len, transformer_options=transformer_options)
201
+ patches_replace = transformer_options.get("patches_replace", {})
202
+ blocks_replace = patches_replace.get("dit", {})
203
+ transformer_options["total_blocks"] = len(self.language_model.layers)
204
+ transformer_options["block_type"] = "double"
205
+
206
+ # Cache prefix K/V across steps. Key includes input_ids (prompt), ref_id
207
+ # (refs scatter into inputs_embeds), and position_ids (RoPE baked into cached K).
208
+ can_cache = not blocks_replace and ar_len > 0
209
+ cache_len = ar_len if can_cache else 0
210
+ ref_id = id(ref_pixel_values) if ref_pixel_values is not None else None
211
+ pos_ids_key = position_ids[..., :cache_len] if can_cache else position_ids
212
+ cache_entries = self._kv_cache_entries
213
+ # Drop stale entries from a previous device (model was unloaded and reloaded).
214
+ if cache_entries and cache_entries[0]["input_ids"].device != input_ids.device:
215
+ cache_entries = []
216
+ self._kv_cache_entries = []
217
+ kv_cache = None
218
+ if can_cache:
219
+ for entry in cache_entries:
220
+ ck = entry["input_ids"]
221
+ ep = entry["position_ids"]
222
+ if (entry["cache_len"] == cache_len
223
+ and ck.shape == input_ids.shape and torch.equal(ck, input_ids)
224
+ and entry["ref_id"] == ref_id
225
+ and ep.shape == pos_ids_key.shape and torch.equal(ep, pos_ids_key)):
226
+ kv_cache = entry
227
+ break
228
+
229
+ if kv_cache is not None:
230
+ # Hot path: project Q/K/V only for fresh positions; past_key_value prepends cached AR K/V.
231
+ hidden_states = inputs_embeds[:, cache_len:]
232
+ sliced_freqs = tuple(t[..., cache_len:, :] for t in freqs_cis)
233
+ for i, layer in enumerate(self.language_model.layers):
234
+ transformer_options["block_index"] = i
235
+ K_i, V_i = kv_cache["kv"][i]
236
+ hidden_states, _ = layer(
237
+ x=hidden_states, attention_mask=None, freqs_cis=sliced_freqs, optimized_attention=two_pass_attn,
238
+ past_key_value=(K_i, V_i, cache_len),
239
+ )
240
+ else:
241
+ # Cold path: run full sequence; if cacheable, snapshot K/V at AR positions.
242
+ snapshots = [] if can_cache else None
243
+ past_kv_cold = () if can_cache else None
244
+ hidden_states = inputs_embeds
245
+ for i, layer in enumerate(self.language_model.layers):
246
+ transformer_options["block_index"] = i
247
+ if ("double_block", i) in blocks_replace:
248
+ def block_wrap(args, _layer=layer):
249
+ out = {}
250
+ out["x"], _ = _layer(
251
+ x=args["x"], attention_mask=args.get("attention_mask"),
252
+ freqs_cis=args["freqs_cis"], optimized_attention=args["optimized_attention"],
253
+ past_key_value=None,
254
+ )
255
+ return out
256
+ out = blocks_replace[("double_block", i)](
257
+ {"x": hidden_states, "attention_mask": None,
258
+ "freqs_cis": freqs_cis, "optimized_attention": two_pass_attn,
259
+ "transformer_options": transformer_options},
260
+ {"original_block": block_wrap},
261
+ )
262
+ hidden_states = out["x"]
263
+ else:
264
+ hidden_states, present_kv = layer(
265
+ x=hidden_states, attention_mask=None,
266
+ freqs_cis=freqs_cis, optimized_attention=two_pass_attn,
267
+ past_key_value=past_kv_cold,
268
+ )
269
+ if snapshots is not None:
270
+ K, V, _ = present_kv
271
+ snapshots.append((K[:, :, :cache_len].contiguous(),
272
+ V[:, :, :cache_len].contiguous()))
273
+ if snapshots is not None:
274
+ # Cap at 2 entries (cond + uncond). Multi-cond workflows LRU-evict.
275
+ new_entry = {
276
+ "input_ids": input_ids.clone(),
277
+ "cache_len": cache_len,
278
+ "kv": snapshots,
279
+ "ref_id": ref_id,
280
+ "position_ids": pos_ids_key.clone(),
281
+ }
282
+ self._kv_cache_entries = (cache_entries + [new_entry])[-2:]
283
+
284
+ if self.language_model.norm is not None:
285
+ hidden_states = self.language_model.norm(hidden_states)
286
+
287
+ # Slice target-image positions before the final projection so the Linear only runs on tgt_image_len tokens.
288
+ # In the hot path hidden_states starts at original position cache_len, so masks/indices shift by cache_len.
289
+ sliced_offset = cache_len if kv_cache is not None else 0
290
+ if vinput_mask is not None:
291
+ vmask = vinput_mask.to(x.device).bool()
292
+ if sliced_offset > 0:
293
+ vmask = vmask[:, sliced_offset:]
294
+ target_hidden = hidden_states[vmask].view(B, -1, hidden_states.shape[-1])[:, :tgt_image_len]
295
+ else:
296
+ txt_seq_len = input_ids.shape[1]
297
+ start = txt_seq_len - sliced_offset
298
+ target_hidden = hidden_states[:, start:start + tgt_image_len]
299
+ x_pred_tgt = self.final_layer2(target_hidden)
300
+
301
+ # fp32 final subtraction, bf16 here noticeably degrades samples.
302
+ x_pred_img = einops.rearrange(
303
+ x_pred_tgt, 'B (H W) (C p1 p2) -> B C (H p1) (W p2)',
304
+ H=h_p, W=w_p, p1=self.patch_size, p2=self.patch_size,
305
+ )
306
+ return (x.float() - x_pred_img.float()) / sigma.view(B, 1, 1, 1).clamp_min(1e-3)
ComfyUI/comfy/ldm/hidream_o1/utils.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HiDream-O1 input-prep helpers: image/resolution math and unified-sequence
2
+ RoPE position-id assembly. The fix_point offset in get_rope_index_fix_point
3
+ lets the target image and patchified ref images share spatial RoPE positions
4
+ despite living at different sequence indices — same 2D image plane.
5
+ """
6
+
7
+ import math
8
+ from typing import Optional
9
+
10
+ import torch
11
+
12
+
13
+ PATCH_SIZE = 32
14
+ CONDITION_IMAGE_SIZE = 384 # ViT-side base size for ref images
15
+
16
+
17
+ def resize_tensor(img_t, image_size, patch_size=16):
18
+ """img_t: (1, 3, H, W) float [0, 1]. Fit to image_size**2 area, patch-aligned, center-cropped."""
19
+
20
+ while min(img_t.shape[-2], img_t.shape[-1]) >= 2 * image_size: # Pre-halves with 2x2 box averaging while the image is still very large
21
+ img_t = torch.nn.functional.avg_pool2d(img_t, kernel_size=2, stride=2)
22
+
23
+ _, _, height, width = img_t.shape
24
+ m = patch_size
25
+ s_max = image_size * image_size
26
+ scale = math.sqrt(s_max / (width * height))
27
+
28
+ candidates = [
29
+ (round(width * scale) // m * m, round(height * scale) // m * m),
30
+ (round(width * scale) // m * m, math.floor(height * scale) // m * m),
31
+ (math.floor(width * scale) // m * m, round(height * scale) // m * m),
32
+ (math.floor(width * scale) // m * m, math.floor(height * scale) // m * m),
33
+ ]
34
+ candidates = sorted(candidates, key=lambda x: x[0] * x[1], reverse=True)
35
+ new_size = candidates[-1]
36
+ for c in candidates:
37
+ if c[0] * c[1] <= s_max:
38
+ new_size = c
39
+ break
40
+
41
+ new_w, new_h = new_size
42
+ s1 = width / new_w
43
+ s2 = height / new_h
44
+ if s1 < s2:
45
+ resize_w, resize_h = new_w, round(height / s1)
46
+ else:
47
+ resize_w, resize_h = round(width / s2), new_h
48
+ img_t = torch.nn.functional.interpolate(img_t, size=(resize_h, resize_w), mode="bicubic")
49
+ top = (resize_h - new_h) // 2
50
+ left = (resize_w - new_w) // 2
51
+ return img_t[..., top:top + new_h, left:left + new_w]
52
+
53
+
54
+ def calculate_dimensions(max_size, ratio):
55
+ """(W, H) for an aspect ratio fitting in max_size**2 area, 32-aligned."""
56
+ width = math.sqrt(max_size * max_size * ratio)
57
+ height = width / ratio
58
+ width = int(width / 32) * 32
59
+ height = int(height / 32) * 32
60
+ return width, height
61
+
62
+
63
+ def ref_max_size(target_max_dim, k):
64
+ """K-dependent ref-image max dim before patchifying."""
65
+ if k == 1:
66
+ return target_max_dim
67
+ if k == 2:
68
+ return target_max_dim * 48 // 64
69
+ if k <= 4:
70
+ return target_max_dim // 2
71
+ if k <= 8:
72
+ return target_max_dim * 24 // 64
73
+ return target_max_dim // 4
74
+
75
+
76
+ def cond_image_size(k):
77
+ """K-dependent ViT-side image size."""
78
+ if k <= 4:
79
+ return CONDITION_IMAGE_SIZE
80
+ if k <= 8:
81
+ return CONDITION_IMAGE_SIZE * 48 // 64
82
+ return CONDITION_IMAGE_SIZE // 2
83
+
84
+
85
+ def get_rope_index_fix_point(
86
+ spatial_merge_size: int,
87
+ image_token_id: int,
88
+ vision_start_token_id: int,
89
+ input_ids: Optional[torch.LongTensor] = None,
90
+ image_grid_thw: Optional[torch.LongTensor] = None,
91
+ attention_mask: Optional[torch.Tensor] = None,
92
+ skip_vision_start_token=None,
93
+ fix_point: int = 4096,
94
+ ):
95
+ mrope_position_deltas = []
96
+ if input_ids is not None and image_grid_thw is not None:
97
+ total_input_ids = input_ids
98
+ if attention_mask is None:
99
+ attention_mask = torch.ones_like(total_input_ids)
100
+ position_ids = torch.ones(
101
+ 3, input_ids.shape[0], input_ids.shape[1],
102
+ dtype=input_ids.dtype, device=input_ids.device,
103
+ )
104
+ attention_mask = attention_mask.to(total_input_ids.device)
105
+ for i, input_ids_b in enumerate(total_input_ids):
106
+ fp = fix_point
107
+ image_index = 0
108
+ input_ids_b = input_ids_b[attention_mask[i] == 1]
109
+ vision_start_indices = torch.argwhere(input_ids_b == vision_start_token_id).squeeze(1)
110
+ vision_tokens = input_ids_b[vision_start_indices + 1]
111
+ image_nums = (vision_tokens == image_token_id).sum()
112
+ input_tokens = input_ids_b.tolist()
113
+ llm_pos_ids_list = []
114
+ st = 0
115
+ remain_images = image_nums
116
+ for _ in range(image_nums):
117
+ if image_token_id in input_tokens and remain_images > 0:
118
+ ed = input_tokens.index(image_token_id, st)
119
+ else:
120
+ ed = len(input_tokens) + 1
121
+ t = image_grid_thw[image_index][0]
122
+ h = image_grid_thw[image_index][1]
123
+ w = image_grid_thw[image_index][2]
124
+ image_index += 1
125
+ remain_images -= 1
126
+ llm_grid_t = t.item()
127
+ llm_grid_h = h.item() // spatial_merge_size
128
+ llm_grid_w = w.item() // spatial_merge_size
129
+ text_len = ed - st
130
+ text_len -= skip_vision_start_token[image_index - 1]
131
+ text_len = max(0, text_len)
132
+ st_idx = llm_pos_ids_list[-1].max() + 1 if len(llm_pos_ids_list) > 0 else 0
133
+ llm_pos_ids_list.append(torch.arange(text_len).view(1, -1).expand(3, -1) + st_idx)
134
+
135
+ t_index = torch.arange(llm_grid_t).view(-1, 1).expand(-1, llm_grid_h * llm_grid_w).flatten()
136
+ h_index = torch.arange(llm_grid_h).view(1, -1, 1).expand(llm_grid_t, -1, llm_grid_w).flatten()
137
+ w_index = torch.arange(llm_grid_w).view(1, 1, -1).expand(llm_grid_t, llm_grid_h, -1).flatten()
138
+
139
+ if skip_vision_start_token[image_index - 1]:
140
+ if fp > 0:
141
+ fp = fp - st_idx
142
+ llm_pos_ids_list.append(torch.stack([t_index, h_index, w_index]) + fp + st_idx)
143
+ fp = 0
144
+ else:
145
+ llm_pos_ids_list.append(torch.stack([t_index, h_index, w_index]) + text_len + st_idx)
146
+ st = ed + llm_grid_t * llm_grid_h * llm_grid_w
147
+
148
+ if st < len(input_tokens):
149
+ st_idx = llm_pos_ids_list[-1].max() + 1 if len(llm_pos_ids_list) > 0 else 0
150
+ text_len = len(input_tokens) - st
151
+ llm_pos_ids_list.append(torch.arange(text_len).view(1, -1).expand(3, -1) + st_idx)
152
+
153
+ llm_positions = torch.cat(llm_pos_ids_list, dim=1).reshape(3, -1)
154
+ position_ids[..., i, attention_mask[i] == 1] = llm_positions.to(position_ids.device)
155
+ mrope_position_deltas.append(llm_positions.max() + 1 - len(total_input_ids[i]))
156
+ mrope_position_deltas = torch.tensor(mrope_position_deltas, device=input_ids.device).unsqueeze(1)
157
+ return position_ids, mrope_position_deltas
158
+
159
+ if attention_mask is not None:
160
+ position_ids = attention_mask.long().cumsum(-1) - 1
161
+ position_ids.masked_fill_(attention_mask == 0, 1)
162
+ position_ids = position_ids.unsqueeze(0).expand(3, -1, -1).to(attention_mask.device)
163
+ max_position_ids = position_ids.max(0, keepdim=False)[0].max(-1, keepdim=True)[0]
164
+ mrope_position_deltas = max_position_ids + 1 - attention_mask.shape[-1]
165
+ else:
166
+ position_ids = (
167
+ torch.arange(input_ids.shape[1], device=input_ids.device)
168
+ .view(1, 1, -1).expand(3, input_ids.shape[0], -1)
169
+ )
170
+ mrope_position_deltas = torch.zeros(
171
+ [input_ids.shape[0], 1], device=input_ids.device, dtype=input_ids.dtype,
172
+ )
173
+ return position_ids, mrope_position_deltas
ComfyUI/comfy/ldm/hunyuan3d/__pycache__/model.cpython-312.pyc ADDED
Binary file (6.03 kB). View file
 
ComfyUI/comfy/ldm/hunyuan3d/__pycache__/vae.cpython-312.pyc ADDED
Binary file (49.6 kB). View file
 
ComfyUI/comfy/ldm/hunyuan3d/model.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from comfy.ldm.flux.layers import (
4
+ DoubleStreamBlock,
5
+ LastLayer,
6
+ MLPEmbedder,
7
+ SingleStreamBlock,
8
+ timestep_embedding,
9
+ )
10
+ import comfy.patcher_extension
11
+
12
+
13
+ class Hunyuan3Dv2(nn.Module):
14
+ def __init__(
15
+ self,
16
+ in_channels=64,
17
+ context_in_dim=1536,
18
+ hidden_size=1024,
19
+ mlp_ratio=4.0,
20
+ num_heads=16,
21
+ depth=16,
22
+ depth_single_blocks=32,
23
+ qkv_bias=True,
24
+ guidance_embed=False,
25
+ image_model=None,
26
+ dtype=None,
27
+ device=None,
28
+ operations=None
29
+ ):
30
+ super().__init__()
31
+ self.dtype = dtype
32
+
33
+ if hidden_size % num_heads != 0:
34
+ raise ValueError(
35
+ f"Hidden size {hidden_size} must be divisible by num_heads {num_heads}"
36
+ )
37
+
38
+ self.max_period = 1000 # While reimplementing the model I noticed that they messed up. This 1000 value was meant to be the time_factor but they set the max_period instead
39
+ self.latent_in = operations.Linear(in_channels, hidden_size, bias=True, dtype=dtype, device=device)
40
+ self.time_in = MLPEmbedder(in_dim=256, hidden_dim=hidden_size, dtype=dtype, device=device, operations=operations)
41
+ self.guidance_in = (
42
+ MLPEmbedder(in_dim=256, hidden_dim=hidden_size, dtype=dtype, device=device, operations=operations) if guidance_embed else None
43
+ )
44
+ self.cond_in = operations.Linear(context_in_dim, hidden_size, dtype=dtype, device=device)
45
+ self.double_blocks = nn.ModuleList(
46
+ [
47
+ DoubleStreamBlock(
48
+ hidden_size,
49
+ num_heads,
50
+ mlp_ratio=mlp_ratio,
51
+ qkv_bias=qkv_bias,
52
+ dtype=dtype, device=device, operations=operations
53
+ )
54
+ for _ in range(depth)
55
+ ]
56
+ )
57
+ self.single_blocks = nn.ModuleList(
58
+ [
59
+ SingleStreamBlock(
60
+ hidden_size,
61
+ num_heads,
62
+ mlp_ratio=mlp_ratio,
63
+ dtype=dtype, device=device, operations=operations
64
+ )
65
+ for _ in range(depth_single_blocks)
66
+ ]
67
+ )
68
+ self.final_layer = LastLayer(hidden_size, 1, in_channels, dtype=dtype, device=device, operations=operations)
69
+
70
+ def forward(self, x, timestep, context, guidance=None, transformer_options={}, **kwargs):
71
+ return comfy.patcher_extension.WrapperExecutor.new_class_executor(
72
+ self._forward,
73
+ self,
74
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.DIFFUSION_MODEL, transformer_options)
75
+ ).execute(x, timestep, context, guidance, transformer_options, **kwargs)
76
+
77
+ def _forward(self, x, timestep, context, guidance=None, transformer_options={}, **kwargs):
78
+ x = x.movedim(-1, -2)
79
+ timestep = 1.0 - timestep
80
+ txt = context
81
+ img = self.latent_in(x)
82
+
83
+ vec = self.time_in(timestep_embedding(timestep, 256, self.max_period).to(dtype=img.dtype))
84
+ if self.guidance_in is not None:
85
+ if guidance is not None:
86
+ vec = vec + self.guidance_in(timestep_embedding(guidance, 256, self.max_period).to(img.dtype))
87
+
88
+ txt = self.cond_in(txt)
89
+ pe = None
90
+ attn_mask = None
91
+
92
+ patches_replace = transformer_options.get("patches_replace", {})
93
+ blocks_replace = patches_replace.get("dit", {})
94
+ for i, block in enumerate(self.double_blocks):
95
+ if ("double_block", i) in blocks_replace:
96
+ def block_wrap(args):
97
+ out = {}
98
+ out["img"], out["txt"] = block(img=args["img"],
99
+ txt=args["txt"],
100
+ vec=args["vec"],
101
+ pe=args["pe"],
102
+ attn_mask=args.get("attn_mask"),
103
+ transformer_options=args["transformer_options"])
104
+ return out
105
+
106
+ out = blocks_replace[("double_block", i)]({"img": img,
107
+ "txt": txt,
108
+ "vec": vec,
109
+ "pe": pe,
110
+ "attn_mask": attn_mask,
111
+ "transformer_options": transformer_options},
112
+ {"original_block": block_wrap})
113
+ txt = out["txt"]
114
+ img = out["img"]
115
+ else:
116
+ img, txt = block(img=img,
117
+ txt=txt,
118
+ vec=vec,
119
+ pe=pe,
120
+ attn_mask=attn_mask,
121
+ transformer_options=transformer_options)
122
+
123
+ img = torch.cat((txt, img), 1)
124
+
125
+ for i, block in enumerate(self.single_blocks):
126
+ if ("single_block", i) in blocks_replace:
127
+ def block_wrap(args):
128
+ out = {}
129
+ out["img"] = block(args["img"],
130
+ vec=args["vec"],
131
+ pe=args["pe"],
132
+ attn_mask=args.get("attn_mask"),
133
+ transformer_options=args["transformer_options"])
134
+ return out
135
+
136
+ out = blocks_replace[("single_block", i)]({"img": img,
137
+ "vec": vec,
138
+ "pe": pe,
139
+ "attn_mask": attn_mask,
140
+ "transformer_options": transformer_options},
141
+ {"original_block": block_wrap})
142
+ img = out["img"]
143
+ else:
144
+ img = block(img, vec=vec, pe=pe, attn_mask=attn_mask, transformer_options=transformer_options)
145
+
146
+ img = img[:, txt.shape[1]:, ...]
147
+ img = self.final_layer(img, vec)
148
+ return img.movedim(-2, -1) * (-1.0)
ComfyUI/comfy/ldm/hunyuan3d/vae.py ADDED
@@ -0,0 +1,988 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Original: https://github.com/Tencent/Hunyuan3D-2/blob/main/hy3dgen/shapegen/models/autoencoders/model.py
2
+ # Since the header on their VAE source file was a bit confusing we asked for permission to use this code from tencent under the GPL license used in ComfyUI.
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ import numpy as np
8
+ import math
9
+ from tqdm import tqdm
10
+
11
+ from typing import Optional
12
+
13
+ import logging
14
+
15
+ import comfy.ops
16
+ ops = comfy.ops.disable_weight_init
17
+
18
+ def fps(src: torch.Tensor, batch: torch.Tensor, sampling_ratio: float, start_random: bool = True):
19
+
20
+ # manually create the pointer vector
21
+ assert src.size(0) == batch.numel()
22
+
23
+ batch_size = int(batch.max()) + 1
24
+ deg = src.new_zeros(batch_size, dtype = torch.long)
25
+
26
+ deg.scatter_add_(0, batch, torch.ones_like(batch))
27
+
28
+ ptr_vec = deg.new_zeros(batch_size + 1)
29
+ torch.cumsum(deg, 0, out=ptr_vec[1:])
30
+
31
+ #return fps_sampling(src, ptr_vec, ratio)
32
+ sampled_indicies = []
33
+
34
+ for b in range(batch_size):
35
+ # start and the end of each batch
36
+ start, end = ptr_vec[b].item(), ptr_vec[b + 1].item()
37
+ # points from the point cloud
38
+ points = src[start:end]
39
+
40
+ num_points = points.size(0)
41
+ num_samples = max(1, math.ceil(num_points * sampling_ratio))
42
+
43
+ selected = torch.zeros(num_samples, device = src.device, dtype = torch.long)
44
+ distances = torch.full((num_points,), float("inf"), device = src.device)
45
+
46
+ # select a random start point
47
+ if start_random:
48
+ farthest = torch.randint(0, num_points, (1,), device = src.device)
49
+ else:
50
+ farthest = torch.tensor([0], device = src.device, dtype = torch.long)
51
+
52
+ for i in range(num_samples):
53
+ selected[i] = farthest
54
+ centroid = points[farthest].squeeze(0)
55
+ dist = torch.norm(points - centroid, dim = 1) # compute euclidean distance
56
+ distances = torch.minimum(distances, dist)
57
+ farthest = torch.argmax(distances)
58
+
59
+ sampled_indicies.append(torch.arange(start, end)[selected])
60
+
61
+ return torch.cat(sampled_indicies, dim = 0)
62
+ class PointCrossAttention(nn.Module):
63
+ def __init__(self,
64
+ num_latents: int,
65
+ downsample_ratio: float,
66
+ pc_size: int,
67
+ pc_sharpedge_size: int,
68
+ point_feats: int,
69
+ width: int,
70
+ heads: int,
71
+ layers: int,
72
+ fourier_embedder,
73
+ normal_pe: bool = False,
74
+ qkv_bias: bool = False,
75
+ use_ln_post: bool = True,
76
+ qk_norm: bool = True):
77
+
78
+ super().__init__()
79
+
80
+ self.fourier_embedder = fourier_embedder
81
+
82
+ self.pc_size = pc_size
83
+ self.normal_pe = normal_pe
84
+ self.downsample_ratio = downsample_ratio
85
+ self.pc_sharpedge_size = pc_sharpedge_size
86
+ self.num_latents = num_latents
87
+ self.point_feats = point_feats
88
+
89
+ self.input_proj = nn.Linear(self.fourier_embedder.out_dim + point_feats, width)
90
+
91
+ self.cross_attn = ResidualCrossAttentionBlock(
92
+ width = width,
93
+ heads = heads,
94
+ qkv_bias = qkv_bias,
95
+ qk_norm = qk_norm
96
+ )
97
+
98
+ self.self_attn = None
99
+ if layers > 0:
100
+ self.self_attn = Transformer(
101
+ width = width,
102
+ heads = heads,
103
+ qkv_bias = qkv_bias,
104
+ qk_norm = qk_norm,
105
+ layers = layers
106
+ )
107
+
108
+ if use_ln_post:
109
+ self.ln_post = nn.LayerNorm(width)
110
+ else:
111
+ self.ln_post = None
112
+
113
+ def sample_points_and_latents(self, point_cloud: torch.Tensor, features: torch.Tensor):
114
+
115
+ """
116
+ Subsample points randomly from the point cloud (input_pc)
117
+ Further sample the subsampled points to get query_pc
118
+ take the fourier embeddings for both input and query pc
119
+
120
+ Mental Note: FPS-sampled points (query_pc) act as latent tokens that attend to and learn from the broader context in input_pc.
121
+ Goal: get a smaller represenation (query_pc) to represent the entire scence structure by learning from a broader subset (input_pc).
122
+ More computationally efficient.
123
+
124
+ Features are additional information for each point in the cloud
125
+ """
126
+
127
+ B, _, D = point_cloud.shape
128
+
129
+ num_latents = int(self.num_latents)
130
+
131
+ num_random_query = self.pc_size / (self.pc_size + self.pc_sharpedge_size) * num_latents
132
+ num_sharpedge_query = num_latents - num_random_query
133
+
134
+ # Split random and sharpedge surface points
135
+ random_pc, sharpedge_pc = torch.split(point_cloud, [self.pc_size, self.pc_sharpedge_size], dim=1)
136
+
137
+ # assert statements
138
+ assert random_pc.shape[1] <= self.pc_size, "Random surface points size must be less than or equal to pc_size"
139
+ assert sharpedge_pc.shape[1] <= self.pc_sharpedge_size, "Sharpedge surface points size must be less than or equal to pc_sharpedge_size"
140
+
141
+ input_random_pc_size = int(num_random_query * self.downsample_ratio)
142
+ random_query_pc, random_input_pc, random_idx_pc, random_idx_query = \
143
+ self.subsample(pc = random_pc, num_query = num_random_query, input_pc_size = input_random_pc_size)
144
+
145
+ input_sharpedge_pc_size = int(num_sharpedge_query * self.downsample_ratio)
146
+
147
+ if input_sharpedge_pc_size == 0:
148
+ sharpedge_input_pc = torch.zeros(B, 0, D, dtype = random_input_pc.dtype).to(point_cloud.device)
149
+ sharpedge_query_pc = torch.zeros(B, 0, D, dtype= random_query_pc.dtype).to(point_cloud.device)
150
+
151
+ else:
152
+ sharpedge_query_pc, sharpedge_input_pc, sharpedge_idx_pc, sharpedge_idx_query = \
153
+ self.subsample(pc = sharpedge_pc, num_query = num_sharpedge_query, input_pc_size = input_sharpedge_pc_size)
154
+
155
+ # concat the random and sharpedges
156
+ query_pc = torch.cat([random_query_pc, sharpedge_query_pc], dim = 1)
157
+ input_pc = torch.cat([random_input_pc, sharpedge_input_pc], dim = 1)
158
+
159
+ query = self.fourier_embedder(query_pc)
160
+ data = self.fourier_embedder(input_pc)
161
+
162
+ if self.point_feats > 0:
163
+ random_surface_features, sharpedge_surface_features = torch.split(features, [self.pc_size, self.pc_sharpedge_size], dim = 1)
164
+
165
+ input_random_surface_features, query_random_features = \
166
+ self.handle_features(features = random_surface_features, idx_pc = random_idx_pc, batch_size = B,
167
+ input_pc_size = input_random_pc_size, idx_query = random_idx_query)
168
+
169
+ if input_sharpedge_pc_size == 0:
170
+ input_sharpedge_surface_features = torch.zeros(B, 0, self.point_feats,
171
+ dtype = input_random_surface_features.dtype, device = point_cloud.device)
172
+
173
+ query_sharpedge_features = torch.zeros(B, 0, self.point_feats,
174
+ dtype = query_random_features.dtype, device = point_cloud.device)
175
+ else:
176
+
177
+ input_sharpedge_surface_features, query_sharpedge_features = \
178
+ self.handle_features(idx_pc = sharpedge_idx_pc, features = sharpedge_surface_features,
179
+ batch_size = B, idx_query = sharpedge_idx_query, input_pc_size = input_sharpedge_pc_size)
180
+
181
+ query_features = torch.cat([query_random_features, query_sharpedge_features], dim = 1)
182
+ input_features = torch.cat([input_random_surface_features, input_sharpedge_surface_features], dim = 1)
183
+
184
+ if self.normal_pe:
185
+ # apply the fourier embeddings on the first 3 dims (xyz)
186
+ input_features_pe = self.fourier_embedder(input_features[..., :3])
187
+ query_features_pe = self.fourier_embedder(query_features[..., :3])
188
+ # replace the first 3 dims with the new PE ones
189
+ input_features = torch.cat([input_features_pe, input_features[..., :3]], dim = -1)
190
+ query_features = torch.cat([query_features_pe, query_features[..., :3]], dim = -1)
191
+
192
+ # concat at the channels dim
193
+ query = torch.cat([query, query_features], dim = -1)
194
+ data = torch.cat([data, input_features], dim = -1)
195
+
196
+ # don't return pc_info to avoid unnecessary memory usuage
197
+ return query.view(B, -1, query.shape[-1]), data.view(B, -1, data.shape[-1])
198
+
199
+ def forward(self, point_cloud: torch.Tensor, features: torch.Tensor):
200
+
201
+ query, data = self.sample_points_and_latents(point_cloud = point_cloud, features = features)
202
+
203
+ # apply projections
204
+ query = self.input_proj(query)
205
+ data = self.input_proj(data)
206
+
207
+ # apply cross attention between query and data
208
+ latents = self.cross_attn(query, data)
209
+
210
+ if self.self_attn is not None:
211
+ latents = self.self_attn(latents)
212
+
213
+ if self.ln_post is not None:
214
+ latents = self.ln_post(latents)
215
+
216
+ return latents
217
+
218
+
219
+ def subsample(self, pc, num_query, input_pc_size: int):
220
+
221
+ """
222
+ num_query: number of points to keep after FPS
223
+ input_pc_size: number of points to select before FPS
224
+ """
225
+
226
+ B, _, D = pc.shape
227
+ query_ratio = num_query / input_pc_size
228
+
229
+ # random subsampling of points inside the point cloud
230
+ idx_pc = torch.randperm(pc.shape[1], device = pc.device)[:input_pc_size]
231
+ input_pc = pc[:, idx_pc, :]
232
+
233
+ # flatten to allow applying fps across the whole batch
234
+ flattent_input_pc = input_pc.view(B * input_pc_size, D)
235
+
236
+ # construct a batch_down tensor to tell fps
237
+ # which points belong to which batch
238
+ N_down = int(flattent_input_pc.shape[0] / B)
239
+ batch_down = torch.arange(B).to(pc.device)
240
+ batch_down = torch.repeat_interleave(batch_down, N_down)
241
+
242
+ idx_query = fps(flattent_input_pc, batch_down, sampling_ratio = query_ratio)
243
+ query_pc = flattent_input_pc[idx_query].view(B, -1, D)
244
+
245
+ return query_pc, input_pc, idx_pc, idx_query
246
+
247
+ def handle_features(self, features, idx_pc, input_pc_size, batch_size: int, idx_query):
248
+
249
+ B = batch_size
250
+
251
+ input_surface_features = features[:, idx_pc, :]
252
+ flattent_input_features = input_surface_features.view(B * input_pc_size, -1)
253
+ query_features = flattent_input_features[idx_query].view(B, -1,
254
+ flattent_input_features.shape[-1])
255
+
256
+ return input_surface_features, query_features
257
+
258
+ def normalize_mesh(mesh, scale = 0.9999):
259
+ """Normalize mesh to fit in [-scale, scale]. Translate mesh so its center is [0,0,0]"""
260
+
261
+ bbox = mesh.bounds
262
+ center = (bbox[1] + bbox[0]) / 2
263
+
264
+ max_extent = (bbox[1] - bbox[0]).max()
265
+ mesh.apply_translation(-center)
266
+ mesh.apply_scale((2 * scale) / max_extent)
267
+
268
+ return mesh
269
+
270
+ def sample_pointcloud(mesh, num = 200000):
271
+ """ Uniformly sample points from the surface of the mesh """
272
+
273
+ points, face_idx = mesh.sample(num, return_index = True)
274
+ normals = mesh.face_normals[face_idx]
275
+ return torch.from_numpy(points.astype(np.float32)), torch.from_numpy(normals.astype(np.float32))
276
+
277
+ def detect_sharp_edges(mesh, threshold=0.985):
278
+ """Return edge indices (a, b) that lie on sharp boundaries of the mesh."""
279
+
280
+ V, F = mesh.vertices, mesh.faces
281
+ VN, FN = mesh.vertex_normals, mesh.face_normals
282
+
283
+ sharp_mask = np.ones(V.shape[0])
284
+ for i in range(3):
285
+ indices = F[:, i]
286
+ alignment = np.einsum('ij,ij->i', VN[indices], FN)
287
+ dot_stack = np.stack((sharp_mask[indices], alignment), axis=-1)
288
+ sharp_mask[indices] = np.min(dot_stack, axis=-1)
289
+
290
+ edge_a = np.concatenate([F[:, 0], F[:, 1], F[:, 2]])
291
+ edge_b = np.concatenate([F[:, 1], F[:, 2], F[:, 0]])
292
+ sharp_edges = (sharp_mask[edge_a] < threshold) & (sharp_mask[edge_b] < threshold)
293
+
294
+ return edge_a[sharp_edges], edge_b[sharp_edges]
295
+
296
+
297
+ def sharp_sample_pointcloud(mesh, num = 16384):
298
+ """ Sample points preferentially from sharp edges in the mesh. """
299
+
300
+ edge_a, edge_b = detect_sharp_edges(mesh)
301
+ V, VN = mesh.vertices, mesh.vertex_normals
302
+
303
+ va, vb = V[edge_a], V[edge_b]
304
+ na, nb = VN[edge_a], VN[edge_b]
305
+
306
+ edge_lengths = np.linalg.norm(vb - va, axis=-1)
307
+ weights = edge_lengths / edge_lengths.sum()
308
+
309
+ indices = np.searchsorted(np.cumsum(weights), np.random.rand(num))
310
+ t = np.random.rand(num, 1)
311
+
312
+ samples = t * va[indices] + (1 - t) * vb[indices]
313
+ normals = t * na[indices] + (1 - t) * nb[indices]
314
+
315
+ return samples.astype(np.float32), normals.astype(np.float32)
316
+
317
+ def load_surface_sharpedge(mesh, num_points=4096, num_sharp_points=4096, sharpedge_flag = True, device = "cuda"):
318
+ """Load a surface with optional sharp-edge annotations from a trimesh mesh."""
319
+
320
+ import trimesh
321
+
322
+ try:
323
+ mesh_full = trimesh.util.concatenate(mesh.dump())
324
+ except Exception:
325
+ mesh_full = trimesh.util.concatenate(mesh)
326
+
327
+ mesh_full = normalize_mesh(mesh_full)
328
+
329
+ faces = mesh_full.faces
330
+ vertices = mesh_full.vertices
331
+ origin_face_count = faces.shape[0]
332
+
333
+ mesh_surface = trimesh.Trimesh(vertices=vertices, faces=faces[:origin_face_count])
334
+ mesh_fill = trimesh.Trimesh(vertices=vertices, faces=faces[origin_face_count:])
335
+
336
+ area_surface = mesh_surface.area
337
+ area_fill = mesh_fill.area
338
+ total_area = area_surface + area_fill
339
+
340
+ sample_num = 499712 // 2
341
+ fill_ratio = area_fill / total_area if total_area > 0 else 0
342
+
343
+ num_fill = int(sample_num * fill_ratio)
344
+ num_surface = sample_num - num_fill
345
+
346
+ surf_pts, surf_normals = sample_pointcloud(mesh_surface, num_surface)
347
+ fill_pts, fill_normals = (torch.zeros(0, 3), torch.zeros(0, 3)) if num_fill == 0 else sample_pointcloud(mesh_fill, num_fill)
348
+
349
+ sharp_pts, sharp_normals = sharp_sample_pointcloud(mesh_surface, sample_num)
350
+
351
+ def assemble_tensor(points, normals, label=None):
352
+
353
+ data = torch.cat([points, normals], dim=1).half().to(device)
354
+
355
+ if label is not None:
356
+ label_tensor = torch.full((data.shape[0], 1), float(label), dtype=torch.float16).to(device)
357
+ data = torch.cat([data, label_tensor], dim=1)
358
+
359
+ return data
360
+
361
+ surface = assemble_tensor(torch.cat([surf_pts.to(device), fill_pts.to(device)], dim=0),
362
+ torch.cat([surf_normals.to(device), fill_normals.to(device)], dim=0),
363
+ label = 0 if sharpedge_flag else None)
364
+
365
+ sharp_surface = assemble_tensor(torch.from_numpy(sharp_pts), torch.from_numpy(sharp_normals),
366
+ label = 1 if sharpedge_flag else None)
367
+
368
+ rng = np.random.default_rng()
369
+
370
+ surface = surface[rng.choice(surface.shape[0], num_points, replace = False)]
371
+ sharp_surface = sharp_surface[rng.choice(sharp_surface.shape[0], num_sharp_points, replace = False)]
372
+
373
+ full = torch.cat([surface, sharp_surface], dim = 0).unsqueeze(0)
374
+
375
+ return full
376
+
377
+ class SharpEdgeSurfaceLoader:
378
+ """ Load mesh surface and sharp edge samples. """
379
+
380
+ def __init__(self, num_uniform_points = 8192, num_sharp_points = 8192):
381
+
382
+ self.num_uniform_points = num_uniform_points
383
+ self.num_sharp_points = num_sharp_points
384
+ self.total_points = num_uniform_points + num_sharp_points
385
+
386
+ def __call__(self, mesh_input, device = "cuda"):
387
+ mesh = self._load_mesh(mesh_input)
388
+ return load_surface_sharpedge(mesh, self.num_uniform_points, self.num_sharp_points, device = device)
389
+
390
+ @staticmethod
391
+ def _load_mesh(mesh_input):
392
+ import trimesh
393
+
394
+ if isinstance(mesh_input, str):
395
+ mesh = trimesh.load(mesh_input, force="mesh", merge_primitives = True)
396
+ else:
397
+ mesh = mesh_input
398
+
399
+ if isinstance(mesh, trimesh.Scene):
400
+ combined = None
401
+ for obj in mesh.geometry.values():
402
+ combined = obj if combined is None else combined + obj
403
+ return combined
404
+
405
+ return mesh
406
+
407
+ class DiagonalGaussianDistribution:
408
+ def __init__(self, params: torch.Tensor, feature_dim: int = -1):
409
+
410
+ # divide quant channels (8) into mean and log variance
411
+ self.mean, self.logvar = torch.chunk(params, 2, dim = feature_dim)
412
+
413
+ self.logvar = torch.clamp(self.logvar, -30.0, 20.0)
414
+ self.std = torch.exp(0.5 * self.logvar)
415
+
416
+ def sample(self):
417
+
418
+ eps = torch.randn_like(self.std)
419
+ z = self.mean + eps * self.std
420
+
421
+ return z
422
+
423
+ ################################################
424
+ # Volume Decoder
425
+ ################################################
426
+
427
+ class VanillaVolumeDecoder():
428
+ @torch.no_grad()
429
+ def __call__(self, latents: torch.Tensor, geo_decoder: callable, octree_resolution: int, bounds = 1.01,
430
+ num_chunks: int = 10_000, enable_pbar: bool = True, **kwargs):
431
+
432
+ if isinstance(bounds, float):
433
+ bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds]
434
+
435
+ bbox_min, bbox_max = torch.tensor(bounds[:3]), torch.tensor(bounds[3:])
436
+
437
+ x = torch.linspace(bbox_min[0], bbox_max[0], int(octree_resolution) + 1, dtype = torch.float32)
438
+ y = torch.linspace(bbox_min[1], bbox_max[1], int(octree_resolution) + 1, dtype = torch.float32)
439
+ z = torch.linspace(bbox_min[2], bbox_max[2], int(octree_resolution) + 1, dtype = torch.float32)
440
+
441
+ [xs, ys, zs] = torch.meshgrid(x, y, z, indexing = "ij")
442
+ xyz = torch.stack((xs, ys, zs), axis=-1).to(latents.device, dtype = latents.dtype).contiguous().reshape(-1, 3)
443
+ grid_size = [int(octree_resolution) + 1, int(octree_resolution) + 1, int(octree_resolution) + 1]
444
+
445
+ batch_logits = []
446
+ for start in tqdm(range(0, xyz.shape[0], num_chunks), desc="Volume Decoding",
447
+ disable=not enable_pbar):
448
+
449
+ chunk_queries = xyz[start: start + num_chunks, :]
450
+ chunk_queries = chunk_queries.unsqueeze(0).repeat(latents.shape[0], 1, 1)
451
+ logits = geo_decoder(queries = chunk_queries, latents = latents)
452
+ batch_logits.append(logits)
453
+
454
+ grid_logits = torch.cat(batch_logits, dim = 1)
455
+ grid_logits = grid_logits.view((latents.shape[0], *grid_size)).float()
456
+
457
+ return grid_logits
458
+
459
+ class FourierEmbedder(nn.Module):
460
+ """The sin/cosine positional embedding. Given an input tensor `x` of shape [n_batch, ..., c_dim], it converts
461
+ each feature dimension of `x[..., i]` into:
462
+ [
463
+ sin(x[..., i]),
464
+ sin(f_1*x[..., i]),
465
+ sin(f_2*x[..., i]),
466
+ ...
467
+ sin(f_N * x[..., i]),
468
+ cos(x[..., i]),
469
+ cos(f_1*x[..., i]),
470
+ cos(f_2*x[..., i]),
471
+ ...
472
+ cos(f_N * x[..., i]),
473
+ x[..., i] # only present if include_input is True.
474
+ ], here f_i is the frequency.
475
+
476
+ Denote the space is [0 / num_freqs, 1 / num_freqs, 2 / num_freqs, 3 / num_freqs, ..., (num_freqs - 1) / num_freqs].
477
+ If logspace is True, then the frequency f_i is [2^(0 / num_freqs), ..., 2^(i / num_freqs), ...];
478
+ Otherwise, the frequencies are linearly spaced between [1.0, 2^(num_freqs - 1)].
479
+
480
+ Args:
481
+ num_freqs (int): the number of frequencies, default is 6;
482
+ logspace (bool): If logspace is True, then the frequency f_i is [..., 2^(i / num_freqs), ...],
483
+ otherwise, the frequencies are linearly spaced between [1.0, 2^(num_freqs - 1)];
484
+ input_dim (int): the input dimension, default is 3;
485
+ include_input (bool): include the input tensor or not, default is True.
486
+
487
+ Attributes:
488
+ frequencies (torch.Tensor): If logspace is True, then the frequency f_i is [..., 2^(i / num_freqs), ...],
489
+ otherwise, the frequencies are linearly spaced between [1.0, 2^(num_freqs - 1);
490
+
491
+ out_dim (int): the embedding size, if include_input is True, it is input_dim * (num_freqs * 2 + 1),
492
+ otherwise, it is input_dim * num_freqs * 2.
493
+
494
+ """
495
+
496
+ def __init__(self,
497
+ num_freqs: int = 6,
498
+ logspace: bool = True,
499
+ input_dim: int = 3,
500
+ include_input: bool = True,
501
+ include_pi: bool = True) -> None:
502
+
503
+ """The initialization"""
504
+
505
+ super().__init__()
506
+
507
+ if logspace:
508
+ frequencies = 2.0 ** torch.arange(
509
+ num_freqs,
510
+ dtype=torch.float32
511
+ )
512
+ else:
513
+ frequencies = torch.linspace(
514
+ 1.0,
515
+ 2.0 ** (num_freqs - 1),
516
+ num_freqs,
517
+ dtype=torch.float32
518
+ )
519
+
520
+ if include_pi:
521
+ frequencies *= torch.pi
522
+
523
+ self.register_buffer("frequencies", frequencies, persistent=False)
524
+ self.include_input = include_input
525
+ self.num_freqs = num_freqs
526
+
527
+ self.out_dim = self.get_dims(input_dim)
528
+
529
+ def get_dims(self, input_dim):
530
+ temp = 1 if self.include_input or self.num_freqs == 0 else 0
531
+ out_dim = input_dim * (self.num_freqs * 2 + temp)
532
+
533
+ return out_dim
534
+
535
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
536
+ """ Forward process.
537
+
538
+ Args:
539
+ x: tensor of shape [..., dim]
540
+
541
+ Returns:
542
+ embedding: an embedding of `x` of shape [..., dim * (num_freqs * 2 + temp)]
543
+ where temp is 1 if include_input is True and 0 otherwise.
544
+ """
545
+
546
+ if self.num_freqs > 0:
547
+ embed = (x[..., None].contiguous() * self.frequencies.to(device=x.device, dtype=x.dtype)).view(*x.shape[:-1], -1)
548
+ if self.include_input:
549
+ return torch.cat((x, embed.sin(), embed.cos()), dim=-1)
550
+ else:
551
+ return torch.cat((embed.sin(), embed.cos()), dim=-1)
552
+ else:
553
+ return x
554
+
555
+ class CrossAttentionProcessor:
556
+ def __call__(self, attn, q, k, v):
557
+ out = comfy.ops.scaled_dot_product_attention(q, k, v)
558
+ return out
559
+
560
+ class DropPath(nn.Module):
561
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
562
+ """
563
+
564
+ def __init__(self, drop_prob: float = 0., scale_by_keep: bool = True):
565
+ super(DropPath, self).__init__()
566
+ self.drop_prob = drop_prob
567
+ self.scale_by_keep = scale_by_keep
568
+
569
+ def forward(self, x):
570
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
571
+
572
+ This is the same as the DropConnect impl I created for EfficientNet, etc networks, however,
573
+ the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...
574
+ See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for
575
+ changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use
576
+ 'survival rate' as the argument.
577
+
578
+ """
579
+ if self.drop_prob == 0. or not self.training:
580
+ return x
581
+ keep_prob = 1 - self.drop_prob
582
+ shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
583
+ random_tensor = x.new_empty(shape).bernoulli_(keep_prob)
584
+ if keep_prob > 0.0 and self.scale_by_keep:
585
+ random_tensor.div_(keep_prob)
586
+ return x * random_tensor
587
+
588
+ def extra_repr(self):
589
+ return f'drop_prob={round(self.drop_prob, 3):0.3f}'
590
+
591
+
592
+ class MLP(nn.Module):
593
+ def __init__(
594
+ self, *,
595
+ width: int,
596
+ expand_ratio: int = 4,
597
+ output_width: int = None,
598
+ drop_path_rate: float = 0.0
599
+ ):
600
+ super().__init__()
601
+ self.width = width
602
+ self.c_fc = ops.Linear(width, width * expand_ratio)
603
+ self.c_proj = ops.Linear(width * expand_ratio, output_width if output_width is not None else width)
604
+ self.gelu = nn.GELU()
605
+ self.drop_path = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
606
+
607
+ def forward(self, x):
608
+ return self.drop_path(self.c_proj(self.gelu(self.c_fc(x))))
609
+
610
+ class QKVMultiheadCrossAttention(nn.Module):
611
+ def __init__(
612
+ self,
613
+ heads: int,
614
+ n_data = None,
615
+ width=None,
616
+ qk_norm=False,
617
+ norm_layer=ops.LayerNorm
618
+ ):
619
+ super().__init__()
620
+ self.heads = heads
621
+ self.n_data = n_data
622
+ self.q_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
623
+ self.k_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
624
+
625
+ def forward(self, q, kv):
626
+
627
+ _, n_ctx, _ = q.shape
628
+ bs, n_data, width = kv.shape
629
+
630
+ attn_ch = width // self.heads // 2
631
+ q = q.view(bs, n_ctx, self.heads, -1)
632
+
633
+ kv = kv.view(bs, n_data, self.heads, -1)
634
+ k, v = torch.split(kv, attn_ch, dim=-1)
635
+
636
+ q = self.q_norm(q)
637
+ k = self.k_norm(k)
638
+
639
+ q, k, v = [t.permute(0, 2, 1, 3) for t in (q, k, v)]
640
+ out = F.scaled_dot_product_attention(q, k, v)
641
+
642
+ out = out.transpose(1, 2).reshape(bs, n_ctx, -1)
643
+
644
+ return out
645
+
646
+ class MultiheadCrossAttention(nn.Module):
647
+ def __init__(
648
+ self,
649
+ *,
650
+ width: int,
651
+ heads: int,
652
+ qkv_bias: bool = True,
653
+ data_width: Optional[int] = None,
654
+ norm_layer=ops.LayerNorm,
655
+ qk_norm: bool = False,
656
+ kv_cache: bool = False,
657
+ ):
658
+ super().__init__()
659
+ self.width = width
660
+ self.heads = heads
661
+ self.data_width = width if data_width is None else data_width
662
+ self.c_q = ops.Linear(width, width, bias=qkv_bias)
663
+ self.c_kv = ops.Linear(self.data_width, width * 2, bias=qkv_bias)
664
+ self.c_proj = ops.Linear(width, width)
665
+ self.attention = QKVMultiheadCrossAttention(
666
+ heads=heads,
667
+ width=width,
668
+ norm_layer=norm_layer,
669
+ qk_norm=qk_norm
670
+ )
671
+ self.kv_cache = kv_cache
672
+ self.data = None
673
+
674
+ def forward(self, x, data):
675
+ x = self.c_q(x)
676
+ if self.kv_cache:
677
+ if self.data is None:
678
+ self.data = self.c_kv(data)
679
+ logging.info('Save kv cache,this should be called only once for one mesh')
680
+ data = self.data
681
+ else:
682
+ data = self.c_kv(data)
683
+ x = self.attention(x, data)
684
+ x = self.c_proj(x)
685
+ return x
686
+
687
+ class ResidualCrossAttentionBlock(nn.Module):
688
+ def __init__(
689
+ self,
690
+ *,
691
+ width: int,
692
+ heads: int,
693
+ mlp_expand_ratio: int = 4,
694
+ data_width: Optional[int] = None,
695
+ qkv_bias: bool = True,
696
+ norm_layer=ops.LayerNorm,
697
+ qk_norm: bool = False
698
+ ):
699
+ super().__init__()
700
+
701
+ if data_width is None:
702
+ data_width = width
703
+
704
+ self.attn = MultiheadCrossAttention(
705
+ width=width,
706
+ heads=heads,
707
+ data_width=data_width,
708
+ qkv_bias=qkv_bias,
709
+ norm_layer=norm_layer,
710
+ qk_norm=qk_norm
711
+ )
712
+ self.ln_1 = norm_layer(width, elementwise_affine=True, eps=1e-6)
713
+ self.ln_2 = norm_layer(data_width, elementwise_affine=True, eps=1e-6)
714
+ self.ln_3 = norm_layer(width, elementwise_affine=True, eps=1e-6)
715
+ self.mlp = MLP(width=width, expand_ratio=mlp_expand_ratio)
716
+
717
+ def forward(self, x: torch.Tensor, data: torch.Tensor):
718
+ x = x + self.attn(self.ln_1(x), self.ln_2(data))
719
+ x = x + self.mlp(self.ln_3(x))
720
+ return x
721
+
722
+
723
+ class QKVMultiheadAttention(nn.Module):
724
+ def __init__(
725
+ self,
726
+ *,
727
+ heads: int,
728
+ width=None,
729
+ qk_norm=False,
730
+ norm_layer=ops.LayerNorm
731
+ ):
732
+ super().__init__()
733
+ self.heads = heads
734
+ self.q_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
735
+ self.k_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
736
+
737
+ def forward(self, qkv):
738
+ bs, n_ctx, width = qkv.shape
739
+ attn_ch = width // self.heads // 3
740
+ qkv = qkv.view(bs, n_ctx, self.heads, -1)
741
+ q, k, v = torch.split(qkv, attn_ch, dim=-1)
742
+
743
+ q = self.q_norm(q)
744
+ k = self.k_norm(k)
745
+
746
+ q, k, v = [t.permute(0, 2, 1, 3) for t in (q, k, v)]
747
+ out = F.scaled_dot_product_attention(q, k, v).transpose(1, 2).reshape(bs, n_ctx, -1)
748
+ return out
749
+
750
+
751
+ class MultiheadAttention(nn.Module):
752
+ def __init__(
753
+ self,
754
+ *,
755
+ width: int,
756
+ heads: int,
757
+ qkv_bias: bool,
758
+ norm_layer=ops.LayerNorm,
759
+ qk_norm: bool = False,
760
+ drop_path_rate: float = 0.0
761
+ ):
762
+ super().__init__()
763
+
764
+ self.c_qkv = ops.Linear(width, width * 3, bias=qkv_bias)
765
+ self.c_proj = ops.Linear(width, width)
766
+ self.attention = QKVMultiheadAttention(
767
+ heads=heads,
768
+ width=width,
769
+ norm_layer=norm_layer,
770
+ qk_norm=qk_norm
771
+ )
772
+ self.drop_path = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
773
+
774
+ def forward(self, x):
775
+ x = self.c_qkv(x)
776
+ x = self.attention(x)
777
+ x = self.drop_path(self.c_proj(x))
778
+ return x
779
+
780
+
781
+ class ResidualAttentionBlock(nn.Module):
782
+ def __init__(
783
+ self,
784
+ *,
785
+ width: int,
786
+ heads: int,
787
+ qkv_bias: bool = True,
788
+ norm_layer=ops.LayerNorm,
789
+ qk_norm: bool = False,
790
+ drop_path_rate: float = 0.0,
791
+ ):
792
+ super().__init__()
793
+ self.attn = MultiheadAttention(
794
+ width=width,
795
+ heads=heads,
796
+ qkv_bias=qkv_bias,
797
+ norm_layer=norm_layer,
798
+ qk_norm=qk_norm,
799
+ drop_path_rate=drop_path_rate
800
+ )
801
+ self.ln_1 = norm_layer(width, elementwise_affine=True, eps=1e-6)
802
+ self.mlp = MLP(width=width, drop_path_rate=drop_path_rate)
803
+ self.ln_2 = norm_layer(width, elementwise_affine=True, eps=1e-6)
804
+
805
+ def forward(self, x: torch.Tensor):
806
+ x = x + self.attn(self.ln_1(x))
807
+ x = x + self.mlp(self.ln_2(x))
808
+ return x
809
+
810
+
811
+ class Transformer(nn.Module):
812
+ def __init__(
813
+ self,
814
+ *,
815
+ width: int,
816
+ layers: int,
817
+ heads: int,
818
+ qkv_bias: bool = True,
819
+ norm_layer=ops.LayerNorm,
820
+ qk_norm: bool = False,
821
+ drop_path_rate: float = 0.0
822
+ ):
823
+ super().__init__()
824
+ self.width = width
825
+ self.layers = layers
826
+ self.resblocks = nn.ModuleList(
827
+ [
828
+ ResidualAttentionBlock(
829
+ width=width,
830
+ heads=heads,
831
+ qkv_bias=qkv_bias,
832
+ norm_layer=norm_layer,
833
+ qk_norm=qk_norm,
834
+ drop_path_rate=drop_path_rate
835
+ )
836
+ for _ in range(layers)
837
+ ]
838
+ )
839
+
840
+ def forward(self, x: torch.Tensor):
841
+ for block in self.resblocks:
842
+ x = block(x)
843
+ return x
844
+
845
+
846
+ class CrossAttentionDecoder(nn.Module):
847
+
848
+ def __init__(
849
+ self,
850
+ *,
851
+ out_channels: int,
852
+ fourier_embedder: FourierEmbedder,
853
+ width: int,
854
+ heads: int,
855
+ mlp_expand_ratio: int = 4,
856
+ downsample_ratio: int = 1,
857
+ enable_ln_post: bool = True,
858
+ qkv_bias: bool = True,
859
+ qk_norm: bool = False,
860
+ label_type: str = "binary"
861
+ ):
862
+ super().__init__()
863
+
864
+ self.enable_ln_post = enable_ln_post
865
+ self.fourier_embedder = fourier_embedder
866
+ self.downsample_ratio = downsample_ratio
867
+ self.query_proj = ops.Linear(self.fourier_embedder.out_dim, width)
868
+ if self.downsample_ratio != 1:
869
+ self.latents_proj = ops.Linear(width * downsample_ratio, width)
870
+ if not self.enable_ln_post:
871
+ qk_norm = False
872
+ self.cross_attn_decoder = ResidualCrossAttentionBlock(
873
+ width=width,
874
+ mlp_expand_ratio=mlp_expand_ratio,
875
+ heads=heads,
876
+ qkv_bias=qkv_bias,
877
+ qk_norm=qk_norm
878
+ )
879
+
880
+ if self.enable_ln_post:
881
+ self.ln_post = ops.LayerNorm(width)
882
+ self.output_proj = ops.Linear(width, out_channels)
883
+ self.label_type = label_type
884
+ self.count = 0
885
+
886
+ def forward(self, queries=None, query_embeddings=None, latents=None):
887
+ if query_embeddings is None:
888
+ query_embeddings = self.query_proj(self.fourier_embedder(queries).to(latents.dtype))
889
+ self.count += query_embeddings.shape[1]
890
+ if self.downsample_ratio != 1:
891
+ latents = self.latents_proj(latents)
892
+ x = self.cross_attn_decoder(query_embeddings, latents)
893
+ if self.enable_ln_post:
894
+ x = self.ln_post(x)
895
+ occ = self.output_proj(x)
896
+ return occ
897
+
898
+
899
+ class ShapeVAE(nn.Module):
900
+ def __init__(
901
+ self,
902
+ *,
903
+ num_latents: int = 4096,
904
+ embed_dim: int = 64,
905
+ width: int = 1024,
906
+ heads: int = 16,
907
+ num_decoder_layers: int = 16,
908
+ num_encoder_layers: int = 8,
909
+ pc_size: int = 81920,
910
+ pc_sharpedge_size: int = 0,
911
+ point_feats: int = 4,
912
+ downsample_ratio: int = 20,
913
+ geo_decoder_downsample_ratio: int = 1,
914
+ geo_decoder_mlp_expand_ratio: int = 4,
915
+ geo_decoder_ln_post: bool = True,
916
+ num_freqs: int = 8,
917
+ qkv_bias: bool = False,
918
+ qk_norm: bool = True,
919
+ drop_path_rate: float = 0.0,
920
+ include_pi: bool = False,
921
+ scale_factor: float = 1.0039506158752403,
922
+ label_type: str = "binary",
923
+ ):
924
+ super().__init__()
925
+ self.geo_decoder_ln_post = geo_decoder_ln_post
926
+
927
+ self.fourier_embedder = FourierEmbedder(num_freqs=num_freqs, include_pi=include_pi)
928
+
929
+ self.encoder = PointCrossAttention(layers = num_encoder_layers,
930
+ num_latents = num_latents,
931
+ downsample_ratio = downsample_ratio,
932
+ heads = heads,
933
+ pc_size = pc_size,
934
+ width = width,
935
+ point_feats = point_feats,
936
+ fourier_embedder = self.fourier_embedder,
937
+ pc_sharpedge_size = pc_sharpedge_size)
938
+
939
+ self.post_kl = ops.Linear(embed_dim, width)
940
+
941
+ self.transformer = Transformer(
942
+ width=width,
943
+ layers=num_decoder_layers,
944
+ heads=heads,
945
+ qkv_bias=qkv_bias,
946
+ qk_norm=qk_norm,
947
+ drop_path_rate=drop_path_rate
948
+ )
949
+
950
+ self.geo_decoder = CrossAttentionDecoder(
951
+ fourier_embedder=self.fourier_embedder,
952
+ out_channels=1,
953
+ mlp_expand_ratio=geo_decoder_mlp_expand_ratio,
954
+ downsample_ratio=geo_decoder_downsample_ratio,
955
+ enable_ln_post=self.geo_decoder_ln_post,
956
+ width=width // geo_decoder_downsample_ratio,
957
+ heads=heads // geo_decoder_downsample_ratio,
958
+ qkv_bias=qkv_bias,
959
+ qk_norm=qk_norm,
960
+ label_type=label_type,
961
+ )
962
+
963
+ self.volume_decoder = VanillaVolumeDecoder()
964
+ self.scale_factor = scale_factor
965
+
966
+ def decode(self, latents, **kwargs):
967
+ latents = self.post_kl(latents.movedim(-2, -1))
968
+ latents = self.transformer(latents)
969
+
970
+ bounds = kwargs.get("bounds", 1.01)
971
+ num_chunks = kwargs.get("num_chunks", 8000)
972
+ octree_resolution = kwargs.get("octree_resolution", 256)
973
+ enable_pbar = kwargs.get("enable_pbar", True)
974
+
975
+ grid_logits = self.volume_decoder(latents, self.geo_decoder, bounds=bounds, num_chunks=num_chunks, octree_resolution=octree_resolution, enable_pbar=enable_pbar)
976
+ return grid_logits.movedim(-2, -1)
977
+
978
+ def encode(self, surface):
979
+
980
+ pc, feats = surface[:, :, :3], surface[:, :, 3:]
981
+ latents = self.encoder(pc, feats)
982
+
983
+ moments = self.pre_kl(latents)
984
+ posterior = DiagonalGaussianDistribution(moments, feature_dim = -1)
985
+
986
+ latents = posterior.sample()
987
+
988
+ return latents
ComfyUI/comfy/ldm/hunyuan3dv2_1/__pycache__/hunyuandit.cpython-312.pyc ADDED
Binary file (30.5 kB). View file
 
ComfyUI/comfy/ldm/hunyuan3dv2_1/hunyuandit.py ADDED
@@ -0,0 +1,668 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ from comfy.ldm.modules.attention import optimized_attention
6
+ import comfy.model_management
7
+
8
+ class GELU(nn.Module):
9
+
10
+ def __init__(self, dim_in: int, dim_out: int, operations, device, dtype):
11
+ super().__init__()
12
+ self.proj = operations.Linear(dim_in, dim_out, device = device, dtype = dtype)
13
+
14
+ def gelu(self, gate: torch.Tensor) -> torch.Tensor:
15
+
16
+ if gate.device.type == "mps":
17
+ return F.gelu(gate.to(dtype = torch.float32)).to(dtype = gate.dtype)
18
+
19
+ return F.gelu(gate)
20
+
21
+ def forward(self, hidden_states):
22
+
23
+ hidden_states = self.proj(hidden_states)
24
+ hidden_states = self.gelu(hidden_states)
25
+
26
+ return hidden_states
27
+
28
+ class FeedForward(nn.Module):
29
+
30
+ def __init__(self, dim: int, dim_out = None, mult: int = 4,
31
+ dropout: float = 0.0, inner_dim = None, operations = None, device = None, dtype = None):
32
+
33
+ super().__init__()
34
+ if inner_dim is None:
35
+ inner_dim = int(dim * mult)
36
+
37
+ dim_out = dim_out if dim_out is not None else dim
38
+
39
+ act_fn = GELU(dim, inner_dim, operations = operations, device = device, dtype = dtype)
40
+
41
+ self.net = nn.ModuleList([])
42
+ self.net.append(act_fn)
43
+
44
+ self.net.append(nn.Dropout(dropout))
45
+ self.net.append(operations.Linear(inner_dim, dim_out, device = device, dtype = dtype))
46
+
47
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
48
+ for module in self.net:
49
+ hidden_states = module(hidden_states)
50
+ return hidden_states
51
+
52
+ class AddAuxLoss(torch.autograd.Function):
53
+
54
+ @staticmethod
55
+ def forward(ctx, x, loss):
56
+ # do nothing in forward (no computation)
57
+ ctx.requires_aux_loss = loss.requires_grad
58
+ ctx.dtype = loss.dtype
59
+
60
+ return x
61
+
62
+ @staticmethod
63
+ def backward(ctx, grad_output):
64
+ # add the aux loss gradients
65
+ grad_loss = None
66
+ # put the aux grad the same as the main grad loss
67
+ # aux grad contributes equally
68
+ if ctx.requires_aux_loss:
69
+ grad_loss = torch.ones(1, dtype = ctx.dtype, device = grad_output.device)
70
+
71
+ return grad_output, grad_loss
72
+
73
+ class MoEGate(nn.Module):
74
+
75
+ def __init__(self, embed_dim, num_experts=16, num_experts_per_tok=2, aux_loss_alpha=0.01, device = None, dtype = None):
76
+
77
+ super().__init__()
78
+ self.top_k = num_experts_per_tok
79
+ self.n_routed_experts = num_experts
80
+
81
+ self.alpha = aux_loss_alpha
82
+
83
+ self.gating_dim = embed_dim
84
+ self.weight = nn.Parameter(torch.empty((self.n_routed_experts, self.gating_dim), device = device, dtype = dtype))
85
+
86
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
87
+
88
+ # flatten hidden states
89
+ hidden_states = hidden_states.view(-1, hidden_states.size(-1))
90
+
91
+ # get logits and pass it to softmax
92
+ logits = F.linear(hidden_states, comfy.model_management.cast_to(self.weight, dtype=hidden_states.dtype, device=hidden_states.device), bias = None)
93
+ scores = logits.softmax(dim = -1)
94
+
95
+ topk_weight, topk_idx = torch.topk(scores, k = self.top_k, dim = -1, sorted = False)
96
+
97
+ if self.training and self.alpha > 0.0:
98
+ scores_for_aux = scores
99
+
100
+ # used bincount instead of one hot encoding
101
+ counts = torch.bincount(topk_idx.view(-1), minlength = self.n_routed_experts).float()
102
+ ce = counts / topk_idx.numel() # normalized expert usage
103
+
104
+ # mean expert score
105
+ Pi = scores_for_aux.mean(0)
106
+
107
+ # expert balance loss
108
+ aux_loss = (Pi * ce * self.n_routed_experts).sum() * self.alpha
109
+ else:
110
+ aux_loss = None
111
+
112
+ return topk_idx, topk_weight, aux_loss
113
+
114
+ class MoEBlock(nn.Module):
115
+ def __init__(self, dim, num_experts: int = 6, moe_top_k: int = 2, dropout: float = 0.0,
116
+ ff_inner_dim: int = None, operations = None, device = None, dtype = None):
117
+ super().__init__()
118
+
119
+ self.moe_top_k = moe_top_k
120
+ self.num_experts = num_experts
121
+
122
+ self.experts = nn.ModuleList([
123
+ FeedForward(dim, dropout = dropout, inner_dim = ff_inner_dim, operations = operations, device = device, dtype = dtype)
124
+ for _ in range(num_experts)
125
+ ])
126
+
127
+ self.gate = MoEGate(dim, num_experts = num_experts, num_experts_per_tok = moe_top_k, device = device, dtype = dtype)
128
+ self.shared_experts = FeedForward(dim, dropout = dropout, inner_dim = ff_inner_dim, operations = operations, device = device, dtype = dtype)
129
+
130
+ def forward(self, hidden_states) -> torch.Tensor:
131
+
132
+ identity = hidden_states
133
+ orig_shape = hidden_states.shape
134
+ topk_idx, topk_weight, aux_loss = self.gate(hidden_states)
135
+
136
+ hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
137
+ flat_topk_idx = topk_idx.view(-1)
138
+
139
+ if self.training:
140
+
141
+ hidden_states = hidden_states.repeat_interleave(self.moe_top_k, dim = 0)
142
+ y = torch.empty_like(hidden_states, dtype = hidden_states.dtype)
143
+
144
+ for i, expert in enumerate(self.experts):
145
+ tmp = expert(hidden_states[flat_topk_idx == i])
146
+ y[flat_topk_idx == i] = tmp.to(hidden_states.dtype)
147
+
148
+ y = (y.view(*topk_weight.shape, -1) * topk_weight.unsqueeze(-1)).sum(dim = 1)
149
+ y = y.view(*orig_shape)
150
+
151
+ y = AddAuxLoss.apply(y, aux_loss)
152
+ else:
153
+ y = self.moe_infer(hidden_states, flat_expert_indices = flat_topk_idx,flat_expert_weights = topk_weight.view(-1, 1)).view(*orig_shape)
154
+
155
+ y = y + self.shared_experts(identity)
156
+
157
+ return y
158
+
159
+ @torch.no_grad()
160
+ def moe_infer(self, x, flat_expert_indices, flat_expert_weights):
161
+
162
+ expert_cache = torch.zeros_like(x)
163
+ idxs = flat_expert_indices.argsort()
164
+
165
+ # no need for .numpy().cpu() here
166
+ tokens_per_expert = flat_expert_indices.bincount().cumsum(0)
167
+ token_idxs = idxs // self.moe_top_k
168
+
169
+ for i, end_idx in enumerate(tokens_per_expert):
170
+
171
+ start_idx = 0 if i == 0 else tokens_per_expert[i-1]
172
+
173
+ if start_idx == end_idx:
174
+ continue
175
+
176
+ expert = self.experts[i]
177
+ exp_token_idx = token_idxs[start_idx:end_idx]
178
+
179
+ expert_tokens = x[exp_token_idx]
180
+ expert_out = expert(expert_tokens)
181
+
182
+ expert_out.mul_(flat_expert_weights[idxs[start_idx:end_idx]])
183
+
184
+ # use index_add_ with a 1-D index tensor directly avoids building a large [N, D] index map and extra memcopy required by scatter_reduce_
185
+ # + avoid dtype conversion
186
+ expert_cache.index_add_(0, exp_token_idx, expert_out)
187
+
188
+ return expert_cache
189
+
190
+ class Timesteps(nn.Module):
191
+ def __init__(self, num_channels: int, downscale_freq_shift: float = 0.0,
192
+ scale: float = 1.0, max_period: int = 10000):
193
+ super().__init__()
194
+
195
+ self.num_channels = num_channels
196
+ half_dim = num_channels // 2
197
+
198
+ # precompute the “inv_freq” vector once
199
+ exponent = -math.log(max_period) * torch.arange(
200
+ half_dim, dtype=torch.float32
201
+ ) / (half_dim - downscale_freq_shift)
202
+
203
+ inv_freq = torch.exp(exponent)
204
+
205
+ # pad
206
+ if num_channels % 2 == 1:
207
+ # we’ll pad a zero at the end of the cos-half
208
+ inv_freq = torch.cat([inv_freq, inv_freq.new_zeros(1)])
209
+
210
+ # register to buffer so it moves with the device
211
+ self.register_buffer("inv_freq", inv_freq, persistent = False)
212
+ self.scale = scale
213
+
214
+ def forward(self, timesteps: torch.Tensor):
215
+
216
+ x = timesteps.float().unsqueeze(1) * self.inv_freq.to(timesteps.device).unsqueeze(0)
217
+
218
+
219
+ # fused CUDA kernels for sin and cos
220
+ sin_emb = x.sin()
221
+ cos_emb = x.cos()
222
+
223
+ emb = torch.cat([sin_emb, cos_emb], dim = 1)
224
+
225
+ # scale factor
226
+ if self.scale != 1.0:
227
+ emb = emb * self.scale
228
+
229
+ # If we padded inv_freq for odd, emb is already wide enough; otherwise:
230
+ if emb.shape[1] > self.num_channels:
231
+ emb = emb[:, :self.num_channels]
232
+
233
+ return emb
234
+
235
+ class TimestepEmbedder(nn.Module):
236
+ def __init__(self, hidden_size, frequency_embedding_size = 256, cond_proj_dim = None, operations = None, device = None, dtype = None):
237
+ super().__init__()
238
+
239
+ self.mlp = nn.Sequential(
240
+ operations.Linear(hidden_size, frequency_embedding_size, bias=True, device = device, dtype = dtype),
241
+ nn.GELU(),
242
+ operations.Linear(frequency_embedding_size, hidden_size, bias=True, device = device, dtype = dtype),
243
+ )
244
+ self.frequency_embedding_size = frequency_embedding_size
245
+
246
+ if cond_proj_dim is not None:
247
+ self.cond_proj = operations.Linear(cond_proj_dim, frequency_embedding_size, bias=False, device = device, dtype = dtype)
248
+
249
+ self.time_embed = Timesteps(hidden_size)
250
+
251
+ def forward(self, timesteps, condition):
252
+
253
+ timestep_embed = self.time_embed(timesteps).type(self.mlp[0].weight.dtype)
254
+
255
+ if condition is not None:
256
+ cond_embed = self.cond_proj(condition)
257
+ timestep_embed = timestep_embed + cond_embed
258
+
259
+ time_conditioned = self.mlp(timestep_embed)
260
+
261
+ # for broadcasting with image tokens
262
+ return time_conditioned.unsqueeze(1)
263
+
264
+ class MLP(nn.Module):
265
+ def __init__(self, *, width: int, operations = None, device = None, dtype = None):
266
+ super().__init__()
267
+ self.width = width
268
+ self.fc1 = operations.Linear(width, width * 4, device = device, dtype = dtype)
269
+ self.fc2 = operations.Linear(width * 4, width, device = device, dtype = dtype)
270
+ self.gelu = nn.GELU()
271
+
272
+ def forward(self, x):
273
+ return self.fc2(self.gelu(self.fc1(x)))
274
+
275
+ class CrossAttention(nn.Module):
276
+ def __init__(
277
+ self,
278
+ qdim,
279
+ kdim,
280
+ num_heads,
281
+ qkv_bias=True,
282
+ qk_norm=False,
283
+ norm_layer=nn.LayerNorm,
284
+ use_fp16: bool = False,
285
+ operations = None,
286
+ dtype = None,
287
+ device = None,
288
+ **kwargs,
289
+ ):
290
+ super().__init__()
291
+ self.qdim = qdim
292
+ self.kdim = kdim
293
+
294
+ self.num_heads = num_heads
295
+ self.head_dim = self.qdim // num_heads
296
+
297
+ self.scale = self.head_dim ** -0.5
298
+
299
+ self.to_q = operations.Linear(qdim, qdim, bias=qkv_bias, device = device, dtype = dtype)
300
+ self.to_k = operations.Linear(kdim, qdim, bias=qkv_bias, device = device, dtype = dtype)
301
+ self.to_v = operations.Linear(kdim, qdim, bias=qkv_bias, device = device, dtype = dtype)
302
+
303
+ if use_fp16:
304
+ eps = 1.0 / 65504
305
+ else:
306
+ eps = 1e-6
307
+
308
+ if norm_layer == nn.LayerNorm:
309
+ norm_layer = operations.LayerNorm
310
+ else:
311
+ norm_layer = operations.RMSNorm
312
+
313
+ self.q_norm = norm_layer(self.head_dim, elementwise_affine=True, eps = eps, device = device, dtype = dtype) if qk_norm else nn.Identity()
314
+ self.k_norm = norm_layer(self.head_dim, elementwise_affine=True, eps = eps, device = device, dtype = dtype) if qk_norm else nn.Identity()
315
+ self.out_proj = operations.Linear(qdim, qdim, bias=True, device = device, dtype = dtype)
316
+
317
+ def forward(self, x, y):
318
+
319
+ b, s1, _ = x.shape
320
+ _, s2, _ = y.shape
321
+
322
+ y = y.to(next(self.to_k.parameters()).dtype)
323
+
324
+ q = self.to_q(x)
325
+ k = self.to_k(y)
326
+ v = self.to_v(y)
327
+
328
+ kv = torch.cat((k, v), dim=-1)
329
+ split_size = kv.shape[-1] // self.num_heads // 2
330
+
331
+ kv = kv.view(b, -1, self.num_heads, split_size * 2)
332
+ k, v = torch.split(kv, split_size, dim=-1)
333
+
334
+ q = q.view(b, s1, self.num_heads, self.head_dim)
335
+ k = k.view(b, s2, self.num_heads, self.head_dim)
336
+ v = v.reshape(b, s2, self.num_heads * self.head_dim)
337
+
338
+ q = self.q_norm(q)
339
+ k = self.k_norm(k)
340
+
341
+ x = optimized_attention(
342
+ q.reshape(b, s1, self.num_heads * self.head_dim),
343
+ k.reshape(b, s2, self.num_heads * self.head_dim),
344
+ v,
345
+ heads=self.num_heads,
346
+ low_precision_attention=False,
347
+ )
348
+
349
+ out = self.out_proj(x)
350
+
351
+ return out
352
+
353
+ class Attention(nn.Module):
354
+
355
+ def __init__(
356
+ self,
357
+ dim,
358
+ num_heads,
359
+ qkv_bias = True,
360
+ qk_norm = False,
361
+ norm_layer = nn.LayerNorm,
362
+ use_fp16: bool = False,
363
+ operations = None,
364
+ device = None,
365
+ dtype = None
366
+ ):
367
+ super().__init__()
368
+ self.dim = dim
369
+ self.num_heads = num_heads
370
+ self.head_dim = self.dim // num_heads
371
+ self.scale = self.head_dim ** -0.5
372
+
373
+ self.to_q = operations.Linear(dim, dim, bias = qkv_bias, device = device, dtype = dtype)
374
+ self.to_k = operations.Linear(dim, dim, bias = qkv_bias, device = device, dtype = dtype)
375
+ self.to_v = operations.Linear(dim, dim, bias = qkv_bias, device = device, dtype = dtype)
376
+
377
+ if use_fp16:
378
+ eps = 1.0 / 65504
379
+ else:
380
+ eps = 1e-6
381
+
382
+ if norm_layer == nn.LayerNorm:
383
+ norm_layer = operations.LayerNorm
384
+ else:
385
+ norm_layer = operations.RMSNorm
386
+
387
+ self.q_norm = norm_layer(self.head_dim, elementwise_affine=True, eps = eps, device = device, dtype = dtype) if qk_norm else nn.Identity()
388
+ self.k_norm = norm_layer(self.head_dim, elementwise_affine=True, eps = eps, device = device, dtype = dtype) if qk_norm else nn.Identity()
389
+ self.out_proj = operations.Linear(dim, dim, device = device, dtype = dtype)
390
+
391
+ def forward(self, x):
392
+ B, N, _ = x.shape
393
+
394
+ query = self.to_q(x)
395
+ key = self.to_k(x)
396
+ value = self.to_v(x)
397
+
398
+ qkv_combined = torch.cat((query, key, value), dim=-1)
399
+ split_size = qkv_combined.shape[-1] // self.num_heads // 3
400
+
401
+ qkv = qkv_combined.view(B, -1, self.num_heads, split_size * 3)
402
+ query, key, value = torch.split(qkv, split_size, dim=-1)
403
+
404
+ query = query.reshape(B, N, self.num_heads, self.head_dim)
405
+ key = key.reshape(B, N, self.num_heads, self.head_dim)
406
+ value = value.reshape(B, N, self.num_heads * self.head_dim)
407
+
408
+ query = self.q_norm(query)
409
+ key = self.k_norm(key)
410
+
411
+ x = optimized_attention(
412
+ query.reshape(B, N, self.num_heads * self.head_dim),
413
+ key.reshape(B, N, self.num_heads * self.head_dim),
414
+ value,
415
+ heads=self.num_heads,
416
+ low_precision_attention=False,
417
+ )
418
+
419
+ x = self.out_proj(x)
420
+ return x
421
+
422
+ class HunYuanDiTBlock(nn.Module):
423
+ def __init__(
424
+ self,
425
+ hidden_size,
426
+ c_emb_size,
427
+ num_heads,
428
+ text_states_dim=1024,
429
+ qk_norm=False,
430
+ norm_layer=nn.LayerNorm,
431
+ qk_norm_layer=True,
432
+ qkv_bias=True,
433
+ skip_connection=True,
434
+ timested_modulate=False,
435
+ use_moe: bool = False,
436
+ num_experts: int = 8,
437
+ moe_top_k: int = 2,
438
+ use_fp16: bool = False,
439
+ operations = None,
440
+ device = None, dtype = None
441
+ ):
442
+ super().__init__()
443
+
444
+ # eps can't be 1e-6 in fp16 mode because of numerical stability issues
445
+ if use_fp16:
446
+ eps = 1.0 / 65504
447
+ else:
448
+ eps = 1e-6
449
+
450
+ self.norm1 = norm_layer(hidden_size, elementwise_affine = True, eps = eps, device = device, dtype = dtype)
451
+
452
+ self.attn1 = Attention(hidden_size, num_heads=num_heads, qkv_bias=qkv_bias, qk_norm=qk_norm,
453
+ norm_layer=qk_norm_layer, use_fp16 = use_fp16, device = device, dtype = dtype, operations = operations)
454
+
455
+ self.norm2 = norm_layer(hidden_size, elementwise_affine = True, eps = eps, device = device, dtype = dtype)
456
+
457
+ self.timested_modulate = timested_modulate
458
+ if self.timested_modulate:
459
+ self.default_modulation = nn.Sequential(
460
+ nn.SiLU(),
461
+ operations.Linear(c_emb_size, hidden_size, bias=True, device = device, dtype = dtype)
462
+ )
463
+
464
+ self.attn2 = CrossAttention(hidden_size, text_states_dim, num_heads=num_heads, qkv_bias=qkv_bias,
465
+ qk_norm=qk_norm, norm_layer=qk_norm_layer, use_fp16 = use_fp16,
466
+ device = device, dtype = dtype, operations = operations)
467
+
468
+ self.norm3 = norm_layer(hidden_size, elementwise_affine = True, eps = eps, device = device, dtype = dtype)
469
+
470
+ if skip_connection:
471
+ self.skip_norm = norm_layer(hidden_size, elementwise_affine = True, eps = eps, device = device, dtype = dtype)
472
+ self.skip_linear = operations.Linear(2 * hidden_size, hidden_size, device = device, dtype = dtype)
473
+ else:
474
+ self.skip_linear = None
475
+
476
+ self.use_moe = use_moe
477
+
478
+ if self.use_moe:
479
+ self.moe = MoEBlock(
480
+ hidden_size,
481
+ num_experts = num_experts,
482
+ moe_top_k = moe_top_k,
483
+ dropout = 0.0,
484
+ ff_inner_dim = int(hidden_size * 4.0),
485
+ device = device, dtype = dtype,
486
+ operations = operations
487
+ )
488
+ else:
489
+ self.mlp = MLP(width=hidden_size, operations=operations, device = device, dtype = dtype)
490
+
491
+ def forward(self, hidden_states, conditioning=None, text_states=None, skip_tensor=None):
492
+
493
+ if self.skip_linear is not None:
494
+ combined = torch.cat([skip_tensor, hidden_states], dim=-1)
495
+ hidden_states = self.skip_linear(combined)
496
+ hidden_states = self.skip_norm(hidden_states)
497
+
498
+ # self attention
499
+ if self.timested_modulate:
500
+ modulation_shift = self.default_modulation(conditioning).unsqueeze(dim=1)
501
+ hidden_states = hidden_states + modulation_shift
502
+
503
+ self_attn_out = self.attn1(self.norm1(hidden_states))
504
+ hidden_states = hidden_states + self_attn_out
505
+
506
+ # cross attention
507
+ hidden_states = hidden_states + self.attn2(self.norm2(hidden_states), text_states)
508
+
509
+ # MLP Layer
510
+ mlp_input = self.norm3(hidden_states)
511
+
512
+ if self.use_moe:
513
+ hidden_states = hidden_states + self.moe(mlp_input)
514
+ else:
515
+ hidden_states = hidden_states + self.mlp(mlp_input)
516
+
517
+ return hidden_states
518
+
519
+ class FinalLayer(nn.Module):
520
+
521
+ def __init__(self, final_hidden_size, out_channels, operations, use_fp16: bool = False, device = None, dtype = None):
522
+ super().__init__()
523
+
524
+ if use_fp16:
525
+ eps = 1.0 / 65504
526
+ else:
527
+ eps = 1e-6
528
+
529
+ self.norm_final = operations.LayerNorm(final_hidden_size, elementwise_affine = True, eps = eps, device = device, dtype = dtype)
530
+ self.linear = operations.Linear(final_hidden_size, out_channels, bias = True, device = device, dtype = dtype)
531
+
532
+ def forward(self, x):
533
+ x = self.norm_final(x)
534
+ x = x[:, 1:]
535
+ x = self.linear(x)
536
+ return x
537
+
538
+ class HunYuanDiTPlain(nn.Module):
539
+
540
+ # init with the defaults values from https://huggingface.co/tencent/Hunyuan3D-2.1/blob/main/hunyuan3d-dit-v2-1/config.yaml
541
+ def __init__(
542
+ self,
543
+ in_channels: int = 64,
544
+ hidden_size: int = 2048,
545
+ context_dim: int = 1024,
546
+ depth: int = 21,
547
+ num_heads: int = 16,
548
+ qk_norm: bool = True,
549
+ qkv_bias: bool = False,
550
+ num_moe_layers: int = 6,
551
+ guidance_cond_proj_dim = 2048,
552
+ norm_type = 'layer',
553
+ num_experts: int = 8,
554
+ moe_top_k: int = 2,
555
+ use_fp16: bool = False,
556
+ dtype = None,
557
+ device = None,
558
+ operations = None,
559
+ **kwargs
560
+ ):
561
+
562
+ self.dtype = dtype
563
+
564
+ super().__init__()
565
+
566
+ self.depth = depth
567
+
568
+ self.in_channels = in_channels
569
+ self.out_channels = in_channels
570
+
571
+ self.num_heads = num_heads
572
+ self.hidden_size = hidden_size
573
+
574
+ norm = operations.LayerNorm if norm_type == 'layer' else operations.RMSNorm
575
+ qk_norm = operations.RMSNorm
576
+
577
+ self.context_dim = context_dim
578
+ self.guidance_cond_proj_dim = guidance_cond_proj_dim
579
+
580
+ self.x_embedder = operations.Linear(in_channels, hidden_size, bias = True, device = device, dtype = dtype)
581
+ self.t_embedder = TimestepEmbedder(hidden_size, hidden_size * 4, cond_proj_dim = guidance_cond_proj_dim, device = device, dtype = dtype, operations = operations)
582
+
583
+
584
+ # HUnYuanDiT Blocks
585
+ self.blocks = nn.ModuleList([
586
+ HunYuanDiTBlock(hidden_size=hidden_size,
587
+ c_emb_size=hidden_size,
588
+ num_heads=num_heads,
589
+ text_states_dim=context_dim,
590
+ qk_norm=qk_norm,
591
+ norm_layer = norm,
592
+ qk_norm_layer = qk_norm,
593
+ skip_connection=layer > depth // 2,
594
+ qkv_bias=qkv_bias,
595
+ use_moe=True if depth - layer <= num_moe_layers else False,
596
+ num_experts=num_experts,
597
+ moe_top_k=moe_top_k,
598
+ use_fp16 = use_fp16,
599
+ device = device, dtype = dtype, operations = operations)
600
+ for layer in range(depth)
601
+ ])
602
+
603
+ self.depth = depth
604
+
605
+ self.final_layer = FinalLayer(hidden_size, self.out_channels, use_fp16 = use_fp16, operations = operations, device = device, dtype = dtype)
606
+
607
+ def forward(self, x, t, context, transformer_options = {}, **kwargs):
608
+
609
+ x = x.movedim(-1, -2)
610
+
611
+ swap_cfg_halves = context.shape[0] >= 2
612
+
613
+ if swap_cfg_halves:
614
+ first_half, second_half = context.chunk(2, dim = 0)
615
+ context = torch.cat([second_half, first_half], dim = 0)
616
+
617
+ main_condition = context
618
+
619
+ t = 1.0 - t
620
+
621
+ time_embedded = self.t_embedder(t, condition = kwargs.get('guidance_cond'))
622
+
623
+ x = x.to(dtype = next(self.x_embedder.parameters()).dtype)
624
+ x_embedded = self.x_embedder(x)
625
+
626
+ combined = torch.cat([time_embedded, x_embedded], dim=1)
627
+
628
+ def block_wrap(args):
629
+ return block(
630
+ args["x"],
631
+ args["t"],
632
+ args["cond"],
633
+ skip_tensor=args.get("skip"),)
634
+
635
+ skip_stack = []
636
+ patches_replace = transformer_options.get("patches_replace", {})
637
+ blocks_replace = patches_replace.get("dit", {})
638
+ for idx, block in enumerate(self.blocks):
639
+ if idx <= self.depth // 2:
640
+ skip_input = None
641
+ else:
642
+ skip_input = skip_stack.pop()
643
+
644
+ if ("block", idx) in blocks_replace:
645
+
646
+ combined = blocks_replace[("block", idx)](
647
+ {
648
+ "x": combined,
649
+ "t": time_embedded,
650
+ "cond": main_condition,
651
+ "skip": skip_input,
652
+ },
653
+ {"original_block": block_wrap},
654
+ )
655
+ else:
656
+ combined = block(combined, time_embedded, main_condition, skip_tensor=skip_input)
657
+
658
+ if idx < self.depth // 2:
659
+ skip_stack.append(combined)
660
+
661
+ output = self.final_layer(combined)
662
+ output = output.movedim(-2, -1) * (-1.0)
663
+
664
+ if swap_cfg_halves:
665
+ first_half, second_half = output.chunk(2, dim = 0)
666
+ output = torch.cat([second_half, first_half], dim = 0)
667
+
668
+ return output
ComfyUI/comfy/ldm/hunyuan_video/__pycache__/model.cpython-312.pyc ADDED
Binary file (29.5 kB). View file
 
ComfyUI/comfy/ldm/hunyuan_video/__pycache__/upsampler.cpython-312.pyc ADDED
Binary file (7.67 kB). View file
 
ComfyUI/comfy/ldm/hunyuan_video/__pycache__/vae.cpython-312.pyc ADDED
Binary file (9.91 kB). View file
 
ComfyUI/comfy/ldm/hunyuan_video/__pycache__/vae_refiner.cpython-312.pyc ADDED
Binary file (17.6 kB). View file
 
ComfyUI/comfy/ldm/hunyuan_video/model.py ADDED
@@ -0,0 +1,497 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #Based on Flux code because of weird hunyuan video code license.
2
+
3
+ import torch
4
+ import comfy.patcher_extension
5
+ import comfy.ldm.flux.layers
6
+ import comfy.ldm.modules.diffusionmodules.mmdit
7
+ from comfy.ldm.modules.attention import optimized_attention
8
+
9
+ from dataclasses import dataclass
10
+ from einops import repeat
11
+
12
+ from torch import Tensor, nn
13
+
14
+ from comfy.ldm.flux.layers import (
15
+ DoubleStreamBlock,
16
+ EmbedND,
17
+ LastLayer,
18
+ MLPEmbedder,
19
+ SingleStreamBlock,
20
+ timestep_embedding
21
+ )
22
+
23
+ import comfy.ldm.common_dit
24
+
25
+
26
+ @dataclass
27
+ class HunyuanVideoParams:
28
+ in_channels: int
29
+ out_channels: int
30
+ vec_in_dim: int
31
+ context_in_dim: int
32
+ hidden_size: int
33
+ mlp_ratio: float
34
+ num_heads: int
35
+ depth: int
36
+ depth_single_blocks: int
37
+ axes_dim: list
38
+ theta: int
39
+ patch_size: list
40
+ qkv_bias: bool
41
+ guidance_embed: bool
42
+ byt5: bool
43
+ meanflow: bool
44
+ use_cond_type_embedding: bool
45
+ vision_in_dim: int
46
+ meanflow_sum: bool
47
+
48
+
49
+ class SelfAttentionRef(nn.Module):
50
+ def __init__(self, dim: int, qkv_bias: bool = False, dtype=None, device=None, operations=None):
51
+ super().__init__()
52
+ self.qkv = operations.Linear(dim, dim * 3, bias=qkv_bias, dtype=dtype, device=device)
53
+ self.proj = operations.Linear(dim, dim, dtype=dtype, device=device)
54
+
55
+
56
+ class TokenRefinerBlock(nn.Module):
57
+ def __init__(
58
+ self,
59
+ hidden_size,
60
+ heads,
61
+ dtype=None,
62
+ device=None,
63
+ operations=None
64
+ ):
65
+ super().__init__()
66
+ self.heads = heads
67
+ mlp_hidden_dim = hidden_size * 4
68
+
69
+ self.adaLN_modulation = nn.Sequential(
70
+ nn.SiLU(),
71
+ operations.Linear(hidden_size, 2 * hidden_size, bias=True, dtype=dtype, device=device),
72
+ )
73
+
74
+ self.norm1 = operations.LayerNorm(hidden_size, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device)
75
+ self.self_attn = SelfAttentionRef(hidden_size, True, dtype=dtype, device=device, operations=operations)
76
+
77
+ self.norm2 = operations.LayerNorm(hidden_size, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device)
78
+
79
+ self.mlp = nn.Sequential(
80
+ operations.Linear(hidden_size, mlp_hidden_dim, bias=True, dtype=dtype, device=device),
81
+ nn.SiLU(),
82
+ operations.Linear(mlp_hidden_dim, hidden_size, bias=True, dtype=dtype, device=device),
83
+ )
84
+
85
+ def forward(self, x, c, mask, transformer_options={}):
86
+ mod1, mod2 = self.adaLN_modulation(c).chunk(2, dim=1)
87
+
88
+ norm_x = self.norm1(x)
89
+ qkv = self.self_attn.qkv(norm_x)
90
+ q, k, v = qkv.reshape(qkv.shape[0], qkv.shape[1], 3, self.heads, -1).permute(2, 0, 3, 1, 4)
91
+ attn = optimized_attention(q, k, v, self.heads, mask=mask, skip_reshape=True, transformer_options=transformer_options)
92
+
93
+ x = x + self.self_attn.proj(attn) * mod1.unsqueeze(1)
94
+ x = x + self.mlp(self.norm2(x)) * mod2.unsqueeze(1)
95
+ return x
96
+
97
+
98
+ class IndividualTokenRefiner(nn.Module):
99
+ def __init__(
100
+ self,
101
+ hidden_size,
102
+ heads,
103
+ num_blocks,
104
+ dtype=None,
105
+ device=None,
106
+ operations=None
107
+ ):
108
+ super().__init__()
109
+ self.blocks = nn.ModuleList(
110
+ [
111
+ TokenRefinerBlock(
112
+ hidden_size=hidden_size,
113
+ heads=heads,
114
+ dtype=dtype,
115
+ device=device,
116
+ operations=operations
117
+ )
118
+ for _ in range(num_blocks)
119
+ ]
120
+ )
121
+
122
+ def forward(self, x, c, mask, transformer_options={}):
123
+ m = None
124
+ if mask is not None:
125
+ m = mask.view(mask.shape[0], 1, 1, mask.shape[1]).repeat(1, 1, mask.shape[1], 1)
126
+ m = m + m.transpose(2, 3)
127
+
128
+ for block in self.blocks:
129
+ x = block(x, c, m, transformer_options=transformer_options)
130
+ return x
131
+
132
+
133
+
134
+ class TokenRefiner(nn.Module):
135
+ def __init__(
136
+ self,
137
+ text_dim,
138
+ hidden_size,
139
+ heads,
140
+ num_blocks,
141
+ dtype=None,
142
+ device=None,
143
+ operations=None
144
+ ):
145
+ super().__init__()
146
+
147
+ self.input_embedder = operations.Linear(text_dim, hidden_size, bias=True, dtype=dtype, device=device)
148
+ self.t_embedder = MLPEmbedder(256, hidden_size, dtype=dtype, device=device, operations=operations)
149
+ self.c_embedder = MLPEmbedder(text_dim, hidden_size, dtype=dtype, device=device, operations=operations)
150
+ self.individual_token_refiner = IndividualTokenRefiner(hidden_size, heads, num_blocks, dtype=dtype, device=device, operations=operations)
151
+
152
+ def forward(
153
+ self,
154
+ x,
155
+ timesteps,
156
+ mask,
157
+ transformer_options={},
158
+ ):
159
+ t = self.t_embedder(timestep_embedding(timesteps, 256, time_factor=1.0).to(x.dtype))
160
+ # m = mask.float().unsqueeze(-1)
161
+ # c = (x.float() * m).sum(dim=1) / m.sum(dim=1) #TODO: the following works when the x.shape is the same length as the tokens but might break otherwise
162
+ if x.dtype == torch.float16:
163
+ c = x.float().sum(dim=1) / x.shape[1]
164
+ else:
165
+ c = x.sum(dim=1) / x.shape[1]
166
+
167
+ c = t + self.c_embedder(c.to(x.dtype))
168
+ x = self.input_embedder(x)
169
+ x = self.individual_token_refiner(x, c, mask, transformer_options=transformer_options)
170
+ return x
171
+
172
+
173
+ class ByT5Mapper(nn.Module):
174
+ def __init__(self, in_dim, out_dim, hidden_dim, out_dim1, use_res=False, dtype=None, device=None, operations=None):
175
+ super().__init__()
176
+ self.layernorm = operations.LayerNorm(in_dim, dtype=dtype, device=device)
177
+ self.fc1 = operations.Linear(in_dim, hidden_dim, dtype=dtype, device=device)
178
+ self.fc2 = operations.Linear(hidden_dim, out_dim, dtype=dtype, device=device)
179
+ self.fc3 = operations.Linear(out_dim, out_dim1, dtype=dtype, device=device)
180
+ self.use_res = use_res
181
+ self.act_fn = nn.GELU()
182
+
183
+ def forward(self, x):
184
+ if self.use_res:
185
+ res = x
186
+ x = self.layernorm(x)
187
+ x = self.fc1(x)
188
+ x = self.act_fn(x)
189
+ x = self.fc2(x)
190
+ x2 = self.act_fn(x)
191
+ x2 = self.fc3(x2)
192
+ if self.use_res:
193
+ x2 = x2 + res
194
+ return x2
195
+
196
+ class HunyuanVideo(nn.Module):
197
+ """
198
+ Transformer model for flow matching on sequences.
199
+ """
200
+
201
+ def __init__(self, image_model=None, final_layer=True, dtype=None, device=None, operations=None, **kwargs):
202
+ super().__init__()
203
+ self.dtype = dtype
204
+ operation_settings = {"operations": operations, "device": device, "dtype": dtype}
205
+
206
+ params = HunyuanVideoParams(**kwargs)
207
+ self.params = params
208
+ self.patch_size = params.patch_size
209
+ self.in_channels = params.in_channels
210
+ self.out_channels = params.out_channels
211
+ self.use_cond_type_embedding = params.use_cond_type_embedding
212
+ self.vision_in_dim = params.vision_in_dim
213
+ if params.hidden_size % params.num_heads != 0:
214
+ raise ValueError(
215
+ f"Hidden size {params.hidden_size} must be divisible by num_heads {params.num_heads}"
216
+ )
217
+ pe_dim = params.hidden_size // params.num_heads
218
+ if sum(params.axes_dim) != pe_dim:
219
+ raise ValueError(f"Got {params.axes_dim} but expected positional dim {pe_dim}")
220
+ self.hidden_size = params.hidden_size
221
+ self.num_heads = params.num_heads
222
+ self.pe_embedder = EmbedND(dim=pe_dim, theta=params.theta, axes_dim=params.axes_dim)
223
+
224
+ self.img_in = comfy.ldm.modules.diffusionmodules.mmdit.PatchEmbed(None, self.patch_size, self.in_channels, self.hidden_size, conv3d=len(self.patch_size) == 3, dtype=dtype, device=device, operations=operations)
225
+ self.time_in = MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size, dtype=dtype, device=device, operations=operations)
226
+ if params.vec_in_dim is not None:
227
+ self.vector_in = MLPEmbedder(params.vec_in_dim, self.hidden_size, dtype=dtype, device=device, operations=operations)
228
+ else:
229
+ self.vector_in = None
230
+
231
+ self.guidance_in = (
232
+ MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size, dtype=dtype, device=device, operations=operations) if params.guidance_embed else nn.Identity()
233
+ )
234
+
235
+ self.txt_in = TokenRefiner(params.context_in_dim, self.hidden_size, self.num_heads, 2, dtype=dtype, device=device, operations=operations)
236
+
237
+ self.double_blocks = nn.ModuleList(
238
+ [
239
+ DoubleStreamBlock(
240
+ self.hidden_size,
241
+ self.num_heads,
242
+ mlp_ratio=params.mlp_ratio,
243
+ qkv_bias=params.qkv_bias,
244
+ dtype=dtype, device=device, operations=operations
245
+ )
246
+ for _ in range(params.depth)
247
+ ]
248
+ )
249
+
250
+ self.single_blocks = nn.ModuleList(
251
+ [
252
+ SingleStreamBlock(self.hidden_size, self.num_heads, mlp_ratio=params.mlp_ratio, dtype=dtype, device=device, operations=operations)
253
+ for _ in range(params.depth_single_blocks)
254
+ ]
255
+ )
256
+
257
+ if params.byt5:
258
+ self.byt5_in = ByT5Mapper(
259
+ in_dim=1472,
260
+ out_dim=2048,
261
+ hidden_dim=2048,
262
+ out_dim1=self.hidden_size,
263
+ use_res=False,
264
+ dtype=dtype, device=device, operations=operations
265
+ )
266
+ else:
267
+ self.byt5_in = None
268
+
269
+ if params.meanflow:
270
+ self.time_r_in = MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size, dtype=dtype, device=device, operations=operations)
271
+ else:
272
+ self.time_r_in = None
273
+
274
+ if final_layer:
275
+ self.final_layer = LastLayer(self.hidden_size, self.patch_size[-1], self.out_channels, dtype=dtype, device=device, operations=operations)
276
+
277
+ # HunyuanVideo 1.5 specific modules
278
+ if self.vision_in_dim is not None:
279
+ from comfy.ldm.wan.model import MLPProj
280
+ self.vision_in = MLPProj(in_dim=self.vision_in_dim, out_dim=self.hidden_size, operation_settings=operation_settings)
281
+ else:
282
+ self.vision_in = None
283
+ if self.use_cond_type_embedding:
284
+ # 0: text_encoder feature 1: byt5 feature 2: vision_encoder feature
285
+ self.cond_type_embedding = nn.Embedding(3, self.hidden_size)
286
+ else:
287
+ self.cond_type_embedding = None
288
+
289
+ def forward_orig(
290
+ self,
291
+ img: Tensor,
292
+ img_ids: Tensor,
293
+ txt: Tensor,
294
+ txt_ids: Tensor,
295
+ txt_mask: Tensor,
296
+ timesteps: Tensor,
297
+ y: Tensor = None,
298
+ txt_byt5=None,
299
+ clip_fea=None,
300
+ guidance: Tensor = None,
301
+ guiding_frame_index=None,
302
+ ref_latent=None,
303
+ disable_time_r=False,
304
+ control=None,
305
+ transformer_options={},
306
+ ) -> Tensor:
307
+ transformer_options = transformer_options.copy()
308
+ patches_replace = transformer_options.get("patches_replace", {})
309
+
310
+ initial_shape = list(img.shape)
311
+ # running on sequences img
312
+ img = self.img_in(img)
313
+ vec = self.time_in(timestep_embedding(timesteps, 256, time_factor=1.0).to(img.dtype))
314
+
315
+ if (self.time_r_in is not None) and (not disable_time_r):
316
+ w = torch.where(transformer_options['sigmas'][0] == transformer_options['sample_sigmas'])[0] # This most likely could be improved
317
+ if len(w) > 0:
318
+ timesteps_r = transformer_options['sample_sigmas'][w[0] + 1]
319
+ timesteps_r = timesteps_r.unsqueeze(0).to(device=timesteps.device, dtype=timesteps.dtype)
320
+ vec_r = self.time_r_in(timestep_embedding(timesteps_r, 256, time_factor=1000.0).to(img.dtype))
321
+ vec = (vec + vec_r) if self.params.meanflow_sum else (vec + vec_r) / 2
322
+
323
+ if ref_latent is not None:
324
+ ref_latent_ids = self.img_ids(ref_latent)
325
+ ref_latent = self.img_in(ref_latent)
326
+ img = torch.cat([ref_latent, img], dim=-2)
327
+ ref_latent_ids[..., 0] = -1
328
+ ref_latent_ids[..., 2] += (initial_shape[-1] // self.patch_size[-1])
329
+ img_ids = torch.cat([ref_latent_ids, img_ids], dim=-2)
330
+
331
+ if guiding_frame_index is not None:
332
+ token_replace_vec = self.time_in(timestep_embedding(guiding_frame_index, 256, time_factor=1.0))
333
+ if self.vector_in is not None:
334
+ vec_ = self.vector_in(y[:, :self.params.vec_in_dim])
335
+ vec = torch.cat([(vec_ + token_replace_vec).unsqueeze(1), (vec_ + vec).unsqueeze(1)], dim=1)
336
+ else:
337
+ vec = torch.cat([(token_replace_vec).unsqueeze(1), (vec).unsqueeze(1)], dim=1)
338
+ frame_tokens = (initial_shape[-1] // self.patch_size[-1]) * (initial_shape[-2] // self.patch_size[-2])
339
+ modulation_dims = [(0, frame_tokens, 0), (frame_tokens, None, 1)]
340
+ modulation_dims_txt = [(0, None, 1)]
341
+ else:
342
+ if self.vector_in is not None:
343
+ vec = vec + self.vector_in(y[:, :self.params.vec_in_dim])
344
+ modulation_dims = None
345
+ modulation_dims_txt = None
346
+
347
+ if self.params.guidance_embed:
348
+ if guidance is not None:
349
+ vec = vec + self.guidance_in(timestep_embedding(guidance, 256).to(img.dtype))
350
+
351
+ if txt_mask is not None and not torch.is_floating_point(txt_mask):
352
+ txt_mask = (txt_mask - 1).to(img.dtype) * torch.finfo(img.dtype).max
353
+
354
+ txt = self.txt_in(txt, timesteps, txt_mask, transformer_options=transformer_options)
355
+
356
+ if self.cond_type_embedding is not None:
357
+ self.cond_type_embedding.to(txt.device)
358
+ cond_emb = self.cond_type_embedding(torch.zeros_like(txt[:, :, 0], device=txt.device, dtype=torch.long))
359
+ txt = txt + cond_emb.to(txt.dtype)
360
+
361
+ if self.byt5_in is not None and txt_byt5 is not None:
362
+ txt_byt5 = self.byt5_in(txt_byt5)
363
+ if self.cond_type_embedding is not None:
364
+ cond_emb = self.cond_type_embedding(torch.ones_like(txt_byt5[:, :, 0], device=txt_byt5.device, dtype=torch.long))
365
+ txt_byt5 = txt_byt5 + cond_emb.to(txt_byt5.dtype)
366
+ txt = torch.cat((txt_byt5, txt), dim=1) # byt5 first for HunyuanVideo1.5
367
+ else:
368
+ txt = torch.cat((txt, txt_byt5), dim=1)
369
+ txt_byt5_ids = torch.zeros((txt_ids.shape[0], txt_byt5.shape[1], txt_ids.shape[-1]), device=txt_ids.device, dtype=txt_ids.dtype)
370
+ txt_ids = torch.cat((txt_ids, txt_byt5_ids), dim=1)
371
+
372
+ if clip_fea is not None:
373
+ txt_vision_states = self.vision_in(clip_fea)
374
+ if self.cond_type_embedding is not None:
375
+ cond_emb = self.cond_type_embedding(2 * torch.ones_like(txt_vision_states[:, :, 0], dtype=torch.long, device=txt_vision_states.device))
376
+ txt_vision_states = txt_vision_states + cond_emb
377
+ txt = torch.cat((txt_vision_states.to(txt.dtype), txt), dim=1)
378
+ extra_txt_ids = torch.zeros((txt_ids.shape[0], txt_vision_states.shape[1], txt_ids.shape[-1]), device=txt_ids.device, dtype=txt_ids.dtype)
379
+ txt_ids = torch.cat((txt_ids, extra_txt_ids), dim=1)
380
+
381
+ ids = torch.cat((txt_ids, img_ids), dim=1)
382
+ pe = self.pe_embedder(ids)
383
+
384
+ img_len = img.shape[1]
385
+ if txt_mask is not None:
386
+ attn_mask_len = img_len + txt.shape[1]
387
+ attn_mask = torch.zeros((1, 1, attn_mask_len), dtype=img.dtype, device=img.device)
388
+ attn_mask[:, 0, :txt.shape[1]] = txt_mask
389
+ else:
390
+ attn_mask = None
391
+
392
+ blocks_replace = patches_replace.get("dit", {})
393
+ transformer_options["total_blocks"] = len(self.double_blocks)
394
+ transformer_options["block_type"] = "double"
395
+ for i, block in enumerate(self.double_blocks):
396
+ transformer_options["block_index"] = i
397
+ if ("double_block", i) in blocks_replace:
398
+ def block_wrap(args):
399
+ out = {}
400
+ out["img"], out["txt"] = block(img=args["img"], txt=args["txt"], vec=args["vec"], pe=args["pe"], attn_mask=args["attention_mask"], modulation_dims_img=args["modulation_dims_img"], modulation_dims_txt=args["modulation_dims_txt"], transformer_options=args["transformer_options"])
401
+ return out
402
+
403
+ out = blocks_replace[("double_block", i)]({"img": img, "txt": txt, "vec": vec, "pe": pe, "attention_mask": attn_mask, 'modulation_dims_img': modulation_dims, 'modulation_dims_txt': modulation_dims_txt, 'transformer_options': transformer_options}, {"original_block": block_wrap})
404
+ txt = out["txt"]
405
+ img = out["img"]
406
+ else:
407
+ img, txt = block(img=img, txt=txt, vec=vec, pe=pe, attn_mask=attn_mask, modulation_dims_img=modulation_dims, modulation_dims_txt=modulation_dims_txt, transformer_options=transformer_options)
408
+
409
+ if control is not None: # Controlnet
410
+ control_i = control.get("input")
411
+ if i < len(control_i):
412
+ add = control_i[i]
413
+ if add is not None:
414
+ img += add
415
+
416
+ img = torch.cat((txt, img), 1)
417
+
418
+ transformer_options["total_blocks"] = len(self.single_blocks)
419
+ transformer_options["block_type"] = "single"
420
+ transformer_options["img_slice"] = [txt.shape[1], img.shape[1]]
421
+ for i, block in enumerate(self.single_blocks):
422
+ transformer_options["block_index"] = i
423
+ if ("single_block", i) in blocks_replace:
424
+ def block_wrap(args):
425
+ out = {}
426
+ out["img"] = block(args["img"], vec=args["vec"], pe=args["pe"], attn_mask=args["attention_mask"], modulation_dims=args["modulation_dims"], transformer_options=args["transformer_options"])
427
+ return out
428
+
429
+ out = blocks_replace[("single_block", i)]({"img": img, "vec": vec, "pe": pe, "attention_mask": attn_mask, 'modulation_dims': modulation_dims, 'transformer_options': transformer_options}, {"original_block": block_wrap})
430
+ img = out["img"]
431
+ else:
432
+ img = block(img, vec=vec, pe=pe, attn_mask=attn_mask, modulation_dims=modulation_dims, transformer_options=transformer_options)
433
+
434
+ if control is not None: # Controlnet
435
+ control_o = control.get("output")
436
+ if i < len(control_o):
437
+ add = control_o[i]
438
+ if add is not None:
439
+ img[:, txt.shape[1]: img_len + txt.shape[1]] += add
440
+
441
+ img = img[:, txt.shape[1]: img_len + txt.shape[1]]
442
+ if ref_latent is not None:
443
+ img = img[:, ref_latent.shape[1]:]
444
+
445
+ img = self.final_layer(img, vec, modulation_dims=modulation_dims) # (N, T, patch_size ** 2 * out_channels)
446
+
447
+ shape = initial_shape[-len(self.patch_size):]
448
+ for i in range(len(shape)):
449
+ shape[i] = shape[i] // self.patch_size[i]
450
+ img = img.reshape([img.shape[0]] + shape + [self.out_channels] + self.patch_size)
451
+ if img.ndim == 8:
452
+ img = img.permute(0, 4, 1, 5, 2, 6, 3, 7)
453
+ img = img.reshape(initial_shape[0], self.out_channels, initial_shape[2], initial_shape[3], initial_shape[4])
454
+ else:
455
+ img = img.permute(0, 3, 1, 4, 2, 5)
456
+ img = img.reshape(initial_shape[0], self.out_channels, initial_shape[2], initial_shape[3])
457
+ return img
458
+
459
+ def img_ids(self, x):
460
+ bs, c, t, h, w = x.shape
461
+ patch_size = self.patch_size
462
+ t_len = ((t + (patch_size[0] // 2)) // patch_size[0])
463
+ h_len = ((h + (patch_size[1] // 2)) // patch_size[1])
464
+ w_len = ((w + (patch_size[2] // 2)) // patch_size[2])
465
+ img_ids = torch.zeros((t_len, h_len, w_len, 3), device=x.device, dtype=x.dtype)
466
+ img_ids[:, :, :, 0] = img_ids[:, :, :, 0] + torch.linspace(0, t_len - 1, steps=t_len, device=x.device, dtype=x.dtype).reshape(-1, 1, 1)
467
+ img_ids[:, :, :, 1] = img_ids[:, :, :, 1] + torch.linspace(0, h_len - 1, steps=h_len, device=x.device, dtype=x.dtype).reshape(1, -1, 1)
468
+ img_ids[:, :, :, 2] = img_ids[:, :, :, 2] + torch.linspace(0, w_len - 1, steps=w_len, device=x.device, dtype=x.dtype).reshape(1, 1, -1)
469
+ return repeat(img_ids, "t h w c -> b (t h w) c", b=bs)
470
+
471
+ def img_ids_2d(self, x):
472
+ bs, c, h, w = x.shape
473
+ patch_size = self.patch_size
474
+ h_len = ((h + (patch_size[0] // 2)) // patch_size[0])
475
+ w_len = ((w + (patch_size[1] // 2)) // patch_size[1])
476
+ img_ids = torch.zeros((h_len, w_len, 2), device=x.device, dtype=x.dtype)
477
+ img_ids[:, :, 0] = img_ids[:, :, 0] + torch.linspace(0, h_len - 1, steps=h_len, device=x.device, dtype=x.dtype).unsqueeze(1)
478
+ img_ids[:, :, 1] = img_ids[:, :, 1] + torch.linspace(0, w_len - 1, steps=w_len, device=x.device, dtype=x.dtype).unsqueeze(0)
479
+ return repeat(img_ids, "h w c -> b (h w) c", b=bs)
480
+
481
+ def forward(self, x, timestep, context, y=None, txt_byt5=None, clip_fea=None, guidance=None, attention_mask=None, guiding_frame_index=None, ref_latent=None, disable_time_r=False, control=None, transformer_options={}, **kwargs):
482
+ return comfy.patcher_extension.WrapperExecutor.new_class_executor(
483
+ self._forward,
484
+ self,
485
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.DIFFUSION_MODEL, transformer_options)
486
+ ).execute(x, timestep, context, y, txt_byt5, clip_fea, guidance, attention_mask, guiding_frame_index, ref_latent, disable_time_r, control, transformer_options, **kwargs)
487
+
488
+ def _forward(self, x, timestep, context, y=None, txt_byt5=None, clip_fea=None, guidance=None, attention_mask=None, guiding_frame_index=None, ref_latent=None, disable_time_r=False, control=None, transformer_options={}, **kwargs):
489
+ bs = x.shape[0]
490
+ if len(self.patch_size) == 3:
491
+ img_ids = self.img_ids(x)
492
+ txt_ids = torch.zeros((bs, context.shape[1], 3), device=x.device, dtype=x.dtype)
493
+ else:
494
+ img_ids = self.img_ids_2d(x)
495
+ txt_ids = torch.zeros((bs, context.shape[1], 2), device=x.device, dtype=x.dtype)
496
+ out = self.forward_orig(x, img_ids, context, txt_ids, attention_mask, timestep, y, txt_byt5, clip_fea, guidance, guiding_frame_index, ref_latent, disable_time_r=disable_time_r, control=control, transformer_options=transformer_options)
497
+ return out
ComfyUI/comfy/ldm/hunyuan_video/upsampler.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from comfy.ldm.modules.diffusionmodules.model import ResnetBlock, VideoConv3d
5
+ from comfy.ldm.hunyuan_video.vae_refiner import RMS_norm
6
+ import comfy.model_management
7
+ import comfy.model_patcher
8
+
9
+ class SRResidualCausalBlock3D(nn.Module):
10
+ def __init__(self, channels: int):
11
+ super().__init__()
12
+ self.block = nn.Sequential(
13
+ VideoConv3d(channels, channels, kernel_size=3),
14
+ nn.SiLU(inplace=True),
15
+ VideoConv3d(channels, channels, kernel_size=3),
16
+ nn.SiLU(inplace=True),
17
+ VideoConv3d(channels, channels, kernel_size=3),
18
+ )
19
+
20
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
21
+ return x + self.block(x)
22
+
23
+ class SRModel3DV2(nn.Module):
24
+ def __init__(
25
+ self,
26
+ in_channels: int,
27
+ out_channels: int,
28
+ hidden_channels: int = 64,
29
+ num_blocks: int = 6,
30
+ global_residual: bool = False,
31
+ ):
32
+ super().__init__()
33
+ self.in_conv = VideoConv3d(in_channels, hidden_channels, kernel_size=3)
34
+ self.blocks = nn.ModuleList([SRResidualCausalBlock3D(hidden_channels) for _ in range(num_blocks)])
35
+ self.out_conv = VideoConv3d(hidden_channels, out_channels, kernel_size=3)
36
+ self.global_residual = bool(global_residual)
37
+
38
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
39
+ residual = x
40
+ y = self.in_conv(x)
41
+ for blk in self.blocks:
42
+ y = blk(y)
43
+ y = self.out_conv(y)
44
+ if self.global_residual and (y.shape == residual.shape):
45
+ y = y + residual
46
+ return y
47
+
48
+
49
+ class Upsampler(nn.Module):
50
+ def __init__(
51
+ self,
52
+ z_channels: int,
53
+ out_channels: int,
54
+ block_out_channels: tuple[int, ...],
55
+ num_res_blocks: int = 2,
56
+ ):
57
+ super().__init__()
58
+ self.num_res_blocks = num_res_blocks
59
+ self.block_out_channels = block_out_channels
60
+ self.z_channels = z_channels
61
+
62
+ ch = block_out_channels[0]
63
+ self.conv_in = VideoConv3d(z_channels, ch, kernel_size=3)
64
+
65
+ self.up = nn.ModuleList()
66
+
67
+ for i, tgt in enumerate(block_out_channels):
68
+ stage = nn.Module()
69
+ stage.block = nn.ModuleList([ResnetBlock(in_channels=ch if j == 0 else tgt,
70
+ out_channels=tgt,
71
+ temb_channels=0,
72
+ conv_shortcut=False,
73
+ conv_op=VideoConv3d, norm_op=RMS_norm)
74
+ for j in range(num_res_blocks + 1)])
75
+ ch = tgt
76
+ self.up.append(stage)
77
+
78
+ self.norm_out = RMS_norm(ch)
79
+ self.conv_out = VideoConv3d(ch, out_channels, kernel_size=3)
80
+
81
+ def forward(self, z):
82
+ """
83
+ Args:
84
+ z: (B, C, T, H, W)
85
+ target_shape: (H, W)
86
+ """
87
+ # z to block_in
88
+ repeats = self.block_out_channels[0] // (self.z_channels)
89
+ x = self.conv_in(z) + z.repeat_interleave(repeats=repeats, dim=1)
90
+
91
+ # upsampling
92
+ for stage in self.up:
93
+ for blk in stage.block:
94
+ x = blk(x)
95
+
96
+ out = self.conv_out(F.silu(self.norm_out(x)))
97
+ return out
98
+
99
+ UPSAMPLERS = {
100
+ "720p": SRModel3DV2,
101
+ "1080p": Upsampler,
102
+ }
103
+
104
+ class HunyuanVideo15SRModel():
105
+ def __init__(self, model_type, config):
106
+ self.load_device = comfy.model_management.vae_device()
107
+ offload_device = comfy.model_management.vae_offload_device()
108
+ self.dtype = comfy.model_management.vae_dtype(self.load_device)
109
+ self.model_class = UPSAMPLERS.get(model_type)
110
+ self.model = self.model_class(**config).eval()
111
+
112
+ self.patcher = comfy.model_patcher.CoreModelPatcher(self.model, load_device=self.load_device, offload_device=offload_device)
113
+
114
+ def load_sd(self, sd):
115
+ return self.model.load_state_dict(sd, strict=True, assign=self.patcher.is_dynamic())
116
+
117
+ def get_sd(self):
118
+ return self.model.state_dict()
119
+
120
+ def resample_latent(self, latent):
121
+ comfy.model_management.load_model_gpu(self.patcher)
122
+ return self.model(latent.to(self.load_device))
ComfyUI/comfy/ldm/hunyuan_video/vae.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+ import torch.nn.functional as F
3
+ from comfy.ldm.modules.diffusionmodules.model import ResnetBlock, AttnBlock
4
+ import comfy.ops
5
+ ops = comfy.ops.disable_weight_init
6
+
7
+
8
+ class PixelShuffle2D(nn.Module):
9
+ def __init__(self, in_dim, out_dim, op=ops.Conv2d):
10
+ super().__init__()
11
+ self.conv = op(in_dim, out_dim >> 2, 3, 1, 1)
12
+ self.ratio = (in_dim << 2) // out_dim
13
+
14
+ def forward(self, x):
15
+ b, c, h, w = x.shape
16
+ h2, w2 = h >> 1, w >> 1
17
+ y = self.conv(x).view(b, -1, h2, 2, w2, 2).permute(0, 3, 5, 1, 2, 4).reshape(b, -1, h2, w2)
18
+ r = x.view(b, c, h2, 2, w2, 2).permute(0, 3, 5, 1, 2, 4).reshape(b, c << 2, h2, w2)
19
+ return y + r.view(b, y.shape[1], self.ratio, h2, w2).mean(2)
20
+
21
+
22
+ class PixelUnshuffle2D(nn.Module):
23
+ def __init__(self, in_dim, out_dim, op=ops.Conv2d):
24
+ super().__init__()
25
+ self.conv = op(in_dim, out_dim << 2, 3, 1, 1)
26
+ self.scale = (out_dim << 2) // in_dim
27
+
28
+ def forward(self, x):
29
+ b, c, h, w = x.shape
30
+ h2, w2 = h << 1, w << 1
31
+ y = self.conv(x).view(b, 2, 2, -1, h, w).permute(0, 3, 4, 1, 5, 2).reshape(b, -1, h2, w2)
32
+ r = x.repeat_interleave(self.scale, 1).view(b, 2, 2, -1, h, w).permute(0, 3, 4, 1, 5, 2).reshape(b, -1, h2, w2)
33
+ return y + r
34
+
35
+
36
+ class Encoder(nn.Module):
37
+ def __init__(self, in_channels, z_channels, block_out_channels, num_res_blocks,
38
+ ffactor_spatial, downsample_match_channel=True, **_):
39
+ super().__init__()
40
+ self.z_channels = z_channels
41
+ self.block_out_channels = block_out_channels
42
+ self.num_res_blocks = num_res_blocks
43
+ self.conv_in = ops.Conv2d(in_channels, block_out_channels[0], 3, 1, 1)
44
+
45
+ self.down = nn.ModuleList()
46
+ ch = block_out_channels[0]
47
+ depth = (ffactor_spatial >> 1).bit_length()
48
+
49
+ for i, tgt in enumerate(block_out_channels):
50
+ stage = nn.Module()
51
+ stage.block = nn.ModuleList([ResnetBlock(in_channels=ch if j == 0 else tgt,
52
+ out_channels=tgt,
53
+ temb_channels=0,
54
+ conv_op=ops.Conv2d)
55
+ for j in range(num_res_blocks)])
56
+ ch = tgt
57
+ if i < depth:
58
+ nxt = block_out_channels[i + 1] if i + 1 < len(block_out_channels) and downsample_match_channel else ch
59
+ stage.downsample = PixelShuffle2D(ch, nxt, ops.Conv2d)
60
+ ch = nxt
61
+ self.down.append(stage)
62
+
63
+ self.mid = nn.Module()
64
+ self.mid.block_1 = ResnetBlock(in_channels=ch, out_channels=ch, temb_channels=0, conv_op=ops.Conv2d)
65
+ self.mid.attn_1 = AttnBlock(ch, conv_op=ops.Conv2d)
66
+ self.mid.block_2 = ResnetBlock(in_channels=ch, out_channels=ch, temb_channels=0, conv_op=ops.Conv2d)
67
+
68
+ self.norm_out = ops.GroupNorm(32, ch, 1e-6, True)
69
+ self.conv_out = ops.Conv2d(ch, z_channels << 1, 3, 1, 1)
70
+
71
+ def forward(self, x):
72
+ x = self.conv_in(x)
73
+
74
+ for stage in self.down:
75
+ for blk in stage.block:
76
+ x = blk(x)
77
+ if hasattr(stage, 'downsample'):
78
+ x = stage.downsample(x)
79
+
80
+ x = self.mid.block_2(self.mid.attn_1(self.mid.block_1(x)))
81
+
82
+ b, c, h, w = x.shape
83
+ grp = c // (self.z_channels << 1)
84
+ skip = x.view(b, c // grp, grp, h, w).mean(2)
85
+
86
+ return self.conv_out(F.silu(self.norm_out(x))) + skip
87
+
88
+
89
+ class Decoder(nn.Module):
90
+ def __init__(self, z_channels, out_channels, block_out_channels, num_res_blocks,
91
+ ffactor_spatial, upsample_match_channel=True, **_):
92
+ super().__init__()
93
+ block_out_channels = block_out_channels[::-1]
94
+ self.z_channels = z_channels
95
+ self.block_out_channels = block_out_channels
96
+ self.num_res_blocks = num_res_blocks
97
+
98
+ ch = block_out_channels[0]
99
+ self.conv_in = ops.Conv2d(z_channels, ch, 3, 1, 1)
100
+
101
+ self.mid = nn.Module()
102
+ self.mid.block_1 = ResnetBlock(in_channels=ch, out_channels=ch, temb_channels=0, conv_op=ops.Conv2d)
103
+ self.mid.attn_1 = AttnBlock(ch, conv_op=ops.Conv2d)
104
+ self.mid.block_2 = ResnetBlock(in_channels=ch, out_channels=ch, temb_channels=0, conv_op=ops.Conv2d)
105
+
106
+ self.up = nn.ModuleList()
107
+ depth = (ffactor_spatial >> 1).bit_length()
108
+
109
+ for i, tgt in enumerate(block_out_channels):
110
+ stage = nn.Module()
111
+ stage.block = nn.ModuleList([ResnetBlock(in_channels=ch if j == 0 else tgt,
112
+ out_channels=tgt,
113
+ temb_channels=0,
114
+ conv_op=ops.Conv2d)
115
+ for j in range(num_res_blocks + 1)])
116
+ ch = tgt
117
+ if i < depth:
118
+ nxt = block_out_channels[i + 1] if i + 1 < len(block_out_channels) and upsample_match_channel else ch
119
+ stage.upsample = PixelUnshuffle2D(ch, nxt, ops.Conv2d)
120
+ ch = nxt
121
+ self.up.append(stage)
122
+
123
+ self.norm_out = ops.GroupNorm(32, ch, 1e-6, True)
124
+ self.conv_out = ops.Conv2d(ch, out_channels, 3, 1, 1)
125
+
126
+ def forward(self, z):
127
+ x = self.conv_in(z) + z.repeat_interleave(self.block_out_channels[0] // self.z_channels, 1)
128
+ x = self.mid.block_2(self.mid.attn_1(self.mid.block_1(x)))
129
+
130
+ for stage in self.up:
131
+ for blk in stage.block:
132
+ x = blk(x)
133
+ if hasattr(stage, 'upsample'):
134
+ x = stage.upsample(x)
135
+
136
+ return self.conv_out(F.silu(self.norm_out(x)))
ComfyUI/comfy/ldm/hunyuan_video/vae_refiner.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from comfy.ldm.modules.diffusionmodules.model import ResnetBlock, AttnBlock, CarriedConv3d, Normalize, conv_carry_causal_3d, torch_cat_if_needed
5
+ import comfy.ops
6
+ import comfy.ldm.models.autoencoder
7
+ import comfy.model_management
8
+ ops = comfy.ops.disable_weight_init
9
+
10
+
11
+ class RMS_norm(nn.Module):
12
+ def __init__(self, dim):
13
+ super().__init__()
14
+ shape = (dim, 1, 1, 1)
15
+ self.scale = dim**0.5
16
+ self.gamma = nn.Parameter(torch.empty(shape))
17
+
18
+ def forward(self, x):
19
+ return F.normalize(x, dim=1) * self.scale * comfy.model_management.cast_to(self.gamma, dtype=x.dtype, device=x.device)
20
+
21
+ class DnSmpl(nn.Module):
22
+ def __init__(self, ic, oc, tds, refiner_vae, op):
23
+ super().__init__()
24
+ fct = 2 * 2 * 2 if tds else 1 * 2 * 2
25
+ assert oc % fct == 0
26
+ self.conv = op(ic, oc // fct, kernel_size=3, stride=1, padding=1)
27
+ self.refiner_vae = refiner_vae
28
+
29
+ self.tds = tds
30
+ self.gs = fct * ic // oc
31
+
32
+ def forward(self, x, conv_carry_in=None, conv_carry_out=None):
33
+ r1 = 2 if self.tds else 1
34
+ h = conv_carry_causal_3d([x], self.conv, conv_carry_in, conv_carry_out)
35
+
36
+ if self.tds and self.refiner_vae and conv_carry_in is None:
37
+
38
+ hf = h[:, :, :1, :, :]
39
+ b, c, f, ht, wd = hf.shape
40
+ hf = hf.reshape(b, c, f, ht // 2, 2, wd // 2, 2)
41
+ hf = hf.permute(0, 4, 6, 1, 2, 3, 5)
42
+ hf = hf.reshape(b, 2 * 2 * c, f, ht // 2, wd // 2)
43
+ hf = torch.cat([hf, hf], dim=1)
44
+
45
+ h = h[:, :, 1:, :, :]
46
+
47
+ xf = x[:, :, :1, :, :]
48
+ b, ci, f, ht, wd = xf.shape
49
+ xf = xf.reshape(b, ci, f, ht // 2, 2, wd // 2, 2)
50
+ xf = xf.permute(0, 4, 6, 1, 2, 3, 5)
51
+ xf = xf.reshape(b, 2 * 2 * ci, f, ht // 2, wd // 2)
52
+ B, C, T, H, W = xf.shape
53
+ xf = xf.view(B, hf.shape[1], self.gs // 2, T, H, W).mean(dim=2)
54
+
55
+ x = x[:, :, 1:, :, :]
56
+
57
+ if h.shape[2] == 0:
58
+ return hf + xf
59
+
60
+ b, c, frms, ht, wd = h.shape
61
+ nf = frms // r1
62
+ h = h.reshape(b, c, nf, r1, ht // 2, 2, wd // 2, 2)
63
+ h = h.permute(0, 3, 5, 7, 1, 2, 4, 6)
64
+ h = h.reshape(b, r1 * 2 * 2 * c, nf, ht // 2, wd // 2)
65
+
66
+ b, ci, frms, ht, wd = x.shape
67
+ nf = frms // r1
68
+ x = x.reshape(b, ci, nf, r1, ht // 2, 2, wd // 2, 2)
69
+ x = x.permute(0, 3, 5, 7, 1, 2, 4, 6)
70
+ x = x.reshape(b, r1 * 2 * 2 * ci, nf, ht // 2, wd // 2)
71
+ B, C, T, H, W = x.shape
72
+ x = x.view(B, h.shape[1], self.gs, T, H, W).mean(dim=2)
73
+
74
+ if self.tds and self.refiner_vae and conv_carry_in is None:
75
+ h = torch.cat([hf, h], dim=2)
76
+ x = torch.cat([xf, x], dim=2)
77
+
78
+ return h + x
79
+
80
+
81
+ class UpSmpl(nn.Module):
82
+ def __init__(self, ic, oc, tus, refiner_vae, op):
83
+ super().__init__()
84
+ fct = 2 * 2 * 2 if tus else 1 * 2 * 2
85
+ self.conv = op(ic, oc * fct, kernel_size=3, stride=1, padding=1)
86
+ self.refiner_vae = refiner_vae
87
+
88
+ self.tus = tus
89
+ self.rp = fct * oc // ic
90
+
91
+ def forward(self, x, conv_carry_in=None, conv_carry_out=None):
92
+ r1 = 2 if self.tus else 1
93
+ h = conv_carry_causal_3d([x], self.conv, conv_carry_in, conv_carry_out)
94
+
95
+ if self.tus and self.refiner_vae and conv_carry_in is None:
96
+ hf = h[:, :, :1, :, :]
97
+ b, c, f, ht, wd = hf.shape
98
+ nc = c // (2 * 2)
99
+ hf = hf.reshape(b, 2, 2, nc, f, ht, wd)
100
+ hf = hf.permute(0, 3, 4, 5, 1, 6, 2)
101
+ hf = hf.reshape(b, nc, f, ht * 2, wd * 2)
102
+ hf = hf[:, : hf.shape[1] // 2]
103
+
104
+ h = h[:, :, 1:, :, :]
105
+
106
+ xf = x[:, :, :1, :, :]
107
+ b, ci, f, ht, wd = xf.shape
108
+ xf = xf.repeat_interleave(repeats=self.rp // 2, dim=1)
109
+ b, c, f, ht, wd = xf.shape
110
+ nc = c // (2 * 2)
111
+ xf = xf.reshape(b, 2, 2, nc, f, ht, wd)
112
+ xf = xf.permute(0, 3, 4, 5, 1, 6, 2)
113
+ xf = xf.reshape(b, nc, f, ht * 2, wd * 2)
114
+
115
+ x = x[:, :, 1:, :, :]
116
+
117
+ b, c, frms, ht, wd = h.shape
118
+ nc = c // (r1 * 2 * 2)
119
+ h = h.reshape(b, r1, 2, 2, nc, frms, ht, wd)
120
+ h = h.permute(0, 4, 5, 1, 6, 2, 7, 3)
121
+ h = h.reshape(b, nc, frms * r1, ht * 2, wd * 2)
122
+
123
+ x = x.repeat_interleave(repeats=self.rp, dim=1)
124
+ b, c, frms, ht, wd = x.shape
125
+ nc = c // (r1 * 2 * 2)
126
+ x = x.reshape(b, r1, 2, 2, nc, frms, ht, wd)
127
+ x = x.permute(0, 4, 5, 1, 6, 2, 7, 3)
128
+ x = x.reshape(b, nc, frms * r1, ht * 2, wd * 2)
129
+
130
+ if self.tus and self.refiner_vae and conv_carry_in is None:
131
+ h = torch.cat([hf, h], dim=2)
132
+ x = torch.cat([xf, x], dim=2)
133
+
134
+ return h + x
135
+
136
+ class Encoder(nn.Module):
137
+ def __init__(self, in_channels, z_channels, block_out_channels, num_res_blocks,
138
+ ffactor_spatial, ffactor_temporal, downsample_match_channel=True, refiner_vae=True, **_):
139
+ super().__init__()
140
+ self.z_channels = z_channels
141
+ self.block_out_channels = block_out_channels
142
+ self.num_res_blocks = num_res_blocks
143
+ self.ffactor_temporal = ffactor_temporal
144
+
145
+ self.refiner_vae = refiner_vae
146
+ if self.refiner_vae:
147
+ conv_op = CarriedConv3d
148
+ norm_op = RMS_norm
149
+ else:
150
+ conv_op = ops.Conv3d
151
+ norm_op = Normalize
152
+
153
+ self.conv_in = conv_op(in_channels, block_out_channels[0], 3, 1, 1)
154
+
155
+ self.down = nn.ModuleList()
156
+ ch = block_out_channels[0]
157
+ depth = (ffactor_spatial >> 1).bit_length()
158
+ depth_temporal = ((ffactor_spatial // self.ffactor_temporal) >> 1).bit_length()
159
+
160
+ for i, tgt in enumerate(block_out_channels):
161
+ stage = nn.Module()
162
+ stage.block = nn.ModuleList([ResnetBlock(in_channels=ch if j == 0 else tgt,
163
+ out_channels=tgt,
164
+ temb_channels=0,
165
+ conv_op=conv_op, norm_op=norm_op)
166
+ for j in range(num_res_blocks)])
167
+ ch = tgt
168
+ if i < depth:
169
+ nxt = block_out_channels[i + 1] if i + 1 < len(block_out_channels) and downsample_match_channel else ch
170
+ stage.downsample = DnSmpl(ch, nxt, tds=i >= depth_temporal, refiner_vae=self.refiner_vae, op=conv_op)
171
+ ch = nxt
172
+ self.down.append(stage)
173
+
174
+ self.mid = nn.Module()
175
+ self.mid.block_1 = ResnetBlock(in_channels=ch, out_channels=ch, conv_op=conv_op, norm_op=norm_op)
176
+ self.mid.attn_1 = AttnBlock(ch, conv_op=ops.Conv3d, norm_op=norm_op)
177
+ self.mid.block_2 = ResnetBlock(in_channels=ch, out_channels=ch, conv_op=conv_op, norm_op=norm_op)
178
+
179
+ self.norm_out = norm_op(ch)
180
+ self.conv_out = conv_op(ch, z_channels << 1, 3, 1, 1)
181
+
182
+ self.regul = comfy.ldm.models.autoencoder.DiagonalGaussianRegularizer()
183
+
184
+ def forward(self, x):
185
+ if not self.refiner_vae and x.shape[2] == 1:
186
+ x = x.expand(-1, -1, self.ffactor_temporal, -1, -1)
187
+
188
+ if self.refiner_vae:
189
+ xl = [x[:, :, :1, :, :]]
190
+ if x.shape[2] > self.ffactor_temporal:
191
+ xl += torch.split(x[:, :, 1: 1 + ((x.shape[2] - 1) // self.ffactor_temporal) * self.ffactor_temporal, :, :], self.ffactor_temporal * 2, dim=2)
192
+ x = xl
193
+ else:
194
+ x = [x]
195
+ out = []
196
+
197
+ conv_carry_in = None
198
+
199
+ for i, x1 in enumerate(x):
200
+ conv_carry_out = []
201
+ if i == len(x) - 1:
202
+ conv_carry_out = None
203
+
204
+ x1 = [ x1 ]
205
+ x1 = conv_carry_causal_3d(x1, self.conv_in, conv_carry_in, conv_carry_out)
206
+
207
+ for stage in self.down:
208
+ for blk in stage.block:
209
+ x1 = blk(x1, None, conv_carry_in, conv_carry_out)
210
+ if hasattr(stage, 'downsample'):
211
+ x1 = stage.downsample(x1, conv_carry_in, conv_carry_out)
212
+
213
+ out.append(x1)
214
+ conv_carry_in = conv_carry_out
215
+
216
+ out = torch_cat_if_needed(out, dim=2)
217
+
218
+ x = self.mid.block_2(self.mid.attn_1(self.mid.block_1(out)))
219
+ del out
220
+
221
+ b, c, t, h, w = x.shape
222
+ grp = c // (self.z_channels << 1)
223
+ skip = x.view(b, c // grp, grp, t, h, w).mean(2)
224
+
225
+ out = conv_carry_causal_3d([F.silu(self.norm_out(x))], self.conv_out) + skip
226
+
227
+ if self.refiner_vae:
228
+ out = self.regul(out)[0]
229
+
230
+ return out
231
+
232
+ class Decoder(nn.Module):
233
+ def __init__(self, z_channels, out_channels, block_out_channels, num_res_blocks,
234
+ ffactor_spatial, ffactor_temporal, upsample_match_channel=True, refiner_vae=True, **_):
235
+ super().__init__()
236
+ block_out_channels = block_out_channels[::-1]
237
+ self.z_channels = z_channels
238
+ self.block_out_channels = block_out_channels
239
+ self.num_res_blocks = num_res_blocks
240
+
241
+ self.refiner_vae = refiner_vae
242
+ if self.refiner_vae:
243
+ conv_op = CarriedConv3d
244
+ norm_op = RMS_norm
245
+ else:
246
+ conv_op = ops.Conv3d
247
+ norm_op = Normalize
248
+
249
+ ch = block_out_channels[0]
250
+ self.conv_in = conv_op(z_channels, ch, kernel_size=3, stride=1, padding=1)
251
+
252
+ self.mid = nn.Module()
253
+ self.mid.block_1 = ResnetBlock(in_channels=ch, out_channels=ch, conv_op=conv_op, norm_op=norm_op)
254
+ self.mid.attn_1 = AttnBlock(ch, conv_op=ops.Conv3d, norm_op=norm_op)
255
+ self.mid.block_2 = ResnetBlock(in_channels=ch, out_channels=ch, conv_op=conv_op, norm_op=norm_op)
256
+
257
+ self.up = nn.ModuleList()
258
+ depth = (ffactor_spatial >> 1).bit_length()
259
+ depth_temporal = (ffactor_temporal >> 1).bit_length()
260
+
261
+ for i, tgt in enumerate(block_out_channels):
262
+ stage = nn.Module()
263
+ stage.block = nn.ModuleList([ResnetBlock(in_channels=ch if j == 0 else tgt,
264
+ out_channels=tgt,
265
+ temb_channels=0,
266
+ conv_op=conv_op, norm_op=norm_op)
267
+ for j in range(num_res_blocks + 1)])
268
+ ch = tgt
269
+ if i < depth:
270
+ nxt = block_out_channels[i + 1] if i + 1 < len(block_out_channels) and upsample_match_channel else ch
271
+ stage.upsample = UpSmpl(ch, nxt, tus=i < depth_temporal, refiner_vae=self.refiner_vae, op=conv_op)
272
+ ch = nxt
273
+ self.up.append(stage)
274
+
275
+ self.norm_out = norm_op(ch)
276
+ self.conv_out = conv_op(ch, out_channels, 3, stride=1, padding=1)
277
+
278
+ def forward(self, z):
279
+ x = conv_carry_causal_3d([z], self.conv_in) + z.repeat_interleave(self.block_out_channels[0] // self.z_channels, 1)
280
+ x = self.mid.block_2(self.mid.attn_1(self.mid.block_1(x)))
281
+
282
+ if self.refiner_vae:
283
+ x = torch.split(x, 2, dim=2)
284
+ else:
285
+ x = [ x ]
286
+ out = []
287
+
288
+ conv_carry_in = None
289
+
290
+ for i, x1 in enumerate(x):
291
+ conv_carry_out = []
292
+ if i == len(x) - 1:
293
+ conv_carry_out = None
294
+ for stage in self.up:
295
+ for blk in stage.block:
296
+ x1 = blk(x1, None, conv_carry_in, conv_carry_out)
297
+ if hasattr(stage, 'upsample'):
298
+ x1 = stage.upsample(x1, conv_carry_in, conv_carry_out)
299
+
300
+ x1 = [ F.silu(self.norm_out(x1)) ]
301
+ x1 = conv_carry_causal_3d(x1, self.conv_out, conv_carry_in, conv_carry_out)
302
+ out.append(x1)
303
+ conv_carry_in = conv_carry_out
304
+ del x
305
+
306
+ out = torch_cat_if_needed(out, dim=2)
307
+
308
+ if not self.refiner_vae:
309
+ if z.shape[-3] == 1:
310
+ out = out[:, :, -1:]
311
+
312
+ return out
313
+
ComfyUI/comfy/ldm/hydit/__pycache__/attn_layers.cpython-312.pyc ADDED
Binary file (14 kB). View file
 
ComfyUI/comfy/ldm/hydit/__pycache__/controlnet.cpython-312.pyc ADDED
Binary file (9.49 kB). View file
 
ComfyUI/comfy/ldm/hydit/__pycache__/models.cpython-312.pyc ADDED
Binary file (18.5 kB). View file
 
ComfyUI/comfy/ldm/hydit/__pycache__/poolers.cpython-312.pyc ADDED
Binary file (3.54 kB). View file
 
ComfyUI/comfy/ldm/hydit/__pycache__/posemb_layers.cpython-312.pyc ADDED
Binary file (9.8 kB). View file
 
ComfyUI/comfy/ldm/hydit/attn_layers.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from typing import Tuple, Union, Optional
4
+ from comfy.ldm.modules.attention import optimized_attention
5
+
6
+
7
+ def reshape_for_broadcast(freqs_cis: Union[torch.Tensor, Tuple[torch.Tensor]], x: torch.Tensor, head_first=False):
8
+ """
9
+ Reshape frequency tensor for broadcasting it with another tensor.
10
+
11
+ This function reshapes the frequency tensor to have the same shape as the target tensor 'x'
12
+ for the purpose of broadcasting the frequency tensor during element-wise operations.
13
+
14
+ Args:
15
+ freqs_cis (Union[torch.Tensor, Tuple[torch.Tensor]]): Frequency tensor to be reshaped.
16
+ x (torch.Tensor): Target tensor for broadcasting compatibility.
17
+ head_first (bool): head dimension first (except batch dim) or not.
18
+
19
+ Returns:
20
+ torch.Tensor: Reshaped frequency tensor.
21
+
22
+ Raises:
23
+ AssertionError: If the frequency tensor doesn't match the expected shape.
24
+ AssertionError: If the target tensor 'x' doesn't have the expected number of dimensions.
25
+ """
26
+ ndim = x.ndim
27
+ assert 0 <= 1 < ndim
28
+
29
+ if isinstance(freqs_cis, tuple):
30
+ # freqs_cis: (cos, sin) in real space
31
+ if head_first:
32
+ assert freqs_cis[0].shape == (x.shape[-2], x.shape[-1]), f'freqs_cis shape {freqs_cis[0].shape} does not match x shape {x.shape}'
33
+ shape = [d if i == ndim - 2 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
34
+ else:
35
+ assert freqs_cis[0].shape == (x.shape[1], x.shape[-1]), f'freqs_cis shape {freqs_cis[0].shape} does not match x shape {x.shape}'
36
+ shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
37
+ return freqs_cis[0].view(*shape), freqs_cis[1].view(*shape)
38
+ else:
39
+ # freqs_cis: values in complex space
40
+ if head_first:
41
+ assert freqs_cis.shape == (x.shape[-2], x.shape[-1]), f'freqs_cis shape {freqs_cis.shape} does not match x shape {x.shape}'
42
+ shape = [d if i == ndim - 2 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
43
+ else:
44
+ assert freqs_cis.shape == (x.shape[1], x.shape[-1]), f'freqs_cis shape {freqs_cis.shape} does not match x shape {x.shape}'
45
+ shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
46
+ return freqs_cis.view(*shape)
47
+
48
+
49
+ def rotate_half(x):
50
+ x_real, x_imag = x.reshape(*x.shape[:-1], -1, 2).unbind(-1) # [B, S, H, D//2]
51
+ return torch.stack([-x_imag, x_real], dim=-1).flatten(3)
52
+
53
+
54
+ def apply_rotary_emb(
55
+ xq: torch.Tensor,
56
+ xk: Optional[torch.Tensor],
57
+ freqs_cis: Union[torch.Tensor, Tuple[torch.Tensor]],
58
+ head_first: bool = False,
59
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
60
+ """
61
+ Apply rotary embeddings to input tensors using the given frequency tensor.
62
+
63
+ This function applies rotary embeddings to the given query 'xq' and key 'xk' tensors using the provided
64
+ frequency tensor 'freqs_cis'. The input tensors are reshaped as complex numbers, and the frequency tensor
65
+ is reshaped for broadcasting compatibility. The resulting tensors contain rotary embeddings and are
66
+ returned as real tensors.
67
+
68
+ Args:
69
+ xq (torch.Tensor): Query tensor to apply rotary embeddings. [B, S, H, D]
70
+ xk (torch.Tensor): Key tensor to apply rotary embeddings. [B, S, H, D]
71
+ freqs_cis (Union[torch.Tensor, Tuple[torch.Tensor]]): Precomputed frequency tensor for complex exponentials.
72
+ head_first (bool): head dimension first (except batch dim) or not.
73
+
74
+ Returns:
75
+ Tuple[torch.Tensor, torch.Tensor]: Tuple of modified query tensor and key tensor with rotary embeddings.
76
+
77
+ """
78
+ xk_out = None
79
+ if isinstance(freqs_cis, tuple):
80
+ cos, sin = reshape_for_broadcast(freqs_cis, xq, head_first) # [S, D]
81
+ xq_out = (xq * cos + rotate_half(xq) * sin)
82
+ if xk is not None:
83
+ xk_out = (xk * cos + rotate_half(xk) * sin)
84
+ else:
85
+ xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [B, S, H, D//2]
86
+ freqs_cis = reshape_for_broadcast(freqs_cis, xq_, head_first).to(xq.device) # [S, D//2] --> [1, S, 1, D//2]
87
+ xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3).type_as(xq)
88
+ if xk is not None:
89
+ xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2)) # [B, S, H, D//2]
90
+ xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3).type_as(xk)
91
+
92
+ return xq_out, xk_out
93
+
94
+
95
+
96
+ class CrossAttention(nn.Module):
97
+ """
98
+ Use QK Normalization.
99
+ """
100
+ def __init__(self,
101
+ qdim,
102
+ kdim,
103
+ num_heads,
104
+ qkv_bias=True,
105
+ qk_norm=False,
106
+ attn_drop=0.0,
107
+ proj_drop=0.0,
108
+ attn_precision=None,
109
+ device=None,
110
+ dtype=None,
111
+ operations=None,
112
+ ):
113
+ factory_kwargs = {'device': device, 'dtype': dtype}
114
+ super().__init__()
115
+ self.attn_precision = attn_precision
116
+ self.qdim = qdim
117
+ self.kdim = kdim
118
+ self.num_heads = num_heads
119
+ assert self.qdim % num_heads == 0, "self.qdim must be divisible by num_heads"
120
+ self.head_dim = self.qdim // num_heads
121
+ assert self.head_dim % 8 == 0 and self.head_dim <= 128, "Only support head_dim <= 128 and divisible by 8"
122
+ self.scale = self.head_dim ** -0.5
123
+
124
+ self.q_proj = operations.Linear(qdim, qdim, bias=qkv_bias, **factory_kwargs)
125
+ self.kv_proj = operations.Linear(kdim, 2 * qdim, bias=qkv_bias, **factory_kwargs)
126
+
127
+ # TODO: eps should be 1 / 65530 if using fp16
128
+ self.q_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity()
129
+ self.k_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity()
130
+ self.attn_drop = nn.Dropout(attn_drop)
131
+ self.out_proj = operations.Linear(qdim, qdim, bias=qkv_bias, **factory_kwargs)
132
+ self.proj_drop = nn.Dropout(proj_drop)
133
+
134
+ def forward(self, x, y, freqs_cis_img=None):
135
+ """
136
+ Parameters
137
+ ----------
138
+ x: torch.Tensor
139
+ (batch, seqlen1, hidden_dim) (where hidden_dim = num heads * head dim)
140
+ y: torch.Tensor
141
+ (batch, seqlen2, hidden_dim2)
142
+ freqs_cis_img: torch.Tensor
143
+ (batch, hidden_dim // 2), RoPE for image
144
+ """
145
+ b, s1, c = x.shape # [b, s1, D]
146
+ _, s2, c = y.shape # [b, s2, 1024]
147
+
148
+ q = self.q_proj(x).view(b, s1, self.num_heads, self.head_dim) # [b, s1, h, d]
149
+ kv = self.kv_proj(y).view(b, s2, 2, self.num_heads, self.head_dim) # [b, s2, 2, h, d]
150
+ k, v = kv.unbind(dim=2) # [b, s, h, d]
151
+ q = self.q_norm(q)
152
+ k = self.k_norm(k)
153
+
154
+ # Apply RoPE if needed
155
+ if freqs_cis_img is not None:
156
+ qq, _ = apply_rotary_emb(q, None, freqs_cis_img)
157
+ assert qq.shape == q.shape, f'qq: {qq.shape}, q: {q.shape}'
158
+ q = qq
159
+
160
+ q = q.transpose(-2, -3).contiguous() # q -> B, L1, H, C - B, H, L1, C
161
+ k = k.transpose(-2, -3).contiguous() # k -> B, L2, H, C - B, H, C, L2
162
+ v = v.transpose(-2, -3).contiguous()
163
+
164
+ context = optimized_attention(q, k, v, self.num_heads, skip_reshape=True, attn_precision=self.attn_precision)
165
+
166
+ out = self.out_proj(context) # context.reshape - B, L1, -1
167
+ out = self.proj_drop(out)
168
+
169
+ out_tuple = (out,)
170
+
171
+ return out_tuple
172
+
173
+
174
+ class Attention(nn.Module):
175
+ """
176
+ We rename some layer names to align with flash attention
177
+ """
178
+ def __init__(self, dim, num_heads, qkv_bias=True, qk_norm=False, attn_drop=0., proj_drop=0., attn_precision=None, dtype=None, device=None, operations=None):
179
+ super().__init__()
180
+ self.attn_precision = attn_precision
181
+ self.dim = dim
182
+ self.num_heads = num_heads
183
+ assert self.dim % num_heads == 0, 'dim should be divisible by num_heads'
184
+ self.head_dim = self.dim // num_heads
185
+ # This assertion is aligned with flash attention
186
+ assert self.head_dim % 8 == 0 and self.head_dim <= 128, "Only support head_dim <= 128 and divisible by 8"
187
+ self.scale = self.head_dim ** -0.5
188
+
189
+ # qkv --> Wqkv
190
+ self.Wqkv = operations.Linear(dim, dim * 3, bias=qkv_bias, dtype=dtype, device=device)
191
+ # TODO: eps should be 1 / 65530 if using fp16
192
+ self.q_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity()
193
+ self.k_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity()
194
+ self.attn_drop = nn.Dropout(attn_drop)
195
+ self.out_proj = operations.Linear(dim, dim, dtype=dtype, device=device)
196
+ self.proj_drop = nn.Dropout(proj_drop)
197
+
198
+ def forward(self, x, freqs_cis_img=None):
199
+ B, N, C = x.shape
200
+ qkv = self.Wqkv(x).reshape(B, N, 3, self.num_heads, self.head_dim).permute(2, 0, 3, 1, 4) # [3, b, h, s, d]
201
+ q, k, v = qkv.unbind(0) # [b, h, s, d]
202
+ q = self.q_norm(q) # [b, h, s, d]
203
+ k = self.k_norm(k) # [b, h, s, d]
204
+
205
+ # Apply RoPE if needed
206
+ if freqs_cis_img is not None:
207
+ qq, kk = apply_rotary_emb(q, k, freqs_cis_img, head_first=True)
208
+ assert qq.shape == q.shape and kk.shape == k.shape, \
209
+ f'qq: {qq.shape}, q: {q.shape}, kk: {kk.shape}, k: {k.shape}'
210
+ q, k = qq, kk
211
+
212
+ x = optimized_attention(q, k, v, self.num_heads, skip_reshape=True, attn_precision=self.attn_precision)
213
+ x = self.out_proj(x)
214
+ x = self.proj_drop(x)
215
+
216
+ out_tuple = (x,)
217
+
218
+ return out_tuple
ComfyUI/comfy/ldm/hydit/controlnet.py ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torch.nn as nn
4
+
5
+
6
+ from comfy.ldm.modules.diffusionmodules.mmdit import (
7
+ TimestepEmbedder,
8
+ PatchEmbed,
9
+ )
10
+ from .poolers import AttentionPool
11
+
12
+ import comfy.latent_formats
13
+ from .models import HunYuanDiTBlock, calc_rope
14
+
15
+
16
+
17
+ class HunYuanControlNet(nn.Module):
18
+ """
19
+ HunYuanDiT: Diffusion model with a Transformer backbone.
20
+
21
+ Inherit ModelMixin and ConfigMixin to be compatible with the sampler StableDiffusionPipeline of diffusers.
22
+
23
+ Inherit PeftAdapterMixin to be compatible with the PEFT training pipeline.
24
+
25
+ Parameters
26
+ ----------
27
+ args: argparse.Namespace
28
+ The arguments parsed by argparse.
29
+ input_size: tuple
30
+ The size of the input image.
31
+ patch_size: int
32
+ The size of the patch.
33
+ in_channels: int
34
+ The number of input channels.
35
+ hidden_size: int
36
+ The hidden size of the transformer backbone.
37
+ depth: int
38
+ The number of transformer blocks.
39
+ num_heads: int
40
+ The number of attention heads.
41
+ mlp_ratio: float
42
+ The ratio of the hidden size of the MLP in the transformer block.
43
+ log_fn: callable
44
+ The logging function.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ input_size: tuple = 128,
50
+ patch_size: int = 2,
51
+ in_channels: int = 4,
52
+ hidden_size: int = 1408,
53
+ depth: int = 40,
54
+ num_heads: int = 16,
55
+ mlp_ratio: float = 4.3637,
56
+ text_states_dim=1024,
57
+ text_states_dim_t5=2048,
58
+ text_len=77,
59
+ text_len_t5=256,
60
+ qk_norm=True, # See http://arxiv.org/abs/2302.05442 for details.
61
+ size_cond=False,
62
+ use_style_cond=False,
63
+ learn_sigma=True,
64
+ norm="layer",
65
+ log_fn: callable = print,
66
+ attn_precision=None,
67
+ dtype=None,
68
+ device=None,
69
+ operations=None,
70
+ **kwargs,
71
+ ):
72
+ super().__init__()
73
+ self.log_fn = log_fn
74
+ self.depth = depth
75
+ self.learn_sigma = learn_sigma
76
+ self.in_channels = in_channels
77
+ self.out_channels = in_channels * 2 if learn_sigma else in_channels
78
+ self.patch_size = patch_size
79
+ self.num_heads = num_heads
80
+ self.hidden_size = hidden_size
81
+ self.text_states_dim = text_states_dim
82
+ self.text_states_dim_t5 = text_states_dim_t5
83
+ self.text_len = text_len
84
+ self.text_len_t5 = text_len_t5
85
+ self.size_cond = size_cond
86
+ self.use_style_cond = use_style_cond
87
+ self.norm = norm
88
+ self.dtype = dtype
89
+ self.latent_format = comfy.latent_formats.SDXL
90
+
91
+ self.mlp_t5 = nn.Sequential(
92
+ nn.Linear(
93
+ self.text_states_dim_t5,
94
+ self.text_states_dim_t5 * 4,
95
+ bias=True,
96
+ dtype=dtype,
97
+ device=device,
98
+ ),
99
+ nn.SiLU(),
100
+ nn.Linear(
101
+ self.text_states_dim_t5 * 4,
102
+ self.text_states_dim,
103
+ bias=True,
104
+ dtype=dtype,
105
+ device=device,
106
+ ),
107
+ )
108
+ # learnable replace
109
+ self.text_embedding_padding = nn.Parameter(
110
+ torch.randn(
111
+ self.text_len + self.text_len_t5,
112
+ self.text_states_dim,
113
+ dtype=dtype,
114
+ device=device,
115
+ )
116
+ )
117
+
118
+ # Attention pooling
119
+ pooler_out_dim = 1024
120
+ self.pooler = AttentionPool(
121
+ self.text_len_t5,
122
+ self.text_states_dim_t5,
123
+ num_heads=8,
124
+ output_dim=pooler_out_dim,
125
+ dtype=dtype,
126
+ device=device,
127
+ operations=operations,
128
+ )
129
+
130
+ # Dimension of the extra input vectors
131
+ self.extra_in_dim = pooler_out_dim
132
+
133
+ if self.size_cond:
134
+ # Image size and crop size conditions
135
+ self.extra_in_dim += 6 * 256
136
+
137
+ if self.use_style_cond:
138
+ # Here we use a default learned embedder layer for future extension.
139
+ self.style_embedder = nn.Embedding(
140
+ 1, hidden_size, dtype=dtype, device=device
141
+ )
142
+ self.extra_in_dim += hidden_size
143
+
144
+ # Text embedding for `add`
145
+ self.x_embedder = PatchEmbed(
146
+ input_size,
147
+ patch_size,
148
+ in_channels,
149
+ hidden_size,
150
+ dtype=dtype,
151
+ device=device,
152
+ operations=operations,
153
+ )
154
+ self.t_embedder = TimestepEmbedder(
155
+ hidden_size, dtype=dtype, device=device, operations=operations
156
+ )
157
+ self.extra_embedder = nn.Sequential(
158
+ operations.Linear(
159
+ self.extra_in_dim, hidden_size * 4, dtype=dtype, device=device
160
+ ),
161
+ nn.SiLU(),
162
+ operations.Linear(
163
+ hidden_size * 4, hidden_size, bias=True, dtype=dtype, device=device
164
+ ),
165
+ )
166
+
167
+ # HUnYuanDiT Blocks
168
+ self.blocks = nn.ModuleList(
169
+ [
170
+ HunYuanDiTBlock(
171
+ hidden_size=hidden_size,
172
+ c_emb_size=hidden_size,
173
+ num_heads=num_heads,
174
+ mlp_ratio=mlp_ratio,
175
+ text_states_dim=self.text_states_dim,
176
+ qk_norm=qk_norm,
177
+ norm_type=self.norm,
178
+ skip=False,
179
+ attn_precision=attn_precision,
180
+ dtype=dtype,
181
+ device=device,
182
+ operations=operations,
183
+ )
184
+ for _ in range(19)
185
+ ]
186
+ )
187
+
188
+ # Input zero linear for the first block
189
+ self.before_proj = operations.Linear(self.hidden_size, self.hidden_size, dtype=dtype, device=device)
190
+
191
+
192
+ # Output zero linear for the every block
193
+ self.after_proj_list = nn.ModuleList(
194
+ [
195
+
196
+ operations.Linear(
197
+ self.hidden_size, self.hidden_size, dtype=dtype, device=device
198
+ )
199
+ for _ in range(len(self.blocks))
200
+ ]
201
+ )
202
+
203
+ def forward(
204
+ self,
205
+ x,
206
+ hint,
207
+ timesteps,
208
+ context,#encoder_hidden_states=None,
209
+ text_embedding_mask=None,
210
+ encoder_hidden_states_t5=None,
211
+ text_embedding_mask_t5=None,
212
+ image_meta_size=None,
213
+ style=None,
214
+ return_dict=False,
215
+ **kwarg,
216
+ ):
217
+ """
218
+ Forward pass of the encoder.
219
+
220
+ Parameters
221
+ ----------
222
+ x: torch.Tensor
223
+ (B, D, H, W)
224
+ t: torch.Tensor
225
+ (B)
226
+ encoder_hidden_states: torch.Tensor
227
+ CLIP text embedding, (B, L_clip, D)
228
+ text_embedding_mask: torch.Tensor
229
+ CLIP text embedding mask, (B, L_clip)
230
+ encoder_hidden_states_t5: torch.Tensor
231
+ T5 text embedding, (B, L_t5, D)
232
+ text_embedding_mask_t5: torch.Tensor
233
+ T5 text embedding mask, (B, L_t5)
234
+ image_meta_size: torch.Tensor
235
+ (B, 6)
236
+ style: torch.Tensor
237
+ (B)
238
+ cos_cis_img: torch.Tensor
239
+ sin_cis_img: torch.Tensor
240
+ return_dict: bool
241
+ Whether to return a dictionary.
242
+ """
243
+ condition = hint
244
+ if condition.shape[0] == 1:
245
+ condition = torch.repeat_interleave(condition, x.shape[0], dim=0)
246
+
247
+ text_states = context # 2,77,1024
248
+ text_states_t5 = encoder_hidden_states_t5 # 2,256,2048
249
+ text_states_mask = text_embedding_mask.bool() # 2,77
250
+ text_states_t5_mask = text_embedding_mask_t5.bool() # 2,256
251
+ b_t5, l_t5, c_t5 = text_states_t5.shape
252
+ text_states_t5 = self.mlp_t5(text_states_t5.view(-1, c_t5)).view(b_t5, l_t5, -1)
253
+
254
+ padding = comfy.ops.cast_to_input(self.text_embedding_padding, text_states)
255
+
256
+ text_states[:, -self.text_len :] = torch.where(
257
+ text_states_mask[:, -self.text_len :].unsqueeze(2),
258
+ text_states[:, -self.text_len :],
259
+ padding[: self.text_len],
260
+ )
261
+ text_states_t5[:, -self.text_len_t5 :] = torch.where(
262
+ text_states_t5_mask[:, -self.text_len_t5 :].unsqueeze(2),
263
+ text_states_t5[:, -self.text_len_t5 :],
264
+ padding[self.text_len :],
265
+ )
266
+
267
+ text_states = torch.cat([text_states, text_states_t5], dim=1) # 2,205,1024
268
+
269
+ # _, _, oh, ow = x.shape
270
+ # th, tw = oh // self.patch_size, ow // self.patch_size
271
+
272
+ # Get image RoPE embedding according to `reso`lution.
273
+ freqs_cis_img = calc_rope(
274
+ x, self.patch_size, self.hidden_size // self.num_heads
275
+ ) # (cos_cis_img, sin_cis_img)
276
+
277
+ # ========================= Build time and image embedding =========================
278
+ t = self.t_embedder(timesteps, dtype=self.dtype)
279
+ x = self.x_embedder(x)
280
+
281
+ # ========================= Concatenate all extra vectors =========================
282
+ # Build text tokens with pooling
283
+ extra_vec = self.pooler(encoder_hidden_states_t5)
284
+
285
+ # Build image meta size tokens if applicable
286
+ # if image_meta_size is not None:
287
+ # image_meta_size = timestep_embedding(image_meta_size.view(-1), 256) # [B * 6, 256]
288
+ # if image_meta_size.dtype != self.dtype:
289
+ # image_meta_size = image_meta_size.half()
290
+ # image_meta_size = image_meta_size.view(-1, 6 * 256)
291
+ # extra_vec = torch.cat([extra_vec, image_meta_size], dim=1) # [B, D + 6 * 256]
292
+
293
+ # Build style tokens
294
+ if style is not None:
295
+ style_embedding = self.style_embedder(style)
296
+ extra_vec = torch.cat([extra_vec, style_embedding], dim=1)
297
+
298
+ # Concatenate all extra vectors
299
+ c = t + self.extra_embedder(extra_vec) # [B, D]
300
+
301
+ # ========================= Deal with Condition =========================
302
+ condition = self.x_embedder(condition)
303
+
304
+ # ========================= Forward pass through HunYuanDiT blocks =========================
305
+ controls = []
306
+ x = x + self.before_proj(condition) # add condition
307
+ for layer, block in enumerate(self.blocks):
308
+ x = block(x, c, text_states, freqs_cis_img)
309
+ controls.append(self.after_proj_list[layer](x)) # zero linear for output
310
+
311
+ return {"output": controls}