Audio Classification
autrainer
audio
ecoacoustic-tagging
HearTheSpecies
ecoacoustics
CoarseSoundNet / clap_feature_extractor.py
AlexanderGbd's picture
Upload clap_feature_extractor.py
e821702 verified
Raw
History Blame Contribute Delete
3.7 kB
from typing import TYPE_CHECKING, List, Optional, Union
import warnings
from audtorch import transforms as AT
from matplotlib.pyplot import get_cmap
import numpy as np
from omegaconf import OmegaConf
import torch
from torchaudio import transforms as TT
import torchlibrosa
from torchvision import transforms as T
from transformers import (
ASTFeatureExtractor,
AutoFeatureExtractor,
Wav2Vec2FeatureExtractor,
WhisperFeatureExtractor,
ClapFeatureExtractor
)
from autrainer.transforms.abstract_transform import AbstractTransform
from autrainer.transforms.smart_compose import SmartCompose
from autrainer.transforms.utils import _to_numpy, _to_tensor
FE_MAPPINGS = {
"AST": {"fe": ASTFeatureExtractor, "padding": "max_length"},
"Whisper": {"fe": WhisperFeatureExtractor, "padding": "max_length"},
"W2V2": {"fe": Wav2Vec2FeatureExtractor, "padding": "longest"},
"CLAP": {"fe": ClapFeatureExtractor, "padding": "repeatpad"},
None: {"fe": AutoFeatureExtractor, "padding": "max_length"},
}
class FeatureExtractor(AbstractTransform):
def __init__(
self,
fe_type: Optional[str] = None,
fe_transfer: Optional[str] = None,
sampling_rate: int = 16000,
hop_length: int = 480,
fft_window_size: int = 1024,
frequency_min: int = 0,
frequency_max: int = 14000,
order: int = -80,
) -> None:
"""Extract features from an audio signal using a feature extractor
from the Hugging Face Transformers library.
Args:
fe_type: The class of feature extractor to use in ["AST", "Whisper",
"W2V2", None]. If None, the AutoFeatureExtractor will be used.
Defaults to None.
fe_transfer: The name of a pretrained feature extractor to use.
If None, the feature extractor will be initialized with default
values. Defaults to None.
sampling_rate: The sampling rate of the audio signal. Defaults to
16000.
order: The order of the transform in the pipeline. Defaults to -80.
Raises:
ValueError: If neither 'fe_type' nor 'fe_transfer' is provided.
"""
super().__init__(order=order)
if fe_type is None and fe_transfer is None:
raise ValueError(
"Either 'fe_type' or 'fe_transfer' must be provided."
)
self.fe_type = fe_type
self.fe_transfer = fe_transfer
self.sampling_rate = sampling_rate
fe_class = FE_MAPPINGS[self.fe_type]["fe"]
padding = FE_MAPPINGS[self.fe_type]["padding"]
if self.fe_transfer is not None:
feature_extractor = fe_class.from_pretrained(self.fe_transfer)
else:
feature_extractor = fe_class()
extractor_dict = {
k: repr(v) for k, v in feature_extractor.__dict__.items()
}
warnings.warn(
f"{fe_class.__name__} "
"initialized with default values:\n"
f"{OmegaConf.to_yaml(extractor_dict)}"
)
def extract_features(signal: np.ndarray) -> torch.Tensor:
if len(signal.shape) == 2:
signal = signal.mean(0)
extracted = feature_extractor(
signal,
sampling_rate=self.sampling_rate,
padding=padding,
return_tensors="pt",
)
return extracted[list(extracted.keys())[0]][0]
self._extract_features = extract_features
def __call__(self, data: torch.Tensor) -> torch.Tensor:
return self._extract_features(data.numpy())