van Merriënboer, Dumoulin, Hamer et al. — Google DeepMind, 2026

Perch 2.0: The Bittern Lesson
for Bioacoustics

A tiny, purely supervised model trained to name 14,795 species beats every self-supervised foundation model at understanding animal sound — and transfers to whales it never heard.

Prerequisites: Cross-entropy + CNN basics + Spectrogram intuition
10
Chapters
6
Simulations

Chapter 0: The Problem

You drop an autonomous microphone in a rainforest. It records for six months. You come back with 4,000 hours of audio. Somewhere in that ocean of sound is the booming call of an endangered bittern, the dialect of a single warbler population, the click train of an orca pod. Where?

This is bioacoustics: using sound to monitor biodiversity. It matters because a hidden microphone is cheap, never sleeps, and doesn't scare the animals. But a human can't listen to 4,000 hours. We need a model that turns raw audio into something searchable — a model that, given a 5-second clip, can say "that's a Cerulean Warbler" or at least "that sounds like this other clip you already labelled."

The core question: An ecologist studying coral-reef fish has 30 labelled examples and zero ML expertise. They have never trained a neural network and never will. Can we hand them a single frozen model whose embeddings are good enough that a 10-line scikit-learn linear classifier on top solves their problem — even though the model was trained almost entirely on birds?

That last clause is the twist. The field has very little labelled marine data, very little insect data, very little amphibian data. It has a mountain of labelled birdsong, because birders have been uploading recordings to citizen-science archives like Xeno-Canto for twenty years. The dream is a model trained mostly on birds that nonetheless transfers to whales, frogs, bats, and mosquitoes.

Why not just do what NLP and vision did?

Everywhere else in ML, the recipe of the last five years has been self-supervised foundation models: train a giant model on a sea of unlabelled data (mask out patches, predict the next token), then fine-tune. DINOv2 saw 142 million images with no labels. wav2vec masked speech. The labels were the bottleneck, so we threw them away.

Bioacoustics tried to copy this. Bird-MAE (masked autoencoder), BirdAVES, SimCLR-style contrastive models — all self-supervised. The authors of Perch tried it too: MAEs, HuBERT, SimCLR.

They all lost. Not by a little — none of these self-supervised models could consistently beat a plain old supervised classifier. The same thing keeps happening across "specialized foundation model" domains (Xu et al., 2024). So the question stops being "how do we make self-supervision work?" and becomes "why is supervision so hard to beat here?"

What "good" means here — and why it's unusual

Most ML papers optimize one number on one test set. Perch 2.0 optimizes for a deployment shape:

RequirementWhy it matters for ecology
Small model (EfficientNet-B3, 12M params)Runs on a laptop; can embed 4,000 hours overnight
Frozen embeddings (no fine-tuning)Ecologists lack GPUs & ML skill; embed once, reuse forever
Linearly separable embeddingsA linear probe / nearest-neighbour search is all they get
Cross-taxa transferTrain on birds, deploy on whales

Hold this list in your head. Every design decision in the paper — the mixup, the three heads, the self-distillation — exists to push the frozen embedding toward being small, linearly separable, and transferable. That is the through-line.

What is the central surprise the Perch 2.0 authors are trying to explain?

Chapter 1: The Bittern Lesson

Rich Sutton's famous essay The Bitter Lesson (2019) argues that general, compute-hungry methods (search, learning) always win over hand-crafted human knowledge. Perch 2.0's title is a pun: the bittern lesson (a bittern is a shy, booming heron). And the lesson is almost the opposite flavour: here, a simple, well-tuned supervised model is the thing that's "difficult to beat."

The key insight: Make the classification task as hard as you can, and the embedding gets better. Fine-grained supervision — telling apart 14,795 species, many in the same genus — forces the network to learn features that separate near-identical sounds. Those razor-sharp features are exactly what transfer to brand-new tasks.

Why fine-grained labels are the secret weapon

Imagine two training regimes for the same network:

Section C.1 of the paper makes this concrete: if you deliberately coarsen the labels (merge species into genera, genera into families), transfer performance gets worse. The harder the original problem, the better the leftover features. This echoes Hong et al. (2024), "Why fine-grained labels in pretraining benefit generalization."

