main
py 1,398 lines 47.8 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """MiMo audio: tokenizer, encoding utilities, and audio encoder.
4
5 Ported from SGLang's mimo_audio.py.
6 Audio tokenizer adapted from https://github.com/XiaomiMiMo/MiMo-Audio-Tokenizer.git
7 """
8
9 import dataclasses
10 import json
11 import logging
12 import math
13 import os
14 import typing as tp
15 from dataclasses import dataclass
16 from functools import wraps
17
18 import torch
19 import torch.distributed as dist
20 import torch.nn as nn
21 import torch.nn.functional as F
22 from einops import rearrange, repeat
23 from transformers.activations import ACT2FN
24 from transformers.configuration_utils import PreTrainedConfig
25 from transformers.modeling_utils import PreTrainedModel
26 from transformers.models.qwen2.configuration_qwen2 import Qwen2Config
27 from transformers.models.qwen2.modeling_qwen2 import Qwen2Model
28
29 logger = logging.getLogger(__name__)
30
31
32 # ---------------------------------------------------------------------------
33 # Vector quantization (from MiMo-Audio-Tokenizer)
34 # ---------------------------------------------------------------------------
35
36
37 def _vq_default(val: tp.Any, d: tp.Any) -> tp.Any:
38 return val if val is not None else d
39
40
41 def _ema_inplace(moving_avg, new, decay: float):
42 if dist.is_initialized():
43 dist.all_reduce(new, op=dist.ReduceOp.SUM)
44 moving_avg.data.mul_(decay).add_(new, alpha=(1 - decay))
45
46
47 def _laplace_smoothing(x, n_categories: int, epsilon: float = 1e-5):
48 return (x + epsilon) / (x.sum() + n_categories * epsilon)
49
50
51 def _uniform_init(*shape: int):
52 t = torch.empty(shape)
53 nn.init.kaiming_uniform_(t)
54 return t
55
56
57 def _sample_vectors(samples, num: int):
58 num_samples, device = samples.shape[0], samples.device
59
60 if num_samples >= num:
61 indices = torch.randperm(num_samples, device=device)[:num]
62 else:
63 indices = torch.randint(0, num_samples, (num,), device=device)
64
65 selected_samples = samples[indices]
66
67 if dist.is_initialized():
68 dist.broadcast(selected_samples, src=0)
69
70 return selected_samples
71
72
73 def _kmeans(samples, num_clusters: int, num_iters: int = 10):
74 dim, dtype = samples.shape[-1], samples.dtype
75
76 means = _sample_vectors(samples, num_clusters)
77
78 for _ in range(num_iters):
79 dists = -(
80 samples.pow(2).sum(1, keepdim=True)
81 - 2 * samples @ means.t()
82 + means.t().pow(2).sum(0, keepdim=True)
83 )
84
85 buckets = dists.max(dim=-1).indices
86 bins = torch.bincount(buckets, minlength=num_clusters)
87
88 new_means = buckets.new_zeros(num_clusters, dim, dtype=dtype)
89 new_means = new_means.scatter_add_(
90 0, repeat(buckets, "n -> n d", d=dim), samples
91 )
92
93 if dist.is_initialized():
94 dist.all_reduce(bins, op=dist.ReduceOp.SUM)
95 dist.all_reduce(new_means, op=dist.ReduceOp.SUM)
96
97 zero_mask = bins == 0
98 bins_min_clamped = bins.masked_fill(zero_mask, 1)
99
100 new_means = new_means / bins_min_clamped[..., None]
101
102 means = torch.where(zero_mask[..., None], means, new_means)
103
104 return means, bins
105
106
107 def _rotate_half(x):
108 x1 = x[..., : x.shape[-1] // 2]
109 x2 = x[..., x.shape[-1] // 2 :]
110 return torch.cat((-x2, x1), dim=-1)
111
112
113 def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
114 cos = cos.unsqueeze(unsqueeze_dim)
115 sin = sin.unsqueeze(unsqueeze_dim)
116 q_embed = (q * cos) + (_rotate_half(q) * sin)
117 k_embed = (k * cos) + (_rotate_half(k) * sin)
118 return q_embed, k_embed
119
120
121 def _compute_default_rope_parameters(
122 config=None, device=None, seq_len=None, **rope_kwargs
123 ):
124 if config is not None and len(rope_kwargs) > 0:
125 raise ValueError(
126 "Unexpected arguments: `**rope_kwargs` and `config` are mutually exclusive"
127 )
128 if len(rope_kwargs) > 0:
129 base = rope_kwargs["base"]
130 dim = rope_kwargs["dim"]
131 elif config is not None:
132 base = config.rope_theta
133 partial_rotary_factor = (
134 config.partial_rotary_factor
135 if hasattr(config, "partial_rotary_factor")
136 else 1.0
137 )
138 head_dim = (
139 getattr(config, "head_dim", None)
140 or config.hidden_size // config.num_attention_heads
141 )
142 dim = int(head_dim * partial_rotary_factor)
143 attention_factor = 1.0
144 inv_freq = 1.0 / (
145 base
146 ** (
147 torch.arange(0, dim, 2, dtype=torch.int64).to(
148 device=device, dtype=torch.float
149 )
150 / dim
151 )
152 )
153 return inv_freq, attention_factor
154
155
156 _ROPE_INIT_FUNCTIONS = {
157 "default": _compute_default_rope_parameters,
158 }
159
160
161 def _dynamic_rope_update(rope_forward):
162 def dynamic_frequency_update(self, position_ids, device):
163 seq_len = torch.max(position_ids) + 1
164 if seq_len > self.max_seq_len_cached:
165 inv_freq, self.attention_scaling = self.rope_init_fn(
166 self.config, device, seq_len=seq_len
167 )
168 self.register_buffer("inv_freq", inv_freq, persistent=False)
169 self.max_seq_len_cached = seq_len
170
171 if (
172 seq_len < self.original_max_seq_len
173 and self.max_seq_len_cached > self.original_max_seq_len
174 ):
175 self.original_inv_freq = self.original_inv_freq.to(device)
176 self.register_buffer("inv_freq", self.original_inv_freq, persistent=False)
177 self.max_seq_len_cached = self.original_max_seq_len
178
179 @wraps(rope_forward)
180 def wrapper(self, x, position_ids):
181 if "dynamic" in self.rope_type:
182 dynamic_frequency_update(self, position_ids, device=x.device)
183 return rope_forward(self, x, position_ids)
184
185 return wrapper
186
187
188 class AudioRotaryEmbedding(nn.Module):
189 def __init__(self, base, dim, max_seq_len, rope_type="default", device=None):
190 super().__init__()
191 self.max_seq_len = max_seq_len
192 self.rope_type = rope_type
193 self.rope_init_fn = _ROPE_INIT_FUNCTIONS[self.rope_type]
194 inv_freq, self.attention_scaling = self.rope_init_fn(
195 device=device, base=base, dim=dim
196 )
197 self.register_buffer("inv_freq", inv_freq, persistent=False)
198 self.original_inv_freq = self.inv_freq
199
200 @torch.no_grad()
201 @_dynamic_rope_update
202 def forward(self, x, position_ids):
203 inv_freq_expanded = self.inv_freq[:, None].float().expand(-1, 1).to(x.device)
204 position_ids_expanded = position_ids[None, :].float()
205 device_type = (
206 x.device.type
207 if isinstance(x.device.type, str) and x.device.type != "mps"
208 else "cpu"
209 )
210 with torch.autocast(device_type=device_type, enabled=False):
211 freqs = (
212 inv_freq_expanded.float() @ position_ids_expanded.float()
213 ).transpose(0, 1)
214 emb = torch.cat((freqs, freqs), dim=-1)
215 cos = emb.cos() * self.attention_scaling
216 sin = emb.sin() * self.attention_scaling
217 return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
218
219
220 class EuclideanCodebook(nn.Module):
221 def __init__(
222 self,
223 dim: int,
224 codebook_size: int,
225 kmeans_init: int = False,
226 kmeans_iters: int = 10,
227 decay: float = 0.99,
228 epsilon: float = 1e-5,
229 threshold_ema_dead_code: int = 2,
230 ):
231 super().__init__()
232 self.decay = decay
233 init_fn: tp.Callable[..., torch.Tensor] | tp.Any = (
234 _uniform_init if not kmeans_init else torch.zeros
235 )
236 embed = init_fn(codebook_size, dim)
237
238 self.codebook_size = codebook_size
239 self.kmeans_iters = kmeans_iters
240 self.epsilon = epsilon
241 self.threshold_ema_dead_code = threshold_ema_dead_code
242
243 self.register_buffer("inited", torch.Tensor([not kmeans_init]))
244 self.register_buffer("cluster_size", torch.zeros(codebook_size))
245 self.register_buffer("embed", embed)
246 self.register_buffer("embed_avg", embed.clone())
247
248 @torch.jit.ignore
249 def init_embed_(self, data):
250 if self.inited:
251 return
252
253 embed, cluster_size = _kmeans(data, self.codebook_size, self.kmeans_iters)
254 self.embed.data.copy_(embed)
255 self.embed_avg.data.copy_(embed.clone())
256 self.cluster_size.data.copy_(cluster_size)
257 self.inited.data.copy_(torch.Tensor([True]))
258
259 def replace_(self, samples, mask):
260 replace_num = mask.sum()
261 modified_codebook = self.embed.clone()
262 modified_codebook[mask] = _sample_vectors(samples, replace_num)
263 self.embed.data.copy_(modified_codebook)
264
265 def expire_codes_(self, batch_samples):
266 if self.threshold_ema_dead_code == 0:
267 return
268
269 expired_codes = self.cluster_size < self.threshold_ema_dead_code
270 if not torch.any(expired_codes):
271 return
272
273 batch_samples = rearrange(batch_samples, "... d -> (...) d")
274 self.replace_(batch_samples, mask=expired_codes)
275
276 def preprocess(self, x):
277 x = rearrange(x, "... d -> (...) d")
278 return x
279
280 def quantize(self, x):
281 embed = self.embed.t()
282 dist_val = -(
283 x.pow(2).sum(1, keepdim=True)
284 - 2 * x @ embed
285 + embed.pow(2).sum(0, keepdim=True)
286 )
287 embed_ind = dist_val.max(dim=-1).indices
288 return embed_ind
289
290 def postprocess_emb(self, embed_ind, shape):
291 return embed_ind.view(*shape[:-1])
292
293 def dequantize(self, embed_ind):
294 quantize = F.embedding(embed_ind, self.embed)
295 return quantize
296
297 def encode(self, x):
298 shape = x.shape
299 x = self.preprocess(x)
300 embed_ind = self.quantize(x)
301 embed_ind = self.postprocess_emb(embed_ind, shape)
302 return embed_ind
303
304 def decode(self, embed_ind):
305 quantize = self.dequantize(embed_ind)
306 return quantize
307
308 def forward(self, x):
309 shape, dtype = x.shape, x.dtype
310 x = self.preprocess(x)
311
312 self.init_embed_(x)
313
314 embed_ind = self.quantize(x)
315 embed_onehot = F.one_hot(embed_ind, self.codebook_size).type(dtype)
316 embed_ind = self.postprocess_emb(embed_ind, shape)
317 quantize = self.dequantize(embed_ind)
318
319 if self.training:
320 self.expire_codes_(x)
321 _ema_inplace(self.cluster_size, embed_onehot.sum(0), self.decay)
322 embed_sum = x.t() @ embed_onehot
323 _ema_inplace(self.embed_avg, embed_sum.t().contiguous(), self.decay)
324 cluster_size = (
325 _laplace_smoothing(self.cluster_size, self.codebook_size, self.epsilon)
326 * self.cluster_size.sum()
327 )
328 embed_normalized = self.embed_avg / cluster_size.unsqueeze(1)
329 self.embed.data.copy_(embed_normalized)
330
331 return quantize, embed_ind
332
333
334 class VectorQuantization(nn.Module):
335 def __init__(
336 self,
337 dim: int,
338 codebook_size: int,
339 codebook_dim: int | None = None,
340 decay: float = 0.99,
341 epsilon: float = 1e-5,
342 kmeans_init: bool = True,
343 kmeans_iters: int = 50,
344 threshold_ema_dead_code: int = 2,
345 commitment_weight: float = 1.0,
346 ):
347 super().__init__()
348 _codebook_dim: int = _vq_default(codebook_dim, dim)
349
350 requires_projection = _codebook_dim != dim
351 self.project_in = (
352 nn.Linear(dim, _codebook_dim) if requires_projection else nn.Identity()
353 )
354 self.project_out = (
355 nn.Linear(_codebook_dim, dim) if requires_projection else nn.Identity()
356 )
357
358 self.epsilon = epsilon
359 self.commitment_weight = commitment_weight
360
361 self._codebook = EuclideanCodebook(
362 dim=_codebook_dim,
363 codebook_size=codebook_size,
364 kmeans_init=kmeans_init,
365 kmeans_iters=kmeans_iters,
366 decay=decay,
367 epsilon=epsilon,
368 threshold_ema_dead_code=threshold_ema_dead_code,
369 )
370 self.codebook_size = codebook_size
371
372 @property
373 def codebook(self):
374 return self._codebook.embed
375
376 def encode(self, x):
377 x = self.project_in(x)
378 embed_in = self._codebook.encode(x)
379 return embed_in
380
381 def decode(self, embed_ind):
382 quantize = self._codebook.decode(embed_ind)
383 quantize = self.project_out(quantize)
384 return quantize
385
386 def forward(self, x):
387 device = x.device
388 x = self.project_in(x)
389
390 quantize, embed_ind = self._codebook(x)
391
392 if self.training:
393 quantize = x + (quantize - x).detach()
394
395 loss = torch.tensor([0.0], device=device, requires_grad=self.training)
396
397 quantize = self.project_out(quantize)
398 return quantize, embed_ind, loss
399
400
401 class ResidualVectorQuantization(nn.Module):
402 def __init__(self, *, num_quantizers, codebook_size, **kwargs):
403 super().__init__()
404 if isinstance(codebook_size, int):
405 codebook_size = [codebook_size] * num_quantizers
406 elif len(codebook_size) < num_quantizers:
407 codebook_size += [codebook_size[-1]] * (num_quantizers - len(codebook_size))
408 self.layers = nn.ModuleList(
409 [
410 VectorQuantization(codebook_size=codebook_size[i], **kwargs)
411 for i in range(num_quantizers)
412 ]
413 )
414
415 def forward(self, x, n_q: int | None = None, layers: list | None = None):
416 quantized_out = 0.0
417 residual = x
418
419 all_losses = []
420 all_indices = []
421 out_quantized = []
422
423 n_q = n_q or len(self.layers)
424
425 for i, layer in enumerate(self.layers[:n_q]):
426 quantized, indices, loss = layer(residual)
427 residual = residual - quantized
428 quantized_out = quantized_out + quantized
429
430 all_indices.append(indices)
431 all_losses.append(loss)
432 if layers and i in layers:
433 out_quantized.append(quantized_out)
434
435 out_losses, out_indices = map(torch.stack, (all_losses, all_indices))
436 return quantized_out, out_indices, out_losses, out_quantized
437
438 def encode(
439 self, x: torch.Tensor, n_q: int | None = None, st: int | None = None
440 ) -> torch.Tensor:
441 residual = x
442 all_indices = []
443 n_q = len(self.layers) if n_q is None else n_q
444 st = 0 if st is None else st
445 for layer in self.layers[st:n_q]:
446 indices = layer.encode(residual)
447 quantized = layer.decode(indices)
448 residual = residual - quantized
449 all_indices.append(indices)
450 out_indices = torch.stack(all_indices)
451 return out_indices
452
453 def decode(self, q_indices: torch.Tensor, st: int = 0) -> torch.Tensor:
454 quantized_out = self.layers[st].decode(q_indices[0])
455 for i in range(1, len(q_indices)):
456 layer = self.layers[st + i]
457 quantized = layer.decode(q_indices[i])
458 quantized_out = quantized_out + quantized
459 return quantized_out
460
461
462 class ResidualVectorQuantizer(nn.Module):
463 def __init__(
464 self,
465 dimension: int = 256,
466 n_q: int = 8,
467 bins: int | list = 1024,
468 decay: float = 0.99,
469 kmeans_init: bool = True,
470 kmeans_iters: int = 50,
471 threshold_ema_dead_code: int = 2,
472 ):
473 super().__init__()
474 self.n_q = n_q
475 self.dimension = dimension
476 self.bins = bins
477 self.decay = decay
478 self.kmeans_init = kmeans_init
479 self.kmeans_iters = kmeans_iters
480 self.threshold_ema_dead_code = threshold_ema_dead_code
481 self.vq = ResidualVectorQuantization(
482 dim=self.dimension,
483 codebook_size=self.bins,
484 num_quantizers=self.n_q,
485 decay=self.decay,
486 kmeans_init=self.kmeans_init,
487 kmeans_iters=self.kmeans_iters,
488 threshold_ema_dead_code=self.threshold_ema_dead_code,
489 )
490
491 def forward(
492 self,
493 x: torch.Tensor,
494 n_q: int | None = None,
495 layers: list | None = None,
496 ):
497 n_q = n_q if n_q else self.n_q
498 quantized, codes, commit_loss, quantized_list = self.vq(
499 x, n_q=n_q, layers=layers
500 )
501 return quantized, codes, torch.mean(commit_loss), quantized_list
502
503 def encode(
504 self, x: torch.Tensor, n_q: int | None = None, st: int | None = None
505 ) -> torch.Tensor:
506 n_q = n_q if n_q else self.n_q
507 st = st or 0
508 codes = self.vq.encode(x, n_q=n_q, st=st)
509 return codes
510
511 def decode(self, codes: torch.Tensor, st: int = 0) -> torch.Tensor:
512 quantized = self.vq.decode(codes, st=st)
513 return quantized
514
515
516 # ---------------------------------------------------------------------------
517 # Audio tokenizer
518 # ---------------------------------------------------------------------------
519
520
521 class MiMoAudioTokenizerConfig(PreTrainedConfig):
522 model_type = "mimo_audio_tokenizer"
523
524 def __init__(
525 self,
526 max_audio_seconds: int = 1800,
527 stride_size: int = 2,
528 avg_pooler: int = 1,
529 d_model: int = 768,
530 scale_embedding: bool = True,
531 kernel_size: int = 3,
532 activation_function: str = "gelu",
533 encoder_layers: int = 8,
534 encoder_skip_layer_id: int | None = None,
535 encoder_attention_heads: int = 12,
536 encoder_ffn_dim: int = 3072,
537 encoder_causal: bool = False,
538 encoder_attn_window_size: list[int] | None = None,
539 decoder_layers: int = 8,
540 decoder_attention_heads: int = 12,
541 decoder_ffn_dim: int = 3072,
542 decoder_kernel_size: int = 3,
543 decoder_stride_size: int = 2,
544 decoder_causal: bool = True,
545 decoder_attn_window_size: list[int] | None = None,
546 nfft: int = 1024,
547 vocoder_dim: int = 512,
548 vocoder_intermediate_dim: int = 4096,
549 vocoder_num_layers: int = 30,
550 n_mels: int = 80,
551 sampling_rate: int = 24000,
552 hop_length: int = 240,
553 window_size: int = 1024,
554 vocoder_padding: str = "same",
555 fmin: int = 0,
556 fmax: int | None = None,
557 num_quantizers: int = 12,
558 codebook_size: list[int] | None = None,
559 threshold_ema_dead_code: int = 10,
560 position_embedding_type: str = "rope",
561 rope_theta: int = 10000,
562 rope_type: str = "default",
563 ln_type: str = "LayerNorm",
564 vocoder_attention_heads: int = 4,
565 vocoder_attn_window_size: list[int] | None = None,
566 use_istft_only: bool = False,
567 hybrid_attention: bool = False,
568 hybrid_block_size: int = 8,
569 swa_per_block: int = 2,
570 **kwargs,
571 ):
572 super().__init__(**kwargs)
573 self.max_audio_seconds = max_audio_seconds
574 self.stride_size = stride_size
575 self.avg_pooler = avg_pooler
576 self.d_model = d_model
577 self.scale_embedding = scale_embedding
578 self.kernel_size = kernel_size
579 self.activation_function = activation_function
580 self.encoder_layers = encoder_layers
581 self.encoder_skip_layer_id = encoder_skip_layer_id
582 self.encoder_attention_heads = encoder_attention_heads
583 self.encoder_ffn_dim = encoder_ffn_dim
584 self.encoder_causal = encoder_causal
585 self.encoder_attn_window_size = (
586 encoder_attn_window_size
587 if encoder_attn_window_size is not None
588 else [-1, -1]
589 )
590 self.decoder_layers = decoder_layers
591 self.decoder_attention_heads = decoder_attention_heads
592 self.decoder_ffn_dim = decoder_ffn_dim
593 self.decoder_kernel_size = decoder_kernel_size
594 self.decoder_stride_size = decoder_stride_size
595 self.decoder_causal = decoder_causal
596 self.decoder_attn_window_size = (
597 decoder_attn_window_size
598 if decoder_attn_window_size is not None
599 else [-1, -1]
600 )
601 self.nfft = nfft
602 self.vocoder_dim = vocoder_dim
603 self.vocoder_intermediate_dim = vocoder_intermediate_dim
604 self.vocoder_num_layers = vocoder_num_layers
605 self.n_mels = n_mels
606 self.sampling_rate = sampling_rate
607 self.hop_length = hop_length
608 self.window_size = window_size
609 self.vocoder_padding = vocoder_padding
610 self.fmin = fmin
611 self.fmax = fmax
612 self.num_quantizers = num_quantizers
613 self.codebook_size = codebook_size if codebook_size is not None else [1024]
614 self.threshold_ema_dead_code = threshold_ema_dead_code
615 self.position_embedding_type = position_embedding_type
616 self.rope_theta = rope_theta
617 self.rope_type = rope_type
618 self.ln_type = ln_type
619 self.vocoder_attention_heads = vocoder_attention_heads
620 self.vocoder_attn_window_size = (
621 vocoder_attn_window_size
622 if vocoder_attn_window_size is not None
623 else [40, 10]
624 )
625 self.use_istft_only = use_istft_only
626 self.hybrid_attention = hybrid_attention
627 self.hybrid_block_size = hybrid_block_size
628 self.swa_per_block = swa_per_block
629
630
631 def get_sequence_mask(inputs, inputs_length):
632 if inputs.dim() == 3:
633 bsz, tgt_len, _ = inputs.size()
634 else:
635 bsz, tgt_len = inputs_length.shape[0], torch.max(inputs_length)
636 sequence_mask = torch.arange(0, tgt_len).to(inputs.device)
637 sequence_mask = torch.lt(sequence_mask, inputs_length.reshape(bsz, 1)).view(
638 bsz, tgt_len, 1
639 )
640 unpacking_index = torch.cumsum(sequence_mask.to(torch.int64).view(-1), dim=0) - 1
641 return sequence_mask, unpacking_index
642
643
644 def unpack_hidden_states(
645 hidden_states, lengths, sequence_mask=None, unpacking_index=None
646 ):
647 bsz = lengths.shape[0]
648 if sequence_mask is None or unpacking_index is None:
649 sequence_mask, unpacking_index = get_sequence_mask(hidden_states, lengths)
650 hidden_states = torch.index_select(hidden_states, 0, unpacking_index).view(
651 bsz, torch.max(lengths), hidden_states.shape[-1]
652 )
653 return torch.where(sequence_mask, hidden_states, 0)
654
655
656 def get_position_ids(lengths):
657 total_len = lengths.sum()
658 offset = torch.cat([torch.zeros(1).to(lengths), lengths[:-1].cumsum(dim=0)])
659 offset = torch.repeat_interleave(offset, lengths)
660 return torch.arange(0, total_len).to(offset) - offset
661
662
663 LAYER_NORM = {"LayerNorm": nn.LayerNorm}
664
665
666 class AudioEncoderAttention(nn.Module):
667 def __init__(
668 self,
669 embed_dim: int,
670 num_heads: int,
671 window_size: tuple[int, int] = (-1, -1),
672 causal: bool = False,
673 ):
674 super().__init__()
675 self.embed_dim = embed_dim
676 self.num_heads = num_heads
677 self.head_dim = embed_dim // num_heads
678 self.window_size = window_size
679 self.causal = causal
680
681 self.k_proj = nn.Linear(embed_dim, embed_dim, bias=False)
682 self.v_proj = nn.Linear(embed_dim, embed_dim, bias=True)
683 self.q_proj = nn.Linear(embed_dim, embed_dim, bias=True)
684 self.out_proj = nn.Linear(embed_dim, embed_dim, bias=True)
685
686 def forward(
687 self,
688 hidden_states: torch.Tensor,
689 cu_seqlens: torch.Tensor,
690 max_seqlen: int,
691 rope_position_embeddings=None,
692 ):
693 from vllm.vllm_flash_attn import flash_attn_varlen_func
694
695 bsz, _ = hidden_states.size()
696
697 query_states = self.q_proj(hidden_states).view(
698 bsz, self.num_heads, self.head_dim
699 )
700 key_states = self.k_proj(hidden_states).view(bsz, self.num_heads, self.head_dim)
701 value_states = self.v_proj(hidden_states).view(
702 bsz, self.num_heads, self.head_dim
703 )
704
705 if rope_position_embeddings is not None:
706 cos, sin = rope_position_embeddings
707 query_states, key_states = apply_rotary_pos_emb(
708 query_states, key_states, cos, sin
709 )
710
711 attn_output = flash_attn_varlen_func(
712 query_states,
713 key_states,
714 value_states,
715 cu_seqlens_q=cu_seqlens,
716 cu_seqlens_k=cu_seqlens,
717 max_seqlen_q=max_seqlen,
718 max_seqlen_k=max_seqlen,
719 causal=self.causal,
720 window_size=list(self.window_size),
721 )
722
723 attn_output = attn_output.reshape(bsz, self.embed_dim)
724 attn_output = self.out_proj(attn_output)
725 return attn_output
726
727
728 class AudioEncoderTransformerLayer(nn.Module):
729 def __init__(
730 self,
731 config: MiMoAudioTokenizerConfig,
732 causal: bool,
733 attn_window_size: tuple[int, int] = (-1, -1),
734 ):
735 super().__init__()
736 self.embed_dim = config.d_model
737
738 self.self_attn = AudioEncoderAttention(
739 embed_dim=self.embed_dim,
740 num_heads=config.encoder_attention_heads,
741 window_size=attn_window_size,
742 causal=causal,
743 )
744 self.self_attn_layer_norm = LAYER_NORM[config.ln_type](self.embed_dim)
745
746 self.activation_fn = ACT2FN[config.activation_function]
747 self.fc1 = nn.Linear(self.embed_dim, config.encoder_ffn_dim)
748 self.fc2 = nn.Linear(config.encoder_ffn_dim, self.embed_dim)
749 self.final_layer_norm = LAYER_NORM[config.ln_type](self.embed_dim)
750
751 def forward(
752 self,
753 hidden_states: torch.Tensor,
754 cu_seqlens: torch.Tensor,
755 max_seqlen: int,
756 rope_position_embeddings: tuple[torch.Tensor, torch.Tensor],
757 ) -> torch.Tensor:
758 residual = hidden_states
759 hidden_states = self.self_attn_layer_norm(hidden_states)
760 hidden_states = self.self_attn(
761 hidden_states,
762 cu_seqlens,
763 max_seqlen,
764 rope_position_embeddings=rope_position_embeddings,
765 )
766 hidden_states = residual + hidden_states
767
768 residual = hidden_states
769 hidden_states = self.final_layer_norm(hidden_states)
770 hidden_states = self.activation_fn(self.fc1(hidden_states))
771 hidden_states = self.fc2(hidden_states)
772 hidden_states = residual + hidden_states
773
774 return hidden_states
775
776
777 class AudioEncoder(nn.Module):
778 def __init__(
779 self,
780 config: MiMoAudioTokenizerConfig,
781 ):
782 super().__init__()
783 self.config = config
784 self.max_source_positions = (
785 config.max_audio_seconds * config.sampling_rate // config.hop_length
786 ) // config.stride_size
787 self.embed_scale = math.sqrt(config.d_model) if config.scale_embedding else 1.0
788 self.skip_layer_idx = config.encoder_skip_layer_id
789
790 self.conv1 = nn.Conv1d(
791 config.n_mels,
792 config.d_model,
793 kernel_size=config.kernel_size,
794 padding=1,
795 )
796 self.conv2 = nn.Conv1d(
797 config.d_model,
798 config.d_model,
799 kernel_size=config.kernel_size,
800 stride=config.stride_size,
801 padding=1,
802 )
803
804 self.position_embedding = AudioRotaryEmbedding(
805 config.rope_theta,
806 config.d_model // config.encoder_attention_heads,
807 self.max_source_positions,
808 config.rope_type,
809 )
810
811 encoder_attn_window_size = config.encoder_attn_window_size
812 assert encoder_attn_window_size is not None
813 assert len(encoder_attn_window_size) == 2
814 attn_window_size = (
815 encoder_attn_window_size[0],
816 encoder_attn_window_size[1],
817 )
818 attn_window_sizes: list[tuple[int, int]] = []
819 if config.hybrid_attention:
820 for i in range(config.encoder_layers):
821 if i % config.swa_per_block < config.swa_per_block - 1:
822 attn_window_sizes.append(attn_window_size)
823 else:
824 attn_window_sizes.append((-1, -1))
825 else:
826 attn_window_sizes = [attn_window_size] * config.encoder_layers
827
828 self.layers = nn.ModuleList(
829 [
830 AudioEncoderTransformerLayer(
831 config=config,
832 causal=config.encoder_causal,
833 attn_window_size=attn_window_sizes[i],
834 )
835 for i in range(config.encoder_layers)
836 ]
837 )
838
839 self.layer_norm = LAYER_NORM[config.ln_type](config.d_model)
840
841 if config.avg_pooler != 1:
842 self.down_sample_layer = nn.Sequential(
843 nn.Conv1d(
844 config.d_model,
845 config.d_model,
846 config.avg_pooler,
847 config.avg_pooler,
848 bias=False,
849 ),
850 nn.GELU(),
851 )
852 self.down_sample_norm = LAYER_NORM[config.ln_type](config.d_model)
853 else:
854 self.down_sample_layer = None
855
856 self.quantizer: ResidualVectorQuantizer | None
857 if config.num_quantizers != 0:
858 self.quantizer = ResidualVectorQuantizer(
859 dimension=config.d_model,
860 n_q=config.num_quantizers,
861 bins=config.codebook_size,
862 threshold_ema_dead_code=config.threshold_ema_dead_code,
863 )
864 else:
865 self.quantizer = None
866
867 def get_features(self, input_features, output_length):
868 input_features = input_features.to(self.conv1.weight)
869 inputs_embeds = nn.functional.gelu(self.conv1(input_features))
870 inputs_embeds = nn.functional.gelu(self.conv2(inputs_embeds))
871 inputs_embeds = inputs_embeds.permute(0, 2, 1)
872 bsz, tgt_len, _ = inputs_embeds.size()
873 hidden_states = inputs_embeds
874
875 position_ids = get_position_ids(output_length).long().to(input_features.device)
876 rope_position_embeddings = self.position_embedding(input_features, position_ids)
877
878 attention_mask, unpacking_index = get_sequence_mask(
879 hidden_states, output_length
880 )
881 hidden_states = torch.masked_select(hidden_states, attention_mask).view(
882 torch.sum(output_length), self.config.d_model
883 )
884
885 cu_seqlens = F.pad(
886 torch.cumsum(output_length, dim=0), (1, 0), "constant", 0
887 ).to(device=hidden_states.device, dtype=torch.int32)
888 max_seqlen = torch.max(output_length).to(torch.int32).item()
889
890 skip_connect_hidden_states = 0.0
891 for idx, encoder_layer in enumerate(self.layers):
892 hidden_states = encoder_layer(
893 hidden_states,
894 cu_seqlens,
895 max_seqlen,
896 rope_position_embeddings=rope_position_embeddings,
897 )
898 if (self.skip_layer_idx is not None) and idx == self.skip_layer_idx - 1:
899 skip_connect_hidden_states = hidden_states.clone()
900
901 hidden_states += skip_connect_hidden_states
902 hidden_states = self.layer_norm(hidden_states)
903
904 if self.down_sample_layer is not None:
905 hidden_states = torch.index_select(hidden_states, 0, unpacking_index).view(
906 bsz, tgt_len, self.config.d_model
907 )
908 if hidden_states.size(1) % self.config.avg_pooler:
909 pad_len = (
910 self.config.avg_pooler
911 - hidden_states.size(1) % self.config.avg_pooler
912 )
913 hidden_states = torch.nn.functional.pad(
914 hidden_states, (0, 0, 0, pad_len), mode="constant", value=0.0
915 )
916 tgt_len += pad_len
917 tgt_len = tgt_len // self.config.avg_pooler
918 hidden_states = self.down_sample_layer(hidden_states.transpose(1, 2))
919 output_length = (
920 output_length // self.config.avg_pooler
921 + (output_length % self.config.avg_pooler != 0).int()
922 )
923 hidden_states = hidden_states.transpose(1, 2)
924 attention_mask, unpacking_index = get_sequence_mask(
925 hidden_states, output_length
926 )
927 hidden_states = torch.masked_select(hidden_states, attention_mask).view(
928 torch.sum(output_length), self.config.d_model
929 )
930 hidden_states = self.down_sample_norm(hidden_states)
931
932 return (
933 hidden_states,
934 output_length,
935 attention_mask,
936 unpacking_index,
937 tgt_len,
938 bsz,
939 )
940
941 def get_output_length(self, mel_len):
942 tgt_len = mel_len + 3 - self.config.kernel_size
943 return (tgt_len + 2 - self.config.kernel_size) // self.config.stride_size + 1
944
945 @torch.no_grad()
946 def encode(
947 self,
948 input_features,
949 input_lens=None,
950 output_length=None,
951 return_codes_only=False,
952 n_q=None,
953 use_quantizer=True,
954 ):
955 if output_length is None:
956 output_length = self.get_output_length(input_lens)
957 input_features = unpack_hidden_states(input_features, input_lens)
958 hidden_states, output_length, attention_mask, unpacking_index, tgt_len, bsz = (
959 self.get_features(
960 input_features=input_features.transpose(1, 2),
961 output_length=output_length,
962 )
963 )
964
965 dtype = hidden_states.dtype
966 if use_quantizer and self.quantizer is not None:
967 self.quantizer.float()
968 codes = self.quantizer.encode(hidden_states.float(), n_q=n_q)
969 if return_codes_only:
970 return codes, output_length
971 hidden_states = self.quantizer.decode(codes)
972 hidden_states = hidden_states.to(dtype)
973 else:
974 codes = None
975
976 hidden_states_packed = hidden_states.clone()
977 hidden_states = torch.index_select(hidden_states, 0, unpacking_index).view(
978 bsz, tgt_len, self.config.d_model
979 )
980 hidden_states = torch.where(attention_mask, hidden_states, 0)
981 return hidden_states, hidden_states_packed, output_length, codes
982
983 @torch.no_grad()
984 def decode_vq(self, codes):
985 assert self.quantizer is not None
986 self.quantizer.float()
987 return self.quantizer.decode(codes)
988
989
990 class MiMoAudioTokenizer(PreTrainedModel):
991 config_class = MiMoAudioTokenizerConfig
992
993 def __init__(self, config: MiMoAudioTokenizerConfig):
994 super().__init__(config)
995 self.config = config
996 self.sampling_rate = config.sampling_rate
997 self.encoder = AudioEncoder(config=config)
998 self.downsample_rate = int(config.hop_length * 2 * config.avg_pooler)
999
1000 def get_output_length(self, mel_len):
1001 tgt_len = mel_len + 3 - self.config.kernel_size
1002 return (tgt_len + 2 - self.config.kernel_size) // self.config.stride_size + 1
1003
1004 @torch.no_grad()
1005 def encode(self, mels, input_lens, use_quantizer=True):
1006 input_features = mels
1007 encoder_output_length = self.get_output_length(input_lens)
1008 hidden_states, hidden_states_packed, encoder_output_length, codes = (
1009 self.encoder.encode(
1010 input_features, input_lens=input_lens, use_quantizer=use_quantizer
1011 )
1012 )
1013 return hidden_states, hidden_states_packed, encoder_output_length, codes
1014
1015
1016 # ---------------------------------------------------------------------------
1017 # Audio encoding utilities
1018 # ---------------------------------------------------------------------------
1019
1020
1021 def group_by_length(features: torch.Tensor, lengths: torch.Tensor, max_length: int):
1022 if features.size(0) != lengths.sum().item():
1023 raise ValueError(
1024 f"Feature size mismatch: {features.size(0)} vs {lengths.sum().item()}"
1025 )
1026
1027 split_points = []
1028 current_sum = 0
1029
1030 for i, seq_len in enumerate(lengths):
1031 if current_sum + seq_len > max_length and current_sum > 0:
1032 split_points.append(i)
1033 current_sum = seq_len.item()
1034 else:
1035 current_sum += seq_len.item()
1036
1037 group_sizes = []
1038 prev = 0
1039 for point in split_points:
1040 group_sizes.append(point - prev)
1041 prev = point
1042 if prev < len(lengths):
1043 group_sizes.append(len(lengths) - prev)
1044
1045 len_groups = torch.split(lengths, group_sizes)
1046 feature_sizes = [group.sum().item() for group in len_groups]
1047 feature_groups = torch.split(features, feature_sizes)
1048
1049 return feature_groups, len_groups
1050
1051
1052 @torch.no_grad()
1053 def encode_batch(
1054 audio_tokenizer_encoder,
1055 input_features: torch.Tensor,
1056 input_lens: torch.Tensor,
1057 max_length: int = 256000,
1058 ):
1059 feature_groups, len_groups = group_by_length(input_features, input_lens, max_length)
1060
1061 encoded_parts = []
1062 for features, lengths in zip(feature_groups, len_groups):
1063 codes, _ = audio_tokenizer_encoder.encode(
1064 input_features=features, input_lens=lengths, return_codes_only=True
1065 )
1066 encoded_parts.append(codes)
1067
1068 return torch.cat(encoded_parts, dim=-1)
1069
1070
1071 def _segment_lengths_for_mel(mel: torch.Tensor, segment_size: int):
1072 """Split mel into segments of segment_size with a possible shorter remainder."""
1073 input_len = mel.size(0)
1074 segs = [segment_size] * (input_len // segment_size)
1075 if input_len % segment_size > 0:
1076 segs.append(input_len % segment_size)
1077 return segs
1078
1079
1080 @torch.no_grad()
1081 def tokenize_audio_batch(mels, audio_tokenizer_encoder, segment_size=6000, device=None):
1082 """Tokenize multiple mels in one encode_batch call.
1083
1084 Returns list of code tensors, each [T_i, C] for that mel.
1085 """
1086 if not mels:
1087 return []
1088 if device is None:
1089 device = next(audio_tokenizer_encoder.parameters()).device
1090 input_len_seg_per_mel = [_segment_lengths_for_mel(m, segment_size) for m in mels]
1091 input_lens_flat = [s for segs in input_len_seg_per_mel for s in segs]
1092 input_features = torch.cat([m.to(device) for m in mels], dim=0)
1093 input_lens_t = torch.tensor(input_lens_flat, dtype=torch.long, device=device)
1094 codes_packed = encode_batch(
1095 audio_tokenizer_encoder,
1096 input_features=input_features,
1097 input_lens=input_lens_t,
1098 )
1099 codes = codes_packed.transpose(0, 1).detach() # [total_code_T, C]
1100 code_lengths = []
1101 for segs in input_len_seg_per_mel:
1102 out_len = audio_tokenizer_encoder.get_output_length(
1103 torch.tensor(segs, dtype=torch.long, device=device)
1104 )
1105 if getattr(audio_tokenizer_encoder, "down_sample_layer", None) is not None:
1106 avg = audio_tokenizer_encoder.config.avg_pooler
1107 out_len = out_len // avg + (out_len % avg != 0).long()
1108 code_lengths.append(out_len.sum().item())
1109 code_list = torch.split(codes, code_lengths)
1110 return list(code_list)
1111
1112
1113 # ---------------------------------------------------------------------------
1114 # MimoAudioEncoderConfig
1115 # ---------------------------------------------------------------------------
1116
1117
1118 @dataclass
1119 class MimoAudioEncoderConfig:
1120 """Config for MimoAudioEncoder.
1121
1122 Field names match the audio_config dict in the model checkpoint.
1123 """
1124
1125 speech_vocab_size: str = "1025-1025-129-129-129-129-129-129"
1126 speech_zeroemb_idx: str = "1024-1024-128-128-128-128-128-128"
1127 group_size: int = 4
1128 audio_channels: int = 8
1129 input_local_layers: int = 6
1130 input_local_dim: int = 1024
1131 input_full_attention: bool = True
1132 input_local_attn_heads: int = 64
1133 input_local_head_dim: int = 16
1134 input_local_intermediate_size: int = 4096
1135 input_local_hidden_dropout: float = 0.0
1136 out_hidden_size: int = 4096
1137 rope_theta: float = 640000.0
1138 partial_rotary_factor: float = 0.334
1139 projection_layers: int = 1
1140 add_post_norm: bool = False
1141 audio_segment_size: int = 6000
1142
1143 @classmethod
1144 def from_dict(cls, d: dict) -> "MimoAudioEncoderConfig":
1145 known = {f.name for f in dataclasses.fields(cls)}
1146 return cls(**{k: v for k, v in d.items() if k in known})
1147
1148
1149 # ---------------------------------------------------------------------------
1150 # AudioProjection
1151 # ---------------------------------------------------------------------------
1152
1153
1154 class AudioProjection(nn.Module):
1155 def __init__(
1156 self,
1157 input_size: int,
1158 hidden_size: int,
1159 output_size: int,
1160 ) -> None:
1161 super().__init__()
1162 self.mlp = nn.Sequential(
1163 nn.Linear(input_size, hidden_size, bias=False),
1164 nn.GELU(),
1165 nn.Linear(hidden_size, output_size, bias=False),
1166 )
1167
1168 def forward(self, x: torch.Tensor) -> torch.Tensor:
1169 return self.mlp(x)
1170
1171
1172 # ---------------------------------------------------------------------------
1173 # MimoAudioEncoder
1174 # ---------------------------------------------------------------------------
1175
1176
1177 class MimoAudioEncoder(nn.Module):
1178 """Audio encoder for MiMo-V2-Omni.
1179
1180 Encodes mel spectrograms into LLM-compatible embeddings via:
1181 1. Audio tokenizer (VQ codes)
1182 2. Speech embeddings lookup
1183 3. Local Qwen2 transformer
1184 4. Linear projection
1185 """
1186
1187 def __init__(self, config, model_path: str = "") -> None:
1188 super().__init__()
1189 if isinstance(config, dict):
1190 config = MimoAudioEncoderConfig.from_dict(config)
1191 self.config = config
1192 self.audio_channels = config.audio_channels
1193 self.audio_group_size = config.group_size
1194 self.audio_segment_size = config.audio_segment_size
1195
1196 speech_vocab_sizes = self._parse_maybe_list(
1197 config.speech_vocab_size, config.audio_channels
1198 )
1199 speech_empty_ids = self._parse_maybe_list(
1200 config.speech_zeroemb_idx, config.audio_channels
1201 )
1202
1203 input_local_config = Qwen2Config(
1204 hidden_size=config.input_local_dim,
1205 num_hidden_layers=config.input_local_layers,
1206 num_attention_heads=config.input_local_attn_heads,
1207 num_key_value_heads=config.input_local_attn_heads,
1208 intermediate_size=config.input_local_intermediate_size,
1209 attention_dropout=config.input_local_hidden_dropout,
1210 rope_theta=config.rope_theta,
1211 partial_rotary_factor=config.partial_rotary_factor,
1212 )
1213
1214 self.input_local_transformer = Qwen2Model(input_local_config)
1215
1216 if not config.add_post_norm:
1217 self.input_local_transformer.norm = nn.Identity()
1218
1219 self.speech_embeddings = nn.ModuleList(
1220 [
1221 nn.Embedding(
1222 speech_vocab_sizes[i],
1223 config.input_local_dim,
1224 padding_idx=speech_empty_ids[i],
1225 )
1226 for i in range(config.audio_channels)
1227 ]
1228 )
1229
1230 if config.projection_layers == 1:
1231 self.projection = nn.Linear(
1232 config.input_local_dim * config.group_size,
1233 config.out_hidden_size,
1234 bias=False,
1235 )
1236 elif config.projection_layers == 2:
1237 self.projection = AudioProjection(
1238 config.input_local_dim * config.group_size,
1239 config.input_local_dim * config.group_size * 4,
1240 config.out_hidden_size,
1241 )
1242 else:
1243 raise ValueError(f"Invalid projection_layers: {config.projection_layers}")
1244
1245 self.audio_tokenizer: MiMoAudioTokenizer | None = None
1246 if model_path:
1247 audio_tokenizer_path = os.path.join(model_path, "audio_tokenizer")
1248 if os.path.exists(audio_tokenizer_path):
1249 dev = torch.get_default_device()
1250 self.audio_tokenizer = self._load_audio_tokenizer(
1251 audio_tokenizer_path, dev
1252 )
1253 else:
1254 logger.warning(
1255 "Audio tokenizer not found at %s, audio encoding disabled",
1256 audio_tokenizer_path,
1257 )
1258
1259 @staticmethod
1260 def _load_audio_tokenizer(path: str, device: torch.device) -> MiMoAudioTokenizer:
1261 """Load MiMoAudioTokenizer from directory."""
1262 from safetensors.torch import load_file
1263
1264 config_path = os.path.join(path, "config.json")
1265 with open(config_path) as f:
1266 config_dict = json.load(f)
1267 config = MiMoAudioTokenizer.config_class(**config_dict)
1268 model = MiMoAudioTokenizer(config)
1269 safetensors_path = os.path.join(path, "model.safetensors")
1270 bin_path = os.path.join(path, "pytorch_model.bin")
1271 if os.path.exists(safetensors_path):
1272 state_dict = load_file(safetensors_path, device="cpu")
1273 elif os.path.exists(bin_path):
1274 state_dict = torch.load(bin_path, map_location="cpu", weights_only=True)
1275 else:
1276 raise FileNotFoundError(
1277 f"No model weights found in {path} "
1278 "(expected model.safetensors or pytorch_model.bin)"
1279 )
1280 model.load_state_dict(state_dict, strict=False)
1281 model = model.to(device=device, dtype=torch.bfloat16)
1282 model.eval()
1283 model.requires_grad_(False)
1284 return model
1285
1286 def _parse_maybe_list(self, value, length: int) -> list[int]:
1287 if isinstance(value, str) and "-" in value:
1288 return [int(s) for s in value.split("-")]
1289 return [int(value)] * length
1290
1291 def apply_input_local_transformer(self, speech_embeddings: torch.Tensor):
1292 output = self.input_local_transformer(
1293 inputs_embeds=speech_embeddings,
1294 return_dict=True,
1295 is_causal=not self.config.input_full_attention,
1296 )
1297 return output.last_hidden_state
1298
1299 def apply_speech_embeddings(self, audio_codes: torch.Tensor) -> torch.Tensor:
1300 num_segments = audio_codes.shape[0]
1301 _audio_embeddings = torch.zeros(
1302 (num_segments, self.config.group_size, self.config.input_local_dim),
1303 dtype=next(self.speech_embeddings[0].parameters()).dtype,
1304 device=audio_codes.device,
1305 )
1306 for i in range(self.config.audio_channels):
1307 _audio_embeddings.add_(self.speech_embeddings[i](audio_codes[:, :, i]))
1308 return _audio_embeddings
1309
1310 def process_audio(self, audio: torch.Tensor) -> torch.Tensor:
1311 """Pad audio codes to group_size boundary.
1312
1313 Args:
1314 audio: [T, audio_channels] code tensor
1315
1316 Returns:
1317 [T//group_size, group_size, audio_channels]
1318
1319 """
1320 T = audio.shape[0]
1321 audio = audio[:, : self.audio_channels]
1322 padded_T = (
1323 (T + self.audio_group_size - 1)
1324 // self.audio_group_size
1325 * self.audio_group_size
1326 )
1327 padded_audio = torch.cat(
1328 [
1329 audio,
1330 torch.zeros(
1331 padded_T - T,
1332 self.audio_channels,
1333 dtype=torch.int32,
1334 device=audio.device,
1335 )
1336 + audio[-1, :],
1337 ],
1338 dim=0,
1339 )
1340 padded_audio = padded_audio.reshape(
1341 padded_T // self.audio_group_size,
1342 self.audio_group_size,
1343 self.audio_channels,
1344 )
1345 return padded_audio
1346
1347 def get_audio_feature(
1348 self, mel_specs: list[torch.Tensor]
1349 ) -> tuple[torch.Tensor, list[int]]:
1350 """Encode mel spectrograms into LLM embedding space.
1351
1352 Args:
1353 mel_specs: list of mel spectrogram tensors, each [T, n_mels]
1354
1355 Returns:
1356 Tuple of:
1357 - audio_embeds: [total_tokens, out_hidden_size] concatenated embeddings
1358 - item_token_lens: list of int, number of tokens per input item
1359
1360 """
1361 if self.audio_tokenizer is None:
1362 raise RuntimeError(
1363 "audio_tokenizer is not loaded. "
1364 "Ensure model_path points to a directory containing audio_tokenizer/."
1365 )
1366
1367 if not mel_specs:
1368 device = next(self.projection.parameters()).device
1369 dtype = next(self.projection.parameters()).dtype
1370 return (
1371 torch.empty(0, self.config.out_hidden_size, device=device, dtype=dtype),
1372 [],
1373 )
1374
1375 device = next(self.audio_tokenizer.encoder.parameters()).device
1376 code_list = tokenize_audio_batch(
1377 mel_specs,
1378 self.audio_tokenizer.encoder,
1379 segment_size=self.audio_segment_size,
1380 device=device,
1381 )
1382
1383 item_token_lens: list[int] = []
1384 codecs_to_concat = []
1385 for codecs in code_list:
1386 padded_codes = self.process_audio(codecs)
1387 codecs_to_concat.append(padded_codes)
1388 item_token_lens.append(padded_codes.shape[0])
1389
1390 audio_codes = torch.cat(
1391 codecs_to_concat, dim=0
1392 ) # [total_T//group_size, group_size, audio_channels]
1393
1394 _audio_embeddings = self.apply_speech_embeddings(audio_codes)
1395 audio_embeds = self.apply_input_local_transformer(_audio_embeddings)
1396 B = audio_embeds.shape[0]
1397 audio_embeds = self.projection(audio_embeds.reshape(B, -1))
1398 return audio_embeds, item_token_lens