Prompt48 commited on
Commit
63d6218
·
verified ·
1 Parent(s): 1cb6a6e

Upload edit\Qwen3-TTS-test\qwen_tts\core\tokenizer_25hz\vq\whisper_encoder.py with huggingface_hub

Browse files
edit//Qwen3-TTS-test//qwen_tts//core//tokenizer_25hz//vq//whisper_encoder.py ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2026 The Alibaba Qwen team.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ import os
17
+ import math
18
+ import torch
19
+ import operator
20
+
21
+ import numpy as np
22
+ import torch.nn.functional as F
23
+
24
+ from functools import lru_cache
25
+ from typing import Optional, Union, List
26
+ from torch import nn, Tensor
27
+ from itertools import accumulate
28
+
29
+ try:
30
+ from flash_attn.flash_attn_interface import flash_attn_varlen_func as flash_attn_varlen_func
31
+ except ImportError:
32
+ try:
33
+ from flash_attn.flash_attn_interface import flash_attn_unpadded_func as flash_attn_varlen_func
34
+ except ImportError:
35
+ print("\n********\nWarning: flash-attn is not installed. Will only run the manual PyTorch version. Please install flash-attn for faster inference.\n********\n ")
36
+ flash_attn_varlen_func = None
37
+
38
+
39
+ N_FFT = 400
40
+ HOP_LENGTH = 160
41
+
42
+
43
+ @lru_cache(maxsize=None)
44
+ def mel_filters(device, n_mels: int) -> torch.Tensor:
45
+ """
46
+ load the mel filterbank matrix for projecting STFT into a Mel spectrogram.
47
+ Allows decoupling librosa dependency; saved using:
48
+
49
+ np.savez_compressed(
50
+ "mel_filters.npz",
51
+ mel_80=librosa.filters.mel(sr=16000, n_fft=400, n_mels=80),
52
+ mel_128=librosa.filters.mel(sr=16000, n_fft=400, n_mels=128),
53
+ )
54
+ """
55
+ assert n_mels in {80, 128}, f"Unsupported n_mels: {n_mels}"
56
+
57
+ filters_path = os.path.join(os.path.dirname(__file__), "assets", "mel_filters.npz")
58
+ with np.load(filters_path, allow_pickle=False) as f:
59
+ return torch.from_numpy(f[f"mel_{n_mels}"]).to(device)
60
+
61
+
62
+ def log_mel_spectrogram(
63
+ audio: Union[str, np.ndarray, torch.Tensor],
64
+ n_mels: int = 80,
65
+ padding: int = 0,
66
+ device: Optional[Union[str, torch.device]] = None,
67
+ ):
68
+ """
69
+ Compute the log-Mel spectrogram of
70
+
71
+ Parameters
72
+ ----------
73
+ audio: Union[str, np.ndarray, torch.Tensor], shape = (*)
74
+ The path to audio or either a NumPy array or Tensor containing the audio waveform in 16 kHz
75
+
76
+ n_mels: int
77
+ The number of Mel-frequency filters, only 80 is supported
78
+
79
+ padding: int
80
+ Number of zero samples to pad to the right
81
+
82
+ device: Optional[Union[str, torch.device]]
83
+ If given, the audio tensor is moved to this device before STFT
84
+
85
+ Returns
86
+ -------
87
+ torch.Tensor, shape = (80, n_frames)
88
+ A Tensor that contains the Mel spectrogram
89
+ """
90
+ if not torch.is_tensor(audio):
91
+ audio = torch.from_numpy(audio)
92
+
93
+ if device is not None:
94
+ audio = audio.to(device)
95
+ if padding > 0:
96
+ audio = F.pad(audio, (0, padding))
97
+ window = torch.hann_window(N_FFT).to(audio.device)
98
+ stft = torch.stft(audio, N_FFT, HOP_LENGTH, window=window, return_complex=True)
99
+ magnitudes = stft[..., :-1].abs() ** 2
100
+
101
+ filters = mel_filters(audio.device, n_mels)
102
+ mel_spec = filters @ magnitudes
103
+
104
+ log_spec = torch.clamp(mel_spec, min=1e-10).log10()
105
+ log_spec = torch.maximum(log_spec, log_spec.max() - 8.0)
106
+ log_spec = (log_spec + 4.0) / 4.0
107
+ return log_spec
108
+
109
+
110
+ def get_T_after_cnn(L_in, dilation=1):
111
+ for (padding, kernel_size, stride) in eval("[(1,3,1)] + [(1,3,2)] "):
112
+ L_out = L_in + 2 * padding - dilation * (kernel_size - 1) - 1
113
+ L_out = 1 + L_out // stride
114
+ L_in = L_out
115
+ return L_out
116
+
117
+
118
+ def get_mel_audio(audio, padding=False, audio_vq_ds_rate = 1, n_mels = 128):
119
+ audio_len = len(audio)
120
+ if padding:
121
+ reduction = 160 * 2 * audio_vq_ds_rate
122
+ audio_pad = math.ceil(audio_len / reduction) * reduction - audio_len
123
+ mel = log_mel_spectrogram(audio, n_mels=n_mels, padding=audio_pad)
124
+ else:
125
+ mel = log_mel_spectrogram(audio, n_mels=n_mels) # [F,T]
126
+ return mel
127
+
128
+
129
+ def sinusoids(length, channels, max_timescale=10000):
130
+ """Returns sinusoids for positional embedding"""
131
+ assert channels % 2 == 0
132
+ log_timescale_increment = np.log(max_timescale) / (channels // 2 - 1)
133
+ inv_timescales = torch.exp(-log_timescale_increment * torch.arange(channels // 2))
134
+ scaled_time = torch.arange(length)[:, np.newaxis] * inv_timescales[np.newaxis, :]
135
+ return torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], dim=1)
136
+
137
+
138
+ class Conv1d(nn.Conv1d):
139
+ def _conv_forward(
140
+ self, x: Tensor, weight: Tensor, bias: Optional[Tensor]
141
+ ) -> Tensor:
142
+ return super()._conv_forward(
143
+ x, weight.to(x.dtype), None if bias is None else bias.to(x.dtype)
144
+ )
145
+
146
+
147
+ class ConvTranspose1d(nn.ConvTranspose1d):
148
+ def _conv_forward(
149
+ self, x: Tensor, weight: Tensor, bias: Optional[Tensor]
150
+ ) -> Tensor:
151
+ return super()._conv_forward(
152
+ x, weight.to(x.dtype), None if bias is None else bias.to(x.dtype)
153
+ )
154
+
155
+
156
+ class Linear(nn.Linear):
157
+ def forward(self, x: Tensor) -> Tensor:
158
+ return F.linear(x, self.weight.to(x.dtype), None if self.bias is None else self.bias.to(x.dtype) )
159
+
160
+
161
+ class MultiHeadAttention(nn.Module):
162
+ def __init__(self, n_state: int, n_head: int):
163
+ super().__init__()
164
+ self.n_head = n_head
165
+ self.query = Linear(n_state, n_state)
166
+ self.key = Linear(n_state, n_state, bias=False)
167
+ self.value = Linear(n_state, n_state)
168
+ self.out = Linear(n_state, n_state)
169
+
170
+ self.use_flash_attention = True
171
+
172
+ def forward(
173
+ self,
174
+ x: Tensor,
175
+ cu_seqlens = None,
176
+ ):
177
+ q = self.query(x)
178
+ k = self.key(x)
179
+ v = self.value(x)
180
+
181
+ if self.use_flash_attention:
182
+ if flash_attn_varlen_func is None:
183
+ x = self.qkv_attention_manual(q, k, v, cu_seqlens=cu_seqlens)
184
+ else:
185
+ if q.dtype not in [torch.float16, torch.bfloat16]:
186
+ x = self.qkv_attention_manual(q, k, v, cu_seqlens=cu_seqlens)
187
+ self.use_flash_attention = False
188
+ else:
189
+ x = self.qkv_flash_attention(q, k, v, cu_seqlens=cu_seqlens)
190
+ else:
191
+ x = self.qkv_attention_manual(q, k, v, cu_seqlens=cu_seqlens)
192
+
193
+ output = self.out(x)
194
+ return output
195
+
196
+ def qkv_flash_attention(
197
+ self, q: Tensor, k: Tensor, v: Tensor, cu_seqlens=None
198
+ ):
199
+ n_ctx, n_state = q.shape
200
+ # scale = (n_state // self.n_head) ** -0.25
201
+ q = q.view(n_ctx, self.n_head, -1)# (batch_size, seqlen, nheads, headdim)
202
+ k = k.view(n_ctx, self.n_head, -1)
203
+ v = v.view(n_ctx, self.n_head, -1)
204
+
205
+ max_seqlen = (cu_seqlens[1:] - cu_seqlens[:-1]).max().item()
206
+
207
+
208
+ x = flash_attn_varlen_func(
209
+ q, k, v, cu_seqlens, cu_seqlens, max_seqlen, max_seqlen, dropout_p=0.0
210
+ )
211
+ x = x.reshape(n_ctx, n_state)
212
+ return x
213
+
214
+ def qkv_attention_manual(
215
+ self, q: Tensor, k: Tensor, v: Tensor, cu_seqlens: Tensor
216
+ ):
217
+ n_ctx, n_state = q.shape
218
+ head_dim = n_state // self.n_head
219
+ scale = head_dim ** -0.5
220
+
221
+ q = q.view(n_ctx, self.n_head, head_dim)
222
+ k = k.view(n_ctx, self.n_head, head_dim)
223
+ v = v.view(n_ctx, self.n_head, head_dim)
224
+
225
+ seqlens = (cu_seqlens[1:] - cu_seqlens[:-1]).tolist()
226
+ batch_size = len(seqlens)
227
+ max_seqlen = max(seqlens)
228
+
229
+ q_padded = torch.zeros(batch_size, max_seqlen, self.n_head, head_dim, dtype=q.dtype, device=q.device)
230
+ k_padded = torch.zeros_like(q_padded)
231
+ v_padded = torch.zeros_like(q_padded)
232
+
233
+ for i in range(batch_size):
234
+ start_idx = cu_seqlens[i]
235
+ end_idx = cu_seqlens[i+1]
236
+ seq_len = seqlens[i]
237
+ q_padded[i, :seq_len] = q[start_idx:end_idx]
238
+ k_padded[i, :seq_len] = k[start_idx:end_idx]
239
+ v_padded[i, :seq_len] = v[start_idx:end_idx]
240
+
241
+ q_padded = q_padded.transpose(1, 2)
242
+ k_padded = k_padded.transpose(1, 2)
243
+ v_padded = v_padded.transpose(1, 2)
244
+
245
+ attn_mask = torch.arange(max_seqlen, device=q.device)[None, :] < torch.tensor(seqlens, device=q.device)[:, None]
246
+ attn_mask = attn_mask.unsqueeze(1).unsqueeze(2)
247
+
248
+ attn_mask = attn_mask.masked_fill(attn_mask == 0, -torch.finfo(q.dtype).max)
249
+
250
+ attn_scores = torch.matmul(q_padded, k_padded.transpose(-2, -1)) * scale
251
+ attn_scores = attn_scores + attn_mask
252
+ attn_weights = F.softmax(attn_scores, dim=-1)
253
+
254
+ context = torch.matmul(attn_weights, v_padded)
255
+
256
+ context = context.transpose(1, 2).contiguous().view(batch_size, max_seqlen, n_state)
257
+
258
+ output_packed = torch.cat([context[i, :seqlens[i]] for i in range(batch_size)], dim=0)
259
+
260
+ assert output_packed.shape == (n_ctx, n_state)
261
+
262
+ return output_packed
263
+
264
+
265
+ class ResidualAttentionBlock(nn.Module):
266
+ def __init__(self, n_state: int, n_head: int,
267
+ enable_mp: bool = False, sequence_parallel: bool = False):
268
+ super().__init__()
269
+ n_mlp = n_state * 4
270
+ self.attn_ln = nn.LayerNorm(n_state)
271
+ self.mlp_ln = nn.LayerNorm(n_state)
272
+
273
+ self.attn = MultiHeadAttention(n_state, n_head)
274
+ self.mlp = nn.Sequential(
275
+ Linear(n_state, n_mlp), nn.GELU(), Linear(n_mlp, n_state)
276
+ )
277
+
278
+ def forward(
279
+ self,
280
+ x: Tensor,
281
+ cu_seqlens = None
282
+ ):
283
+ x = x + self.attn(self.attn_ln(x), cu_seqlens=cu_seqlens)
284
+ x = x + self.mlp(self.mlp_ln(x))
285
+ return x
286
+
287
+
288
+ class WhisperEncoder(nn.Module):
289
+ def __init__(
290
+ self,
291
+ n_mels: int,
292
+ n_ctx: int,
293
+ n_state: int,
294
+ n_head: int,
295
+ n_layer: int,
296
+ n_window: int = 1500,
297
+ output_dim: int = 512,
298
+ grad_checkpointing: bool = False,
299
+ enable_mp: bool = False,
300
+ audio_sequence_parallel: bool = False,
301
+ ):
302
+ super().__init__()
303
+ self.conv1 = Conv1d(n_mels, n_state, kernel_size=3, padding=1)
304
+ self.conv2 = Conv1d(n_state, n_state, kernel_size=3, stride=2, padding=1)
305
+ self.register_buffer("positional_embedding", sinusoids(n_ctx, n_state))
306
+ self.n_layer = n_layer
307
+ self.n_mels = n_mels
308
+
309
+ self.blocks = nn.ModuleList(
310
+ [ResidualAttentionBlock(n_state, n_head, enable_mp=enable_mp, sequence_parallel=audio_sequence_parallel)
311
+ for _ in range(n_layer)]
312
+ )
313
+ self.ln_post = nn.LayerNorm(n_state)
314
+ self.avg_pooler = nn.AvgPool1d(2, stride=2)
315
+
316
+ self.proj = torch.nn.Linear(n_state, output_dim)
317
+
318
+ self.audio_bos_eos_token = nn.Embedding(2, output_dim)
319
+
320
+ self.output_dim = output_dim
321
+ self.grad_checkpointing = grad_checkpointing
322
+ self.enable_mp = enable_mp
323
+ self.n_head = n_head
324
+ self.n_state = n_state
325
+ self.n_window = n_window
326
+
327
+ self.audio_sequence_parallel = audio_sequence_parallel
328
+
329
+ self.tp_world_size = 1
330
+
331
+ self.set_audio_sync()
332
+
333
+ def set_audio_sync(self):
334
+ for name, param in self.named_parameters():
335
+ if not name.startswith("blocks"):
336
+ setattr(param, "audio_sync", True)
337
+
338
+ def forward(self, x_list: List[Tensor], audio_mellens:List[int], audio_aftercnnlens:List[int], audio_seqlens:List[int]):
339
+ """
340
+ x : torch.Tensor, shape = (n_mels, n_ctx)
341
+ the mel spectrogram of the audio
342
+ """
343
+
344
+ aftercnn_x_list = []
345
+ for each_x in x_list:
346
+ each_x_split_list = each_x.split(self.n_window * 2, dim=1)
347
+ for each_x_split in each_x_split_list:
348
+ each_x_split = F.gelu(self.conv1(each_x_split))
349
+ each_x_split = F.gelu(self.conv2(each_x_split))
350
+ each_x_split = each_x_split.permute(1, 0) # L,D
351
+ each_positional_embedding_split = self.positional_embedding[:each_x_split.shape[0]]
352
+ aftercnn_x_list.append(each_x_split+each_positional_embedding_split.to(each_x_split.dtype))
353
+
354
+ x = torch.cat(aftercnn_x_list, dim=0)
355
+ src_len = x.size(0)
356
+
357
+ output_list = []
358
+ for item in audio_aftercnnlens:
359
+ while item > self.n_window:
360
+ output_list.append(self.n_window)
361
+ item -= self.n_window
362
+ output_list.append(item)
363
+
364
+ cu_seqlens = list(accumulate(output_list, func=operator.add,initial=0))
365
+ cu_seqlens = torch.Tensor(cu_seqlens).to(device=x.device, dtype=torch.int32)
366
+
367
+ layer_id = 0
368
+ for block in self.blocks:
369
+ layer_id+=1
370
+ x = block(x, cu_seqlens=cu_seqlens)
371
+
372
+ if self.avg_pooler:
373
+ x_list = x.split(audio_aftercnnlens, dim=0)
374
+ token_x_list = []
375
+ for x in x_list:
376
+ x = x.permute(1, 0)
377
+ x = self.avg_pooler(x)
378
+ x = x.permute(1, 0)
379
+ token_x_list.append(x)
380
+ x = torch.cat(token_x_list, dim=0)
381
+
382
+ x = self.ln_post(x)
383
+ x = self.proj(x)
384
+
385
+ output = torch.zeros(
386
+ (x.size(0) + len(audio_seqlens) * 2, x.size(1)),
387
+ device=x.device, dtype=x.dtype
388
+ )
389
+
390
+ audio_seqlens_acc = list(accumulate(audio_seqlens, func=operator.add, initial=0))
391
+ start_ids = torch.tensor(audio_seqlens_acc[:-1], device=x.device, dtype=torch.int32)
392
+ end_ids = torch.tensor(audio_seqlens_acc[1:], device=x.device, dtype=torch.int32) - 1
393
+
394
+ audio_tokens_mask = torch.ones(output.size(0), device=x.device, dtype=torch.bool)
395
+ audio_tokens_mask[start_ids] = False
396
+ audio_tokens_mask[end_ids] = False
397
+ output[start_ids] = self.audio_bos_eos_token.weight[0].to(x.dtype)
398
+ output[end_ids] = self.audio_bos_eos_token.weight[1].to(x.dtype)
399
+ output[audio_tokens_mask] = x
400
+ return output
401
+
402
+ def lock(self, layers: int):
403
+ self.conv1.requires_grad_(False)
404
+ self.conv2.requires_grad_(False)
405
+ for i in range(min(layers, len(self.blocks))):
406
+ self.blocks[i].requires_grad_(False)