Label Granularity → Embedding Quality
Label granularity:
Species-level: classes are pushed apart — embeddings are linearly separable.

Watch the embedding cloud: with 2 coarse labels the points blur into two soft blobs; with 14,795 fine labels the model carves clean, separable clusters. A linear probe on the right-hand picture is trivial; on the left it's hopeless.

Why birds transfer to everything

Two facts make avian audio a freakishly good pre-training source:

  1. Birdsong is insanely diverse (Kroodsma, 2004) — buzzes, whistles, trills, clicks, harmonics. A model that handles all of it has effectively seen most of the acoustic primitives animals use.
  2. Sound production is physically universal (Elemans et al., 2015): birds and mammals make sound with the same fluid-dynamic mechanisms. A feature that captures a bird's frequency sweep also captures a whale's.
According to the paper, what happens to transfer performance when you make training labels coarser?

Chapter 2: From Audio to Embedding

Before any learning happens, raw sound must become a tensor a CNN can chew on. Let's trace one 5-second clip through the front of the model, shape by shape.

Step 1 — The frontend: waveform → log-mel spectrogram

The model ingests monaural audio at 32 kHz. A 5-second clip is therefore:

5 s × 32{,}000 samples/s = 160{,}000 samples → tensor shape [160000]

A raw waveform is a terrible input — it's a 1-D wiggle where the same bird call shifted by one millisecond looks completely different numerically. So we convert to a spectrogram: chop the signal into short overlapping frames, take the Fourier transform of each, and stack the frequency content over time. The result is a picture: time across, frequency up, brightness = energy.

The exact recipe the paper uses:

ParameterValueWhy
Window length20 msLong enough to resolve frequency, short enough to localise in time
Hop length10 ms50% overlap → smooth time axis
Frames out5005 s ÷ 10 ms = 500 time steps
Mel bins128Perceptual frequency axis (60 Hz – 16 kHz)
[160000]  → frontend →  log-mel spectrogram of shape [500, 128]

Two design choices worth understanding. The mel scale spaces frequency bins the way the ear does — fine resolution low down (where most animal calls live), coarse up high. The log (of energy) compresses dynamic range, so a loud call and a faint call have comparable contrast — exactly like how we perceive loudness. The bins span 60 Hz–16 kHz, which is also why the authors throw out all bat recordings: bats vocalize above 16 kHz and simply don't exist in this representation.

Waveform → Log-Mel Spectrogram (drag to scrub)
Top: 160,000-sample waveform. Bottom: [500, 128] log-mel — the actual model input.

Step 2 — The embedding model: EfficientNet-B3

That [500, 128] picture goes into an EfficientNet-B3 — a convolutional residual network with depthwise convolutions, 12M parameters. (Perch 1.0 used the smaller B1, 7.8M; the extra data justified scaling up.) The CNN downsamples spatially and grows the channel axis, producing a spatial embedding:

ES ∈ ℝ5 × 3 × 1536   (time × frequency × features)

Then we average over the two spatial axes (the 5×3 grid) to get a single vector — the mean embedding:

EA = meantime,freq(ES) ∈ ℝ1536

This 1536-dim vector is the product. Everything the ecologist uses — nearest-neighbour search, clustering, the linear probe — operates on EA. The whole rest of the paper is machinery to make EA as good as possible, then thrown away at deployment. The heads exist only during training.

Data-flow cheat sheet:  [160000] waveform → [500,128] log-mel → EfficientNet-B3 → ES [5,3,1536] spatial → mean-pool → EA [1536] mean embedding. ES feeds the prototype head (it needs spatial detail); EA feeds the linear and source-prediction heads.
What is the final 1536-dimensional vector EA obtained by?

Chapter 3: Multi-Source Mixup

Here's a problem buried in the data. Recordings range from under a second to over an hour, and the labels are weak: a 2-minute file tagged "Cerulean Warbler" doesn't tell you which 5 seconds actually contain the bird. The bird might be silent for most of it. So when we crop a random 5-second window, we might get pure wind.

Perch 1.0 fixed this with energy-peak selection — a wavelet detector that finds the loudest moment and crops there, assuming the labelled species is the loudest thing. Perch 2.0 keeps this option but also asks a sharper question: how do we make the classification problem harder, on purpose, to force better features? (Remember Chapter 1: harder task → better embedding.)

