| |
| """ |
| Extract Whisper Encoder hidden states from an audio file. |
| Loads openai/whisper-large-v3-turbo from HuggingFace transformers |
| and produces (seq_len, 1280) hidden states. |
| """ |
|
|
| import argparse |
| import logging |
| import sys |
|
|
| import librosa |
| import numpy as np |
| import torch |
|
|
| logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(name)s:%(message)s") |
| logger = logging.getLogger(__name__) |
|
|
|
|
| class WhisperEncoder: |
| """Wrapper around Whisper-large-v3-turbo encoder for feature extraction.""" |
|
|
| MODEL_ID = "openai/whisper-large-v3-turbo" |
|
|
| def __init__(self, device: str = "cpu"): |
| self.device = device |
| logger.info(f"Loading Whisper encoder from {self.MODEL_ID}...") |
| from transformers import WhisperModel |
|
|
| self.model = WhisperModel.from_pretrained( |
| self.MODEL_ID, |
| torch_dtype=torch.float32, |
| low_cpu_mem_usage=True, |
| ).to(device) |
| self.model.eval() |
| |
| self.encoder = self.model.encoder |
| |
| for param in self.encoder.parameters(): |
| param.requires_grad = False |
| logger.info("Whisper encoder loaded successfully.") |
|
|
| @torch.no_grad() |
| def encode(self, audio: np.ndarray, sampling_rate: int = 16000) -> np.ndarray: |
| """ |
| Encode audio waveform to hidden states. |
| |
| Args: |
| audio: 1D numpy array of audio samples |
| sampling_rate: Sample rate of input audio (will resample to 16000 if needed) |
| |
| Returns: |
| numpy array of shape (seq_len, 1280) with encoder hidden states |
| """ |
| |
| if sampling_rate != 16000: |
| audio = librosa.resample(audio, orig_sr=sampling_rate, target_sr=16000) |
| sampling_rate = 16000 |
|
|
| |
| |
| from transformers import WhisperFeatureExtractor |
|
|
| feature_extractor = WhisperFeatureExtractor.from_pretrained(self.MODEL_ID) |
| |
| input_features = feature_extractor( |
| audio, sampling_rate=sampling_rate, return_tensors="pt" |
| ).input_features |
| input_features = input_features.to(self.device) |
|
|
| |
| encoder_outputs = self.encoder(input_features) |
| |
| hidden_states = encoder_outputs.last_hidden_state.squeeze(0).cpu().numpy() |
| |
| return hidden_states |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser( |
| description="Extract Whisper encoder hidden states from audio" |
| ) |
| parser.add_argument("audio_path", help="Path to audio file") |
| parser.add_argument( |
| "--device", |
| default="cpu", |
| choices=["cpu", "cuda"], |
| help="Device to run encoder on", |
| ) |
| args = parser.parse_args() |
|
|
| |
| logger.info(f"Loading audio: {args.audio_path}") |
| audio, sr = librosa.load(args.audio_path, sr=16000, mono=True) |
| logger.info(f"Audio loaded: {len(audio)} samples, {sr}Hz, {len(audio)/sr:.2f}s") |
|
|
| |
| encoder = WhisperEncoder(device=args.device) |
|
|
| |
| hidden_states = encoder.encode(audio, sampling_rate=sr) |
| logger.info(f"Hidden states shape: {hidden_states.shape}") |
| logger.info(f"Hidden states dtype: {hidden_states.dtype}") |
| logger.info(f"Hidden states range: [{hidden_states.min():.4f}, {hidden_states.max():.4f}]") |
|
|
| print(f"\nHidden states shape: {hidden_states.shape}") |
| print(f"Sequence length: {hidden_states.shape[0]}") |
| print(f"Feature dimension: {hidden_states.shape[1]}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |