Ornimetrics

Bird recognition for a smart feeder that runs entirely on a Raspberry Pi 5 with a Hailo-8 accelerator. No cloud, no GPU at runtime. A camera watches the feeder; the system finds birds in the frame, names the species, checks whether one looks hurt, and tries to tell individuals apart over time. There's an optional microphone path that identifies birds by their calls. Everything visual hangs off a single shared backbone, which is what keeps it light enough to actually run on a $100 board.

This is a research preview. The detector and species classifier are solid; the welfare screen and individual re-ID are early and honest about it. If you're going to reuse any of the weights, read the Licenses section β€” the pieces are not all under the same one.

Authors: built by the Ornimetrics project (Thomas Yu), in close collaboration with WWCC (Jaret's team), who were a huge help throughout β€” from shaping the direction to feedback, testing, and the bird-ID/wildlife-support side of the work. This wouldn't exist in this form without them.


The system at a glance

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Raspberry Pi 5 ──────────────────────────┐
 camera ──► β”‚  detector (Hailo-8)  ─►  bird crop  ─►  shared EfficientNetV2-S      β”‚
            β”‚      gate                              β”œβ”€β–Ί species   (which bird)    β”‚
            β”‚                                        β”œβ”€β–Ί welfare   (looks hurt?)   β”‚
            β”‚                                        └─► re-ID     (which one)     β”‚
 mic    ──► β”‚  BirdNET (CPU)  ─►  species by sound  (optional, separate process)   β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The detector runs continuously on the Hailo. The three heads only run when the detector actually finds a bird, on the Pi's CPU, so they never slow the live video down. Because species/welfare/re-ID share one backbone, a bird is encoded once and read three ways.


Models in detail

1. Detector (the gate)

  • Architecture: YOLOv11n, 416Γ—416 input, INT8, compiled to a Hailo .hef.
  • Classes: bird, squirrel, person, dog.
  • Why those four: birds are the subject; squirrels/people/dogs are the common feeder "intruders" worth flagging (and useful for trap logic on the hardware side).
  • Performance: ~0.93 mAP@50 on a held-out validation split; ~30 fps on the Hailo.
  • Files: models/model_feeder4.hef, labels in models/detector.names.

2. Species classifier (NABirds)

  • Architecture: EfficientNetV2-S, 256Γ—256, seeded from a bird-pretrained backbone and fine-tuned on NABirds.
  • Classes: 555 North-American species.
  • Performance: 86.9% top-1 on the NABirds validation set (and 85.7% on a small fresh sample run on the actual Hailo hardware).
  • Files: models/species_classifier_nabirds.onnx (CPU), .hef (Hailo), .json (class list + RGB normalization stats).
  • License note: research/non-commercial (NABirds terms).

3. Species classifier (Creative-Commons)

  • Same architecture, trained on Creative-Commons iNaturalist photos instead.
  • 302 species, ~73% top-1. Lower than the NABirds model because the CC data is smaller and noisier per species, but it's the version you can use commercially.
  • File: models/species_classifier_inat.onnx.

4. Welfare screen

  • Idea: there is no public dataset of injured wild birds, so this isn't a supervised "injured detector." Instead it learns what healthy birds look like in the backbone's feature space and measures how far a new bird sits from that distribution (Mahalanobis distance). Injured, sick, and dead birds land far out.
  • Performance: AUC 0.974 (healthy vs dead) and 0.963 (healthy vs injured) on iNaturalist photos β€” using zero injured images for training.
  • Important: it's a screening flag ("a human should look at this bird"), not a diagnosis. A false "it's fine" can cost a bird its life, so a person stays in the loop.
  • Files: models/embedder.onnx (backbone β†’ 1280-d feature), models/welfare_scorer.npz (the healthy distribution: mean + inverse covariance).

5. Individual re-ID

  • Architecture: an ArcFace embedding head on the same backbone (256-d), trained with species as a proxy for fine-grained appearance.
  • How it's used: embed the bird crop, compare against a small per-species gallery with cosine distance; new individuals get enrolled automatically.
  • Reality check: RGB-only individual re-ID is hard. It works best for distinctive birds over short time windows, and it's meant to improve as a feeder accumulates repeat sightings of its regulars. Don't expect species-level reliability here.
  • Files: models/reid_embedder.onnx, .hef.

Intended use

  • Backyard / research bird-feeder monitoring on edge hardware.
  • A starting point for on-device wildlife pipelines (detect β†’ classify β†’ flag).
  • The welfare screen as an alerting tool that routes a possible injury to a human.

Out of scope

  • Anything where a wrong call has real consequences without a human checking β€” especially the welfare flag. It is not a veterinary or diagnostic tool.
  • Species outside North America (the NABirds model simply won't know them).
  • High-stakes individual identification β€” re-ID here is approximate.

Training data

  • Detector: several Roboflow bird/squirrel/person/dog detection sets, merged and re-mapped to the four clean classes above (~7.6k train images).
  • Species (NABirds): NABirds β€” 48k images, 555 species, ~24k train / ~24k validation.
  • Species (CC): ~12k Creative-Commons iNaturalist photos of North-American birds (research-grade, CC0/CC-BY/CC-BY-NC), organized by species.
  • Welfare: healthy / dead / injured bird images from iNaturalist (the "dead" annotation is reliable; "injured" candidates were hand-checked). Healthy is the training distribution; dead/injured are only used to validate the separation.

Training procedure

  • Backbone: convnext/ViT options were ruled out because they don't map cleanly to the Hailo-8; EfficientNetV2-S compiles well and shares nicely across heads.
  • Species: two-stage transfer learning β€” freeze the backbone and warm up the head, then fine-tune the whole network at a low LR with cosine schedule, mixup, cutmix and label smoothing. ~220 epochs on NABirds.
  • Re-ID: ArcFace metric-learning head on top of the trained backbone (~40 epochs).
  • Welfare: no training β€” backbone features of healthy birds β†’ Mahalanobis model.
  • Compilation: ONNX β†’ Hailo .hef via the Hailo Dataflow Compiler (INT8), with a small real-image calibration set. Welfare/re-ID run on CPU via ONNX Runtime.
  • Hardware: trained on a single consumer GPU; runs on a Raspberry Pi 5 + Hailo-8.

Evaluation

Model Task Metric Result
Detector bird / squirrel / person / dog mAP@50 0.93
Species (NABirds) 555 NA species top-1 86.9%
Species (iNat CC) 302 species top-1 ~73%
Welfare healthy vs dead AUC 0.974
Welfare healthy vs injured AUC 0.963

On-device throughput: ~24 fps species inference on the Hailo; ~28 fps for the live stream with detector + species running together.


Using the models

Species classifier (CPU, ONNX Runtime):

import onnxruntime as ort, numpy as np, cv2, json

cfg = json.load(open("models/species_classifier_nabirds.json"))
size = cfg["input_size"]; mean = np.array(cfg["rgb_mean"]); std = np.array(cfg["rgb_std"])
sess = ort.InferenceSession("models/species_classifier_nabirds.onnx")

img = cv2.cvtColor(cv2.resize(cv2.imread("bird.jpg"), (size, size)), cv2.COLOR_BGR2RGB)
x = ((img / 255.0 - mean) / std).transpose(2, 0, 1)[None].astype(np.float32)
logits = sess.run(None, {sess.get_inputs()[0].name: x})[0][0]
p = np.exp(logits - logits.max()); p /= p.sum()
top = p.argsort()[::-1][:3]
print([(cfg["classes"][i], float(p[i])) for i in top])

Welfare score (anomaly distance β€” higher = more unusual vs healthy):

import numpy as np
s = np.load("models/welfare_scorer.npz")
emb = ...  # 1280-d output of models/embedder.onnx on the same crop
d = emb - s["mean"]
distance = float(d @ s["inv_cov"] @ d)   # compare to the healthy baseline in the file

The full live pipeline (detector + all heads + the web dashboard) lives in the project repo, not here.


Limitations and honest caveats

  • Domain gap is the big one. The accuracy numbers are on reasonably clean photos. Through a cheap webcam, glass, or at distance, the species model drops and the welfare flag over-fires (it reads the unfamiliar camera domain as "unusual"). The intended fix is fine-tuning / recalibrating on a given feeder's own footage.
  • Welfare needs per-camera recalibration. Out of the box, in a new setup, expect false alarms until the healthy baseline is rebuilt from that camera's own birds.
  • Re-ID is approximate. Treat individual IDs as hints, not facts.
  • Coverage. North-America-centric. Unknown species get confidently mislabeled.
  • The detector is AGPL (YOLOv11), which constrains how it can be redistributed β€” separate from the classifier weights.

Licenses

  • Backbone, welfare and re-ID heads: Apache-2.0 (built on the birder project).
  • NABirds species model: non-commercial research use (NABirds dataset terms).
  • iNaturalist (CC) species model: usable under CC-BY / CC-BY-NC β€” the commercial path.
  • Detector: AGPL-3.0 (YOLOv11), kept separate from the classifiers.

Acknowledgments

Huge thanks to WWCC and Jaret's team β€” collaborators on this project and a major help with direction, testing, and the bird-identification and injured-bird-support side of the work. Also to the people and institutions whose data and tools made it possible: NABirds (Cornell Lab of Ornithology), iNaturalist and the photographers who share their observations, the birder project, BirdNET, Ultralytics, and Hailo.

Citation

@misc{ornimetrics2026,
  title  = {Ornimetrics: On-Device Bird Detection, Species ID, Welfare Screening and Re-ID for Raspberry Pi + Hailo},
  author = {Yu, Thomas and {WWCC}},
  year   = {2026},
  howpublished = {\url{https://huggingface.co/Ornimetrics/ornimetrics-edge}}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support