Manufacturing difficulty with mixup

Standard mixup (Zhang et al., 2018) blends two training examples into one and asks the model to predict both. Perch 2.0 generalizes it to more than two sources. The procedure, step by step:

  1. Pick how many components to blend. Sample a count from a beta-binomial, then add one so you always have at least one:
    N ∼ BetaBin(n, α, β) + 1
    In the winning configuration N ranged over {2,…,5}. (beta-binomial = a binomial whose success-probability is itself drawn from a Beta, giving a flexible, over-dispersed count.)
  2. Pick blend weights from a symmetric Dirichlet (a distribution over things that sum to 1):
    w = (w1, …, wN) ∼ SymDir(N, ω)
    The concentration ω (best around 10–30) controls how equal the weights are — high ω → all clips roughly equal loudness.
  3. Build the composite signal as the weighted sum, then renormalize the gain:
    xmix = ( Σi wi xi ) / √( Σi wi2 )
    The denominator keeps total loudness roughly constant no matter how many clips you stack (the energy of a sum of independent signals grows like the root-sum-of-squares of the weights).
  4. Build the target as a MULTI-HOT vector, not a weighted average. Every species in the blend gets a 1 (well, an equal share — see Ch 4), regardless of how loud it is.
The crucial twist vs. original mixup: Original mixup blends the labels too (0.7·cat + 0.3·dog). Perch refuses. If three birds are audible — even one very faintly — the model must recognize all three with high confidence. Why? Because in a real soundscape, a quiet distant bird is still present and the ecologist wants it found. Loudness ≠ importance. So the target is multi-hot, not soft.

Worked numerical example

Say N=3 with weights w = (0.6, 0.3, 0.1) for a robin, a thrush, and a faint warbler. The normalizer is

√(0.6² + 0.3² + 0.1²) = √(0.36+0.09+0.01) = √0.46 ≈ 0.678

So xmix = (0.6·robin + 0.3·thrush + 0.1·warbler) / 0.678. The robin enters at 0.6/0.678 ≈ 0.88× its original amplitude. And the target? [robin=1, thrush=1, warbler=1] — the warbler at 0.1 weight is demanded just as confidently as the robin at 0.6.

Build a Multi-Source Mix (drag the weights)

Drag any bar to change its weight. Watch two things: the gain normalizer keeps the composite loudness flat as you add sources, and the target row stays all-1 no matter how quiet a source gets. That's the multi-hot rule made visible.

Why does Perch 2.0 use a multi-hot target instead of mixup's usual weighted-average target?

Chapter 4: The Three Heads (showcase)

Now the heart of the architecture. From the shared embedding, training drives three output heads, each with its own loss. None of them survive to deployment — they're scaffolding that shapes EA. Let's meet them, then watch gradients flow.

Head 1 — Linear classifier (the student)
Takes EA [1536] → softmax over 14,795 species. Cross-entropy. Pushes embeddings to be linearly separable.
Head 2 — Prototype classifier / ProtoPNet (the teacher)
Takes the spatial ES [5,3,1536]. Learns 4 prototypes per class; prediction = max prototype activation. Its soft outputs become targets for Head 1 (self-distillation).
Head 3 — Source-prediction (DIET)
Low-rank linear (rank 512) on EA → which of 1.5M source recordings did this window come from? An auxiliary self-supervised loss.

Why three? Each shapes the embedding differently

HeadInputForces the embedding to…
LinearEA [1536]be a place where a straight line separates species → great for linear probes
PrototypeES [5,3,1536]contain localized, part-based evidence ("this trill looks like that stored prototype")
SourceEA [1536]encode fine recording-level identity → maximal feature granularity
The Three-Head Training Graph (step the gradients)
Forward pass: embedding feeds all three heads.

Step through it. On the forward pass the embedding lights up all three heads. On the backward pass, notice the red ✕ on the prototype→embedding edge — that's the stop-gradient. The teacher's gradients are not allowed to update the shared embedding. Why that matters is the whole next chapter.

"new" in the paper's Figure 2: The prototype/self-distillation path and the source-prediction head are the new pieces vs. Perch 1.0. The linear-classifier-only model already worked; these two additions are what pushed it to state-of-the-art.
Which head receives the spatial embedding ES rather than the pooled EA?

