Sanyuan Chen, Yu Wu, Chengyi Wang, Shujie Liu, Daniel Tompkins, Zhuo Chen, Furu Wei (Microsoft) — ICML 2023 / arXiv 2022

BEATs: Audio Pre-Training with Acoustic Tokenizers

The first self-supervised audio model whose masked-prediction targets are semantic discrete tokens — produced by a tokenizer that co-evolves with the model in an iterative loop. It closed the gap between reconstruction-style and label-style audio SSL and set state of the art on AudioSet.

Prerequisites: Self-attention (see the Transformer veanor) + softmax / cross-entropy + mel spectrograms (intuition only). Vector quantization is built from zero here.
10
Chapters
9
Simulations
2
Code Labs

Chapter 0: What is the right target for masked audio?

You have ten million YouTube clips and no labels. You want a model that, after a tiny bit of fine-tuning, can tell a dog bark from a doorbell, a violin from a viola, applause from rain. The trick everyone uses is masked prediction: hide part of the input, ask the model to fill it in, and the representations it learns along the way turn out to be useful for everything downstream. BERT did this for text, MAE did it for images, HuBERT did it for speech. The question this paper answers is deceptively narrow: when you mask part of an audio clip, what exactly should the model be asked to predict?

That question is the whole ball game, and before BEATs nobody had a satisfying answer for general audio. Let's see why the obvious choices were broken.

Choice A: predict the raw acoustics (reconstruction)

The simplest target is the audio itself — predict the masked mel-spectrogram patch, pixel-for-pixel, with an L1 or L2 loss. This is what SSAST and MAE-style audio models (Audio-MAE) do. It works, but it spends the model's capacity on the wrong thing. A mel patch is full of low-level texture: the exact phase of a hum, the speckle of background noise, the precise energy in band 73. Forcing the model to regress all of that pulls its representation toward acoustic detail and away from meaning. You end up an excellent denoiser and a mediocre classifier.

Choice B: predict a discrete code from a fixed tokenizer (the speech recipe)

For speech, HuBERT and wav2vec 2.0 instead predict a discrete target — a cluster id. HuBERT runs k-means on MFCC features to assign every frame a label in {1..K}, then asks the model to classify the masked frame into the right cluster. Classification (cross-entropy over K classes) is a much friendlier loss than regression: it ignores within-cluster acoustic detail and only cares about which bucket the sound belongs to. The problem: the buckets come from k-means on hand-picked low-level features. For speech those features happen to track phonemes. For general audio — music, machinery, animal calls, ambience — k-means on MFCCs gives you buckets that mostly track loudness and spectral shape, not what the sound is. The target is discrete but not semantic.

The target spectrum: acoustic ↔ semantic

Slide from a purely acoustic target (reconstruct the patch) to a purely semantic one (predict an event id). Watch the two failure modes: an acoustic target wastes capacity on texture; a hand-built discrete target loses meaning. BEATs aims for the green band — discrete and semantic — and gets there by letting the tokenizer learn.

target type acoustic

So the field had a fork: discrete-but-dumb (HuBERT-style cluster ids) or continuous-but-detail-obsessed (MAE-style reconstruction). BEATs' thesis is that you should not have to choose. You want a target that is discrete (so the loss is a clean classification) and semantic (so predicting it forces the model to understand the sound). The catch: a semantic discrete target does not exist for free. You cannot k-means your way to "this 16×16 patch is part of a guitar." You have to learn the tokenizer — and learn it in a way that injects meaning into the codes.

Misconception: "Discrete targets are just a speedup over reconstruction." No — the discreteness is the point, but only if the codes are semantic. A discrete target built by k-means on MFCCs (HuBERT) is not interchangeable with BEATs' learned acoustic tokens. BEATs' whole contribution is a recipe for making the codebook itself carry meaning, by distilling a trained model's semantic knowledge into the discrete labels and then iterating. Swap in random clusters and the discreteness buys you almost nothing.

BEATs in one breath

Acoustic tokenizer
Quantizes each spectrogram patch into a discrete code id — the prediction target
↓ supplies labels to
Masked-prediction model
Transformer encoder; masks ~75% of patches and classifies their token ids (cross-entropy)
↓ distilled back into
Re-trained tokenizer
Codes are re-fit to predict the trained model's outputs — labels become more semantic
↓   repeat   ↑
Iterate
Better model → better tokenizer → better model. Two iterations suffice.

