Audio CNN (ResNet-34) for Environmental Sound Classification (ESC-50)
A 21.3M-parameter ResNet-34 CNN that classifies 50 everyday sounds (dog bark, rain, siren, chirping birds, keyboard typing, …) from log-mel spectrograms. It was initialised from ImageNet weights and fine-tuned on ESC-50.
| Accuracy (recipe, 5-fold CV) | 91.3% ± 1.3 |
| This checkpoint (held-out fold 4) | 93.25% top-1 · 99.0% top-3 · 0.931 macro F1 |
| Baseline (same architecture, from scratch) | 83.0% |
| Human listeners on ESC-50 | 81.3% |
| CPU inference | ~57 ms per 5 s clip (2 CPU threads) |
| Training cost | ~2.2 min on one A10G GPU |
Code, training pipeline and an interactive layer-visualisation dashboard: github.com/Akash-Sakala/audio-cnn
Quick start
pip install torch torchaudio soundfile safetensors huggingface_hub
The architecture is plain PyTorch (no custom library), so download the repo and import model.py:
import sys
from huggingface_hub import snapshot_download
path = snapshot_download("Akash-Sakala/audio-cnn-resnet34-esc50", allow_patterns=["*.py", "*.json", "*.safetensors"])
sys.path.insert(0, path)
from model import AudioClassifier
clf = AudioClassifier.from_pretrained(path) # CPU or GPU, picked automatically
print(clf.predict("birds.wav", top_k=3))
# [('chirping_birds', 0.832), ('frog', 0.019), ('rain', 0.008)]
Or from the command line after cloning this repo:
python inference.py dog_bark.wav rain.wav --top-k 3
- Any input format: WAV, FLAC or OGG, at any sample rate, mono or stereo. Audio is converted to 44.1 kHz mono automatically.
- Feature maps:
clf.predict(path, return_feature_maps=True)also returns the activations of every layer and residual block, for interpretability.
Model details
| Property | Value |
|---|---|
| Architecture | ResNet-34 layout: 7×7 stem conv + max-pool, BasicBlocks 3-4-6-3 (64→512 ch), global avg-pool, dropout 0.5, linear head |
| Parameters | 21,304,050 |
| Input | 1 × 128 mel bins × 431 frames (5 s clip) |
| Output | logits over 50 ESC-50 classes (config.json → id2label) |
| Initialisation | ImageNet ResNet-34 (torchvision IMAGENET1K_V1, same weights as timm/resnet34.tv_in1k). All 216 backbone tensors map 1:1; the RGB stem filters are summed into 1 input channel; the head is newly initialised |
| Saved weights | EMA (exponential moving average) of the weights at the final epoch |
| Format | model.safetensors (fp32, 85 MB) |
Stage output shapes (5 s clip): stem 64×32×108 → layer1 64×32×108 → layer2 128×16×54 → layer3 256×8×27 → layer4 512×4×14.
Input pipeline
| Step | Setting |
|---|---|
| Audio | mono, 44.1 kHz |
| Mel spectrogram | n_fft 1024, hop 512, 128 mel bins, 20 Hz – 22.05 kHz |
| dB scaling | AmplitudeToDB(top_db=80), clamped per clip |
| Normalisation | (x − (−18.07)) / 21.25, statistics computed on the training folds |
All values are in config.json["frontend"]. model.py applies them automatically.
Training
| Hyperparameter | Value |
|---|---|
| Data | ESC-50 folds 1, 2, 3, 5 (1,600 clips); fold 4 held out (400 clips) |
| Epochs / batch size | 60 / 32 |
| Optimiser | AdamW: backbone lr 3e-4, head lr 3e-3; weight decay 0.05 (none on BatchNorm or bias) |
| LR schedule | 3-epoch linear warm-up, then cosine decay to 0 |
| Loss | Soft-target cross-entropy, label smoothing 0.1 |
| Augmentation | Waveform mixup Beta(0.4, 0.4) on every batch · SpecAugment 2× frequency masks (24) + 2× time masks (60) · random circular time shift · random gain ±6 dB |
| Weight averaging | EMA, decay 0.998 |
| Precision / hardware | bf16 autocast, channels_last · 1× NVIDIA A10G (Modal) |
| Wall-clock | ~2.2 min (all clips decoded once and kept in GPU memory) |
| Seed | 42 |
Evaluation
Protocol.
- ESC-50's official 5-fold split is used; clips from the same source recording always stay in the same fold.
- Each model trains on 4 folds and is tested on the 5th.
- The reported number is the final-epoch EMA model. No checkpoint was chosen by looking at the test fold.