Chapter 5: Self-Distillation from Prototypes

We have two species classifiers reading the same embedding: a plain linear head and a fancier prototype head. The paper makes the prototype head teach the linear head. This is self-distillation: a model improving by learning from a slightly-better version of itself.

What a prototype classifier is

ProtoPNet (Chen et al., 2019) reasons by analogy: it stores a handful of learned prototypes per class — little reference patterns — and classifies a new clip by "this region looks like that stored prototype." Perch learns 4 prototypes per class and the prediction uses the maximum activation across them. An orthogonality loss pushes the 4 prototypes apart so they capture different aspects of a call (the intro buzz vs. the terminal trill) rather than collapsing to one.

Because it consumes the spatial ES and matches local patterns, the prototype head tends to make sharper, better-calibrated predictions than the global linear head. It's the better classifier — so it's the teacher.

The mechanism: soft targets + stop-gradient

Instead of training the linear head against the hard multi-hot label, in Phase II we train it against the prototype head's soft probability distribution:

Ldistill = CrossEntropy( plinear(EA),  stopgrad[ pproto(ES) ] )

Two pieces decode this. pproto is the teacher's softmax — a soft target like "92% Cerulean, 5% Black-throated Blue, 3% other," which carries dark knowledge: the relative similarity between classes that a hard one-hot label throws away. And stopgrad[·] means: treat the teacher's output as a fixed constant when computing gradients.

Why the stop-gradient is non-negotiable. Both heads share the same embedding. If the teacher's gradients could flow back into the embedding, the system could cheat: make the embedding trivially easy for the teacher, then have the teacher "teach" garbage to the student. The stop-gradient forces an honest hierarchy — the embedding is shaped by the real losses (species CE, source), the teacher reads it passively, and only the student gets distilled. Teacher and student share a body but the teacher can't move it.

