Original source
---
id: audio-features
title: Audio Features, Classification and Metrics
code: AF
subtitle: Sample, frame, window, mel, MFCC, classify and score audio. Stdlib Python from the lessons.
hue: 25
sources: phases/06-speech-and-audio/01-audio-fundamentals, phases/06-speech-and-audio/02-spectrograms-mel-features, phases/06-speech-and-audio/03-audio-classification, phases/06-speech-and-audio/17-audio-evaluation-metrics
source_hash: bfd4e5e3ac478c89
---
## Waveform to label
type: architecture
from: phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/03-audio-classification/docs/en.md, phases/06-speech-and-audio/03-audio-classification/code/main.py
```arch
node | wav | 1,1 | Waveform | floats in [-1, 1] | client
node | frame | 2,1 | Frames | 400 samples, hop 160 | process
node | stft | 3,1 | STFT | Hann window, FFT | process
node | mel | 4,1 | Mel filterbank | 80 triangles | process
node | log | 4,2 | Log-mel | Whisper input | store
node | mfcc | 3,2 | MFCC | DCT-II, keep 13 | process
node | pool | 2,2 | Pool | mean + var, 26 dims | process
node | clf | 1,2 | Classifier | k-NN, CNN, AST, BEATs | model
edge | wav | frame |
edge | frame | stft |
edge | stft | mel | magnitude
edge | mel | log | log
edge | log | mfcc | DCT
edge | mfcc | pool |
edge | pool | clf | cosine
```
## Formulas
type: concepts
from: phases/06-speech-and-audio/01-audio-fundamentals/docs/en.md, phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/03-audio-classification/docs/en.md
- **Time**: $t = n / sr$. A 10 s clip at 16 kHz is 160,000 floats.
- **Nyquist**: $sr / 2$. Energy above it aliases to lower bins.
- **Alias**: a 7 kHz tone sampled at 10 kHz folds to $10 - 7 = 3$ kHz.
- **Bin**: bin $k$ is $k \cdot sr / N$ Hz. Resolution is $sr / N$.
- **Mel**: $m = 2595 \cdot \log_{10}(1 + f / 700)$
- **Hann**: $w(n) = 0.5 (1 - \cos(2 \pi n / (N - 1)))$
- **Frames**: $1 + (T - L) / hop$. 10 s at 16 kHz gives 998 frames.
- **Mixup**: $x = \lambda x_1 + (1 - \lambda) x_2$, same for $y$.
## Feature defaults
type: defaults
from: phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/01-audio-fundamentals/docs/en.md
| Setting | Default | Note |
|---|---|---|
| Frame length | 400 | 25 ms at 16 kHz |
| Hop | 160 | 10 ms at 16 kHz |
| Window | Hann | Tapers frame edges to zero |
| Mel bins, ASR | 80 | Cover 0 to 8 kHz |
| Mel bins, classification | 128 | AST, PANNs, BEATs |
| MFCC count | 13 | Drop coefficient 0, it is energy |
| Log floor `eps` | 1e-10 | log(mel_spec + 1e-10) |
| Keyword spotting | 40 MFCCs | For tiny devices |
## Tasks in code
type: task-table
from: phases/06-speech-and-audio/01-audio-fundamentals/code/main.py, phases/06-speech-and-audio/02-spectrograms-mel-features/code/main.py, phases/06-speech-and-audio/03-audio-classification/code/main.py
| Task | Code |
|---|---|
| Synthesize a tone | `sine(freq_hz, sr, seconds, amp=0.5)` |
| Find the dominant frequency | `peak_freq(samples, sr)` |
| Frame a signal | `frame_signal(signal, frame_len, hop)` |
| STFT magnitude | `stft_magnitude(signal, frame_len, hop)` |
| Mel filterbank | `mel_filterbank(n_mels, n_fft, sr)` |
| Log-mel | `log_transform(mel_spec, eps=1e-10)` |
| MFCC | `dct_ii(x, n_coeffs)` |
| k-NN vote | `knn(q, bank, labels, k=3)` |
## MFCC k-NN baseline
type: annotated-code
lang: python
from: phases/06-speech-and-audio/03-audio-classification/code/main.py
```python
sr = 8000 # demo rate in the code
mag = stft_mag(signal, frame_len, hop) # Hann, then DFT per frame
fb = mel_filterbank(n_mels, frame_len, sr) # n_mels x (n_fft // 2 + 1)
mels = apply_filterbank(mag, fb) # weighted sum per mel bin
lm = log_transform(mels) # log(max(v, eps))
feats = [dct_ii(f, n_mfcc) for f in lm] # 13 coefficients per frame
emb = summarize(feats) # mean + var, 26 dims
pred = knn(emb, X_train, y_train, k=3) # cosine top k, majority vote
```
## Score a model
type: annotated-code
lang: python
from: phases/06-speech-and-audio/17-audio-evaluation-metrics/docs/en.md
span: 2
```python
from jiwer import wer, Compose, ToLowerCase, RemovePunctuation, Strip
transform = Compose([ToLowerCase(), RemovePunctuation(), Strip()])
score = wer(truth="Please turn on the lights.", hypothesis="please turn on the light",
truth_transform=transform, hypothesis_transform=transform)
sv = EncoderClassifier.from_hparams("speechbrain/spkrec-ecapa-voxceleb")
secs = torch.nn.functional.cosine_similarity(emb_ref, emb_clone, dim=-1).item() # SECS
fad = FrechetAudioDistance()
score = fad.get_fad_score("generated_folder/", "reference_folder/") # lower is better
```
## Libraries
type: command-table
from: phases/06-speech-and-audio/01-audio-fundamentals/docs/en.md, phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/03-audio-classification/docs/en.md, phases/06-speech-and-audio/17-audio-evaluation-metrics/docs/en.md
| Command | What it does |
|---|---|
| `soundfile` | Reads WAV, FLAC, OGG as float32 |
| `torchaudio.transforms.Resample` | Resamples with anti-aliasing built in |
| `numpy.fft.rfft` | Real FFT for real audio |
| `torch.stft` | Vectorized STFT |
| `librosa.power_to_db` | Reference-normalized dB |
| `ffprobe` | Reports sr, channels and codec of a file |
| `jiwer` | WER and CER with normalization |
| `ASTForAudioClassification.from_pretrained` | Loads AST to fine-tune |
## Pick a classifier
type: concepts
from: phases/06-speech-and-audio/03-audio-classification/docs/en.md
- **Under 1000 clips**: k-NN on MFCC means plus audio augmentation.
- **1K to 100K clips**: BEATs or AST fine-tune.
- **Over 100K clips**: train from scratch or fine-tune Whisper-encoder.
- **Real-time, edge**: 40-MFCC CNN, quantized to int8.
- **Multi-label**: BEATs-iter3 with BCE loss, mixup and SpecAugment.
- **Exclusive classes**: report top-1 and top-5 accuracy.
- **Imbalanced classes**: report per-class recall and macro F1.
## Metrics
type: glossary
from: phases/06-speech-and-audio/17-audio-evaluation-metrics/docs/en.md
- **WER**: Word Error Rate. (S + D + I) / N after normalization.
- **CER**: Character Error Rate. For tone languages.
- **RTFx**: audio seconds per wall-clock second. Higher is better.
- **MOS**: Mean Opinion Score. 1 to 5, 20+ listeners, 100+ samples.
- **UTMOS**: learned MOS predictor. Correlates ~0.9 with human MOS.
- **SECS**: ECAPA cosine of reference and clone. Above 0.75 is recognizable.
- **EER**: threshold where FAR equals FRR. ECAPA on VoxCeleb1-O: 0.87%.
- **DER**: (FA + Miss + Confusion) / total speaker time.
- **FAD**: Fréchet distance on VGGish embeddings. Lower is better.
## Troubleshooting
type: troubleshooting
from: phases/06-speech-and-audio/01-audio-fundamentals/docs/en.md, phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/17-audio-evaluation-metrics/docs/en.md
| Symptom | Cause | Fix |
|---|---|---|
| Garbage that looks like a model bug | 44.1 kHz stereo into Whisper | Resample to 16 kHz mono float32 |
| FFT peak at a false frequency | Energy above Nyquist aliased | Low-pass filter before downsampling |
| Silent failure after deploy | 80 mels in training, 128 at inference | Log the feature shape at both ends |
| Mels look different | Featurized at 22.05 kHz | Fix SR before featurization |
| Whisper input looks wrong | dB-mel, not log-mel | Feed log-mel. Custom code does not autodetect |
| WER doubles in production | Per-utterance norm in training, global at inference | Use the same normalization |
| Flat trailing frames | Zero-padding at the clip end | Pad symmetrically or replicate |
| 5% WER hides 30% on accents | Aggregate WER | Report by demographic slice |
## Questions
type: qa
from: phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/01-audio-fundamentals/docs/en.md, phases/06-speech-and-audio/17-audio-evaluation-metrics/docs/en.md
- **Why mel, not Hz?** Humans hear pitch on a log scale.
- **Why a window?** It removes spectral leakage at the frame edges.
- **Why log-magnitude?** Raw magnitudes span 5-6 orders of magnitude.
- **Bigger FFT?** Better frequency resolution. Worse time resolution.
- **Why FFT, not DFT?** The DFT is O(N²). The FFT is O(N log N).
- **Why minDCF?** It weights cost at a chosen operating point.
## Tips
type: tips
from: phases/06-speech-and-audio/01-audio-fundamentals/docs/en.md, phases/06-speech-and-audio/02-spectrograms-mel-features/docs/en.md, phases/06-speech-and-audio/03-audio-classification/docs/en.md, phases/06-speech-and-audio/17-audio-evaluation-metrics/docs/en.md
- Match sample rate before you match anything else.
- If you are not working on music, start with 80 log-mels.
- Start with a frozen backbone, not a fresh model.
- Use balanced sampling in training, not in evaluation.
- Normalize text before you score WER. Report the rule.
- Report P50/P95/P99 for latency.
- Keep an in-house held-out set. Public benchmarks saturate.