BirdNET v2.4 ONNX Backbone
Backbone-only ONNX exports of the BirdNET v2.4 bird sound classifier. The classification head has been removed, leaving only frontend + feature-extraction. The head is also provided as a separate model that takes the embedding as input, see Classifier head.
Two variants are provided, matching the originals from justinchuby/BirdNET-onnx: model_backbone.onnx and birdnet_backbone.onnx. Both models output a single tensor named embedding with shape (1, 1024).
A TFLite backbone, BirdNET_V2.4_Model_FP32_backbone.tflite, is also provided. It is cut from
BirdNET_GLOBAL_6K_V2.4_Model_FP32.tflite (same repo) at the model/GLOBAL_AVG_POOL/Mean tensor
by extract_tflite_backbone.py. Input INPUT (batch, 144000), output embedding (batch, 1024).
Embeddings are numerically verified against the reference TF SavedModel published on Zenodo (BirdNET_v2.4_protobuf).
Quick start
import numpy as np
import onnxruntime as ort
from huggingface_hub import hf_hub_download
# Download backbone
path = hf_hub_download(
repo_id="biodiversica/BirdNET-onnx-backbone",
filename="model_backbone.onnx",
)
sess = ort.InferenceSession(path)
# 3 s of audio at 48 kHz
audio = np.zeros((1, 144000), dtype=np.float32)
(embedding,) = sess.run(["embedding"], {"INPUT": audio})
print(embedding.shape) # (1, 1024)
For birdnet_backbone.onnx the input key is "input" (lowercase):
path = hf_hub_download(
repo_id="biodiversica/BirdNET-onnx-backbone",
filename="birdnet_backbone.onnx",
)
sess = ort.InferenceSession(path)
(embedding,) = sess.run(["embedding"], {"input": audio})
print(embedding.shape) # (1, 1024)
Classifier head
The classifier head is the dense layer that follows the backbone, available as birdnet_classifier.onnx and
BirdNET_V2.4_Model_FP32_classifier.tflite. Both take embedding (batch, 1024) and output logits (batch, 6522).
model.onnx, birdnet.onnx and the TFLite model have identical head weights, so birdnet_classifier.onnx works with
both ONNX backbones.
The output is raw logits, as in the full models. Apply a sigmoid to get confidence scores. Classes follow the order of
BirdNET_GLOBAL_6K_V2.4_Labels.txt.
path = hf_hub_download(
repo_id="biodiversica/BirdNET-onnx-backbone",
filename="birdnet_classifier.onnx",
)
sess = ort.InferenceSession(path)
(logits,) = sess.run(["logits"], {"embedding": embedding})
print(logits.shape) # (1, 6522)
scores = 1 / (1 + np.exp(-logits))
Extraction procedure
The extraction and testing procedure can be reproduced using extract_backbone.py. The script will:
- Download
model.onnxandbirdnet.onnxfrom justinchuby/BirdNET-onnx. - Download the BirdNET v2.4 TF SavedModel from Zenodo (BirdNET_v2.4_protobuf).
- Extract the backbone subgraph (everything up to and including the
model/GLOBAL_AVG_POOL/Mean_reduced_0node), renaming the output toembedding. - Save
model_backbone.onnxandbirdnet_backbone.onnx. - Run a numerical comparison between ONNX and TF SavedModel embeddings on a fixed random waveform (seed 42, 3 s at 48 kHz).
Expected output:
=== Downloading models ===
Downloaded model.onnx -> ...
Downloaded birdnet.onnx -> ...
Downloading BirdNET protobuf from Zenodo...
Extracted audio-model -> ...
=== Extracting backbones ===
Backbone saved -> model_backbone.onnx
inputs : ['INPUT']
outputs: ['embedding']
Backbone saved -> birdnet_backbone.onnx
inputs : ['input']
outputs: ['embedding']
=== Comparing embeddings against Zenodo TF SavedModel ===
PB embedding shape: (1, 1024)
model_backend.onnx:
ONNX embedding shape: (1, 1024)
|diff| mean=1.230468e-06 max=9.298325e-06
Embeddings match PB reference with rtol=1e-03, atol=1e-03 PASSED
birdnet_backend.onnx:
ONNX embedding shape: (1, 1024)
|diff| mean=6.440870e-05 max=5.004406e-04
Embeddings match PB reference with rtol=1e-03, atol=1e-03 PASSED
The classifier heads are extracted by extract_classifier.py. Run it after extract_backbone.py and
extract_tflite_backbone.py, since it uses their backbones. It checks on a batch of 3 fixed random waveforms that
backbone + classifier reproduces each full model and the basic signature of the TF SavedModel, and exits with an error
if any comparison fails.
How extraction works
The _extract function in extract_backbone.py performs a backwards BFS from the
model/GLOBAL_AVG_POOL/Mean_reduced_0 output node (the global average pool), collecting
every node that contributes to that output and discarding everything downstream (the
classification dense layer). The output tensor is then renamed to embedding. It then
rebuilds a minimal ONNX graph containing only the retained nodes and their initializers.
extract_classifier.py does the reverse: it walks forward from the same pool tensor, keeps only the downstream nodes
(ONNX MatMul + Add, TFLite FULLY_CONNECTED) and makes that tensor the graph input, named embedding.
Credits
- Original ONNX conversion: justinchuby/BirdNET-onnx
- Reference protobuf: BirdNET_v2.4_protobuf on Zenodo
- Downloads last month
- 154
Model tree for biodiversica/BirdNET-onnx-backbone
Base model
justinchuby/BirdNET-onnx