don0726 commited on
Commit
3009db2
·
verified ·
1 Parent(s): 2553f0e

Upload 5 files

Browse files
meanvc2/__init__.py ADDED
File without changes
meanvc2/dit_kvcache.py ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ein notation:
3
+ b - batch
4
+ n - sequence
5
+ nt - text sequence
6
+ nw - raw wave length
7
+ d - dimension
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import torch
13
+ from torch import nn
14
+ import torch.nn.functional as F
15
+ from einops import rearrange
16
+
17
+ from x_transformers.x_transformers import RotaryEmbedding
18
+
19
+ # from src.model.prompt_vp import MRTE
20
+ from .model_modules import (
21
+ TimestepEmbedding,
22
+ ConvNeXtV2Block,
23
+ ConvPositionEmbedding,
24
+ AdaLayerNorm_Final,
25
+ precompute_freqs_cis,
26
+ get_pos_embed_indices,
27
+ )
28
+
29
+ from .modules_kvcache import (
30
+ DiTBlock,
31
+ ChunkDiTBlock,
32
+ )
33
+
34
+ class GlobalTimbreMemory(nn.Module):
35
+ """Global Timbre Memory (GTM)
36
+ Decomposes the global speaker embedding into K reusable timbre prototype slots.
37
+ A speaker-specific 2-layer MLP generates speaker-specific KV, fused with a universal prior.
38
+ """
39
+ def __init__(self, spk_dim=256, memory_slots=8, hidden_dim=256):
40
+ super().__init__()
41
+ self.memory_slots = memory_slots
42
+ self.hidden_dim = hidden_dim
43
+
44
+ # Speaker-specific mapping -- 2-layer MLP for increased expressiveness
45
+ self.mlp_k = nn.Sequential(
46
+ nn.Linear(spk_dim, spk_dim),
47
+ nn.SiLU(),
48
+ nn.Linear(spk_dim, memory_slots * hidden_dim),
49
+ )
50
+ self.mlp_v = nn.Sequential(
51
+ nn.Linear(spk_dim, spk_dim),
52
+ nn.SiLU(),
53
+ nn.Linear(spk_dim, memory_slots * hidden_dim),
54
+ )
55
+
56
+ # Universal speaker-agnostic prototypes (learns common pronunciation patterns), small-variance init
57
+ self.k_prior = nn.Parameter(torch.zeros(memory_slots, hidden_dim))
58
+ self.v_prior = nn.Parameter(torch.zeros(memory_slots, hidden_dim))
59
+ nn.init.normal_(self.k_prior, std=0.02)
60
+ nn.init.normal_(self.v_prior, std=0.02)
61
+
62
+ # LayerNorm after fusion for stable training
63
+ self.norm_k = nn.LayerNorm(hidden_dim)
64
+ self.norm_v = nn.LayerNorm(hidden_dim)
65
+
66
+ def forward(self, spks):
67
+ # spks: [B, spk_dim] static global speaker embedding
68
+ B = spks.shape[0]
69
+ # Generate speaker-specific key-value pairs
70
+ k_spk = self.mlp_k(spks).reshape(B, self.memory_slots, self.hidden_dim)
71
+ v_spk = self.mlp_v(spks).reshape(B, self.memory_slots, self.hidden_dim)
72
+ # Fuse with universal prototypes + LayerNorm
73
+ k = self.norm_k(k_spk + torch.tanh(self.k_prior).unsqueeze(0)) # [B, K, D]
74
+ v = self.norm_v(v_spk + torch.tanh(self.v_prior).unsqueeze(0)) # [B, K, D]
75
+ return k, v
76
+
77
+
78
+ class TemporalTimbreEncoder(nn.Module):
79
+ """Temporal Timbre Encoder (TVT processing block)
80
+ Frame-level content vectors serve as Query in Multi-Head Cross-Attention with GTM.
81
+ The resulting time-varying timbre features are fused with the global speaker embedding
82
+ via gated Slerp, preserving the unit hypersphere geometry of the speaker embedding.
83
+ """
84
+ def __init__(self, content_dim=256, hidden_dim=256, attn_dim=128, num_heads=4):
85
+ super().__init__()
86
+ self.num_heads = num_heads
87
+ self.head_dim = attn_dim // num_heads
88
+ assert attn_dim % num_heads == 0
89
+
90
+ # Multi-Head Cross-Attention projections
91
+ self.q_proj = nn.Linear(content_dim, attn_dim)
92
+ self.k_proj = nn.Linear(hidden_dim, attn_dim) # Input from GTM hidden_dim
93
+ self.v_proj = nn.Linear(hidden_dim, attn_dim) # Independent V projection
94
+ self.out_proj = nn.Linear(attn_dim, content_dim) # Output projection back to content_dim
95
+
96
+ self.attn_scale = self.head_dim ** -0.5
97
+ self.attn_norm = nn.LayerNorm(content_dim)
98
+
99
+
100
+ def forward(self, bn, k_mem, v_mem):
101
+ """Args:
102
+ bn: [B, T, content_dim] frame-level content features
103
+ k_mem: [B, K, hidden_dim] GTM keys
104
+ v_mem: [B, K, hidden_dim] GTM values
105
+ Returns:
106
+ timbre_cond: [B, T, content_dim] time-varying timbre conditioning
107
+ """
108
+ B, T, _ = bn.shape
109
+ K = k_mem.shape[1]
110
+
111
+ # ---- 1. Multi-Head Cross-Attention: content queries × GTM ----
112
+ q = self.q_proj(bn) # [B, T, attn_dim]
113
+ k = self.k_proj(k_mem) # [B, K, attn_dim]
114
+ v = self.v_proj(v_mem) # [B, K, attn_dim]
115
+
116
+ # reshape → [B, num_heads, seq_len, head_dim]
117
+ q = q.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
118
+ k = k.view(B, K, self.num_heads, self.head_dim).transpose(1, 2)
119
+ v = v.view(B, K, self.num_heads, self.head_dim).transpose(1, 2)
120
+
121
+ attn = torch.matmul(q, k.transpose(-2, -1)) * self.attn_scale # [B, H, T, K]
122
+ attn = torch.softmax(attn, dim=-1)
123
+ v_t = torch.matmul(attn, v) # [B, H, T, head_dim]
124
+
125
+ # merge heads -> output projection
126
+ v_t = v_t.transpose(1, 2).contiguous().view(B, T, -1) # [B, T, attn_dim]
127
+ timbre_cond = self.attn_norm(self.out_proj(v_t)) # [B, T, content_dim]
128
+
129
+ return timbre_cond
130
+
131
+ class InputEmbedding(nn.Module):
132
+ def __init__(self, mel_dim, cond_dim, out_dim):
133
+ super().__init__()
134
+ self.proj = nn.Linear(mel_dim + cond_dim * 2, out_dim)
135
+ # self.conv_pos_embed = ConvPositionEmbedding(dim=out_dim)
136
+
137
+ def forward(self, x: float["b n d"], cond: float["b n d"], spks: float["b n d"], drop_audio_cond=False): # noqa: F722
138
+ # def forward(self, x: float["b n d"], cond: float["b n d"], timbre_cond: float["b n d"], drop_audio_cond=False): # noqa: F722
139
+ if drop_audio_cond: # cfg for cond audio
140
+ cond = torch.zeros_like(cond)
141
+ spks = torch.zeros_like(spks)
142
+
143
+ x = self.proj(torch.cat((x, cond, spks), dim=-1))
144
+ # x = self.conv_pos_embed(x) + x
145
+ return x
146
+
147
+
148
+
149
+ # Transformer backbone using DiT blocks
150
+
151
+
152
+ class DiT(nn.Module):
153
+ def __init__(
154
+ self,
155
+ *,
156
+ dim,
157
+ depth=8,
158
+ heads=8,
159
+ dim_head=64,
160
+ dropout=0.1,
161
+ ff_mult=4,
162
+ mel_dim=80,
163
+ bn_dim=256,
164
+ qk_norm=None,
165
+ conv_layers=0,
166
+ chunk_size=8,
167
+ block_size=4,
168
+ pe_attn_head=None,
169
+ long_skip_connection=False,
170
+ checkpoint_activations=False,
171
+ forward_layers=[0], # Layer 0 allowed to look ahead
172
+ backward_layers=[0,1,2,3], # Layer 3 allowed to look behind
173
+ t_f_num=[1,0,0,0],
174
+ t_p_num=[2,2,1,1],
175
+ ):
176
+ super().__init__()
177
+
178
+ self.t_time_embed = TimestepEmbedding(dim)
179
+ self.r_time_embed = TimestepEmbedding(dim)
180
+ self.input_embed = InputEmbedding(mel_dim, bn_dim, dim)
181
+ self.rotary_embed = RotaryEmbedding(dim_head)
182
+
183
+ self.dim = dim
184
+ self.depth = depth
185
+
186
+ # GTM + TVT time-varying timbre module (replaces MRTE)
187
+ self.gtm = GlobalTimbreMemory(spk_dim=bn_dim, memory_slots=32, hidden_dim=bn_dim)
188
+ self.temporal_timbre = TemporalTimbreEncoder(
189
+ content_dim=bn_dim, hidden_dim=bn_dim,
190
+ attn_dim=128, num_heads=4,
191
+ )
192
+
193
+ forward_layers = set(forward_layers) if forward_layers else set()
194
+ backward_layers = set(backward_layers) if backward_layers else set()
195
+
196
+ self.transformer_blocks = nn.ModuleList(
197
+ [
198
+ ChunkDiTBlock(
199
+ dim=dim,
200
+ heads=heads,
201
+ dim_head=dim_head,
202
+ ff_mult=ff_mult,
203
+ dropout=dropout,
204
+ qk_norm=qk_norm,
205
+ chunk_size=chunk_size,
206
+ block_size=block_size,
207
+ pe_attn_head=pe_attn_head,
208
+ t_p=t_p_num[i] if i in backward_layers else 0, # backward
209
+ t_f=t_f_num[i] if i in forward_layers else 0, # forward
210
+ )
211
+ for i in range(depth)
212
+ ]
213
+ )
214
+ self.long_skip_connection = nn.Linear(dim * 2, dim, bias=False) if long_skip_connection else None
215
+
216
+ self.norm_out = AdaLayerNorm_Final(dim) # final modulation
217
+ self.proj_out = nn.Linear(dim, mel_dim)
218
+
219
+ self.checkpoint_activations = checkpoint_activations
220
+
221
+ self.initialize_weights()
222
+
223
+ def initialize_weights(self):
224
+ # Zero-out AdaLN layers in DiT blocks:
225
+ for block in self.transformer_blocks:
226
+ nn.init.constant_(block.attn_norm.linear.weight, 0)
227
+ nn.init.constant_(block.attn_norm.linear.bias, 0)
228
+
229
+ # Zero-out output layers:
230
+ nn.init.constant_(self.norm_out.linear.weight, 0)
231
+ nn.init.constant_(self.norm_out.linear.bias, 0)
232
+ nn.init.constant_(self.proj_out.weight, 0)
233
+ nn.init.constant_(self.proj_out.bias, 0)
234
+
235
+ def ckpt_wrapper(self, module):
236
+ # https://github.com/chuanyangjin/fast-DiT/blob/main/models.py
237
+ def ckpt_forward(*inputs):
238
+ outputs = module(*inputs)
239
+ return outputs
240
+
241
+ return ckpt_forward
242
+
243
+
244
+ def forward(
245
+ self,
246
+ x: float["b n d"], # nosied input audio # noqa: F722 B, T, 80
247
+ t: float["b"] | float[""], # time step # noqa: F821 F722
248
+ r: float["b"] | float[""], # time step # noqa: F821 F722
249
+ cache: float["b n d"],
250
+ cond: float["b n d"], # bn # noqa: F722 B, T, 256
251
+ spks: float["b d"], # spks # noqa: F722 B, 256
252
+ offset=0,
253
+ mask: bool["b n"] | None = None, # noqa: F722
254
+ is_inference: bool = False,
255
+ is_uncondition: bool = False,
256
+ cfg_mask: bool["b"] | None = None, # noqa: F722
257
+ kv_cache=None,
258
+ ):
259
+
260
+ batch, seq_len = x.shape[0], x.shape[1]
261
+
262
+ # ---- timestep embedding ----
263
+ t = self.t_time_embed(t)
264
+ r = self.r_time_embed(r)
265
+ t = t + r
266
+
267
+ # ---- GTM: global speaker embedding -> timbre memory key-value pairs ----
268
+ k_mem, v_mem = self.gtm(spks) # spks: [B, 256] -> k,v: [B, K, 256]
269
+
270
+ # ---- TVT: frame-level BN x GTM -> timbre-enhanced timbre_cond ----
271
+ timbre_cond = self.temporal_timbre(cond, k_mem, v_mem) # [B, T, bn_dim]
272
+
273
+ # Expand spks_global to frame level, as pure global identity condition (independent of timbre_cond)
274
+ spks_expanded = spks.unsqueeze(1).expand(-1, cond.shape[1], -1) # [B, T, spk_dim]
275
+
276
+ # ---- CFG masking ----
277
+ if cfg_mask is not None:
278
+ cfg_mask_ = rearrange(cfg_mask, "b -> b 1 1")
279
+ timbre_cond = torch.where(cfg_mask_, torch.zeros_like(timbre_cond), timbre_cond)
280
+ spks_expanded = torch.where(cfg_mask_, torch.zeros_like(spks_expanded), spks_expanded)
281
+
282
+ # Dual-path input: timbre_cond (content+timbre) + spks_expanded (pure global identity)
283
+ x = self.input_embed(x, timbre_cond, spks_expanded, drop_audio_cond=is_uncondition)
284
+
285
+ # train
286
+ if not is_inference:
287
+
288
+ rope = self.rotary_embed.forward_from_seq_len(seq_len)
289
+ # infer
290
+ else:
291
+ if cache != None:
292
+ cache = self.cache_embed(cache)
293
+ x = torch.concat((cache, x), dim=1) # [b, cache_len + seq_len, dim]
294
+
295
+ # inference does not need to consider mask
296
+ cache_len = cache.shape[1]
297
+ rope_cache = self.rotary_embed.forward_from_seq_len(cache_len)
298
+ rope_x = self.rotary_embed.forward_from_seq_len(offset + seq_len)
299
+ rope = (torch.concat((rope_cache[0], rope_x[0][:, -seq_len:, :]), dim=1), rope_cache[1])
300
+ else:
301
+ rope = self.rotary_embed.forward_from_seq_len(offset + seq_len)
302
+
303
+
304
+ if self.long_skip_connection is not None:
305
+ residual = x
306
+
307
+ new_kv_cache = []
308
+ # inner_hidden_states = []
309
+ for index_block, block in enumerate(self.transformer_blocks):
310
+ if kv_cache is not None:
311
+ block_kv_cache = kv_cache[index_block]
312
+ else:
313
+ block_kv_cache = None
314
+ if self.checkpoint_activations:
315
+ # https://pytorch.org/docs/stable/checkpoint.html#torch.utils.checkpoint.checkpoint
316
+ x, new_block_kv_cache = torch.utils.checkpoint.checkpoint(self.ckpt_wrapper(block), x, t, mask, rope, block_kv_cache, use_reentrant=False)
317
+ else:
318
+ x, new_block_kv_cache = block(x, t, mask=mask, rope=rope, is_inference=is_inference, kv_cache=block_kv_cache)
319
+ new_kv_cache.append(new_block_kv_cache)
320
+ if self.long_skip_connection is not None:
321
+ x = self.long_skip_connection(torch.cat((x, residual), dim=-1))
322
+
323
+
324
+ # x = x[:, -seq_len:, :]
325
+ x = self.norm_out(x, t)
326
+
327
+ output = self.proj_out(x)
328
+
329
+ return output, new_kv_cache
330
+
331
+
332
+
meanvc2/model_modules.py ADDED
@@ -0,0 +1,1040 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ein notation:
3
+ b - batch
4
+ n - sequence
5
+ nt - text sequence
6
+ nw - raw wave length
7
+ d - dimension
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import math
13
+ from typing import Optional
14
+
15
+ import torch
16
+ import torch.nn.functional as F
17
+ import torchaudio
18
+ from librosa.filters import mel as librosa_mel_fn
19
+ from torch import nn
20
+ from x_transformers.x_transformers import apply_rotary_pos_emb
21
+
22
+
23
+ # raw wav to mel spec
24
+
25
+
26
+ mel_basis_cache = {}
27
+ hann_window_cache = {}
28
+
29
+
30
+ def get_bigvgan_mel_spectrogram(
31
+ waveform,
32
+ n_fft=1024,
33
+ n_mel_channels=100,
34
+ target_sample_rate=24000,
35
+ hop_length=256,
36
+ win_length=1024,
37
+ fmin=0,
38
+ fmax=None,
39
+ center=False,
40
+ ): # Copy from https://github.com/NVIDIA/BigVGAN/tree/main
41
+ device = waveform.device
42
+ key = f"{n_fft}_{n_mel_channels}_{target_sample_rate}_{hop_length}_{win_length}_{fmin}_{fmax}_{device}"
43
+
44
+ if key not in mel_basis_cache:
45
+ mel = librosa_mel_fn(sr=target_sample_rate, n_fft=n_fft, n_mels=n_mel_channels, fmin=fmin, fmax=fmax)
46
+ mel_basis_cache[key] = torch.from_numpy(mel).float().to(device) # TODO: why they need .float()?
47
+ hann_window_cache[key] = torch.hann_window(win_length).to(device)
48
+
49
+ mel_basis = mel_basis_cache[key]
50
+ hann_window = hann_window_cache[key]
51
+
52
+ padding = (n_fft - hop_length) // 2
53
+ waveform = torch.nn.functional.pad(waveform.unsqueeze(1), (padding, padding), mode="reflect").squeeze(1)
54
+
55
+ spec = torch.stft(
56
+ waveform,
57
+ n_fft,
58
+ hop_length=hop_length,
59
+ win_length=win_length,
60
+ window=hann_window,
61
+ center=center,
62
+ pad_mode="reflect",
63
+ normalized=False,
64
+ onesided=True,
65
+ return_complex=True,
66
+ )
67
+ spec = torch.sqrt(torch.view_as_real(spec).pow(2).sum(-1) + 1e-9)
68
+
69
+ mel_spec = torch.matmul(mel_basis, spec)
70
+ mel_spec = torch.log(torch.clamp(mel_spec, min=1e-5))
71
+
72
+ return mel_spec
73
+
74
+
75
+ def get_vocos_mel_spectrogram(
76
+ waveform,
77
+ n_fft=1024,
78
+ n_mel_channels=100,
79
+ target_sample_rate=24000,
80
+ hop_length=256,
81
+ win_length=1024,
82
+ ):
83
+ mel_stft = torchaudio.transforms.MelSpectrogram(
84
+ sample_rate=target_sample_rate,
85
+ n_fft=n_fft,
86
+ win_length=win_length,
87
+ hop_length=hop_length,
88
+ n_mels=n_mel_channels,
89
+ power=1,
90
+ center=True,
91
+ normalized=False,
92
+ norm=None,
93
+ ).to(waveform.device)
94
+ if len(waveform.shape) == 3:
95
+ waveform = waveform.squeeze(1) # 'b 1 nw -> b nw'
96
+
97
+ assert len(waveform.shape) == 2
98
+
99
+ mel = mel_stft(waveform)
100
+ mel = mel.clamp(min=1e-5).log()
101
+ return mel
102
+
103
+
104
+ class MelSpec(nn.Module):
105
+ def __init__(
106
+ self,
107
+ n_fft=1024,
108
+ hop_length=256,
109
+ win_length=1024,
110
+ n_mel_channels=100,
111
+ target_sample_rate=24_000,
112
+ mel_spec_type="vocos",
113
+ ):
114
+ super().__init__()
115
+ assert mel_spec_type in ["vocos", "bigvgan"], print("We only support two extract mel backend: vocos or bigvgan")
116
+
117
+ self.n_fft = n_fft
118
+ self.hop_length = hop_length
119
+ self.win_length = win_length
120
+ self.n_mel_channels = n_mel_channels
121
+ self.target_sample_rate = target_sample_rate
122
+
123
+ if mel_spec_type == "vocos":
124
+ self.extractor = get_vocos_mel_spectrogram
125
+ elif mel_spec_type == "bigvgan":
126
+ self.extractor = get_bigvgan_mel_spectrogram
127
+
128
+ self.register_buffer("dummy", torch.tensor(0), persistent=False)
129
+
130
+ def forward(self, wav):
131
+ if self.dummy.device != wav.device:
132
+ self.to(wav.device)
133
+
134
+ mel = self.extractor(
135
+ waveform=wav,
136
+ n_fft=self.n_fft,
137
+ n_mel_channels=self.n_mel_channels,
138
+ target_sample_rate=self.target_sample_rate,
139
+ hop_length=self.hop_length,
140
+ win_length=self.win_length,
141
+ )
142
+
143
+ return mel
144
+
145
+
146
+ # sinusoidal position embedding
147
+
148
+
149
+ class SinusPositionEmbedding(nn.Module):
150
+ def __init__(self, dim):
151
+ super().__init__()
152
+ self.dim = dim
153
+
154
+ def forward(self, x, scale=1000):
155
+ device = x.device
156
+ half_dim = self.dim // 2
157
+ emb = math.log(10000) / (half_dim - 1)
158
+ emb = torch.exp(torch.arange(half_dim, device=device).float() * -emb)
159
+ emb = scale * x.unsqueeze(1) * emb.unsqueeze(0)
160
+ emb = torch.cat((emb.sin(), emb.cos()), dim=-1)
161
+ return emb
162
+
163
+
164
+ # convolutional position embedding
165
+
166
+
167
+ class ConvPositionEmbedding(nn.Module):
168
+ def __init__(self, dim, kernel_size=31, groups=16):
169
+ super().__init__()
170
+ assert kernel_size % 2 != 0
171
+ self.conv1d = nn.Sequential(
172
+ nn.Conv1d(dim, dim, kernel_size, groups=groups, padding=kernel_size // 2),
173
+ nn.Mish(),
174
+ nn.Conv1d(dim, dim, kernel_size, groups=groups, padding=kernel_size // 2),
175
+ nn.Mish(),
176
+ )
177
+
178
+ def forward(self, x: float["b n d"], mask: bool["b n"] | None = None): # noqa: F722
179
+ if mask is not None:
180
+ mask = mask[..., None]
181
+ x = x.masked_fill(~mask, 0.0)
182
+
183
+ x = x.permute(0, 2, 1)
184
+ x = self.conv1d(x)
185
+ out = x.permute(0, 2, 1)
186
+
187
+ if mask is not None:
188
+ out = out.masked_fill(~mask, 0.0)
189
+
190
+ return out
191
+
192
+
193
+ # rotary positional embedding related
194
+
195
+
196
+ def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0, theta_rescale_factor=1.0):
197
+ # proposed by reddit user bloc97, to rescale rotary embeddings to longer sequence length without fine-tuning
198
+ # has some connection to NTK literature
199
+ # https://www.reddit.com/r/LocalLLaMA/comments/14lz7j5/ntkaware_scaled_rope_allows_llama_models_to_have/
200
+ # https://github.com/lucidrains/rotary-embedding-torch/blob/main/rotary_embedding_torch/rotary_embedding_torch.py
201
+ theta *= theta_rescale_factor ** (dim / (dim - 2))
202
+ freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
203
+ t = torch.arange(end, device=freqs.device) # type: ignore
204
+ freqs = torch.outer(t, freqs).float() # type: ignore
205
+ freqs_cos = torch.cos(freqs) # real part
206
+ freqs_sin = torch.sin(freqs) # imaginary part
207
+ return torch.cat([freqs_cos, freqs_sin], dim=-1)
208
+
209
+
210
+ def get_pos_embed_indices(start, length, max_pos, scale=1.0):
211
+ # length = length if isinstance(length, int) else length.max()
212
+ scale = scale * torch.ones_like(start, dtype=torch.float32) # in case scale is a scalar
213
+ pos = (
214
+ start.unsqueeze(1)
215
+ + (torch.arange(length, device=start.device, dtype=torch.float32).unsqueeze(0) * scale.unsqueeze(1)).long()
216
+ )
217
+ # avoid extra long error.
218
+ pos = torch.where(pos < max_pos, pos, max_pos - 1)
219
+ return pos
220
+
221
+
222
+ # Global Response Normalization layer (Instance Normalization ?)
223
+
224
+
225
+ class GRN(nn.Module):
226
+ def __init__(self, dim):
227
+ super().__init__()
228
+ self.gamma = nn.Parameter(torch.zeros(1, 1, dim))
229
+ self.beta = nn.Parameter(torch.zeros(1, 1, dim))
230
+
231
+ def forward(self, x):
232
+ Gx = torch.norm(x, p=2, dim=1, keepdim=True)
233
+ Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)
234
+ return self.gamma * (x * Nx) + self.beta + x
235
+
236
+
237
+ # ConvNeXt-V2 Block https://github.com/facebookresearch/ConvNeXt-V2/blob/main/models/convnextv2.py
238
+ # ref: https://github.com/bfs18/e2_tts/blob/main/rfwave/modules.py#L108
239
+
240
+
241
+ class ConvNeXtV2Block(nn.Module):
242
+ def __init__(
243
+ self,
244
+ dim: int,
245
+ intermediate_dim: int,
246
+ dilation: int = 1,
247
+ ):
248
+ super().__init__()
249
+ padding = (dilation * (7 - 1)) // 2
250
+ self.dwconv = nn.Conv1d(
251
+ dim, dim, kernel_size=7, padding=padding, groups=dim, dilation=dilation
252
+ ) # depthwise conv
253
+ self.norm = nn.LayerNorm(dim, eps=1e-6)
254
+ self.pwconv1 = nn.Linear(dim, intermediate_dim) # pointwise/1x1 convs, implemented with linear layers
255
+ self.act = nn.GELU()
256
+ self.grn = GRN(intermediate_dim)
257
+ self.pwconv2 = nn.Linear(intermediate_dim, dim)
258
+
259
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
260
+ residual = x
261
+ x = x.transpose(1, 2) # b n d -> b d n
262
+ x = self.dwconv(x)
263
+ x = x.transpose(1, 2) # b d n -> b n d
264
+ x = self.norm(x)
265
+ x = self.pwconv1(x)
266
+ x = self.act(x)
267
+ x = self.grn(x)
268
+ x = self.pwconv2(x)
269
+ return residual + x
270
+
271
+
272
+ # RMSNorm
273
+
274
+
275
+ class RMSNorm(nn.Module):
276
+ def __init__(self, dim: int, eps: float):
277
+ super().__init__()
278
+ self.eps = eps
279
+ self.weight = nn.Parameter(torch.ones(dim))
280
+ self.native_rms_norm = float(torch.__version__[:3]) >= 2.4
281
+
282
+ def forward(self, x):
283
+ if self.native_rms_norm:
284
+ if self.weight.dtype in [torch.float16, torch.bfloat16]:
285
+ x = x.to(self.weight.dtype)
286
+ x = F.rms_norm(x, normalized_shape=(x.shape[-1],), weight=self.weight, eps=self.eps)
287
+ else:
288
+ variance = x.to(torch.float32).pow(2).mean(-1, keepdim=True)
289
+ x = x * torch.rsqrt(variance + self.eps)
290
+ if self.weight.dtype in [torch.float16, torch.bfloat16]:
291
+ x = x.to(self.weight.dtype)
292
+ x = x * self.weight
293
+
294
+ return x
295
+
296
+
297
+ # AdaLayerNorm
298
+ # return with modulated x for attn input, and params for later mlp modulation
299
+
300
+
301
+ class AdaLayerNorm(nn.Module):
302
+ def __init__(self, dim):
303
+ super().__init__()
304
+
305
+ self.silu = nn.SiLU()
306
+ self.linear = nn.Linear(dim, dim * 6)
307
+
308
+ self.norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
309
+
310
+ def forward(self, x, emb=None):
311
+ emb = self.linear(self.silu(emb))
312
+ shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = torch.chunk(emb, 6, dim=1)
313
+
314
+ x = self.norm(x) * (1 + scale_msa[:, None]) + shift_msa[:, None]
315
+ return x, gate_msa, shift_mlp, scale_mlp, gate_mlp
316
+
317
+
318
+ # AdaLayerNorm for final layer
319
+ # return only with modulated x for attn input, cuz no more mlp modulation
320
+
321
+
322
+ class AdaLayerNorm_Final(nn.Module):
323
+ def __init__(self, dim):
324
+ super().__init__()
325
+
326
+ self.silu = nn.SiLU()
327
+ self.linear = nn.Linear(dim, dim * 2)
328
+
329
+ self.norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
330
+
331
+ def forward(self, x, emb):
332
+ emb = self.linear(self.silu(emb))
333
+ scale, shift = torch.chunk(emb, 2, dim=1)
334
+
335
+ x = self.norm(x) * (1 + scale)[:, None, :] + shift[:, None, :]
336
+ return x
337
+
338
+
339
+ # FeedForward
340
+
341
+
342
+ class FeedForward(nn.Module):
343
+ def __init__(self, dim, dim_out=None, mult=4, dropout=0.0, approximate: str = "none"):
344
+ super().__init__()
345
+ inner_dim = int(dim * mult)
346
+ dim_out = dim_out if dim_out is not None else dim
347
+
348
+ activation = nn.GELU(approximate=approximate)
349
+ project_in = nn.Sequential(nn.Linear(dim, inner_dim), activation)
350
+ self.ff = nn.Sequential(project_in, nn.Dropout(dropout), nn.Linear(inner_dim, dim_out))
351
+
352
+ def forward(self, x):
353
+ return self.ff(x)
354
+
355
+
356
+ # Attention with possible joint part
357
+ # modified from diffusers/src/diffusers/models/attention_processor.py
358
+
359
+
360
+ class Attention(nn.Module):
361
+ def __init__(
362
+ self,
363
+ processor: JointAttnProcessor | AttnProcessor | ChunkAttnProcessor | BlockAttnProcessor,
364
+ dim: int,
365
+ heads: int = 8,
366
+ dim_head: int = 64,
367
+ dropout: float = 0.0,
368
+ context_dim: Optional[int] = None, # if not None -> joint attention
369
+ context_pre_only: bool = False,
370
+ qk_norm: Optional[str] = None,
371
+ ):
372
+ super().__init__()
373
+
374
+ if not hasattr(F, "scaled_dot_product_attention"):
375
+ raise ImportError("Attention equires PyTorch 2.0, to use it, please upgrade PyTorch to 2.0.")
376
+
377
+ self.processor = processor
378
+
379
+ self.dim = dim
380
+ self.heads = heads
381
+ self.inner_dim = dim_head * heads
382
+ self.dropout = dropout
383
+
384
+ self.context_dim = context_dim
385
+ self.context_pre_only = context_pre_only
386
+
387
+ self.to_q = nn.Linear(dim, self.inner_dim)
388
+ self.to_k = nn.Linear(dim, self.inner_dim)
389
+ self.to_v = nn.Linear(dim, self.inner_dim)
390
+
391
+ if qk_norm is None:
392
+ self.q_norm = None
393
+ self.k_norm = None
394
+ elif qk_norm == "rms_norm":
395
+ self.q_norm = RMSNorm(dim_head, eps=1e-6)
396
+ self.k_norm = RMSNorm(dim_head, eps=1e-6)
397
+ else:
398
+ raise ValueError(f"Unimplemented qk_norm: {qk_norm}")
399
+
400
+ if self.context_dim is not None:
401
+ self.to_q_c = nn.Linear(context_dim, self.inner_dim)
402
+ self.to_k_c = nn.Linear(context_dim, self.inner_dim)
403
+ self.to_v_c = nn.Linear(context_dim, self.inner_dim)
404
+ if qk_norm is None:
405
+ self.c_q_norm = None
406
+ self.c_k_norm = None
407
+ elif qk_norm == "rms_norm":
408
+ self.c_q_norm = RMSNorm(dim_head, eps=1e-6)
409
+ self.c_k_norm = RMSNorm(dim_head, eps=1e-6)
410
+
411
+ self.to_out = nn.ModuleList([])
412
+ self.to_out.append(nn.Linear(self.inner_dim, dim))
413
+ self.to_out.append(nn.Dropout(dropout))
414
+
415
+ if self.context_dim is not None and not self.context_pre_only:
416
+ self.to_out_c = nn.Linear(self.inner_dim, context_dim)
417
+
418
+ def forward(
419
+ self,
420
+ x: float["b n d"], # noised input x # noqa: F722
421
+ c: float["b n d"] = None, # context c # noqa: F722
422
+ mask: bool["b n"] | None = None, # noqa: F722
423
+ rope=None, # rotary position embedding for x
424
+ c_rope=None, # rotary position embedding for c
425
+ is_inference=False,
426
+ ) -> torch.Tensor:
427
+ if c is not None:
428
+ return self.processor(self, x, c=c, mask=mask, rope=rope, c_rope=c_rope, is_inference=is_inference)
429
+ else:
430
+ return self.processor(self, x, mask=mask, rope=rope, is_inference=is_inference)
431
+
432
+
433
+ # Attention processor
434
+
435
+
436
+ class AttnProcessor:
437
+ def __init__(
438
+ self,
439
+ pe_attn_head: int | None = None, # number of attention head to apply rope, None for all
440
+ ):
441
+
442
+ self.pe_attn_head = pe_attn_head
443
+
444
+ def __call__(
445
+ self,
446
+ attn: Attention,
447
+ x: float["b n d"], # noised input x # noqa: F722
448
+ mask: bool["b n"] | None = None, # noqa: F722
449
+ rope=None, # rotary position embedding
450
+ ) -> torch.FloatTensor:
451
+ batch_size = x.shape[0]
452
+
453
+ # `sample` projections
454
+ query = attn.to_q(x)
455
+ key = attn.to_k(x)
456
+ value = attn.to_v(x)
457
+
458
+ # attention
459
+ inner_dim = key.shape[-1]
460
+ head_dim = inner_dim // attn.heads
461
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
462
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
463
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
464
+
465
+ # qk norm
466
+ if attn.q_norm is not None:
467
+ query = attn.q_norm(query)
468
+ if attn.k_norm is not None:
469
+ key = attn.k_norm(key)
470
+
471
+ # apply rotary position embedding
472
+ if rope is not None:
473
+ freqs, xpos_scale = rope
474
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
475
+
476
+ if self.pe_attn_head is not None:
477
+ pn = self.pe_attn_head
478
+ query[:, :pn, :, :] = apply_rotary_pos_emb(query[:, :pn, :, :], freqs, q_xpos_scale)
479
+ key[:, :pn, :, :] = apply_rotary_pos_emb(key[:, :pn, :, :], freqs, k_xpos_scale)
480
+ else:
481
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
482
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
483
+
484
+ # mask. e.g. inference got a batch with different target durations, mask out the padding
485
+ if mask is not None:
486
+ attn_mask = mask
487
+ attn_mask = attn_mask.unsqueeze(1).unsqueeze(1) # 'b n -> b 1 1 n'
488
+ attn_mask = attn_mask.expand(batch_size, attn.heads, query.shape[-2], key.shape[-2])
489
+ else:
490
+ attn_mask = None
491
+
492
+ x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
493
+ # x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=True)
494
+ x = x.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
495
+ x = x.to(query.dtype)
496
+
497
+ # linear proj
498
+ x = attn.to_out[0](x)
499
+ # dropout
500
+ x = attn.to_out[1](x)
501
+
502
+ if mask is not None:
503
+ mask = mask.unsqueeze(-1)
504
+ x = x.masked_fill(~mask, 0.0)
505
+
506
+ return x
507
+
508
+ def scaled_dot_product_attention_only(query, key, value, attn_mask=None, dropout_p=0.0,
509
+ is_causal=False, scale=None, enable_gqa=False) -> torch.Tensor:
510
+
511
+ L, S = query.size(-2), key.size(-2)
512
+ B = query.size(0)
513
+ scale_factor = 1 / math.sqrt(query.size(-1)) if scale is None else scale
514
+ attn_bias = torch.zeros(B, 1, L, S, dtype=query.dtype, device=query.device)
515
+ if is_causal:
516
+ assert attn_mask is None
517
+ temp_mask = torch.ones(B, 1, L, S, dtype=torch.bool).tril(diagonal=0)
518
+ attn_bias.masked_fill_(temp_mask.logical_not(), float("-inf"))
519
+ attn_bias.to(query.dtype)
520
+
521
+ if attn_mask is not None:
522
+ if attn_mask.dtype == torch.bool:
523
+ attn_bias.masked_fill_(attn_mask.logical_not(), float("-inf"))
524
+ else:
525
+ attn_bias = attn_mask + attn_bias
526
+
527
+ if enable_gqa:
528
+ key = key.repeat_interleave(query.size(-3)//key.size(-3), -3)
529
+ value = value.repeat_interleave(query.size(-3)//value.size(-3), -3)
530
+
531
+ attn_weight = query @ key.transpose(-2, -1) * scale_factor
532
+ attn_weight += attn_bias
533
+ attn_weight = torch.softmax(attn_weight, dim=-1)
534
+ attn_weight = torch.dropout(attn_weight, dropout_p, train=True)
535
+ return attn_weight @ value
536
+
537
+ class BlockAttnProcessor:
538
+ def __init__(self, chunk_size: int, block_size: int, t_p: int, t_f: int, pe_attn_head: int | None = None,):
539
+ """
540
+ Args:
541
+ chunk_size (int): Number of tokens per chunk
542
+ block_size (int): Number of tokens per block.
543
+ t_p (int): Number of past chunks to attend to
544
+ t_f (int): Number of leading blocks in the future chunk to attend to
545
+ """
546
+ self.pe_attn_head = pe_attn_head
547
+ self.chunk_size = chunk_size
548
+ self.block_size = block_size
549
+ self.t_p = t_p
550
+ self.t_f = t_f
551
+
552
+ def try_cached_mask(self, seq_len, device):
553
+ idx = torch.arange(seq_len, device=device)
554
+ ci = idx // self.chunk_size
555
+
556
+ qi = ci[:, None]
557
+ kj = ci[None, :]
558
+
559
+ # Within the same chunk
560
+ same_chunk = (qi == kj)
561
+
562
+ # Previous t_p chunks
563
+ # prev_chunk = (kj == (qi - self.t_p))
564
+ prev_chunk = (kj >= (qi - self.t_p)) & (kj < qi)
565
+
566
+ # First t_f blocks of the next chunk
567
+ # First compute key(j)'s offset within its own chunk; this offset is bounded by block_size * t_f
568
+ offset_in_chunk = (idx % self.chunk_size)[None, :]
569
+ next_chunk_first_block = (kj == (qi + 1)) & (offset_in_chunk < self.block_size * self.t_f)
570
+
571
+ computed_mask = same_chunk | prev_chunk | next_chunk_first_block
572
+
573
+ return computed_mask
574
+
575
+ def __call__(
576
+ self,
577
+ attn: Attention,
578
+ x: float["b n d"], # noised input x # noqa: F722
579
+ mask: bool["b n"] | None = None, # noqa: F722
580
+ rope=None, # rotary position embedding
581
+ is_inference=False,
582
+ ) -> torch.FloatTensor:
583
+
584
+ batch_size, seq_len, _ = x.shape
585
+ device = x.device
586
+
587
+ # 1. Compute query, key, value projections
588
+ query = attn.to_q(x) # Linear layer expands dims [b, n, d * heads]
589
+ key = attn.to_k(x)
590
+ value = attn.to_v(x) #torch.Size([batch, seq, 1024])
591
+
592
+ ## 3. Reshape query, key, value into multi-head format: [batch, heads, seq_len, head_dim] attention
593
+ inner_dim = key.shape[-1] # d * heads
594
+ head_dim = inner_dim // attn.heads
595
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) # [b, heads, n, d]
596
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
597
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
598
+
599
+ # qk norm
600
+ if attn.q_norm is not None:
601
+ query = attn.q_norm(query)
602
+ if attn.k_norm is not None:
603
+ key = attn.k_norm(key)
604
+
605
+
606
+ # apply rotary position embedding
607
+ # Apply rotary position encoding to q and k
608
+ if rope is not None:
609
+ freqs, xpos_scale = rope
610
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
611
+
612
+ if self.pe_attn_head is not None:
613
+ pn = self.pe_attn_head
614
+ query[:, :pn, :, :] = apply_rotary_pos_emb(query[:, :pn, :, :], freqs, q_xpos_scale)
615
+ key[:, :pn, :, :] = apply_rotary_pos_emb(key[:, :pn, :, :], freqs, k_xpos_scale)
616
+ else:
617
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
618
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
619
+
620
+ # [b, i, j] = True means token i can attend to token j,
621
+ # [b, i, j] = False means token i cannot attend to token j,
622
+ computed_mask = self.try_cached_mask(seq_len,device).unsqueeze(0).expand(batch_size, -1, -1) # [b, seq_len, seq_len]
623
+
624
+ # 4.5 Expand the final mask to multi-head dimensions; shape becomes [batch, heads, seq_len, seq_len] #torch.Size([2, 16, 636, 636])
625
+ attn_mask = computed_mask.unsqueeze(1).expand(batch_size, 1, seq_len, seq_len)
626
+
627
+ # 5. Call PyTorch 2.0 scaled_dot_product_attention
628
+ attn_output = scaled_dot_product_attention_only(
629
+ query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False
630
+ )#attn_mask.to(query.dtype)
631
+ # attn_output shape: [batch, heads, seq_len, head_dim]
632
+
633
+ # 6. Restore shape; concatenate multi-head back to original dims [batch, seq_len, inner_dim]
634
+ attn_output = attn_output.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
635
+ attn_output = attn_output.to(query.dtype)
636
+
637
+ # 7. Pass through output projection and dropout
638
+ attn_output = attn.to_out[0](attn_output)
639
+ attn_output = attn.to_out[1](attn_output)
640
+
641
+ # Expand mask to [batch, seq_len, 1] and zero out the output accordingly
642
+ if mask is not None:
643
+ mask = mask.unsqueeze(-1)
644
+ attn_output = attn_output.masked_fill(~mask, 0.0)
645
+
646
+ return attn_output
647
+
648
+ class ChunkAttnProcessor:
649
+ def __init__(
650
+ self,
651
+ chunk_size: int,
652
+ pe_attn_head=None, # number of attention head to apply rope, None for all
653
+ ):
654
+ self.chunk_size = chunk_size
655
+ self.pe_attn_head = pe_attn_head
656
+
657
+ def __call__(
658
+ self,
659
+ attn: Attention,
660
+ x: float["b 2*N*chunk_size d"], # noised input x # noqa: F722
661
+ mask: bool["b n"] | None = None, # noqa: F722
662
+ rope=None, # rotary position embedding
663
+ is_inference=False,
664
+ ) -> torch.FloatTensor:
665
+ batch_size, seq_len, _ = x.shape
666
+
667
+ # `sample` projections
668
+ query = attn.to_q(x)
669
+ key = attn.to_k(x)
670
+ value = attn.to_v(x)
671
+
672
+ # attention
673
+ inner_dim = key.shape[-1]
674
+ head_dim = inner_dim // attn.heads
675
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
676
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
677
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
678
+
679
+ # qk norm
680
+ if attn.q_norm is not None:
681
+ query = attn.q_norm(query)
682
+ if attn.k_norm is not None:
683
+ key = attn.k_norm(key)
684
+
685
+ # apply rotary position embedding
686
+ if rope is not None:
687
+ freqs, xpos_scale = rope
688
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
689
+
690
+ if self.pe_attn_head is not None:
691
+ pn = self.pe_attn_head
692
+ query[:, :pn, :, :] = apply_rotary_pos_emb(query[:, :pn, :, :], freqs, q_xpos_scale)
693
+ key[:, :pn, :, :] = apply_rotary_pos_emb(key[:, :pn, :, :], freqs, k_xpos_scale)
694
+ else:
695
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
696
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
697
+
698
+ indices = torch.arange(seq_len, device=x.device)
699
+ chunk_indices = indices // self.chunk_size
700
+ N = int(seq_len / 2 / self.chunk_size)
701
+
702
+ # attn_mask_1 = chunk_indices.unsqueeze(0) <= chunk_indices.unsqueeze(1)
703
+ # attn_mask_2 = (chunk_indices.unsqueeze(0) + N < chunk_indices.unsqueeze(1)) | (chunk_indices.unsqueeze(0) == chunk_indices.unsqueeze(1))
704
+ # attn_mask = attn_mask_1 & attn_mask_2
705
+
706
+ # Generate left/right side identifiers (left side = first N*chunk_size frames)
707
+ is_right_side = indices >= (N * self.chunk_size)
708
+
709
+ # Left blocks (M_i) can attend to <= current block's left blocks
710
+ # left_mask = chunk_indices.unsqueeze(0) <= chunk_indices.unsqueeze(1)
711
+
712
+ # Right blocks (M'_i) can only attend to left clean blocks (all M_j, j < i) and itself
713
+ # right_mask = (
714
+ # (chunk_indices.unsqueeze(0) < (chunk_indices.unsqueeze(1) - N)) | # Access left clean blocks
715
+ # (chunk_indices.unsqueeze(0) == chunk_indices.unsqueeze(1)) # Access itself
716
+ # )
717
+
718
+ max_lookback = 5
719
+ num_cache_blocks = N # N
720
+
721
+ # 3. Expand dims for broadcasting
722
+ ci = chunk_indices.unsqueeze(0) # [L,1], row: chunk the query position belongs to ??? shouldn't it be [1, L]?
723
+ cj = chunk_indices.unsqueeze(1) # [1,L], col: chunk the key position belongs to ??? shouldn't it be [L, 1]?
724
+
725
+ # 4. Compute relative new block index: for block j, rel_j = cj - N; only rel_j >= 0 is a new block
726
+ rel_j = cj - num_cache_blocks # [1,L]
727
+
728
+ # 5. Self-attention: token can always attend to itself
729
+ mask_self = ci == cj # [L,L]
730
+
731
+ mask_cache = (
732
+ (rel_j >= 0) &
733
+ (ci < num_cache_blocks) &
734
+ (ci < rel_j) &
735
+ (ci >= rel_j - max_lookback)
736
+ )
737
+
738
+ right_mask = mask_self | mask_cache # [L,L] boolean matrix
739
+
740
+
741
+ lookback_k = 5 # Look back at most 5 previous blocks + self = 6 blocks total
742
+ block_diff = cj - ci
743
+ left_mask = (block_diff >= 0) & (block_diff <= lookback_k)
744
+
745
+ # Combine masks
746
+ if not is_inference:
747
+ # attn_mask = torch.where(
748
+ # is_right_side.unsqueeze(1), # Apply right_mask to right-side blocks
749
+ # right_mask,
750
+ # left_mask, # Apply left_mask to left-side blocks
751
+ # )
752
+ attn_mask = right_mask
753
+ else:
754
+ attn_mask = left_mask
755
+
756
+
757
+ if mask is not None:
758
+ pad_mask = mask.unsqueeze(1) & mask.unsqueeze(2) | torch.eye(seq_len, device=x.device).unsqueeze(0).bool()
759
+ attn_mask = attn_mask.unsqueeze(0).expand(batch_size, -1, -1) & pad_mask
760
+ else:
761
+ attn_mask = attn_mask.unsqueeze(0).expand(batch_size, -1, -1)
762
+
763
+ attn_mask = attn_mask.unsqueeze(1).expand(batch_size, 1, seq_len, seq_len)
764
+
765
+ # x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
766
+ x = scaled_dot_product_attention_only(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
767
+ # x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=True)
768
+ x = x.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
769
+ x = x.to(query.dtype)
770
+
771
+ # linear proj
772
+ x = attn.to_out[0](x)
773
+ # dropout
774
+ x = attn.to_out[1](x)
775
+
776
+ if mask is not None:
777
+ mask = mask.unsqueeze(-1)
778
+ x = x.masked_fill(~mask, 0.0)
779
+
780
+ return x
781
+
782
+ # Joint Attention processor for MM-DiT
783
+ # modified from diffusers/src/diffusers/models/attention_processor.py
784
+
785
+
786
+ class JointAttnProcessor:
787
+ def __init__(self):
788
+ pass
789
+
790
+ def __call__(
791
+ self,
792
+ attn: Attention,
793
+ x: float["b n d"], # noised input x # noqa: F722
794
+ c: float["b nt d"] = None, # context c, here text # noqa: F722
795
+ mask: bool["b n"] | None = None, # noqa: F722
796
+ rope=None, # rotary position embedding for x
797
+ c_rope=None, # rotary position embedding for c
798
+ ) -> torch.FloatTensor:
799
+ residual = x
800
+
801
+ batch_size = c.shape[0]
802
+
803
+ # `sample` projections
804
+ query = attn.to_q(x)
805
+ key = attn.to_k(x)
806
+ value = attn.to_v(x)
807
+
808
+ # `context` projections
809
+ c_query = attn.to_q_c(c)
810
+ c_key = attn.to_k_c(c)
811
+ c_value = attn.to_v_c(c)
812
+
813
+ # attention
814
+ inner_dim = key.shape[-1]
815
+ head_dim = inner_dim // attn.heads
816
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
817
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
818
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
819
+ c_query = c_query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
820
+ c_key = c_key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
821
+ c_value = c_value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
822
+
823
+ # qk norm
824
+ if attn.q_norm is not None:
825
+ query = attn.q_norm(query)
826
+ if attn.k_norm is not None:
827
+ key = attn.k_norm(key)
828
+ if attn.c_q_norm is not None:
829
+ c_query = attn.c_q_norm(c_query)
830
+ if attn.c_k_norm is not None:
831
+ c_key = attn.c_k_norm(c_key)
832
+
833
+ # apply rope for context and noised input independently
834
+ if rope is not None:
835
+ freqs, xpos_scale = rope
836
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
837
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
838
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
839
+ if c_rope is not None:
840
+ freqs, xpos_scale = c_rope
841
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
842
+ c_query = apply_rotary_pos_emb(c_query, freqs, q_xpos_scale)
843
+ c_key = apply_rotary_pos_emb(c_key, freqs, k_xpos_scale)
844
+
845
+ # joint attention
846
+ query = torch.cat([query, c_query], dim=2)
847
+ key = torch.cat([key, c_key], dim=2)
848
+ value = torch.cat([value, c_value], dim=2)
849
+
850
+ # mask. e.g. inference got a batch with different target durations, mask out the padding
851
+ if mask is not None:
852
+ attn_mask = F.pad(mask, (0, c.shape[1]), value=True) # no mask for c (text)
853
+ attn_mask = attn_mask.unsqueeze(1).unsqueeze(1) # 'b n -> b 1 1 n'
854
+ attn_mask = attn_mask.expand(batch_size, attn.heads, query.shape[-2], key.shape[-2])
855
+ else:
856
+ attn_mask = None
857
+
858
+ x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
859
+ x = x.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
860
+ x = x.to(query.dtype)
861
+
862
+ # Split the attention outputs.
863
+ x, c = (
864
+ x[:, : residual.shape[1]],
865
+ x[:, residual.shape[1] :],
866
+ )
867
+
868
+ # linear proj
869
+ x = attn.to_out[0](x)
870
+ # dropout
871
+ x = attn.to_out[1](x)
872
+ if not attn.context_pre_only:
873
+ c = attn.to_out_c(c)
874
+
875
+ if mask is not None:
876
+ mask = mask.unsqueeze(-1)
877
+ x = x.masked_fill(~mask, 0.0)
878
+ # c = c.masked_fill(~mask, 0.) # no mask for c (text)
879
+
880
+ return x, c
881
+
882
+
883
+ # DiT Block
884
+
885
+
886
+ class DiTBlock(nn.Module):
887
+ def __init__(self, dim, heads, dim_head, ff_mult=4, dropout=0.1, qk_norm=None, pe_attn_head=None):
888
+ super().__init__()
889
+
890
+ self.attn_norm = AdaLayerNorm(dim)
891
+ self.attn = Attention(
892
+ processor=AttnProcessor(pe_attn_head=pe_attn_head),
893
+ dim=dim,
894
+ heads=heads,
895
+ dim_head=dim_head,
896
+ dropout=dropout,
897
+ qk_norm=qk_norm,
898
+ )
899
+
900
+ self.ff_norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
901
+ self.ff = FeedForward(dim=dim, mult=ff_mult, dropout=dropout, approximate="tanh")
902
+
903
+ def forward(self, x, t, mask=None, rope=None): # x: noised input, t: time embedding
904
+ # pre-norm & modulation for attention input
905
+ norm, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.attn_norm(x, emb=t)
906
+
907
+ # attention
908
+ attn_output = self.attn(x=norm, mask=mask, rope=rope)
909
+
910
+ # process attention output for input x
911
+ x = x + gate_msa.unsqueeze(1) * attn_output
912
+
913
+ norm = self.ff_norm(x) * (1 + scale_mlp[:, None]) + shift_mlp[:, None]
914
+ ff_output = self.ff(norm)
915
+ x = x + gate_mlp.unsqueeze(1) * ff_output
916
+
917
+ return x
918
+
919
+
920
+ class ChunkDiTBlock(nn.Module):
921
+ def __init__(self, dim, heads, dim_head, ff_mult=4, dropout=0.1, qk_norm=None, chunk_size=16, block_size=8, t_p=0, t_f=0, pe_attn_head=None):
922
+ super().__init__()
923
+
924
+ self.attn_norm = AdaLayerNorm(dim)
925
+ self.attn = Attention(
926
+ processor=BlockAttnProcessor(chunk_size=chunk_size, block_size=block_size, t_p=t_p, t_f=t_f, pe_attn_head=pe_attn_head),
927
+ dim=dim,
928
+ heads=heads,
929
+ dim_head=dim_head,
930
+ dropout=dropout,
931
+ qk_norm=qk_norm,
932
+ )
933
+
934
+ self.ff_norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
935
+ self.ff = FeedForward(dim=dim, mult=ff_mult, dropout=dropout, approximate="tanh")
936
+
937
+ def forward(self, x, t, mask=None, rope=None, is_inference=False): # x: noised input, t: time embedding
938
+ # pre-norm & modulation for attention input
939
+ norm, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.attn_norm(x, emb=t)
940
+
941
+ # attention
942
+ attn_output = self.attn(x=norm, mask=mask, rope=rope, is_inference=is_inference)
943
+
944
+ # process attention output for input x
945
+ x = x + gate_msa.unsqueeze(1) * attn_output
946
+
947
+ norm = self.ff_norm(x) * (1 + scale_mlp[:, None]) + shift_mlp[:, None]
948
+ ff_output = self.ff(norm)
949
+ x = x + gate_mlp.unsqueeze(1) * ff_output
950
+
951
+ return x
952
+
953
+ # MMDiT Block https://arxiv.org/abs/2403.03206
954
+
955
+
956
+ class MMDiTBlock(nn.Module):
957
+ r"""
958
+ modified from diffusers/src/diffusers/models/attention.py
959
+
960
+ notes.
961
+ _c: context related. text, cond, etc. (left part in sd3 fig2.b)
962
+ _x: noised input related. (right part)
963
+ context_pre_only: last layer only do prenorm + modulation cuz no more ffn
964
+ """
965
+
966
+ def __init__(
967
+ self, dim, heads, dim_head, ff_mult=4, dropout=0.1, context_dim=None, context_pre_only=False, qk_norm=None
968
+ ):
969
+ super().__init__()
970
+ if context_dim is None:
971
+ context_dim = dim
972
+ self.context_pre_only = context_pre_only
973
+
974
+ self.attn_norm_c = AdaLayerNorm_Final(context_dim) if context_pre_only else AdaLayerNorm(context_dim)
975
+ self.attn_norm_x = AdaLayerNorm(dim)
976
+ self.attn = Attention(
977
+ processor=JointAttnProcessor(),
978
+ dim=dim,
979
+ heads=heads,
980
+ dim_head=dim_head,
981
+ dropout=dropout,
982
+ context_dim=context_dim,
983
+ context_pre_only=context_pre_only,
984
+ qk_norm=qk_norm,
985
+ )
986
+
987
+ if not context_pre_only:
988
+ self.ff_norm_c = nn.LayerNorm(context_dim, elementwise_affine=False, eps=1e-6)
989
+ self.ff_c = FeedForward(dim=context_dim, mult=ff_mult, dropout=dropout, approximate="tanh")
990
+ else:
991
+ self.ff_norm_c = None
992
+ self.ff_c = None
993
+ self.ff_norm_x = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
994
+ self.ff_x = FeedForward(dim=dim, mult=ff_mult, dropout=dropout, approximate="tanh")
995
+
996
+ def forward(self, x, c, t, mask=None, rope=None, c_rope=None): # x: noised input, c: context, t: time embedding
997
+ # pre-norm & modulation for attention input
998
+ if self.context_pre_only:
999
+ norm_c = self.attn_norm_c(c, t)
1000
+ else:
1001
+ norm_c, c_gate_msa, c_shift_mlp, c_scale_mlp, c_gate_mlp = self.attn_norm_c(c, emb=t)
1002
+ norm_x, x_gate_msa, x_shift_mlp, x_scale_mlp, x_gate_mlp = self.attn_norm_x(x, emb=t)
1003
+
1004
+ # attention
1005
+ x_attn_output, c_attn_output = self.attn(x=norm_x, c=norm_c, mask=mask, rope=rope, c_rope=c_rope)
1006
+
1007
+ # process attention output for context c
1008
+ if self.context_pre_only:
1009
+ c = None
1010
+ else: # if not last layer
1011
+ c = c + c_gate_msa.unsqueeze(1) * c_attn_output
1012
+
1013
+ norm_c = self.ff_norm_c(c) * (1 + c_scale_mlp[:, None]) + c_shift_mlp[:, None]
1014
+ c_ff_output = self.ff_c(norm_c)
1015
+ c = c + c_gate_mlp.unsqueeze(1) * c_ff_output
1016
+
1017
+ # process attention output for input x
1018
+ x = x + x_gate_msa.unsqueeze(1) * x_attn_output
1019
+
1020
+ norm_x = self.ff_norm_x(x) * (1 + x_scale_mlp[:, None]) + x_shift_mlp[:, None]
1021
+ x_ff_output = self.ff_x(norm_x)
1022
+ x = x + x_gate_mlp.unsqueeze(1) * x_ff_output
1023
+
1024
+ return c, x
1025
+
1026
+
1027
+ # time step conditioning embedding
1028
+
1029
+
1030
+ class TimestepEmbedding(nn.Module):
1031
+ def __init__(self, dim, freq_embed_dim=256):
1032
+ super().__init__()
1033
+ self.time_embed = SinusPositionEmbedding(freq_embed_dim)
1034
+ self.time_mlp = nn.Sequential(nn.Linear(freq_embed_dim, dim), nn.SiLU(), nn.Linear(dim, dim))
1035
+
1036
+ def forward(self, timestep: float["b"]): # noqa: F821
1037
+ time_hidden = self.time_embed(timestep)
1038
+ time_hidden = time_hidden.to(timestep.dtype)
1039
+ time = self.time_mlp(time_hidden) # b d
1040
+ return time
meanvc2/modules_kvcache.py ADDED
@@ -0,0 +1,1058 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ein notation:
3
+ b - batch
4
+ n - sequence
5
+ nt - text sequence
6
+ nw - raw wave length
7
+ d - dimension
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import math
13
+ from typing import Optional
14
+
15
+ import torch
16
+ import torch.nn.functional as F
17
+ import torchaudio
18
+ from librosa.filters import mel as librosa_mel_fn
19
+ from torch import nn
20
+ from x_transformers.x_transformers import apply_rotary_pos_emb
21
+
22
+
23
+ # raw wav to mel spec
24
+
25
+
26
+ mel_basis_cache = {}
27
+ hann_window_cache = {}
28
+
29
+
30
+ def get_bigvgan_mel_spectrogram(
31
+ waveform,
32
+ n_fft=1024,
33
+ n_mel_channels=100,
34
+ target_sample_rate=24000,
35
+ hop_length=256,
36
+ win_length=1024,
37
+ fmin=0,
38
+ fmax=None,
39
+ center=False,
40
+ ): # Copy from https://github.com/NVIDIA/BigVGAN/tree/main
41
+ device = waveform.device
42
+ key = f"{n_fft}_{n_mel_channels}_{target_sample_rate}_{hop_length}_{win_length}_{fmin}_{fmax}_{device}"
43
+
44
+ if key not in mel_basis_cache:
45
+ mel = librosa_mel_fn(sr=target_sample_rate, n_fft=n_fft, n_mels=n_mel_channels, fmin=fmin, fmax=fmax)
46
+ mel_basis_cache[key] = torch.from_numpy(mel).float().to(device) # TODO: why they need .float()?
47
+ hann_window_cache[key] = torch.hann_window(win_length).to(device)
48
+
49
+ mel_basis = mel_basis_cache[key]
50
+ hann_window = hann_window_cache[key]
51
+
52
+ padding = (n_fft - hop_length) // 2
53
+ waveform = torch.nn.functional.pad(waveform.unsqueeze(1), (padding, padding), mode="reflect").squeeze(1)
54
+
55
+ spec = torch.stft(
56
+ waveform,
57
+ n_fft,
58
+ hop_length=hop_length,
59
+ win_length=win_length,
60
+ window=hann_window,
61
+ center=center,
62
+ pad_mode="reflect",
63
+ normalized=False,
64
+ onesided=True,
65
+ return_complex=True,
66
+ )
67
+ spec = torch.sqrt(torch.view_as_real(spec).pow(2).sum(-1) + 1e-9)
68
+
69
+ mel_spec = torch.matmul(mel_basis, spec)
70
+ mel_spec = torch.log(torch.clamp(mel_spec, min=1e-5))
71
+
72
+ return mel_spec
73
+
74
+
75
+ def get_vocos_mel_spectrogram(
76
+ waveform,
77
+ n_fft=1024,
78
+ n_mel_channels=100,
79
+ target_sample_rate=24000,
80
+ hop_length=256,
81
+ win_length=1024,
82
+ ):
83
+ mel_stft = torchaudio.transforms.MelSpectrogram(
84
+ sample_rate=target_sample_rate,
85
+ n_fft=n_fft,
86
+ win_length=win_length,
87
+ hop_length=hop_length,
88
+ n_mels=n_mel_channels,
89
+ power=1,
90
+ center=True,
91
+ normalized=False,
92
+ norm=None,
93
+ ).to(waveform.device)
94
+ if len(waveform.shape) == 3:
95
+ waveform = waveform.squeeze(1) # 'b 1 nw -> b nw'
96
+
97
+ assert len(waveform.shape) == 2
98
+
99
+ mel = mel_stft(waveform)
100
+ mel = mel.clamp(min=1e-5).log()
101
+ return mel
102
+
103
+
104
+ class MelSpec(nn.Module):
105
+ def __init__(
106
+ self,
107
+ n_fft=1024,
108
+ hop_length=256,
109
+ win_length=1024,
110
+ n_mel_channels=100,
111
+ target_sample_rate=24_000,
112
+ mel_spec_type="vocos",
113
+ ):
114
+ super().__init__()
115
+ assert mel_spec_type in ["vocos", "bigvgan"], print("We only support two extract mel backend: vocos or bigvgan")
116
+
117
+ self.n_fft = n_fft
118
+ self.hop_length = hop_length
119
+ self.win_length = win_length
120
+ self.n_mel_channels = n_mel_channels
121
+ self.target_sample_rate = target_sample_rate
122
+
123
+ if mel_spec_type == "vocos":
124
+ self.extractor = get_vocos_mel_spectrogram
125
+ elif mel_spec_type == "bigvgan":
126
+ self.extractor = get_bigvgan_mel_spectrogram
127
+
128
+ self.register_buffer("dummy", torch.tensor(0), persistent=False)
129
+
130
+ def forward(self, wav):
131
+ if self.dummy.device != wav.device:
132
+ self.to(wav.device)
133
+
134
+ mel = self.extractor(
135
+ waveform=wav,
136
+ n_fft=self.n_fft,
137
+ n_mel_channels=self.n_mel_channels,
138
+ target_sample_rate=self.target_sample_rate,
139
+ hop_length=self.hop_length,
140
+ win_length=self.win_length,
141
+ )
142
+
143
+ return mel
144
+
145
+
146
+ # sinusoidal position embedding
147
+
148
+
149
+ class SinusPositionEmbedding(nn.Module):
150
+ def __init__(self, dim):
151
+ super().__init__()
152
+ self.dim = dim
153
+
154
+ def forward(self, x, scale=1000):
155
+ device = x.device
156
+ half_dim = self.dim // 2
157
+ emb = math.log(10000) / (half_dim - 1)
158
+ emb = torch.exp(torch.arange(half_dim, device=device).float() * -emb)
159
+ emb = scale * x.unsqueeze(1) * emb.unsqueeze(0)
160
+ emb = torch.cat((emb.sin(), emb.cos()), dim=-1)
161
+ return emb
162
+
163
+
164
+ # convolutional position embedding
165
+
166
+
167
+ class ConvPositionEmbedding(nn.Module):
168
+ def __init__(self, dim, kernel_size=31, groups=16):
169
+ super().__init__()
170
+ assert kernel_size % 2 != 0
171
+ self.conv1d = nn.Sequential(
172
+ nn.Conv1d(dim, dim, kernel_size, groups=groups, padding=kernel_size // 2),
173
+ nn.Mish(),
174
+ nn.Conv1d(dim, dim, kernel_size, groups=groups, padding=kernel_size // 2),
175
+ nn.Mish(),
176
+ )
177
+
178
+ def forward(self, x: float["b n d"], mask: bool["b n"] | None = None): # noqa: F722
179
+ if mask is not None:
180
+ mask = mask[..., None]
181
+ x = x.masked_fill(~mask, 0.0)
182
+
183
+ x = x.permute(0, 2, 1)
184
+ x = self.conv1d(x)
185
+ out = x.permute(0, 2, 1)
186
+
187
+ if mask is not None:
188
+ out = out.masked_fill(~mask, 0.0)
189
+
190
+ return out
191
+
192
+
193
+ # rotary positional embedding related
194
+
195
+
196
+ def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0, theta_rescale_factor=1.0):
197
+ # proposed by reddit user bloc97, to rescale rotary embeddings to longer sequence length without fine-tuning
198
+ # has some connection to NTK literature
199
+ # https://www.reddit.com/r/LocalLLaMA/comments/14lz7j5/ntkaware_scaled_rope_allows_llama_models_to_have/
200
+ # https://github.com/lucidrains/rotary-embedding-torch/blob/main/rotary_embedding_torch/rotary_embedding_torch.py
201
+ theta *= theta_rescale_factor ** (dim / (dim - 2))
202
+ freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
203
+ t = torch.arange(end, device=freqs.device) # type: ignore
204
+ freqs = torch.outer(t, freqs).float() # type: ignore
205
+ freqs_cos = torch.cos(freqs) # real part
206
+ freqs_sin = torch.sin(freqs) # imaginary part
207
+ return torch.cat([freqs_cos, freqs_sin], dim=-1)
208
+
209
+
210
+ def get_pos_embed_indices(start, length, max_pos, scale=1.0):
211
+ # length = length if isinstance(length, int) else length.max()
212
+ scale = scale * torch.ones_like(start, dtype=torch.float32) # in case scale is a scalar
213
+ pos = (
214
+ start.unsqueeze(1)
215
+ + (torch.arange(length, device=start.device, dtype=torch.float32).unsqueeze(0) * scale.unsqueeze(1)).long()
216
+ )
217
+ # avoid extra long error.
218
+ pos = torch.where(pos < max_pos, pos, max_pos - 1)
219
+ return pos
220
+
221
+
222
+ # Global Response Normalization layer (Instance Normalization ?)
223
+
224
+
225
+ class GRN(nn.Module):
226
+ def __init__(self, dim):
227
+ super().__init__()
228
+ self.gamma = nn.Parameter(torch.zeros(1, 1, dim))
229
+ self.beta = nn.Parameter(torch.zeros(1, 1, dim))
230
+
231
+ def forward(self, x):
232
+ Gx = torch.norm(x, p=2, dim=1, keepdim=True)
233
+ Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)
234
+ return self.gamma * (x * Nx) + self.beta + x
235
+
236
+
237
+ # ConvNeXt-V2 Block https://github.com/facebookresearch/ConvNeXt-V2/blob/main/models/convnextv2.py
238
+ # ref: https://github.com/bfs18/e2_tts/blob/main/rfwave/modules.py#L108
239
+
240
+
241
+ class ConvNeXtV2Block(nn.Module):
242
+ def __init__(
243
+ self,
244
+ dim: int,
245
+ intermediate_dim: int,
246
+ dilation: int = 1,
247
+ ):
248
+ super().__init__()
249
+ padding = (dilation * (7 - 1)) // 2
250
+ self.dwconv = nn.Conv1d(
251
+ dim, dim, kernel_size=7, padding=padding, groups=dim, dilation=dilation
252
+ ) # depthwise conv
253
+ self.norm = nn.LayerNorm(dim, eps=1e-6)
254
+ self.pwconv1 = nn.Linear(dim, intermediate_dim) # pointwise/1x1 convs, implemented with linear layers
255
+ self.act = nn.GELU()
256
+ self.grn = GRN(intermediate_dim)
257
+ self.pwconv2 = nn.Linear(intermediate_dim, dim)
258
+
259
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
260
+ residual = x
261
+ x = x.transpose(1, 2) # b n d -> b d n
262
+ x = self.dwconv(x)
263
+ x = x.transpose(1, 2) # b d n -> b n d
264
+ x = self.norm(x)
265
+ x = self.pwconv1(x)
266
+ x = self.act(x)
267
+ x = self.grn(x)
268
+ x = self.pwconv2(x)
269
+ return residual + x
270
+
271
+
272
+ # RMSNorm
273
+
274
+
275
+ class RMSNorm(nn.Module):
276
+ def __init__(self, dim: int, eps: float):
277
+ super().__init__()
278
+ self.eps = eps
279
+ self.weight = nn.Parameter(torch.ones(dim))
280
+ self.native_rms_norm = float(torch.__version__[:3]) >= 2.4
281
+
282
+ def forward(self, x):
283
+ if self.native_rms_norm:
284
+ if self.weight.dtype in [torch.float16, torch.bfloat16]:
285
+ x = x.to(self.weight.dtype)
286
+ x = F.rms_norm(x, normalized_shape=(x.shape[-1],), weight=self.weight, eps=self.eps)
287
+ else:
288
+ variance = x.to(torch.float32).pow(2).mean(-1, keepdim=True)
289
+ x = x * torch.rsqrt(variance + self.eps)
290
+ if self.weight.dtype in [torch.float16, torch.bfloat16]:
291
+ x = x.to(self.weight.dtype)
292
+ x = x * self.weight
293
+
294
+ return x
295
+
296
+
297
+ # AdaLayerNorm
298
+ # return with modulated x for attn input, and params for later mlp modulation
299
+
300
+
301
+ class AdaLayerNorm(nn.Module):
302
+ def __init__(self, dim):
303
+ super().__init__()
304
+
305
+ self.silu = nn.SiLU()
306
+ self.linear = nn.Linear(dim, dim * 6)
307
+
308
+ self.norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
309
+
310
+ def forward(self, x, emb=None):
311
+ emb = self.linear(self.silu(emb))
312
+ shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = torch.chunk(emb, 6, dim=1)
313
+
314
+ x = self.norm(x) * (1 + scale_msa[:, None]) + shift_msa[:, None]
315
+ return x, gate_msa, shift_mlp, scale_mlp, gate_mlp
316
+
317
+
318
+ # AdaLayerNorm for final layer
319
+ # return only with modulated x for attn input, cuz no more mlp modulation
320
+
321
+
322
+ class AdaLayerNorm_Final(nn.Module):
323
+ def __init__(self, dim):
324
+ super().__init__()
325
+
326
+ self.silu = nn.SiLU()
327
+ self.linear = nn.Linear(dim, dim * 2)
328
+
329
+ self.norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
330
+
331
+ def forward(self, x, emb):
332
+ emb = self.linear(self.silu(emb))
333
+ scale, shift = torch.chunk(emb, 2, dim=1)
334
+
335
+ x = self.norm(x) * (1 + scale)[:, None, :] + shift[:, None, :]
336
+ return x
337
+
338
+
339
+ # FeedForward
340
+
341
+
342
+ class FeedForward(nn.Module):
343
+ def __init__(self, dim, dim_out=None, mult=4, dropout=0.0, approximate: str = "none"):
344
+ super().__init__()
345
+ inner_dim = int(dim * mult)
346
+ dim_out = dim_out if dim_out is not None else dim
347
+
348
+ activation = nn.GELU(approximate=approximate)
349
+ project_in = nn.Sequential(nn.Linear(dim, inner_dim), activation)
350
+ self.ff = nn.Sequential(project_in, nn.Dropout(dropout), nn.Linear(inner_dim, dim_out))
351
+
352
+ def forward(self, x):
353
+ return self.ff(x)
354
+
355
+
356
+ # Attention with possible joint part
357
+ # modified from diffusers/src/diffusers/models/attention_processor.py
358
+
359
+
360
+ class Attention(nn.Module):
361
+ def __init__(
362
+ self,
363
+ processor: JointAttnProcessor | AttnProcessor | ChunkAttnProcessor | BlockAttnProcessor,
364
+ dim: int,
365
+ heads: int = 8,
366
+ dim_head: int = 64,
367
+ dropout: float = 0.0,
368
+ context_dim: Optional[int] = None, # if not None -> joint attention
369
+ context_pre_only: bool = False,
370
+ qk_norm: Optional[str] = None,
371
+ ):
372
+ super().__init__()
373
+
374
+ if not hasattr(F, "scaled_dot_product_attention"):
375
+ raise ImportError("Attention equires PyTorch 2.0, to use it, please upgrade PyTorch to 2.0.")
376
+
377
+ self.processor = processor
378
+
379
+ self.dim = dim
380
+ self.heads = heads
381
+ self.inner_dim = dim_head * heads
382
+ self.dropout = dropout
383
+
384
+ self.context_dim = context_dim
385
+ self.context_pre_only = context_pre_only
386
+
387
+ self.to_q = nn.Linear(dim, self.inner_dim)
388
+ self.to_k = nn.Linear(dim, self.inner_dim)
389
+ self.to_v = nn.Linear(dim, self.inner_dim)
390
+
391
+ if qk_norm is None:
392
+ self.q_norm = None
393
+ self.k_norm = None
394
+ elif qk_norm == "rms_norm":
395
+ self.q_norm = RMSNorm(dim_head, eps=1e-6)
396
+ self.k_norm = RMSNorm(dim_head, eps=1e-6)
397
+ else:
398
+ raise ValueError(f"Unimplemented qk_norm: {qk_norm}")
399
+
400
+ if self.context_dim is not None:
401
+ self.to_q_c = nn.Linear(context_dim, self.inner_dim)
402
+ self.to_k_c = nn.Linear(context_dim, self.inner_dim)
403
+ self.to_v_c = nn.Linear(context_dim, self.inner_dim)
404
+ if qk_norm is None:
405
+ self.c_q_norm = None
406
+ self.c_k_norm = None
407
+ elif qk_norm == "rms_norm":
408
+ self.c_q_norm = RMSNorm(dim_head, eps=1e-6)
409
+ self.c_k_norm = RMSNorm(dim_head, eps=1e-6)
410
+
411
+ self.to_out = nn.ModuleList([])
412
+ self.to_out.append(nn.Linear(self.inner_dim, dim))
413
+ self.to_out.append(nn.Dropout(dropout))
414
+
415
+ if self.context_dim is not None and not self.context_pre_only:
416
+ self.to_out_c = nn.Linear(self.inner_dim, context_dim)
417
+
418
+ def forward(
419
+ self,
420
+ x: float["b n d"], # noised input x # noqa: F722
421
+ c: float["b n d"] = None, # context c # noqa: F722
422
+ mask: bool["b n"] | None = None, # noqa: F722
423
+ rope=None, # rotary position embedding for x
424
+ c_rope=None, # rotary position embedding for c
425
+ is_inference=False,
426
+ kv_cache=None,
427
+ ) -> torch.Tensor:
428
+ if c is not None:
429
+ return self.processor(self, x, c=c, mask=mask, rope=rope, c_rope=c_rope, is_inference=is_inference, kv_cache=kv_cache)
430
+ else:
431
+ return self.processor(self, x, mask=mask, rope=rope, is_inference=is_inference, kv_cache=kv_cache)
432
+
433
+
434
+ # Attention processor
435
+
436
+
437
+ class AttnProcessor:
438
+ def __init__(
439
+ self,
440
+ pe_attn_head: int | None = None, # number of attention head to apply rope, None for all
441
+ ):
442
+
443
+ self.pe_attn_head = pe_attn_head
444
+
445
+ def __call__(
446
+ self,
447
+ attn: Attention,
448
+ x: float["b n d"], # noised input x # noqa: F722
449
+ mask: bool["b n"] | None = None, # noqa: F722
450
+ rope=None, # rotary position embedding
451
+ ) -> torch.FloatTensor:
452
+ batch_size = x.shape[0]
453
+
454
+ # `sample` projections
455
+ query = attn.to_q(x)
456
+ key = attn.to_k(x)
457
+ value = attn.to_v(x)
458
+
459
+ # attention
460
+ inner_dim = key.shape[-1]
461
+ head_dim = inner_dim // attn.heads
462
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
463
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
464
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
465
+
466
+ # qk norm
467
+ if attn.q_norm is not None:
468
+ query = attn.q_norm(query)
469
+ if attn.k_norm is not None:
470
+ key = attn.k_norm(key)
471
+
472
+ # apply rotary position embedding
473
+ if rope is not None:
474
+ freqs, xpos_scale = rope
475
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
476
+
477
+ if self.pe_attn_head is not None:
478
+ pn = self.pe_attn_head
479
+ query[:, :pn, :, :] = apply_rotary_pos_emb(query[:, :pn, :, :], freqs, q_xpos_scale)
480
+ key[:, :pn, :, :] = apply_rotary_pos_emb(key[:, :pn, :, :], freqs, k_xpos_scale)
481
+ else:
482
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
483
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
484
+
485
+ # mask. e.g. inference got a batch with different target durations, mask out the padding
486
+ if mask is not None:
487
+ attn_mask = mask
488
+ attn_mask = attn_mask.unsqueeze(1).unsqueeze(1) # 'b n -> b 1 1 n'
489
+ attn_mask = attn_mask.expand(batch_size, attn.heads, query.shape[-2], key.shape[-2])
490
+ else:
491
+ attn_mask = None
492
+
493
+ x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
494
+ # x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=True)
495
+ x = x.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
496
+ x = x.to(query.dtype)
497
+
498
+ # linear proj
499
+ x = attn.to_out[0](x)
500
+ # dropout
501
+ x = attn.to_out[1](x)
502
+
503
+ if mask is not None:
504
+ mask = mask.unsqueeze(-1)
505
+ x = x.masked_fill(~mask, 0.0)
506
+
507
+ return x
508
+
509
+ def scaled_dot_product_attention_only(query, key, value, attn_mask=None, dropout_p=0.0,
510
+ is_causal=False, scale=None, enable_gqa=False) -> torch.Tensor:
511
+
512
+ L, S = query.size(-2), key.size(-2)
513
+ B = query.size(0)
514
+ scale_factor = 1 / math.sqrt(query.size(-1)) if scale is None else scale
515
+ attn_bias = torch.zeros(B, 1, L, S, dtype=query.dtype, device=query.device)
516
+ if is_causal:
517
+ assert attn_mask is None
518
+ temp_mask = torch.ones(B, 1, L, S, dtype=torch.bool).tril(diagonal=0)
519
+ attn_bias.masked_fill_(temp_mask.logical_not(), float("-inf"))
520
+ attn_bias.to(query.dtype)
521
+
522
+ if attn_mask is not None:
523
+ if attn_mask.dtype == torch.bool:
524
+ attn_bias.masked_fill_(attn_mask[:,:,-attn_bias.shape[2]:,:].logical_not(), float("-inf"))
525
+ else:
526
+ attn_bias = attn_mask + attn_bias
527
+
528
+ if enable_gqa:
529
+ key = key.repeat_interleave(query.size(-3)//key.size(-3), -3)
530
+ value = value.repeat_interleave(query.size(-3)//value.size(-3), -3)
531
+
532
+ attn_weight = query @ key.transpose(-2, -1) * scale_factor
533
+ attn_weight += attn_bias
534
+ attn_weight = torch.softmax(attn_weight, dim=-1)
535
+ attn_weight = torch.dropout(attn_weight, dropout_p, train=True)
536
+ return attn_weight @ value
537
+
538
+ class BlockAttnProcessor:
539
+ def __init__(self, chunk_size: int, block_size: int, t_p: int, t_f: int, pe_attn_head: int | None = None,):
540
+ """
541
+ Args:
542
+ chunk_size (int): Number of tokens per chunk
543
+ block_size (int): Number of tokens per block.
544
+ t_p (int): Number of past chunks to attend to
545
+ t_f (int): Number of leading blocks in the future chunk to attend to
546
+ """
547
+ self.pe_attn_head = pe_attn_head
548
+ self.chunk_size = chunk_size
549
+ self.block_size = block_size
550
+ self.t_p = t_p
551
+ self.t_f = t_f
552
+
553
+ def try_cached_mask(self, seq_len, device):
554
+ idx = torch.arange(seq_len, device=device)
555
+ ci = idx // self.chunk_size
556
+
557
+ qi = ci[:, None]
558
+ kj = ci[None, :]
559
+
560
+ # Within the same chunk
561
+ same_chunk = (qi == kj)
562
+
563
+ # Previous t_p chunks
564
+ # prev_chunk = (kj == (qi - self.t_p))
565
+ prev_chunk = (kj >= (qi - self.t_p)) & (kj < qi)
566
+
567
+ # First t_f blocks of the next chunk
568
+ # First compute key(j)'s offset within its own chunk; this offset is bounded by block_size * t_f
569
+ offset_in_chunk = (idx % self.chunk_size)[None, :]
570
+ next_chunk_first_block = (kj == (qi + 1)) & (offset_in_chunk < self.block_size * self.t_f)
571
+
572
+ computed_mask = same_chunk | prev_chunk | next_chunk_first_block
573
+
574
+ return computed_mask
575
+
576
+ def __call__(
577
+ self,
578
+ attn: Attention,
579
+ x: float["b n d"], # noised input x # noqa: F722
580
+ mask: bool["b n"] | None = None, # noqa: F722
581
+ rope=None, # rotary position embedding
582
+ is_inference=False,
583
+ kv_cache=None,
584
+ ) -> torch.FloatTensor:
585
+
586
+ # batch_size, seq_len, _ = x.shape
587
+ batch_size = x.shape[0]
588
+ device = x.device
589
+
590
+ # 1. Compute query, key, value projections
591
+ query = attn.to_q(x) # Linear layer expands dims [b, n, d * heads]
592
+ key = attn.to_k(x)
593
+ value = attn.to_v(x) #torch.Size([batch, seq, 1024])
594
+
595
+ ## 3. Reshape query, key, value into multi-head format: [batch, heads, seq_len, head_dim] attention
596
+ inner_dim = key.shape[-1] # d * heads
597
+ head_dim = inner_dim // attn.heads
598
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2) # [b, heads, n, d]
599
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
600
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
601
+
602
+ # qk norm
603
+ if attn.q_norm is not None:
604
+ query = attn.q_norm(query)
605
+ if attn.k_norm is not None:
606
+ key = attn.k_norm(key)
607
+
608
+ # kvcache
609
+ if kv_cache is None:
610
+ key_cache = None
611
+ value_cache = None
612
+ else:
613
+ key_cache, value_cache = kv_cache
614
+
615
+ if kv_cache is not None:
616
+ key = torch.cat([key_cache, key], dim=2)
617
+ if value_cache is not None:
618
+ value = torch.cat([value_cache, value], dim=2)
619
+
620
+ new_kv_cache = (key[:, :, :-self.block_size, :], value[:, :, :-self.block_size, :]) # Subsequent blocks are future info; do not cache them
621
+
622
+ batch_size, _, seq_len, _ = key.shape
623
+
624
+ # apply rotary position embedding
625
+ # Apply rotary position encoding to q and k
626
+ if rope is not None:
627
+ freqs, xpos_scale = rope
628
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
629
+
630
+ if self.pe_attn_head is not None:
631
+ pn = self.pe_attn_head
632
+ query[:, :pn, :, :] = apply_rotary_pos_emb(query[:, :pn, :, :], freqs, q_xpos_scale)
633
+ key[:, :pn, :, :] = apply_rotary_pos_emb(key[:, :pn, :, :], freqs, k_xpos_scale)
634
+ else:
635
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
636
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
637
+
638
+ # [b, i, j] = True means token i can attend to token j,
639
+ # [b, i, j] = False means token i cannot attend to token j,
640
+ computed_mask = self.try_cached_mask(seq_len,device).unsqueeze(0).expand(batch_size, -1, -1) # [b, seq_len, seq_len]
641
+
642
+ # 4.5 Expand the final mask to multi-head dimensions; shape becomes [batch, heads, seq_len, seq_len] #torch.Size([2, 16, 636, 636])
643
+ attn_mask = computed_mask.unsqueeze(1).expand(batch_size, 1, seq_len, seq_len)
644
+
645
+ # 5. Call PyTorch 2.0 scaled_dot_product_attention
646
+ attn_output = scaled_dot_product_attention_only(
647
+ query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False
648
+ )#attn_mask.to(query.dtype)
649
+ # attn_output shape: [batch, heads, seq_len, head_dim]
650
+
651
+ # 6. Restore shape; concatenate multi-head back to original dims [batch, seq_len, inner_dim]
652
+ attn_output = attn_output.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
653
+ attn_output = attn_output.to(query.dtype)
654
+
655
+ # 7. Pass through output projection and dropout
656
+ attn_output = attn.to_out[0](attn_output)
657
+ attn_output = attn.to_out[1](attn_output)
658
+
659
+ # Expand mask to [batch, seq_len, 1] and zero out the output accordingly
660
+ if mask is not None:
661
+ mask = mask.unsqueeze(-1)
662
+ attn_output = attn_output.masked_fill(~mask, 0.0)
663
+
664
+ return attn_output, new_kv_cache
665
+
666
+ class ChunkAttnProcessor:
667
+ def __init__(
668
+ self,
669
+ chunk_size: int,
670
+ pe_attn_head=None, # number of attention head to apply rope, None for all
671
+ ):
672
+ self.chunk_size = chunk_size
673
+ self.pe_attn_head = pe_attn_head
674
+
675
+ def __call__(
676
+ self,
677
+ attn: Attention,
678
+ x: float["b 2*N*chunk_size d"], # noised input x # noqa: F722
679
+ mask: bool["b n"] | None = None, # noqa: F722
680
+ rope=None, # rotary position embedding
681
+ is_inference=False,
682
+ ) -> torch.FloatTensor:
683
+ batch_size, seq_len, _ = x.shape
684
+
685
+ # `sample` projections
686
+ query = attn.to_q(x)
687
+ key = attn.to_k(x)
688
+ value = attn.to_v(x)
689
+
690
+ # attention
691
+ inner_dim = key.shape[-1]
692
+ head_dim = inner_dim // attn.heads
693
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
694
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
695
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
696
+
697
+ # qk norm
698
+ if attn.q_norm is not None:
699
+ query = attn.q_norm(query)
700
+ if attn.k_norm is not None:
701
+ key = attn.k_norm(key)
702
+
703
+ # apply rotary position embedding
704
+ if rope is not None:
705
+ freqs, xpos_scale = rope
706
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
707
+
708
+ if self.pe_attn_head is not None:
709
+ pn = self.pe_attn_head
710
+ query[:, :pn, :, :] = apply_rotary_pos_emb(query[:, :pn, :, :], freqs, q_xpos_scale)
711
+ key[:, :pn, :, :] = apply_rotary_pos_emb(key[:, :pn, :, :], freqs, k_xpos_scale)
712
+ else:
713
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
714
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
715
+
716
+ indices = torch.arange(seq_len, device=x.device)
717
+ chunk_indices = indices // self.chunk_size
718
+ N = int(seq_len / 2 / self.chunk_size)
719
+
720
+ # attn_mask_1 = chunk_indices.unsqueeze(0) <= chunk_indices.unsqueeze(1)
721
+ # attn_mask_2 = (chunk_indices.unsqueeze(0) + N < chunk_indices.unsqueeze(1)) | (chunk_indices.unsqueeze(0) == chunk_indices.unsqueeze(1))
722
+ # attn_mask = attn_mask_1 & attn_mask_2
723
+
724
+ # Generate left/right side identifiers (left side = first N*chunk_size frames)
725
+ is_right_side = indices >= (N * self.chunk_size)
726
+
727
+ # Left blocks (M_i) can attend to <= current block's left blocks
728
+ # left_mask = chunk_indices.unsqueeze(0) <= chunk_indices.unsqueeze(1)
729
+
730
+ # Right blocks (M'_i) can only attend to left clean blocks (all M_j, j < i) and itself
731
+ # right_mask = (
732
+ # (chunk_indices.unsqueeze(0) < (chunk_indices.unsqueeze(1) - N)) | # Access left clean blocks
733
+ # (chunk_indices.unsqueeze(0) == chunk_indices.unsqueeze(1)) # Access itself
734
+ # )
735
+
736
+ max_lookback = 5
737
+ num_cache_blocks = N # N
738
+
739
+ # 3. Expand dims for broadcasting
740
+ ci = chunk_indices.unsqueeze(0) # [L,1], row: chunk the query position belongs to ??? shouldn't it be [1, L]?
741
+ cj = chunk_indices.unsqueeze(1) # [1,L], col: chunk the key position belongs to ??? shouldn't it be [L, 1]?
742
+
743
+ # 4. Compute relative new block index: for block j, rel_j = cj - N; only rel_j >= 0 is a new block
744
+ rel_j = cj - num_cache_blocks # [1,L]
745
+
746
+ # 5. Self-attention: token can always attend to itself
747
+ mask_self = ci == cj # [L,L]
748
+
749
+ mask_cache = (
750
+ (rel_j >= 0) &
751
+ (ci < num_cache_blocks) &
752
+ (ci < rel_j) &
753
+ (ci >= rel_j - max_lookback)
754
+ )
755
+
756
+ right_mask = mask_self | mask_cache # [L,L] boolean matrix
757
+
758
+
759
+ lookback_k = 5 # Look back at most 5 previous blocks + self = 6 blocks total
760
+ block_diff = cj - ci
761
+ left_mask = (block_diff >= 0) & (block_diff <= lookback_k)
762
+
763
+ # Combine masks
764
+ if not is_inference:
765
+ # attn_mask = torch.where(
766
+ # is_right_side.unsqueeze(1), # Apply right_mask to right-side blocks
767
+ # right_mask,
768
+ # left_mask, # Apply left_mask to left-side blocks
769
+ # )
770
+ attn_mask = right_mask
771
+ else:
772
+ attn_mask = left_mask
773
+
774
+
775
+ if mask is not None:
776
+ pad_mask = mask.unsqueeze(1) & mask.unsqueeze(2) | torch.eye(seq_len, device=x.device).unsqueeze(0).bool()
777
+ attn_mask = attn_mask.unsqueeze(0).expand(batch_size, -1, -1) & pad_mask
778
+ else:
779
+ attn_mask = attn_mask.unsqueeze(0).expand(batch_size, -1, -1)
780
+
781
+ attn_mask = attn_mask.unsqueeze(1).expand(batch_size, 1, seq_len, seq_len)
782
+
783
+ # x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
784
+ x = scaled_dot_product_attention_only(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
785
+ # x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=True)
786
+ x = x.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
787
+ x = x.to(query.dtype)
788
+
789
+ # linear proj
790
+ x = attn.to_out[0](x)
791
+ # dropout
792
+ x = attn.to_out[1](x)
793
+
794
+ if mask is not None:
795
+ mask = mask.unsqueeze(-1)
796
+ x = x.masked_fill(~mask, 0.0)
797
+
798
+ return x
799
+
800
+ # Joint Attention processor for MM-DiT
801
+ # modified from diffusers/src/diffusers/models/attention_processor.py
802
+
803
+
804
+ class JointAttnProcessor:
805
+ def __init__(self):
806
+ pass
807
+
808
+ def __call__(
809
+ self,
810
+ attn: Attention,
811
+ x: float["b n d"], # noised input x # noqa: F722
812
+ c: float["b nt d"] = None, # context c, here text # noqa: F722
813
+ mask: bool["b n"] | None = None, # noqa: F722
814
+ rope=None, # rotary position embedding for x
815
+ c_rope=None, # rotary position embedding for c
816
+ ) -> torch.FloatTensor:
817
+ residual = x
818
+
819
+ batch_size = c.shape[0]
820
+
821
+ # `sample` projections
822
+ query = attn.to_q(x)
823
+ key = attn.to_k(x)
824
+ value = attn.to_v(x)
825
+
826
+ # `context` projections
827
+ c_query = attn.to_q_c(c)
828
+ c_key = attn.to_k_c(c)
829
+ c_value = attn.to_v_c(c)
830
+
831
+ # attention
832
+ inner_dim = key.shape[-1]
833
+ head_dim = inner_dim // attn.heads
834
+ query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
835
+ key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
836
+ value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
837
+ c_query = c_query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
838
+ c_key = c_key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
839
+ c_value = c_value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
840
+
841
+ # qk norm
842
+ if attn.q_norm is not None:
843
+ query = attn.q_norm(query)
844
+ if attn.k_norm is not None:
845
+ key = attn.k_norm(key)
846
+ if attn.c_q_norm is not None:
847
+ c_query = attn.c_q_norm(c_query)
848
+ if attn.c_k_norm is not None:
849
+ c_key = attn.c_k_norm(c_key)
850
+
851
+ # apply rope for context and noised input independently
852
+ if rope is not None:
853
+ freqs, xpos_scale = rope
854
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
855
+ query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
856
+ key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
857
+ if c_rope is not None:
858
+ freqs, xpos_scale = c_rope
859
+ q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
860
+ c_query = apply_rotary_pos_emb(c_query, freqs, q_xpos_scale)
861
+ c_key = apply_rotary_pos_emb(c_key, freqs, k_xpos_scale)
862
+
863
+ # joint attention
864
+ query = torch.cat([query, c_query], dim=2)
865
+ key = torch.cat([key, c_key], dim=2)
866
+ value = torch.cat([value, c_value], dim=2)
867
+
868
+ # mask. e.g. inference got a batch with different target durations, mask out the padding
869
+ if mask is not None:
870
+ attn_mask = F.pad(mask, (0, c.shape[1]), value=True) # no mask for c (text)
871
+ attn_mask = attn_mask.unsqueeze(1).unsqueeze(1) # 'b n -> b 1 1 n'
872
+ attn_mask = attn_mask.expand(batch_size, attn.heads, query.shape[-2], key.shape[-2])
873
+ else:
874
+ attn_mask = None
875
+
876
+ x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
877
+ x = x.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
878
+ x = x.to(query.dtype)
879
+
880
+ # Split the attention outputs.
881
+ x, c = (
882
+ x[:, : residual.shape[1]],
883
+ x[:, residual.shape[1] :],
884
+ )
885
+
886
+ # linear proj
887
+ x = attn.to_out[0](x)
888
+ # dropout
889
+ x = attn.to_out[1](x)
890
+ if not attn.context_pre_only:
891
+ c = attn.to_out_c(c)
892
+
893
+ if mask is not None:
894
+ mask = mask.unsqueeze(-1)
895
+ x = x.masked_fill(~mask, 0.0)
896
+ # c = c.masked_fill(~mask, 0.) # no mask for c (text)
897
+
898
+ return x, c
899
+
900
+
901
+ # DiT Block
902
+
903
+
904
+ class DiTBlock(nn.Module):
905
+ def __init__(self, dim, heads, dim_head, ff_mult=4, dropout=0.1, qk_norm=None, pe_attn_head=None):
906
+ super().__init__()
907
+
908
+ self.attn_norm = AdaLayerNorm(dim)
909
+ self.attn = Attention(
910
+ processor=AttnProcessor(pe_attn_head=pe_attn_head),
911
+ dim=dim,
912
+ heads=heads,
913
+ dim_head=dim_head,
914
+ dropout=dropout,
915
+ qk_norm=qk_norm,
916
+ )
917
+
918
+ self.ff_norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
919
+ self.ff = FeedForward(dim=dim, mult=ff_mult, dropout=dropout, approximate="tanh")
920
+
921
+ def forward(self, x, t, mask=None, rope=None): # x: noised input, t: time embedding
922
+ # pre-norm & modulation for attention input
923
+ norm, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.attn_norm(x, emb=t)
924
+
925
+ # attention
926
+ attn_output = self.attn(x=norm, mask=mask, rope=rope)
927
+
928
+ # process attention output for input x
929
+ x = x + gate_msa.unsqueeze(1) * attn_output
930
+
931
+ norm = self.ff_norm(x) * (1 + scale_mlp[:, None]) + shift_mlp[:, None]
932
+ ff_output = self.ff(norm)
933
+ x = x + gate_mlp.unsqueeze(1) * ff_output
934
+
935
+ return x
936
+
937
+
938
+ class ChunkDiTBlock(nn.Module):
939
+ def __init__(self, dim, heads, dim_head, ff_mult=4, dropout=0.1, qk_norm=None, chunk_size=16, block_size=8, t_p=0, t_f=0, pe_attn_head=None):
940
+ super().__init__()
941
+
942
+ self.attn_norm = AdaLayerNorm(dim)
943
+ self.attn = Attention(
944
+ processor=BlockAttnProcessor(chunk_size=chunk_size, block_size=block_size, t_p=t_p, t_f=t_f, pe_attn_head=pe_attn_head),
945
+ dim=dim,
946
+ heads=heads,
947
+ dim_head=dim_head,
948
+ dropout=dropout,
949
+ qk_norm=qk_norm,
950
+ )
951
+
952
+ self.ff_norm = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
953
+ self.ff = FeedForward(dim=dim, mult=ff_mult, dropout=dropout, approximate="tanh")
954
+
955
+ def forward(self, x, t, mask=None, rope=None, is_inference=False, kv_cache=None): # x: noised input, t: time embedding
956
+ # pre-norm & modulation for attention input
957
+ norm, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.attn_norm(x, emb=t)
958
+
959
+ # attention
960
+ attn_output, new_kv_cache = self.attn(x=norm, mask=mask, rope=rope, is_inference=is_inference, kv_cache=kv_cache)
961
+
962
+ # process attention output for input x
963
+ x = x + gate_msa.unsqueeze(1) * attn_output
964
+
965
+ norm = self.ff_norm(x) * (1 + scale_mlp[:, None]) + shift_mlp[:, None]
966
+ ff_output = self.ff(norm)
967
+ x = x + gate_mlp.unsqueeze(1) * ff_output
968
+
969
+ return x, new_kv_cache
970
+
971
+ # MMDiT Block https://arxiv.org/abs/2403.03206
972
+
973
+
974
+ class MMDiTBlock(nn.Module):
975
+ r"""
976
+ modified from diffusers/src/diffusers/models/attention.py
977
+
978
+ notes.
979
+ _c: context related. text, cond, etc. (left part in sd3 fig2.b)
980
+ _x: noised input related. (right part)
981
+ context_pre_only: last layer only do prenorm + modulation cuz no more ffn
982
+ """
983
+
984
+ def __init__(
985
+ self, dim, heads, dim_head, ff_mult=4, dropout=0.1, context_dim=None, context_pre_only=False, qk_norm=None
986
+ ):
987
+ super().__init__()
988
+ if context_dim is None:
989
+ context_dim = dim
990
+ self.context_pre_only = context_pre_only
991
+
992
+ self.attn_norm_c = AdaLayerNorm_Final(context_dim) if context_pre_only else AdaLayerNorm(context_dim)
993
+ self.attn_norm_x = AdaLayerNorm(dim)
994
+ self.attn = Attention(
995
+ processor=JointAttnProcessor(),
996
+ dim=dim,
997
+ heads=heads,
998
+ dim_head=dim_head,
999
+ dropout=dropout,
1000
+ context_dim=context_dim,
1001
+ context_pre_only=context_pre_only,
1002
+ qk_norm=qk_norm,
1003
+ )
1004
+
1005
+ if not context_pre_only:
1006
+ self.ff_norm_c = nn.LayerNorm(context_dim, elementwise_affine=False, eps=1e-6)
1007
+ self.ff_c = FeedForward(dim=context_dim, mult=ff_mult, dropout=dropout, approximate="tanh")
1008
+ else:
1009
+ self.ff_norm_c = None
1010
+ self.ff_c = None
1011
+ self.ff_norm_x = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
1012
+ self.ff_x = FeedForward(dim=dim, mult=ff_mult, dropout=dropout, approximate="tanh")
1013
+
1014
+ def forward(self, x, c, t, mask=None, rope=None, c_rope=None): # x: noised input, c: context, t: time embedding
1015
+ # pre-norm & modulation for attention input
1016
+ if self.context_pre_only:
1017
+ norm_c = self.attn_norm_c(c, t)
1018
+ else:
1019
+ norm_c, c_gate_msa, c_shift_mlp, c_scale_mlp, c_gate_mlp = self.attn_norm_c(c, emb=t)
1020
+ norm_x, x_gate_msa, x_shift_mlp, x_scale_mlp, x_gate_mlp = self.attn_norm_x(x, emb=t)
1021
+
1022
+ # attention
1023
+ x_attn_output, c_attn_output = self.attn(x=norm_x, c=norm_c, mask=mask, rope=rope, c_rope=c_rope)
1024
+
1025
+ # process attention output for context c
1026
+ if self.context_pre_only:
1027
+ c = None
1028
+ else: # if not last layer
1029
+ c = c + c_gate_msa.unsqueeze(1) * c_attn_output
1030
+
1031
+ norm_c = self.ff_norm_c(c) * (1 + c_scale_mlp[:, None]) + c_shift_mlp[:, None]
1032
+ c_ff_output = self.ff_c(norm_c)
1033
+ c = c + c_gate_mlp.unsqueeze(1) * c_ff_output
1034
+
1035
+ # process attention output for input x
1036
+ x = x + x_gate_msa.unsqueeze(1) * x_attn_output
1037
+
1038
+ norm_x = self.ff_norm_x(x) * (1 + x_scale_mlp[:, None]) + x_shift_mlp[:, None]
1039
+ x_ff_output = self.ff_x(norm_x)
1040
+ x = x + x_gate_mlp.unsqueeze(1) * x_ff_output
1041
+
1042
+ return c, x
1043
+
1044
+
1045
+ # time step conditioning embedding
1046
+
1047
+
1048
+ class TimestepEmbedding(nn.Module):
1049
+ def __init__(self, dim, freq_embed_dim=256):
1050
+ super().__init__()
1051
+ self.time_embed = SinusPositionEmbedding(freq_embed_dim)
1052
+ self.time_mlp = nn.Sequential(nn.Linear(freq_embed_dim, dim), nn.SiLU(), nn.Linear(dim, dim))
1053
+
1054
+ def forward(self, timestep: float["b"]): # noqa: F821
1055
+ time_hidden = self.time_embed(timestep)
1056
+ time_hidden = time_hidden.to(timestep.dtype)
1057
+ time = self.time_mlp(time_hidden) # b d
1058
+ return time
meanvc2/speaker.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Speaker embedding extraction using WavLM Large + ECAPA-TDNN.
3
+
4
+ Loads a fine-tuned speaker verification model and extracts 256-dim speaker
5
+ embeddings from reference audio for use in the VC pipeline.
6
+
7
+ Source: meanvc_run/speaker_verification/ (ecapa_tdnn.py + verification.py)
8
+
9
+ Dependencies: torch, torchaudio, soundfile, numpy
10
+ Optional: s3prl (for WavLM feature extraction; install from source if needed)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import numpy as np
16
+ import torch
17
+ import torch.nn as nn
18
+ import torch.nn.functional as F
19
+ import torchaudio.transforms as trans
20
+ from torchaudio.transforms import Resample
21
+
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Lightweight ECAPA-TDNN components (self-contained, no s3prl for fbank mode)
25
+ # ---------------------------------------------------------------------------
26
+
27
+ class Conv1dReluBn(nn.Module):
28
+ def __init__(self, in_channels, out_channels, kernel_size=1, stride=1,
29
+ padding=0, dilation=1, bias=True):
30
+ super().__init__()
31
+ self.conv = nn.Conv1d(in_channels, out_channels, kernel_size, stride,
32
+ padding, dilation, bias=bias)
33
+ self.bn = nn.BatchNorm1d(out_channels)
34
+
35
+ def forward(self, x):
36
+ return self.bn(F.relu(self.conv(x)))
37
+
38
+
39
+ class Res2Conv1dReluBn(nn.Module):
40
+ def __init__(self, channels, kernel_size=1, stride=1, padding=0,
41
+ dilation=1, bias=True, scale=4):
42
+ super().__init__()
43
+ assert channels % scale == 0
44
+ self.scale = scale
45
+ self.width = channels // scale
46
+ self.nums = scale if scale == 1 else scale - 1
47
+ self.convs = nn.ModuleList([
48
+ nn.Conv1d(self.width, self.width, kernel_size, stride, padding, dilation, bias=bias)
49
+ for _ in range(self.nums)
50
+ ])
51
+ self.bns = nn.ModuleList([
52
+ nn.BatchNorm1d(self.width) for _ in range(self.nums)
53
+ ])
54
+
55
+ def forward(self, x):
56
+ out = []
57
+ spx = torch.split(x, self.width, 1)
58
+ sp = None
59
+ for i in range(self.nums):
60
+ sp = spx[i] if sp is None else sp + spx[i]
61
+ sp = self.bns[i](F.relu(self.convs[i](sp)))
62
+ out.append(sp)
63
+ if self.scale != 1:
64
+ out.append(spx[self.nums])
65
+ return torch.cat(out, dim=1)
66
+
67
+
68
+ class SE_Connect(nn.Module):
69
+ def __init__(self, channels, se_bottleneck_dim=128):
70
+ super().__init__()
71
+ self.linear1 = nn.Linear(channels, se_bottleneck_dim)
72
+ self.linear2 = nn.Linear(se_bottleneck_dim, channels)
73
+
74
+ def forward(self, x):
75
+ out = x.mean(dim=2)
76
+ out = F.relu(self.linear1(out))
77
+ out = torch.sigmoid(self.linear2(out))
78
+ return x * out.unsqueeze(2)
79
+
80
+
81
+ class SE_Res2Block(nn.Module):
82
+ def __init__(self, in_channels, out_channels, kernel_size, stride, padding,
83
+ dilation, scale, se_bottleneck_dim):
84
+ super().__init__()
85
+ # Submodule names must match the reference models/ecapa_tdnn.py
86
+ # so that the fine-tuned checkpoint weights load correctly.
87
+ self.Conv1dReluBn1 = Conv1dReluBn(in_channels, out_channels, kernel_size=1, stride=1, padding=0)
88
+ self.Res2Conv1dReluBn = Res2Conv1dReluBn(out_channels, kernel_size, stride, padding, dilation, scale=scale)
89
+ self.Conv1dReluBn2 = Conv1dReluBn(out_channels, out_channels, kernel_size=1, stride=1, padding=0)
90
+ self.SE_Connect = SE_Connect(out_channels, se_bottleneck_dim)
91
+ self.shortcut = None
92
+ if in_channels != out_channels:
93
+ self.shortcut = nn.Conv1d(in_channels, out_channels, kernel_size=1)
94
+
95
+ def forward(self, x):
96
+ residual = self.shortcut(x) if self.shortcut else x
97
+ x = self.Conv1dReluBn1(x)
98
+ x = self.Res2Conv1dReluBn(x)
99
+ x = self.Conv1dReluBn2(x)
100
+ x = self.SE_Connect(x)
101
+ return x + residual
102
+
103
+
104
+ class AttentiveStatsPool(nn.Module):
105
+ def __init__(self, in_dim, attention_channels=128, global_context_att=False):
106
+ super().__init__()
107
+ self.global_context_att = global_context_att
108
+ if global_context_att:
109
+ self.linear1 = nn.Conv1d(in_dim * 3, attention_channels, kernel_size=1)
110
+ else:
111
+ self.linear1 = nn.Conv1d(in_dim, attention_channels, kernel_size=1)
112
+ self.linear2 = nn.Conv1d(attention_channels, in_dim, kernel_size=1)
113
+
114
+ def forward(self, x):
115
+ if self.global_context_att:
116
+ context_mean = torch.mean(x, dim=-1, keepdim=True).expand_as(x)
117
+ context_std = torch.sqrt(torch.var(x, dim=-1, keepdim=True) + 1e-10).expand_as(x)
118
+ x_in = torch.cat((x, context_mean, context_std), dim=1)
119
+ else:
120
+ x_in = x
121
+ alpha = torch.softmax(self.linear2(torch.tanh(self.linear1(x_in))), dim=2)
122
+ mean = torch.sum(alpha * x, dim=2)
123
+ residuals = torch.sum(alpha * (x ** 2), dim=2) - mean ** 2
124
+ std = torch.sqrt(residuals.clamp(min=1e-9))
125
+ return torch.cat([mean, std], dim=1)
126
+
127
+
128
+ # ---------------------------------------------------------------------------
129
+ # ECAPA-TDNN with WavLM feature extractor
130
+ # ---------------------------------------------------------------------------
131
+
132
+ class ECAPA_TDNN(nn.Module):
133
+ """ECAPA-TDNN speaker embedding model with WavLM Large backbone."""
134
+
135
+ def __init__(self, feat_dim=1024, channels=512, emb_dim=256,
136
+ feat_type='wavlm_large', sr=16000,
137
+ feature_selection="hidden_states", update_extract=False,
138
+ config_path=None):
139
+ super().__init__()
140
+
141
+ self.feat_type = feat_type
142
+ self.feature_selection = feature_selection
143
+ self.update_extract = update_extract
144
+ self.sr = sr
145
+
146
+ if feat_type == "fbank" or feat_type == "mfcc":
147
+ self.update_extract = False
148
+ win_len = int(sr * 0.025)
149
+ hop_len = int(sr * 0.01)
150
+ if feat_type == 'fbank':
151
+ self.feature_extract = trans.MelSpectrogram(
152
+ sample_rate=sr, n_fft=512, win_length=win_len,
153
+ hop_length=hop_len, f_min=0.0, f_max=sr // 2,
154
+ pad=0, n_mels=feat_dim,
155
+ )
156
+ else:
157
+ melkwargs = {'n_fft': 512, 'win_length': win_len, 'hop_length': hop_len,
158
+ 'f_min': 0.0, 'f_max': sr // 2, 'pad': 0}
159
+ self.feature_extract = trans.MFCC(
160
+ sample_rate=sr, n_mfcc=feat_dim, log_mels=False, melkwargs=melkwargs,
161
+ )
162
+ else:
163
+ if config_path is not None:
164
+ # Build UpstreamExpert from tiny config (~10 KB), skipping the
165
+ # 1.2 GB wavlm_large.pt. Replicates UpstreamExpert.__init__
166
+ # (expert.py:34-54) but without torch.load(ckpt) and
167
+ # load_state_dict — the fine-tuned ckpt provides all weights.
168
+ from s3prl_wavlm.WavLM import WavLM, WavLMConfig
169
+ from s3prl_wavlm.expert import UpstreamExpert
170
+ from s3prl_wavlm.interfaces import UpstreamBase
171
+
172
+ if isinstance(config_path, dict):
173
+ cfg_dict = config_path
174
+ else:
175
+ cfg_dict = torch.load(config_path, map_location='cpu')
176
+ cfg = WavLMConfig(cfg_dict)
177
+ wavlm = WavLM(cfg)
178
+ wavlm.feature_grad_mult = 0.0
179
+ wavlm.encoder.layerdrop = 0.0
180
+
181
+ expert = UpstreamExpert.__new__(UpstreamExpert)
182
+ UpstreamBase.__init__(expert)
183
+ expert.cfg = cfg
184
+ expert.model = wavlm
185
+ expert.model.feature_grad_mult = 0.0
186
+ expert.model.encoder.layerdrop = 0.0
187
+
188
+ if len(expert.hooks) == 0:
189
+ for module_id in range(len(wavlm.encoder.layers)):
190
+ expert.add_hook(
191
+ f"self.model.encoder.layers[{module_id}]",
192
+ lambda input, output: input[0].transpose(0, 1),
193
+ )
194
+ expert.add_hook("self.model.encoder",
195
+ lambda input, output: output[0])
196
+ expert._init_layerdrop = wavlm.encoder.layerdrop
197
+
198
+ self.feature_extract = expert
199
+ else:
200
+ raise ValueError("config_path (WavLM cfg dict) is required")
201
+
202
+ # Disable fp32_attention for layers that have it (compatibility)
203
+ if len(self.feature_extract.model.encoder.layers) == 24:
204
+ for layer_idx in [11, 23]:
205
+ layer = self.feature_extract.model.encoder.layers[layer_idx]
206
+ if hasattr(layer.self_attn, "fp32_attention"):
207
+ layer.self_attn.fp32_attention = False
208
+
209
+ self.feat_num = self._get_feat_num()
210
+ self.feature_weight = nn.Parameter(torch.zeros(self.feat_num))
211
+
212
+ if feat_type != 'fbank' and feat_type != 'mfcc':
213
+ freeze_list = ['final_proj', 'label_embs_concat', 'mask_emb', 'project_q', 'quantizer']
214
+ for name, param in self.feature_extract.named_parameters():
215
+ for freeze_val in freeze_list:
216
+ if freeze_val in name:
217
+ param.requires_grad = False
218
+ break
219
+
220
+ if not self.update_extract:
221
+ for param in self.feature_extract.parameters():
222
+ param.requires_grad = False
223
+
224
+ self.instance_norm = nn.InstanceNorm1d(feat_dim)
225
+ self.channels = [channels] * 4 + [1536]
226
+
227
+ self.layer1 = Conv1dReluBn(feat_dim, self.channels[0], kernel_size=5, padding=2)
228
+ self.layer2 = SE_Res2Block(self.channels[0], self.channels[1],
229
+ kernel_size=3, stride=1, padding=2, dilation=2,
230
+ scale=8, se_bottleneck_dim=128)
231
+ self.layer3 = SE_Res2Block(self.channels[1], self.channels[2],
232
+ kernel_size=3, stride=1, padding=3, dilation=3,
233
+ scale=8, se_bottleneck_dim=128)
234
+ self.layer4 = SE_Res2Block(self.channels[2], self.channels[3],
235
+ kernel_size=3, stride=1, padding=4, dilation=4,
236
+ scale=8, se_bottleneck_dim=128)
237
+
238
+ cat_channels = channels * 3
239
+ self.conv = nn.Conv1d(cat_channels, self.channels[-1], kernel_size=1)
240
+ self.pooling = AttentiveStatsPool(self.channels[-1], attention_channels=128,
241
+ global_context_att=False)
242
+ self.bn = nn.BatchNorm1d(self.channels[-1] * 2)
243
+ self.linear = nn.Linear(self.channels[-1] * 2, emb_dim)
244
+
245
+ def _get_feat_num(self):
246
+ self.feature_extract.eval()
247
+ wav = [torch.randn(self.sr).to(next(self.feature_extract.parameters()).device)]
248
+ with torch.no_grad():
249
+ features = self.feature_extract(wav)
250
+ select_feature = features[self.feature_selection]
251
+ if isinstance(select_feature, (list, tuple)):
252
+ return len(select_feature)
253
+ return 1
254
+
255
+ def _get_feat(self, x):
256
+ if self.update_extract:
257
+ x = self.feature_extract([sample for sample in x])
258
+ else:
259
+ with torch.no_grad():
260
+ if self.feat_type == 'fbank' or self.feat_type == 'mfcc':
261
+ x = self.feature_extract(x) + 1e-6
262
+ else:
263
+ x = self.feature_extract([sample for sample in x])
264
+
265
+ if self.feat_type == 'fbank':
266
+ x = x.log()
267
+
268
+ if self.feat_type != "fbank" and self.feat_type != "mfcc":
269
+ x = x[self.feature_selection]
270
+ if isinstance(x, (list, tuple)):
271
+ x = torch.stack(x, dim=0)
272
+ else:
273
+ x = x.unsqueeze(0)
274
+ norm_weights = F.softmax(self.feature_weight, dim=-1).unsqueeze(-1).unsqueeze(-1).unsqueeze(-1)
275
+ x = (norm_weights * x).sum(dim=0)
276
+ x = torch.transpose(x, 1, 2) + 1e-6
277
+
278
+ x = self.instance_norm(x)
279
+ return x
280
+
281
+ def forward(self, x):
282
+ x = self._get_feat(x)
283
+ out1 = self.layer1(x)
284
+ out2 = self.layer2(out1)
285
+ out3 = self.layer3(out2)
286
+ out4 = self.layer4(out3)
287
+ out = torch.cat([out2, out3, out4], dim=1)
288
+ out = F.relu(self.conv(out))
289
+ out = self.bn(self.pooling(out))
290
+ out = self.linear(out)
291
+ return out
292
+
293
+
294
+ def ECAPA_TDNN_SMALL(feat_dim, emb_dim=256, feat_type='fbank', sr=16000,
295
+ feature_selection="hidden_states", update_extract=False,
296
+ config_path=None):
297
+ return ECAPA_TDNN(
298
+ feat_dim=feat_dim, channels=512, emb_dim=emb_dim,
299
+ feat_type=feat_type, sr=sr,
300
+ feature_selection=feature_selection,
301
+ update_extract=update_extract,
302
+ config_path=config_path,
303
+ )
304
+
305
+
306
+ # ---------------------------------------------------------------------------
307
+ # Public API
308
+ # ---------------------------------------------------------------------------
309
+
310
+ def init_speaker_model(ckpt_path=None, device='cpu', wavlm_config=None):
311
+ """
312
+ Load the WavLM Large + ECAPA-TDNN speaker verification model.
313
+
314
+ Args:
315
+ ckpt_path: path to fine-tuned checkpoint (wavlm_large_finetune.pth).
316
+ Contains ALL backbone + ECAPA-TDNN weights.
317
+ device: 'cpu' or 'cuda'
318
+ wavlm_config: path to WavLM config (wavlm_large_cfg.pt, ~10 KB).
319
+ Extracted from wavlm_large.pt via extract_wavlm_config.py.
320
+ When provided, skips loading the 1.2 GB base checkpoint — the
321
+ WavLM backbone is built from config and all weights come from
322
+ ckpt_path via load_state_dict().
323
+ Returns:
324
+ model: ECAPA_TDNN model in eval mode, on the specified device
325
+ """
326
+ model = ECAPA_TDNN_SMALL(
327
+ feat_dim=1024, emb_dim=256,
328
+ feat_type='wavlm_large',
329
+ feature_selection="hidden_states",
330
+ update_extract=False,
331
+ config_path=wavlm_config,
332
+ )
333
+ if ckpt_path is not None:
334
+ state_dict = torch.load(ckpt_path, map_location='cpu', weights_only=True)
335
+ if 'model' in state_dict:
336
+ state_dict = state_dict['model']
337
+ missing, unexpected = model.load_state_dict(state_dict, strict=False)
338
+ missing, unexpected = list(missing), list(unexpected)
339
+ print(f"[speaker] loaded ckpt: {len(state_dict)} tensors | "
340
+ f"missing={len(missing)} unexpected={len(unexpected)}", flush=True)
341
+ if missing:
342
+ print(f"[speaker] missing (first 10): {missing[:10]}", flush=True)
343
+ if unexpected:
344
+ print(f"[speaker] unexpected (first 10): {unexpected[:10]}", flush=True)
345
+ model.eval()
346
+ model.to(device)
347
+ return model
348
+
349
+
350
+ def extract_embedding(model, wav, sample_rate=16000, device='cpu'):
351
+ """
352
+ Extract 256-dim speaker embedding from audio.
353
+
354
+ Args:
355
+ model: ECAPA_TDNN model from init_speaker_model()
356
+ wav: either a file path (str) or a torch.Tensor [1, samples] or numpy array
357
+ sample_rate: target sample rate (used if loading from file)
358
+ device: compute device
359
+
360
+ Returns:
361
+ torch.Tensor [1, 256] — L2-normalized speaker embedding
362
+ """
363
+ import soundfile as sf
364
+
365
+ if isinstance(wav, str):
366
+ data, sr = sf.read(wav)
367
+ if data.ndim == 2:
368
+ data = np.mean(data, axis=1)
369
+ wav = torch.from_numpy(data).unsqueeze(0).float().to(device)
370
+ if sr != sample_rate:
371
+ resample = Resample(orig_freq=sr, new_freq=sample_rate).to(device)
372
+ wav = resample(wav)
373
+ elif isinstance(wav, np.ndarray):
374
+ wav = torch.from_numpy(wav).unsqueeze(0).float().to(device)
375
+ elif isinstance(wav, torch.Tensor):
376
+ wav = wav.to(device)
377
+ if wav.ndim == 1:
378
+ wav = wav.unsqueeze(0)
379
+
380
+ with torch.no_grad():
381
+ emb = model(wav)
382
+
383
+ # NOTE: No L2 normalization — aligned with extract_spk_emb_wavlm_multi_mp3.py
384
+ # which outputs raw (unnormalized) embeddings.
385
+ return emb