Spaces:
Running
Running
Download ced_runtime.py from teamup-tech/CED-Tiny: direct link, hf CLI and curl.
- Browser
- Download file 2.7 kB
-
https://huggingface.co/spaces/teamup-tech/CED-Tiny/resolve/main/ced_runtime.py
- Command line
-
hf download hf://spaces/teamup-tech/CED-Tiny/ced_runtime.py
-
curl -L -o ced_runtime.py https://huggingface.co/spaces/teamup-tech/CED-Tiny/resolve/main/ced_runtime.py
2.7 kB
| from __future__ import annotations | |
| from functools import lru_cache | |
| import numpy as np | |
| import soundfile as sf | |
| import torch | |
| from scipy.signal import resample_poly | |
| from transformers import AutoFeatureExtractor, AutoModelForAudioClassification | |
| MODEL_ID = "mispeech/ced-tiny" | |
| MODEL_REVISION = "ace276d29dd0bb3f3517b0fa8cf300738c409019" | |
| TARGET_SAMPLE_RATE = 16000 | |
| WINDOW_SAMPLES = 10 * TARGET_SAMPLE_RATE | |
| def _load_model(): | |
| feature_extractor = AutoFeatureExtractor.from_pretrained( | |
| MODEL_ID, | |
| revision=MODEL_REVISION, | |
| trust_remote_code=True, | |
| ) | |
| model = AutoModelForAudioClassification.from_pretrained( | |
| MODEL_ID, | |
| revision=MODEL_REVISION, | |
| trust_remote_code=True, | |
| ) | |
| model.to("cpu") | |
| model.eval() | |
| return feature_extractor, model | |
| def _load_audio(path: str) -> np.ndarray: | |
| audio, sample_rate = sf.read(path, dtype="float32", always_2d=True) | |
| if sample_rate <= 0 or audio.size == 0: | |
| raise ValueError("The audio file is empty or has an invalid sample rate.") | |
| if not np.isfinite(audio).all(): | |
| raise ValueError("The audio file contains non-finite samples.") | |
| audio = audio.mean(axis=1) | |
| if sample_rate != TARGET_SAMPLE_RATE: | |
| divisor = int(np.gcd(sample_rate, TARGET_SAMPLE_RATE)) | |
| audio = resample_poly( | |
| audio, | |
| TARGET_SAMPLE_RATE // divisor, | |
| sample_rate // divisor, | |
| ).astype(np.float32, copy=False) | |
| return np.ascontiguousarray(audio, dtype=np.float32) | |
| def classify_audio(path: str, top_k: int = 10) -> list[dict[str, float | str]]: | |
| audio = _load_audio(path) | |
| feature_extractor, model = _load_model() | |
| window_probabilities = [] | |
| for start in range(0, len(audio), WINDOW_SAMPLES): | |
| window = audio[start : start + WINDOW_SAMPLES] | |
| inputs = feature_extractor( | |
| window, | |
| sampling_rate=TARGET_SAMPLE_RATE, | |
| return_tensors="pt", | |
| ) | |
| with torch.inference_mode(): | |
| logits = model(**inputs).logits[0] | |
| window_probabilities.append(torch.sigmoid(logits)) | |
| probabilities = torch.stack(window_probabilities).mean(dim=0) | |
| if not torch.isfinite(probabilities).all(): | |
| raise ValueError("The model returned non-finite scores.") | |
| count = min(max(1, int(top_k)), probabilities.numel()) | |
| scores, indices = torch.topk(probabilities, k=count) | |
| labels = model.config.id2label | |
| return [ | |
| { | |
| "rank": rank, | |
| "label": str(labels.get(int(index), int(index))), | |
| "score": round(float(score), 6), | |
| } | |
| for rank, (score, index) in enumerate(zip(scores, indices), start=1) | |
| ] | |