Views
No views yet
384 kHz mono WAV
-> log10 mel spectrogram (n_fft=1024, hop=768, n_mels=128, fmin=9000, fmax=150000)
-> per-segment normalize (mean/std, subtract per-bin median, clip 0..6)
-> sliding window 512 frames (~1.024 s), hop 250 frames (0.5 s)
-> CNN [1,1,512,128] -> [1,22] logits
-> sigmoid (multi-label; prob = 1/(1+exp(-logit)))spectrogram [batch, 1, 512, 128] float32 (1 channel, 512 time frames, 128 mel bins)logits [batch, 22] float32 (21 species + Background)original_code/supervised.py)original_code/data384.py (wav2spectrograms). The mel bin center frequencies are provided in original_code/mel128_freq9k_150k.txt.bsgbat_labels.txt lists the 22 output classes in model index order:0 Barbastella barbastellus 11 Pipistrellus nathusii
1 Eptesicus nilssonii 12 Pipistrellus pipistrellus
2 Eptesicus serotinus 13 Pipistrellus pygmaeus
3 Hypsugo savii 14 Plecotus auritus
4 Miniopterus schreibersii 15 Plecotus austriacus
5 Myotis alcathoe 16 Rhinolophus euryale
6 Myotis crypticus 17 Rhinolophus ferrumequinum
7 Myotis daubentonii 18 Rhinolophus hipposideros
8 Nyctalus leisleri 19 Tadarida teniotis
9 Nyctalus noctula 20 Vespertilio murinus
10 Pipistrellus kuhlii 21 Backgroundbsgbat_v0.21_r1.onnx through r6.onnx), matching the original release. The authors intend them to be used as an ensemble: run all six and combine the per-class logits (or probabilities) with min, max, mean, or median. A single checkpoint also works on its own.| File | Description |
|---|---|
bsgbat_v0.21_r1.onnx .. r6.onnx | The six ensemble checkpoints (FP32, ~83 MB each) |
bsgbat_labels.txt | 22 class labels in output index order |
original_code/ | Original BSG-BAT preprocessing and model code (for exact reproduction) |
original_code/mel128_freq9k_150k.txt | Mel bin center frequencies |
original_code/species21bg | Original label/index mapping |
export_onnx.py | The script used to convert the PyTorch checkpoints to ONNX |
SHA256SUMS | Checksums for all files |
1import numpy as np
2import librosa
3import onnxruntime as ort
4
5# 1. Build the spectrogram exactly as the model expects (see original_code/data384.py)
6def wav_to_segments(wavfile, ntime=512, nhop=250, nfreq=128):
7 y, sr = librosa.load(wavfile, sr=384000, mono=True, res_type="kaiser_fast")
8 S = librosa.feature.melspectrogram(
9 y=y, sr=sr, n_fft=1024, hop_length=768,
10 n_mels=nfreq, fmin=9000, fmax=150000,
11 ).T
12 segs = []
13 for start in range(0, max(len(S) - ntime, 0) + 1, nhop):
14 seg = np.log10(S[start:start + ntime] + 1e-6)
15 seg = (seg - seg.mean()) / seg.std()
16 seg = np.clip(seg - np.median(seg, axis=0), 0.0, 6.0)
17 segs.append(seg.astype(np.float32))
18 return np.stack(segs) # [n, 512, 128]
19
20segments = wav_to_segments("bat_recording_384kHz.wav")
21x = segments[:, None, :, :] # [n, 1, 512, 128]
22
23# 2. Run the ensemble and average the logits
24sessions = [ort.InferenceSession(f"bsgbat_v0.21_r{i}.onnx",
25 providers=["CPUExecutionProvider"]) for i in range(1, 7)]
26logits = np.mean([s.run(["logits"], {"spectrogram": x})[0] for s in sessions], axis=0)
27probs = 1.0 / (1.0 + np.exp(-logits)) # [n, 22], multi-label
28
29labels = [l.strip() for l in open("bsgbat_labels.txt") if l.strip()]
30detected = (probs > 0.5).any(axis=0)
31for i, present in enumerate(detected):
32 if present and labels[i] != "Background":
33 print(f"{labels[i]}: max prob {probs[:, i].max():.2f}")probs > 0.5 corresponds to the original default threshold (logit > 0). The original compute_logits.py writes per-segment logits so you can choose species-specific thresholds.model_v0.21_r1.pt .. r6.pt).torch.onnx.export (dynamo exporter, opset 18), dynamic batch axis, weights stored inline (single self-contained .onnx).export_onnx.py. The Net definition is copied verbatim from original_code/supervised.py.bsg-bat team (2025). BSG-BAT (v0.21). Zenodo. https://doi.org/10.5281/zenodo.15495676