That loop is the paper. By the end of this veanor you will have built the quantizer, the masked-prediction loss, and the distillation objective with your own hands. Let's start where the data starts: turning a waveform into something a Transformer can read.

Why is a discrete cluster id from k-means on MFCCs (the HuBERT recipe) a poor masked-prediction target for general audio?

Chapter 1: From waveform to patches

A Transformer eats a sequence of vectors. Audio arrives as a 1-D waveform — tens of thousands of samples per second. The standard bridge, which BEATs inherits from the vision-transformer view of audio (HTS-AT, AST), has two steps: turn the waveform into a 2-D mel spectrogram, then chop that image into square patches.

Step 1: the mel spectrogram

Run a short-time Fourier transform: slide a ~25 ms window across the waveform every ~10 ms, take the magnitude of its frequency content, and warp the frequency axis onto the perceptual mel scale (which spaces low frequencies finely and high frequencies coarsely, like the ear does). For BEATs the result is a matrix with 128 mel bins on the frequency axis and one column per 10 ms frame. A 10-second clip at this hop is roughly 998 frames × 128 mels — call it F frames by M mels.

Step 2: patchify

Treat that spectrogram as a single-channel image of shape [1, F, M] and split it into non-overlapping 16×16 patches, exactly as a ViT splits a photo. With F ≈ 1000 and M = 128 this yields about (1000/16) × (128/16) = 62 × 8 ≈ 496 patches. Each patch is a 16×16 = 256-number tile of the spectrogram. A small convolution (a "patch-embed" stem) projects each tile to a D-dimensional vector — in BEATs, D = 768. We now have a sequence:

X = [x1, x2, …, xN]     N ≈ 496,   each xn ∈ ℝ768

This is the object every later chapter operates on. The tokenizer assigns each patch xn a discrete code; the encoder masks a subset of patches and predicts those codes; the distillation step re-fits the codes. Everything is per-patch.

Worked example: counting the patches

Let's make the shapes concrete on a tiny clip so the arithmetic is unambiguous. Take a 1-second clip, hop 10 ms, so F = 100 frames; M = 128 mels; patch = 16. Patches along time: ⌊100/16⌋ = 6 (the leftover 4 frames are dropped or padded). Patches along frequency: 128/16 = 8. Total patches N = 6 × 8 = 48. Each patch is 256 raw numbers; the conv stem maps 256 → 768. So a 1-second clip becomes a sequence of 48 vectors of length 768 — a [48, 768] tensor. Double the clip length, double N; the per-patch dimension never changes.

Patchifying a spectrogram

A mel spectrogram (frequency up, time right) carved into 16×16 patches. Drag the slider to change the patch size and watch how N — the number of tokens the Transformer sees — changes. Bigger patches = fewer tokens = cheaper attention but coarser resolution.

patch size 16
Why patches and not frames? A per-frame model (one token per 10 ms column) gives ~1000 tokens for a 10-second clip and O(N²) attention blows up. Patching pools a 16×16 time×frequency block into one token, cutting N by ~16× along time and ~16× along frequency. It also bakes in a useful inductive bias: a patch is a little time-frequency tile, the natural unit of an acoustic "event" (a transient, a harmonic stack, a noise burst).

Misconception: "BEATs predicts the next audio sample, like a language model predicts the next word." No. There is no autoregression and no waveform regression in pre-training. BEATs is a masked, bidirectional, classification objective over patch tokens: random patches are blanked, the encoder sees the rest, and it predicts the discrete code of each blanked patch. It is BERT-for-spectrogram-patches, not GPT-for-audio.
A 4-second clip gives F = 400 frames and M = 128 mels. With 16×16 patches, how many patch tokens N does the encoder see?

Chapter 2: The Acoustic Tokenizer

