Prompt48 commited on
Commit
58e7ae6
·
verified ·
1 Parent(s): 4a0ab7a

Upload edit\Qwen3-TTS-test\.venv\Lib\site-packages\transformers\models\granite_speech\feature_extraction_granite_speech.py with huggingface_hub

Browse files
edit//Qwen3-TTS-test//.venv//Lib//site-packages//transformers//models//granite_speech//feature_extraction_granite_speech.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2025 The HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Feature extractor class for Granite Speech."""
16
+
17
+ import math
18
+ from collections.abc import Sequence
19
+ from typing import Optional
20
+
21
+ import numpy as np
22
+
23
+ from ...feature_extraction_utils import BatchFeature, FeatureExtractionMixin
24
+ from ...tokenization_utils_base import AudioInput
25
+ from ...utils import is_torch_available, is_torchaudio_available, logging
26
+ from ...utils.import_utils import requires_backends
27
+
28
+
29
+ logger = logging.get_logger(__name__)
30
+
31
+ if is_torch_available():
32
+ import torch
33
+
34
+ if is_torchaudio_available():
35
+ import torchaudio
36
+
37
+
38
+ class GraniteSpeechFeatureExtractor(FeatureExtractionMixin):
39
+ model_input_names = ["input_features"]
40
+
41
+ def __init__(
42
+ self,
43
+ sampling_rate: int = 16000,
44
+ n_fft: int = 512,
45
+ win_length: int = 400,
46
+ hop_length: int = 160,
47
+ n_mels: int = 80,
48
+ projector_window_size: int = 15,
49
+ projector_downsample_rate: int = 5,
50
+ **kwargs,
51
+ ):
52
+ super().__init__(**kwargs)
53
+ self.sampling_rate = sampling_rate
54
+ self.melspec_kwargs = {
55
+ "sample_rate": sampling_rate,
56
+ "n_fft": n_fft,
57
+ "win_length": win_length,
58
+ "hop_length": hop_length,
59
+ "n_mels": n_mels,
60
+ }
61
+ requires_backends(self, ["torchaudio"])
62
+ self.mel_filters = torchaudio.transforms.MelSpectrogram(**self.melspec_kwargs)
63
+ self.projector_window_size = projector_window_size
64
+ self.projector_downsample_rate = projector_downsample_rate
65
+
66
+ def __call__(
67
+ self,
68
+ audios: AudioInput,
69
+ device: Optional[str] = "cpu",
70
+ ) -> BatchFeature:
71
+ requires_backends(self, ["torchaudio"])
72
+
73
+ speech_inputs = {}
74
+ batched_audio, audio_lengths = self._get_audios_and_audio_lengths(audios)
75
+ speech_inputs["input_features"] = self._extract_mel_spectrograms(
76
+ batched_audio,
77
+ device=device,
78
+ )
79
+ audio_embed_sizes = self._get_num_audio_features(audio_lengths)
80
+ speech_inputs["audio_embed_sizes"] = audio_embed_sizes
81
+ # TODO (@alex-jw-brooks): Currently input_features_mask is not
82
+ # a great name, because input_features and input_features_mask
83
+ # have different shapes (before/after the projector).
84
+ #
85
+ # We should align this with other multimodal models, e.g,. llava
86
+ # and qwen2audio and refactor this to ensure input_feature_mask
87
+ # has the same dimensionality as input_features, or compute it in
88
+ # the model based on the audio embedding sizes (since we do not
89
+ # have an attention mask for the audio features to infer padding from).
90
+ speech_inputs["input_features_mask"] = torch.arange(max(audio_embed_sizes)).view(1, -1) < torch.tensor(
91
+ audio_embed_sizes
92
+ ).view(-1, 1)
93
+ return BatchFeature(data=speech_inputs)
94
+
95
+ def _extract_mel_spectrograms(self, audio: "torch.Tensor", device="cpu"):
96
+ """
97
+ Compute the Mel features to be passed to the conformer encoder.
98
+ """
99
+ requires_backends(self, ["torchaudio"])
100
+ if device is not None:
101
+ melspec = self.mel_filters.to(device)
102
+ audio = audio.to(device)
103
+ else:
104
+ melspec = self.mel_filters
105
+
106
+ bsz = audio.shape[0]
107
+ with torch.no_grad():
108
+ # Compute mel features
109
+ mel = melspec(audio.float())
110
+ logmel = mel.transpose(-1, -2).clip_(min=1e-10).log10_()
111
+ mx = logmel.amax(dim=(-2, -1), keepdim=True)
112
+ logmel = torch.maximum(logmel, mx - 8.0).div_(4).add_(1)
113
+ # remove last frame if odd
114
+ if logmel.shape[1] % 2 == 1:
115
+ logmel = logmel[:, :-1]
116
+
117
+ # stacking and skipping by 2
118
+ audio = logmel.reshape(bsz, -1, 2 * logmel.shape[-1])
119
+
120
+ return audio
121
+
122
+ def _get_num_audio_features(self, audio_lengths: Sequence[int]) -> Sequence[int]:
123
+ """
124
+ Gets the (variable length) number of features (i.e., projector output) for the sequences
125
+ being considered.
126
+
127
+ Args:
128
+ audio_lengths (`Sequence[int]`):
129
+ Sequence of one or more raw audio lengths.
130
+ """
131
+ hop_length = self.melspec_kwargs["hop_length"]
132
+ effective_window_size = self.projector_window_size // self.projector_downsample_rate
133
+
134
+ projector_lengths = []
135
+ for raw_length in audio_lengths:
136
+ # mel sequence length computation
137
+ mel_length = raw_length // hop_length + 1
138
+ # encoder frame takes two mel features
139
+ encoder_length = mel_length // 2
140
+ nblocks = math.ceil(encoder_length / self.projector_window_size)
141
+ # projector output length
142
+ projector_length = nblocks * effective_window_size
143
+ projector_lengths.append(projector_length)
144
+
145
+ return projector_lengths
146
+
147
+ def _get_audios_and_audio_lengths(self, audios: AudioInput) -> Sequence["torch.Tensor", Sequence[int]]:
148
+ """
149
+ Coerces audio inputs to torch tensors and extracts audio lengths prior to stacking.
150
+
151
+ Args:
152
+ audios (`AudioInput`):
153
+ Audio sequence, numpy array, or torch tensor.
154
+ """
155
+ requires_backends(self, ["torch"])
156
+
157
+ # Coerce to PyTorch tensors if we have numpy arrays, since
158
+ # currently we have a dependency on torch/torchaudio anyway
159
+ if isinstance(audios, np.ndarray):
160
+ audios = torch.from_numpy(audios)
161
+ elif isinstance(audios, Sequence) and isinstance(audios[0], np.ndarray):
162
+ audios = [torch.from_numpy(arr) for arr in audios]
163
+
164
+ if isinstance(audios, torch.Tensor):
165
+ if audios.ndim == 1:
166
+ audios = audios.unsqueeze(0)
167
+ if not torch.is_floating_point(audios):
168
+ raise ValueError("Invalid audio provided. Audio should be a floating point between 0 and 1")
169
+
170
+ if audios.shape[0] > 1:
171
+ logger.warning("Audio samples are already collated; assuming they all have the same length")
172
+ lengths = [audios.shape[-1]] * audios.shape[0]
173
+ return audios, lengths
174
+
175
+ elif isinstance(audios, Sequence) and isinstance(audios[0], torch.Tensor):
176
+ if not torch.is_floating_point(audios[0]):
177
+ raise ValueError("Invalid audio provided. Audio should be a floating point between 0 and 1")
178
+ lengths = [audio.shape[-1] for audio in audios]
179
+ audios = [audio.squeeze(0) for audio in audios]
180
+ audios = torch.nn.utils.rnn.pad_sequence(audios, batch_first=True, padding_value=0.0)
181
+ return audios, lengths
182
+
183
+ raise TypeError("Invalid audio provided. Audio should be a one or more torch tensors or numpy arrays")
184
+
185
+
186
+ __all__ = ["GraniteSpeechFeatureExtractor"]