5-fold cross-validation (training recipe)
| Fold 1 | Fold 2 | Fold 3 | Fold 4 (this checkpoint) | Fold 5 | Mean ± std |
|---|---|---|---|---|---|
| 90.75% | 90.25% | 92.00% | 93.25% | 90.25% | 91.30% ± 1.30 |

This checkpoint is the fold-4 model. Its 93.25% is the best of the five folds. Use 91.3% as the expected accuracy of the recipe. Same-seed reruns vary by about ±0.5 points because of GPU non-determinism.
This checkpoint on its held-out fold (400 clips, re-evaluated from model.safetensors)
| Top-1 | Top-3 | Top-5 | Macro precision | Macro recall | Macro F1 |
|---|---|---|---|---|---|
| 93.25% | 99.00% | 99.50% | 0.941 | 0.933 | 0.931 |
35 of the 50 classes score 8/8. The errors are mostly between acoustically similar pairs:

| Most frequent confusions | Count |
|---|---|
| laughing → crying baby | 3 |
| sheep → cow | 3 |
| drinking/sipping → pouring water | 3 |
| helicopter → airplane / wind | 1 + 1 |
| door wood creaks → door wood knock | 1 |
Full per-class counts: eval/fold4_per_class.json. CV summary: eval/cv5_results.json.
Comparison on ESC-50
| Model | Pretraining | Accuracy |
|---|---|---|
| Piczak CNN (2015) | none | 64.5% |
| Human listeners | — | 81.3% |
| PANNs CNN14 (from scratch) | none | 83.3% |
| This architecture, from scratch (baseline) | none | 83.0% |
| ImageNet ResNet (Palanisamy et al., 2020) | ImageNet | 90.65% |
| This model (5-fold CV) | ImageNet | 91.3% |
| PANNs CNN14 (fine-tuned) | AudioSet | 94.7% |
| BEATs | AudioSet | 98.1% |
It is competitive with other ImageNet-pretrained CNNs. Models pretrained on AudioSet, a large audio dataset, still score higher.
Intended use and limitations
-
Intended for: research, teaching and prototyping environmental-sound recognition, and studying CNN interpretability on spectrograms through the feature maps.
-
Closed set of 50 classes. Any input is assigned one of the ESC-50 labels; there is no "unknown" class. Put a confidence threshold on top for open-world use.
-
5-second clips. Longer audio works, since pooling is global, but mixed-event recordings should be split into windows.
-
Domain shift. ESC-50 clips are short, curated Freesound recordings. Accuracy on noisy real-world audio, other microphones or overlapping sources will be lower.
-
Confidence scores are soft by design. Label smoothing and mixup keep correct predictions at a median top-1 probability of 0.84, while wrong ones have a median of 0.41 and a maximum of 0.72. That makes a simple threshold effective on held-out fold 4:
Top-1 threshold Coverage Accuracy on kept clips none 100% 93.3% ≥ 0.5 84.8% 97.3% ≥ 0.6 81.2% 98.5% -
Non-commercial. The model inherits ESC-50's CC BY-NC 3.0 licence, so it is not for commercial use.
Files
| File | Description |
|---|---|
model.safetensors | Weights (EMA, final epoch) |
config.json | Labels, frontend settings incl. normalisation stats, training config |
model.py | Architecture, frontend and AudioClassifier (from_pretrained, predict) |
inference.py | Command-line classifier |
requirements.txt | Dependencies |
eval/ | 5-fold CV summary and per-class results |
images/ | Training curves and evaluation charts |
Reproduce
git clone https://github.com/Akash-Sakala/audio-cnn && cd audio-cnn
pip install -r requirements-local.txt && modal setup
modal run train_v2.py --folds 1,2,3,4,5 --run-name v2_cv5
Licence and citation
- Weights: CC BY-NC 3.0, following the ESC-50 dataset licence.
- Code (GitHub): MIT. It builds on Andreas Trolle's audio-cnn.
@inproceedings{piczak2015dataset,
title = {{ESC}: {Dataset} for {Environmental Sound Classification}},
author = {Piczak, Karol J.},
booktitle = {Proceedings of the 23rd {Annual ACM Conference} on {Multimedia}},
pages = {1015--1018},
year = {2015},
doi = {10.1145/2733373.2806390}
}