The tokenizer is the heart of BEATs. Its job: take each patch vector and emit a single integer in {1,…,K} — its code id. The set of K possible codes is the codebook. BEATs uses a codebook of K = 1024 entries, each a learnable vector in a low-dimensional code space (the paper uses a 256-dim quantizer space, projected from the encoder's 768). Quantizing means: for a patch, find the nearest codebook vector and report its index.

Concretely the tokenizer is itself a small Transformer (the "tokenizer encoder") followed by a vector-quantization (VQ) layer. Let zn ∈ ℝd be the tokenizer's continuous output for patch n, and let the codebook be {e1,…,eK} with each ek ∈ ℝd. The code id is nearest-neighbour:

cn = argmink ‖ zn − ek22

and the quantized vector handed downstream is just the chosen codebook entry, q̂n = ecn. Two patches that map to the same nearest entry get the same token — they are declared "the same kind of sound."

The normalized-distance trick

BEATs (following the BEiT-v2 / VQ-KD line) ℓ2-normalizes both zn and the codebook entries before computing distance. On the unit sphere, squared Euclidean distance and cosine similarity are equivalent: ‖a−b‖² = 2−2·a·b when ‖a‖=‖b‖=1. So nearest-neighbour quantization becomes "pick the code with the highest cosine similarity." Normalizing keeps the codebook from collapsing onto a few high-norm entries and makes training far more stable — a recurring lesson in VQ.

The gradient problem and the straight-through estimator

argmin is not differentiable — you cannot backprop through "pick the nearest". The fix, from VQ-VAE, is the straight-through estimator: on the forward pass use the quantized q̂n; on the backward pass copy the gradient straight through as if q̂n = zn. In code this is the one-liner q = z + stop_grad(qhat − z): the value equals q̂n, but the gradient flows to zn unchanged.

To actually move the codebook and the encoder toward each other, VQ adds two auxiliary terms. With sg[·] the stop-gradient:

Lvq = ‖ sg[zn] − ecn22  +  β ‖ zn − sg[ecn] ‖22

The first term (the codebook loss) pulls the chosen code toward the encoder output. The second (the commitment loss, weight β ≈ 0.25) pulls the encoder output toward its code so the encoder "commits" to codes instead of drifting. (BEATs in practice uses the exponential-moving-average update for the codebook, an equivalent of the first term; the commitment term stays.)

Worked example: quantizing one patch by hand

Take a 2-D code space (d = 2) and a tiny codebook of three entries: e1 = (1, 0), e2 = (0, 1), e3 = (−1, 0). The tokenizer outputs z = (0.8, 0.3). Distances:

‖z−e1‖² = (0.8−1)² + (0.3−0)² = 0.04 + 0.09 = 0.13
‖z−e2‖² = (0.8−0)² + (0.3−1)² = 0.64 + 0.49 = 1.13
‖z−e3‖² = (0.8−(−1))² + 0.09 = 3.24 + 0.09 = 3.33

The smallest is e1, so c = 1 and the quantized vector is (1, 0). The commitment loss would then push z toward (1, 0), and the codebook update would nudge e1 toward (0.8, 0.3). You will reproduce exactly this nearest-code logic in Code Lab #1.

Vector quantization on the plane

Eight codebook vectors (teal dots) partition the plane into Voronoi cells. Drag the encoder output (warm dot) and watch which code it snaps to — and the squared distance to each. The cell boundaries are exactly where the argmin flips. This is one token assignment.

z x z y code —
python
# Vector quantization with the straight-through estimator (VQ-VAE)
import torch
import torch.nn.functional as F

def quantize(z, codebook, beta=0.25):
    """
    z:        [N, d]   tokenizer outputs (one per patch)
    codebook: [K, d]   the K learnable code vectors
    returns:  q [N, d] quantized, ids [N], vq_loss
    """
    # L2-normalize so distance == cosine (BEATs / BEiT-v2 trick)
    zn  = F.normalize(z, dim=-1)
    en  = F.normalize(codebook, dim=-1)
    # Squared distances [N, K]; argmin over K = nearest code
    d2  = (zn.pow(2).sum(-1, keepdim=True)
           - 2 * zn @ en.T
           + en.pow(2).sum(-1))      # [N, K]
    ids = d2.argmin(-1)                  # [N] the token ids
    qhat = en[ids]                          # [N, d] chosen codes
    # Codebook + commitment losses
    cb  = F.mse_loss(qhat, zn.detach())
    cm  = F.mse_loss(zn, qhat.detach())
    vq_loss = cb + beta * cm
    # Straight-through: forward = qhat, backward = identity to z
    q = zn + (qhat - zn).detach()
    return q, ids, vq_loss
Misconception: "More codes (bigger K) is always better, so use a huge codebook." Bigger K splits the audio space more finely, but if K is too large most codes are never used (codebook collapse) and the labels become so specific that masked prediction degenerates into memorizing exact patches — back to the reconstruction failure mode. K = 1024 is a deliberate middle ground: enough buckets to be expressive, few enough that each is hit often and stays semantic. The ℓ2-normalization and EMA updates exist precisely to keep all K codes alive.
Why does the straight-through estimator exist in the VQ layer?

Chapter 3: Masked Prediction — the model's objective

Now freeze the tokenizer for a moment and look at the model being pre-trained. Given the patch sequence X = [x1,…,xN], the tokenizer has labeled every patch with a code id cn ∈ {1,…,K}. We sample a mask set M ⊂ {1,…,N} covering about 75% of the patches. For masked positions we replace xn with a shared learnable [MASK] embedding; unmasked positions pass through unchanged. The Transformer encoder reads this corrupted sequence and produces hidden states h1,…,hN. A linear "prediction head" maps each masked position's hidden state to a distribution over the K codes:

p(c | n) = softmax(W hn + b)     W ∈ ℝK×D,   p ∈ ΔK−1

and the loss is plain cross-entropy against the tokenizer's labels, summed over masked positions only:

LMAM = − ∑n ∈ M log p(cn | n)

("MAM" = masked audio modeling.) That is the entire pre-training objective for the model. No reconstruction, no waveform, no autoregression — just "for each blanked patch, classify which of the 1024 acoustic codes it was." Because the codes are semantic (we'll earn that adjective in Chapters 4–5), classifying them forces the encoder to reason about what the surrounding sound is, not just what it looks like.

Why mask 75%? Why only score masked positions?

Two design choices that look small and aren't:

High mask ratio. If you mask only 15% (BERT's text ratio), audio patches are so locally redundant that the model can solve each blank by copying a neighbour — a barely-disturbed harmonic stack is trivially interpolated. Masking ~75% (as MAE found for images, and BEATs adopts) removes the easy local cues and forces long-range, semantic inference: to fill a hole you must recognize the event spanning the whole clip.

Score only masked positions. If you also asked the model to predict unmasked patches it can see, it would just learn a copy — the loss would reward identity, not understanding. Restricting LMAM to M makes every contributing term a genuine guess.

Worked example: the cross-entropy on one masked patch

Suppose K = 4 codes and the prediction head outputs logits (2.0, 1.0, 0.1, −1.0) for a masked patch whose true code is c = 1 (the first). Softmax: exponentiate → (7.39, 2.72, 1.11, 0.37), sum = 11.59, so p = (0.638, 0.235, 0.096, 0.032). The loss for this patch is −log p1 = −log 0.638 = 0.449 nats. If the model had been confident-and-correct (p1 → 1) the loss → 0; confident-and-wrong (p1 → 0) sends it to ∞. Cross-entropy only looks at the probability assigned to the right code — the within-code acoustic texture is invisible to it. That invisibility is the whole reason discrete targets beat reconstruction.

Masked audio modeling on a patch grid

A 12×8 grid of spectrogram patches. Slide the mask ratio: masked patches (warm) are replaced by [MASK]; the encoder must predict their token ids from the visible (teal) ones. The counter shows how many of the visible patches are "easy neighbours" — at 75% almost none survive, forcing semantic inference.

mask ratio 75%
python
# Masked Audio Modeling loss — predict tokenizer codes at masked patches
import torch
import torch.nn.functional as F

def mam_loss(encoder, head, patches, code_ids, mask_ratio=0.75):
    N, D = patches.shape
    # 1. choose ~75% of positions to mask
    n_mask = int(N * mask_ratio)
    mask = torch.randperm(N)[:n_mask]
    # 2. replace masked patches with the learnable [MASK] embedding
    x = patches.clone()
    x[mask] = head.mask_token        # [D] broadcast
    # 3. encode the corrupted sequence (bidirectional, all visible at once)
    h = encoder(x)                    # [N, D]
    # 4. classify each masked position over the K codes
    logits = head.proj(h[mask])       # [n_mask, K]
    # 5. cross-entropy against tokenizer labels, masked positions only
    return F.cross_entropy(logits, code_ids[mask])
Misconception: "Masking 75% throws away too much — the model can't possibly fill it." It can, because the target is semantic and the clip is globally coherent. A 75% hole in a violin recording is recoverable not by local interpolation but by recognizing "this is a sustained bowed string" and predicting violin-codes everywhere. The high mask ratio is what converts the task from local copying into global understanding. Lower it and the representation gets worse, not better — confirmed in the ablations.
In BEATs pre-training, what loss is applied and where?

Chapter 4: Label Distillation — making codes semantic

We have postponed the central question long enough: how does a code id become semantic? A VQ codebook trained only to reconstruct, or trained on random patches, gives codes that cluster acoustically — they separate loud from quiet, high from low — but not violin from flute. BEATs' answer is label distillation (it calls the objective the acoustic tokenizer's knowledge distillation): train the tokenizer so that its discrete codes predict the outputs of a trained masked-prediction model. The model has, through pre-training and fine-tuning, learned a semantic representation; distillation pours that semantics into the discrete codes.

The estimator/teacher split

The tokenizer is trained as a tiny student that must reconstruct a teacher's behaviour through the bottleneck of a discrete code. Two pieces:

Teacher
A frozen BEATs encoder from the previous iteration (or its fine-tuned classifier). Produces a target representation tn per patch.
↓ tokenizer must reproduce its knowledge through a code
Tokenizer (student)
patch → zn → quantize to code ecn → a small decoder predicts t̂n from the code.

The distillation loss makes the prediction-from-code match the teacher. BEATs maximizes the cosine similarity between the code-derived prediction t̂n and the teacher target tn (equivalently, minimizes a normalized MSE):

Ldistill = − ∑n cos( t̂n, sg[tn] )  +  Lvq

where t̂n is computed from the quantized code only, sg[·] freezes the teacher, and Lvq is the codebook/commitment term from Chapter 2. The crucial constraint: t̂n may depend on the patch only through its discrete code ecn. So if two patches must yield very different teacher representations, they are forced into different codes. The discreteness becomes an information bottleneck that the codebook must spend wisely on whatever the teacher considers meaningful — i.e. on semantics.

Why cosine, not raw MSE? Teacher representations live on very different scales across layers and patches; matching their direction (cosine) rather than their magnitude makes distillation robust to scale and prevents the trivial solution of shrinking everything toward the mean. It's the same reason Chapter 2 normalized before quantizing — on the sphere, direction is the signal.

Worked example: distillation pressure on the codebook

Imagine three patches A, B, C with teacher targets tA = (1, 0), tB = (0.9, 0.1), tC = (0, 1). The teacher says A and B are nearly identical (cos ≈ 0.996) and C is orthogonal. A code can only emit one prediction t̂ per id. If A and B share code 1 (predicting (0.95, 0.05)) the cosine loss is tiny for both. But forcing C into code 1 as well would cost cos((0.95,0.05),(0,1)) ≈ 0.05 — terrible. So distillation pushes C onto a different code. The codebook self-organizes so that "patches the teacher treats alike share a code; patches the teacher distinguishes get split." That is semantics, learned. You'll implement this similarity-driven split in Code Lab #2.

Distillation re-organizes the codebook

Left: a tokenizer trained only on acoustics — codes split by loudness/pitch (rings). Right: after distillation — codes split by what the teacher considers the same event (colored clusters). Drag the slider to interpolate and watch low-level rings dissolve into semantic clusters.

acoustic → semantic acoustic codes
python
# Acoustic-tokenizer knowledge distillation (cosine objective)
import torch
import torch.nn.functional as F

def tokenizer_distill_loss(tok, decoder, teacher, patches):
    # teacher is FROZEN — the trained BEATs model from the last iteration
    with torch.no_grad():
        t = teacher(patches)                 # [N, D] target representation
    z = tok(patches)                        # [N, d] tokenizer outputs
    q, ids, vq = quantize(z, tok.codebook)   # discrete bottleneck
    # predict the teacher target FROM THE CODE ONLY
    t_hat = decoder(q)                       # [N, D]
    # match direction, not magnitude
    distill = -F.cosine_similarity(t_hat, t.detach(), dim=-1).mean()
    return distill + vq, ids
Misconception: "Distillation just copies the teacher, so the tokenizer can't be better than the teacher." The point isn't to beat the teacher — it's to compress the teacher's semantics into 1024 discrete buckets. Those buckets then become a cleaner, lower-variance target for the next round of masked prediction than the teacher's continuous outputs would be. The student tokenizer is worse than the teacher as a classifier but better as a label source, because a discrete label is a denoised, committed decision. That asymmetry is what makes the iterative loop (next chapter) actually improve.
What forces BEATs' acoustic codes to become semantic rather than merely acoustic?

Chapter 5: The Iterative Loop

We have a chicken-and-egg problem. To make codes semantic (Chapter 4) we distill from a trained BEATs model. But to train that model (Chapter 3) we need semantic codes. Which comes first? BEATs breaks the cycle with a cold start and then iterates.

Iteration 0: the random-projection tokenizer (cold start)

You cannot distill from a teacher you don't have. So the very first tokenizer is not learned at all — it is a fixed random-projection quantizer. Project each patch through a random (frozen) matrix into the code space, then nearest-neighbour against a random codebook. The codes are acoustically meaningful but not semantic — exactly the HuBERT-style starting point. Crucially, even a random discrete target is enough to bootstrap a first masked-prediction model that learns something useful, just as HuBERT's first iteration runs on k-means-of-MFCC labels.

The alternation

Iter 1 — tokenizer
Random-projection quantizer (frozen). No learning; just provides bootstrap labels.
Iter 1 — model
Masked prediction of the random codes → a first semantic encoder.
↓ this model becomes the teacher
Iter 2 — tokenizer
Now learn the tokenizer by distilling the Iter-1 model. Codes become semantic.
Iter 2 — model
Re-do masked prediction on the new semantic codes → the strong BEATs encoder.

Each pass through the loop has two phases that never train together: (a) freeze the model, train the tokenizer by distillation; (b) freeze the tokenizer, train the model by masked prediction. Like the EM algorithm or like HuBERT's relabeling rounds, alternating between two frozen-and-trained roles is what keeps the loop stable. Joint end-to-end training would let the model and tokenizer collude on a degenerate code (e.g. constant labels with zero loss). The freezing prevents collapse.

Why does iterating help at all? Information flows uphill each pass. Iter-1's model squeezes weak semantics out of random labels. Distilling it gives Iter-2 labels that are more semantic than random. Training on better labels yields a better Iter-2 model — which, if you distilled it again, would give even better labels. In practice the gains saturate fast: BEATs reports that two iterations capture almost all the benefit, so they stop there. A third pass barely moves the needle.

Worked example: tracing label quality across iterations

Score "label semanticity" as the fraction of same-event patches that share a code (higher = more semantic). Suppose random-projection labels give 0.30 (mostly acoustic accidents). Iter-1's model, trained on those, learns features that — when distilled — produce codes scoring 0.62. Iter-2's model, trained on the 0.62 labels, distills to 0.71. Iter-3 would give ~0.73. The deltas — +0.32, +0.09, +0.02 — show the textbook diminishing returns that justify stopping at two. (These numbers are illustrative; the paper reports the analogous downstream-accuracy gains plateauing by iteration 2.)

Bootstrap to convergence

Press "Iterate" to run the loop. Each press: (1) train the model on the current labels (the encoder's accuracy bar rises), then (2) distill it into a new tokenizer (the label-quality bar rises). Watch both climb together and saturate after ~2 rounds — the paper's empirical stopping point.

Iteration 0 — random-projection labels
Misconception: "The tokenizer and the model are trained jointly, end-to-end." They are emphatically not. In each phase one is frozen. Joint training admits a trivial collapse: the tokenizer outputs a constant code, the model predicts that constant, the loss hits zero, and nothing has been learned. Alternating optimization with a frozen teacher (the EM-style structure) is precisely what makes the discrete target a stable learning signal instead of a degenerate one.
What kicks off iteration 1, before any semantic tokenizer exists?

Chapter 6: The Encoder — what actually does the work

Both the tokenizer and the masked-prediction model share the same backbone: a ViT-style Transformer encoder adapted for spectrograms, drawn from HTS-AT-flavoured audio transformers. Let's pin down the architecture and the data flow with real shapes.

The stack

StageOperationTensor shape
InputMel spectrogram[1, F, 128]
Patch embedConv stem, 16×16 stride 16, → D=768[N, 768], N≈496
Pos. encodingConvolutional positional embedding (depthwise conv)[N, 768]
×12 blocksSelf-attn (rel-pos bias) → Add&Norm → FFN → Add&Norm[N, 768]
Pre-train headLinear → K logits (masked positions only)[|M|, 1024]
Fine-tune headMean-pool over N → Linear → C classes[C]

The base BEATs encoder is roughly 90M parameters — 12 Transformer layers, hidden width 768, 12 attention heads, FFN width 3072. Two adaptations matter for audio:

Convolutional positional embedding. Instead of (or in addition to) sinusoidal position codes, a depthwise convolution over the patch sequence injects relative position — it lets nearby patches in time-frequency know they are neighbours, which is more natural for the 2-D grid structure of a spectrogram than 1-D sinusoids.

Relative-position bias in attention. Each attention score gets an additive learned bias depending on the relative offset between query and key patch. So the raw attention is

Aij = softmaxj( qi·kj / √dk + bi−j )

where bi−j is a learned scalar shared by all patch pairs the same distance apart. This is the relative-position scheme from Swin/HTS-AT — it improves length generalization and locality without fixing a maximum sequence length the way learned absolute positions do.

Pre-train vs fine-tune: only the head changes

During pre-training the encoder reads a masked patch sequence and the head classifies codes at masked positions. During fine-tuning the same encoder reads the full (unmasked) sequence; a new head mean-pools all N hidden states into a clip-level vector and classifies it into the C downstream labels (e.g. 527 AudioSet classes). The expensive 90M-parameter encoder is reused verbatim — only the cheap output head is replaced. That reuse is the entire value proposition of self-supervised pre-training: pay once for the encoder on unlabeled data, amortize over many downstream tasks.

Worked example: where the FLOPs go

For N = 496 patches and D = 768, one attention layer costs roughly N²·D for the QKT·V products ≈ 496²·768 ≈ 1.9×108 mults, while the FFN costs roughly N·D·(4D) ≈ 496·768·3072 ≈ 1.2×109 — the FFN dominates a single layer at this sequence length. But because attention is O(N²), doubling the clip length (N→992) quadruples the attention term while only doubling the FFN term. This is why long-audio modeling is hard and why patching (which keeps N small) is essential.

The BEATs encoder data flow

Click "Highlight" to step through the stack and watch the tensor shape at each stage — from spectrogram to patches to 12 Transformer blocks to either the pre-train code head or the fine-tune class head.

[1, F, 128] → [N, 768]
Misconception: "BEATs needs a special decoder like MAE." MAE reconstructs pixels and so needs a heavy decoder to map latent → image. BEATs predicts a discrete code id with a single linear layer over the encoder's hidden state — no decoder. (The only decoder anywhere is the tiny one inside the tokenizer during distillation, predicting the teacher target from a code — and it's discarded after the tokenizer is trained.) The asymmetry — discrete classification head vs. pixel-reconstruction decoder — is a direct consequence of choosing a discrete target.
When moving from pre-training to downstream fine-tuning, what changes in the BEATs model?

Chapter 7: Results & Ablations

BEATs' headline claim is straightforward: with the same encoder size and data, swapping the masked-prediction target from reconstruction or hand-built clusters to iterated semantic codes moves audio classification to state of the art. The flagship benchmark is AudioSet (~2M weakly-labeled 10-second YouTube clips, 527 sound classes, scored by mean average precision, mAP).

The headline numbers (qualitative where exact figures are uncertain)

SettingWhat it showsAudioSet-2M mAP
Prior SSL (SSAST, MAE-style)reconstruction / patch-recovery targetslower (mid-40s)
BEATs iter 1 (random-proj. labels)discrete but non-semantic targetstrong already
BEATs iter 3 (semantic codes)distilled, iterated discrete targetSOTA single model (~48.6 mAP)
BEATs ensemblemultiple fine-tuned models~50.6 mAP (new SOTA)

The single-model BEATs reached roughly 48.6 mAP on AudioSet-2M and the ensemble roughly 50.6 mAP — the best reported at the time, surpassing supervised and prior-SSL audio transformers. It also topped smaller benchmarks (ESC-50 environmental sounds near the high-90s accuracy, strong scores on speech-command and other tasks), showing the representation transfers beyond AudioSet.

The ablations that prove the thesis

The paper's experiments are designed to isolate why it works:

Worked example: reading an mAP delta

mAP averages the per-class average precision over all 527 classes. Suppose reconstruction-target pre-training gives 45.0 mAP and semantic-code pre-training gives 48.6. The +3.6 absolute looks small, but on AudioSet — where the gap between consecutive SOTA papers is often well under a point — 3.6 mAP from a single design change (the target) is large. It says: on average across every sound class, the semantic-code model ranks true positives meaningfully higher. The cost was zero extra labels — the whole pipeline ran on the same unlabeled audio.

Ablation: the target is the lever

Toggle the masked-prediction target and read the (illustrative) downstream mAP. Reconstruction and random-projection codes lag; iterated semantic codes lead. Same encoder, same data — only the target differs.

Reconstruction target
Misconception: "BEATs wins because it's a bigger model trained on more data." The controlled ablations hold encoder size and data fixed and vary only the target. The gain is attributable to making the discrete labels semantic, not to scale. That's what makes the result a method result rather than a compute result — and why the recipe transfers to whatever encoder you plug in.
Which ablation result is the paper's central evidence?

Chapter 8: BEATs Explorer

This is the whole pipeline in one interactive surface. A synthetic clip is patchified; a learnable-looking codebook tokenizes each patch into a code id; a fraction of patches are masked; the masked-prediction head guesses their codes. Drive every knob and watch the mask, the token map, and the (simulated) prediction accuracy respond. There's no quiz here — this is the payoff. Read the three readouts as you move the controls.

End-to-end: patchify → tokenize → mask → predict

Top: the patch grid colored by token id (each color = one of K codes). Masked patches are dimmed and X'd. Bottom: a bar of predicted-vs-true codes at masked positions. Raise K for a finer codebook, raise mask to make the task harder, raise iter to make the codes more semantic (and the model better at recovering them).

codebook K mask %
iteration

Things to notice as you play:

That interaction — high mask ratio is only learnable when the target is semantic, which only happens after iteration — is the single most important intuition in the paper. The mask ratio and the iterative tokenizer are not two independent tricks; they are two halves of one mechanism.

Chapter 9: Limitations & Connections

BEATs is a clean, influential result, but it is not magic. Where does it strain, and where does it sit in the larger map of representation learning?

Limitations

Where BEATs sits

BEATs is the audio member of a family of discrete-token masked-prediction methods that all share one move — make the prediction target a learned discrete code rather than raw input:

MethodDomainDiscrete target fromRelation to BEATs
HuBERTSpeechk-means on features, re-clustered each iterThe iterative-relabeling idea; non-semantic clusters
BEiT / BEiT-v2ImagesdVAE / VQ-KD codes (distilled)Direct ancestor of the distilled-codebook idea
MAE / Audio-MAEImage / Audionone — reconstructs pixels/patchesThe reconstruction baseline BEATs beats
BEATsAudioiterated semantic acoustic tokenizerThis paper — semantic codes + iteration

Read next on Engineermaxxing

The cheat sheet

ConceptOne-line summary
GoalSelf-supervised audio encoder whose masked-prediction target is discrete and semantic.
InputMel spectrogram [1,F,128] → 16×16 patches → N≈496 vectors of dim 768.
TokenizerSmall Transformer + VQ codebook (K=1024); patch → nearest code id. ℓ2-normalized, straight-through gradient.
Model objectiveLMAM: mask ~75% of patches, cross-entropy classify their code ids (masked positions only).
Making codes semanticDistill a frozen teacher: predict its representation from the code only, cosine loss. Forces same-event patches to share a code.
Iterative loopCold start with random-projection labels → train model → distill tokenizer → retrain. Saturates by iter 2.
Encoder~90M, 12-layer ViT/HTS-AT-style; conv positional embed + relative-position attention bias.
Fine-tuneReuse encoder on full sequence; swap head → mean-pool + linear over C classes.
ResultSOTA on AudioSet (~48.6 single / ~50.6 ensemble mAP); ablations show the target is the lever.
Key tradeoffMulti-stage, costly pipeline; O(N²) attention caps clip length; tokenizer hyperparameters are heuristic.
The one idea to keep: BEATs shows that in masked self-supervision, the target is a first-class design variable — not an afterthought. By learning a discrete, semantic tokenizer (instead of accepting raw reconstruction or hand-built clusters) and refreshing it iteratively against a model that the same tokenizer helped train, you get a prediction target that pulls the encoder toward meaning. Discrete + semantic + iterated: that is the recipe, and it generalizes far beyond audio.