← AI Engineering
Deep Learning · Audio · Speech Emotion Recognition

Speech Emotion Recognition: What Transfer Learning Can and Can't Hear

Classifying emotion in speech — happy, sad, angry, and more — by treating a Mel spectrogram as a "photograph" for a ResNet18 pretrained on natural images. The real story isn't the final accuracy number, but what it took to get a trustworthy one: an overfitting fix, an augmentation strategy, and a reproducibility bug caught before it could mislead the result.

Python PyTorch ResNet18 SpecAugment Transfer Learning

The problem

RAVDESS provides 1,440 speech recordings from 24 actors, each portraying one of 8 emotions in a neutral North American accent. The same Mel-spectrogram + ResNet18 recipe that worked well for satellite imagery was applied here — but speech emotion turned out to be a much harder domain shift from natural photographs, and getting a trustworthy result required fixing two real problems along the way, not just tuning hyperparameters.

Two Mel spectrograms side by side, one labeled Angry and one labeled Calm, showing the time-frequency energy pattern of the same sentence spoken in each emotion
The same sentence, spoken angry (left) and calm (right). Angry shows more concentrated energy in the lower-to-mid frequency bands and sharper, more clipped bursts; calm is visibly softer and more diffuse — this is the kind of pattern the network has to learn to tell apart, across all 8 emotions.

Key results

64.6%
Final test accuracy (8 classes)
+17pts
Gain over frozen-backbone baseline
46→16pts
Train/test gap, before → after SpecAugment
sad ↔ calm
Dominant confusion, every configuration

From underfitting to overfitting to a workable middle ground

A frozen ResNet18 backbone with only a new linear layer trained (4,104 parameters) underfit the problem — 42.2% train accuracy, actually lower than its 47.6% test accuracy, meaning the model wasn't finding much signal in ImageNet-derived features at all. Unfreezing the last residual block (layer4) with a differential learning rate fixed that, but swung hard the other way: 99.9% train accuracy against just 53.5% test accuracy, memorizing training clips instead of generalizing. SpecAugment — randomly masking frequency and time bands on the training spectrograms only — brought the gap back under control without giving up the accuracy gain.

ConfigurationTrain accTest accGap
Frozen backbone (linear probe)42.2%47.6%underfitting
Unfrozen layer4, no augmentation99.9%53.5%~46 pts
Unfrozen layer4 + SpecAugment80.8%64.6%~16 pts

A reproducibility bug, caught before it mattered

While extending training to more epochs, a Colab runtime restart forced the dataset-building step to re-run — and test accuracy unexpectedly jumped, on what looked like a like-for-like re-run. Checking the classification report's per-class support counts revealed the cause: the file-parsing loop listed each actor's audio files without sorting them, so the sample order — and therefore which files landed in train vs. test under a fixed random seed — wasn't guaranteed to stay the same across runs. A one-line fix (sorting the file list) made the split deterministic, and every result reported here was re-verified on that fixed split.

Not the confusion that was expected

Across every configuration tested, the dominant confusion was sad ↔ calm — not calm ↔ neutral, the pairing initially expected to be hardest to separate. Both sad and calm are low-arousal emotions with flat prosody, and the pattern held even as overall accuracy improved and the underlying test set changed before and after the reproducibility fix — evidence this is a genuine acoustic limit of the pipeline, not noise from one particular split. High-arousal emotions (angry, disgust, surprised) were consistently the easiest to classify, both reaching 75-79% recall in the final model.

At 64.6%, absolute accuracy remains well below the 91.8% achieved with the same transfer-learning recipe on satellite imagery. The gap is consistent with the hypothesis that ImageNet-pretrained features transfer less effectively the further the target domain sits from natural photographs — a spectrogram's time-frequency structure is a much bigger shift than satellite imagery, which still looks broadly "photograph-like."

Tools used

Python PyTorch torchaudio torchvision scikit-learn Google Colab