The two-phase schedule (and why it's two phases)

Phase I (≤300K steps)Phase II (≤400K steps)
Linear headtrained on multi-hot labelstrained on prototype soft targets (distill)
Prototype headtrained, but not used as teacher yetnow the teacher
Source headtrainedtrained (lower weight)
Vizier-preferred mixupheavy (N=2–5)little/none (mostly N=1)
Distill loss weight0high (1.5–4.5)

You can't distill from a teacher that doesn't exist yet. Phase I builds a competent prototype teacher. Phase II then uses it. By Phase II the embedding is already good, so the model wants gentler treatment: small learning rate, almost no mixup, less dropout.

A surprising payoff. With self-distillation, random 5-second windows train just as well as the careful energy-peak selection that Perch 1.0 needed. The authors hypothesize the distillation phase cleans up the label noise that random cropping introduces — so they got to delete a whole hand-engineered signal detector. A small bitter(n) lesson in itself.
What does the stop-gradient between the prototype head and the embedding prevent?

Chapter 6: Source Prediction (DIET)

The third head is the strangest and most clever. It asks the model to predict: which of the 1.5 million source recordings did this 5-second window come from? Each recording is literally its own class. This is the DIET objective (Balestriero, 2023): "Datum IndEx as Target."

The trick hidden in plain sight

A one-hour recording can be sliced into dozens of completely non-overlapping 5-second windows. They share no audio samples — a window from minute 3 and a window from minute 47 are acoustically unrelated. Yet they have the same source label. So to predict the source from a single window, the model must learn the stable, recording-level fingerprint — the individual bird's voice, the habitat's ambient signature, the microphone's character — that persists across the whole file.

Self-supervised in disguise. No human labelled these — the source ID is free metadata. Yet the authors point out it's also just an extremely fine-grained supervised classification (1.5M classes!). And recall Chapter 1: extreme fine-grainedness is exactly what forges transferable features. The windowing is the data augmentation that makes the task non-trivial. A similar objective helps re-identify individual animals (Lapp et al., 2025).

Engineering: why a low-rank head

A normal linear head from a 1536-dim embedding to 1.5M classes would be a weight matrix of

1536 × 1{,}500{,}000 ≈ 2.3 billion parameters

— larger than the entire rest of the model by 100×. Absurd. So the source head is low-rank, rank 512:

logits = EA · W1 · W2,   W1 ∈ ℝ1536×512,   W2 ∈ ℝ512×1.5M

This factorization says "there are really only ~512 latent dimensions that distinguish recordings" — and it shrinks the head's parameters dramatically while keeping the gradient signal. One footnote-level gotcha: with 1.5M classes the cross-entropy loss is numerically large, so its loss weight is tuned carefully (Vizier picked 0.1–0.9 in Phase I, dropping toward 0 in Phase II) to avoid drowning out the species loss.

How the three losses combine

Ltotal = Lspecies-CE + λproto·Lproto + λdistill·Ldistill + λsrc·Lsource + λorth·Lorthogonality

All minimized with Adam. The λ weights were swept with Vizier (Google's black-box hyperparameter optimizer): 100 models per stage, two stages per phase. Each model took 20–30 hours on a TPUv3-8.

Source Prediction: one recording, many windows, one fingerprint
A long recording, sliced into non-overlapping windows — all share source ID #4187.
Why must the source-prediction head learn recording-level features rather than memorizing the audio?

Chapter 7: Probing & Evaluation

The model is trained. Now the embedding model is frozen — no more gradients ever touch it. How do we use it, and how do we know it's good? Both the deployment workflow and the model-selection procedure are built around three frozen-embedding tasks.

Three ways to use a frozen embedding

ModeLabels neededHow it works
Pre-trained classifier (Pre)noneUse the built-in head's scores directly (only for known species)
Retrieval (1-shot)1 exampleEmbed a query, rank everything by cosine distance to it
Linear probe (LP)~16/classTrain a tiny scikit-learn linear classifier on frozen embeddings
Prototype probe (PP)~16/classSame, but with the prototype head — better on detection tasks

The reason this list exists: practitioners have little labelled data and no GPUs. Embedding the dataset once and running a linear probe is cheap, requires no ML expertise, and reuses the same embeddings for clustering and search. This is the "agile modeling" workflow (Dumoulin et al., 2025).

Model selection: optimizing for the right thing

You can't pick the best model on a single held-out accuracy — you'd pick one that's good at that domain and brittle elsewhere. So Perch validates on 19 datasets across three task types (pre-trained classification, retrieval, linear transfer) covering bird soundscapes, call-types, dialects, and non-avian taxa.

The aggregation choice is deliberate: a geometric mean of per-task scores, not an arithmetic mean.

score = ( Πi=1k si )1/k
Why geometric, not arithmetic? The geometric mean punishes variance. A model scoring [0.9, 0.9, 0.1] has arithmetic mean 0.63 but geometric mean (0.9·0.9·0.1)1/3 ≈ 0.43. It rewards models that are consistently decent everywhere over models that are brilliant on one benchmark and useless on another — exactly the property you want from a general foundation model (van Merriënboer et al., 2024).
Arithmetic vs Geometric Mean — drag the worst score
Drag the leftmost bar down. Watch the geometric mean collapse faster.
Why does Perch 2.0 aggregate validation scores with a geometric mean?

Chapter 8: The Results

Two benchmarks. BirdSet: six fully-annotated bird soundscapes (US, Hawai‘i, Peru, Colombia). BEANS: twelve cross-taxa tasks — birds, land & marine mammals, anurans, insects. Crucially, Perch 2.0 uses no fine-tuning: on BirdSet it applies its prototype head directly; on BEANS it trains only a linear/prototype probe on frozen embeddings.

BirdSet AUROC — Perch 2.0 vs baselines (no fine-tuning)

On the AUROC metric the authors trust most (the most stable, per van Merriënboer et al.), Perch 2.0 reaches 0.908 on BirdSet, beating AudioProtoPNet-5 (0.896), Bird-MAE-L (0.886), and its own predecessor Perch 1.0 (0.839) — all without touching the embedding weights.

The headline numbers

ModelBirdSet AUROCBirdSet cmAPBEANS Acc
Perch 1.00.8390.356
Bird-MAE-L (self-sup.)0.8860.440
AudioProtoPNet-50.8960.423
BioLingual (zero-shot)0.479 (mAP)
Perch 2.0 (Random)0.9080.4310.665

The result that stunned even the authors

It beats specialized marine models — at marine tasks — despite having almost no marine training data. On transfer to whale/orca/reef datasets (DCLDE, NOAA, ReefSet), Perch 2.0's bird-trained embeddings outperform Surf Perch and Google's Multispecies Whale Model, which were built specifically for the ocean. This is the Chapter 1 thesis vindicated: fine-grained birdsong features are so general that they cross the entire tree of life.

Three quieter but important findings

Why supervision keeps winning here — the hypotheses

  1. Enough labels. Self-supervision wins when labels are scarce. Bioacoustics has 1.5M labelled recordings — Cole et al. (2022) show that past hundreds of thousands of labels, supervised becomes very hard to beat.
  2. Self-supervision is augmentation-fragile. SSL leans heavily on hand-tuned augmentations; the right ones for audio aren't known yet (Morningstar et al., 2024).
  3. Fine-grained labels are gold. 15,000 species, many in the same genus → the supervised features are unusually rich (Hong et al., 2024).
What is the most striking transfer result in the paper?

Chapter 9: Connections & Cheat Sheet

Perch 2.0 sits at a crossroads of audio ML, transfer learning, and interpretable deep learning. Here's how it links to ideas you may already know — and a one-page summary of every symbol.

2018
mixup — blend two examples; Perch generalizes to N sources + multi-hot
2019
ProtoPNet — "this looks like that" prototypes; becomes Perch's teacher head
2023
Perch 1.0 / DIET — birdsong embeddings; datum-index-as-target self-supervision
2026
Perch 2.0 — multi-taxa, self-distillation, source prediction; SOTA without fine-tuning

The core algorithm in runnable Python

The whole training objective — three heads, the stop-gradient, the multi-hot mixup target — fits in one readable forward pass:

# Perch 2.0 training step (the core insight, simplified) import torch, torch.nn.functional as F def perch_loss(audio_mix, multihot_target, src_id, backbone, lin_head, proto_head, src_head, phase=2, lam_src=0.3, lam_distill=3.0): # 1. shared embedding: [B,160000] -> E_S [B,5,3,1536] -> E_A [B,1536] E_S = backbone(audio_mix) # spatial embedding E_A = E_S.mean(dim=(1, 2)) # mean-pool over time,freq # 2. species cross-entropy (target shares mass 1/k over k present species) p_lin = lin_head(E_A) # [B,14795] logits tgt = multihot_target / multihot_target.sum(1, keepdim=True) L_species = F.cross_entropy(p_lin, tgt) # 3. prototype teacher reads SPATIAL embedding p_proto = proto_head(E_S) # [B,14795] L_proto = F.cross_entropy(p_proto, tgt) + proto_head.orthogonality() # 4. self-distillation: student learns from teacher, gradient STOPPED L_distill = 0.0 if phase == 2: soft = p_proto.softmax(-1).detach() # <-- stop-gradient! L_distill = F.cross_entropy(p_lin, soft) # 5. source prediction (DIET): low-rank head over 1.5M recordings L_src = F.cross_entropy(src_head(E_A), src_id) return L_species + L_proto + lam_distill*L_distill + lam_src*L_src

The single most important line is p_proto.softmax(-1).detach().detach() is the stop-gradient. Remove it and the teacher would warp the embedding to flatter itself. Everything else is bookkeeping.

Cheat sheet — every symbol

SymbolMeaningShape / value
xmixmulti-source mixup waveform[160000]
N ∼ BetaBin(n,α,β)+1number of blended sources{1..6}, best 2–5
w ∼ SymDir(N,ω)blend weights (sum to 1)ω ≈ 10–30
ESspatial embedding → prototype head[5, 3, 1536]
EAmean embedding (the deployed product)[1536]
Lspecieslinear-head softmax CE on species14,795 classes
Lprotoprototype-head CE + orthogonality4 protos/class
Ldistillstudent ← stopgrad(teacher soft targets)λ ≈ 1.5–4.5
LsourceDIET: predict source recording (low-rank)rank 512, 1.5M cls

The one sentence to remember

If your domain has hundreds of thousands of fine-grained labels, don't reach for self-supervision — train a small supervised model on the hardest classification task you can construct, freeze it, and let its embeddings be the foundation. The bittern is shy, but the lesson is loud.

"Simple, supervised models are difficult to beat."
— The Bittern Lesson