This is the official GitHub repository for the paper: Unmute the Patch Tokens: Rethinking Probing in Multi-Label Audio Classification, accepted at ICLR 2026.
If you want to directly use the probing methods, not the complete pipeline.
Because the naming in the codebase differs slightly from the simplified names used in the paper, please refer to the mapping below:
| Paper Name | Code class name | File location |
|---|---|---|
| ProtoBin | Prototypical_multi_binarized_simple | heads/prototypical.py |
| ProtoFloat | Prototypical_multi_simple | heads/prototypical.py |
| Prototypical (from Bird-MAE) | prototypical_multi | heads/prototypical.py |
Here is an example of how the input is extracted from the EAT model, reshaped, and processed before being fed into the probing head.
In this implementation, the probes utilize the full patch tokens and subtract the class (cls) features to compute the relative features ($z_f$).
# extract features from EAT (normalization is handled internally)
features = model.extract_features(images)
cls_token = features[:, 0]
patch_tokens = features[:, 1:]
# calculate dimensions and reshape patch tokens
B, _, T, F = images.shape
ps = model.model.local_encoder.proj.kernel_size[0]
H_ps, W_ps = T // ps, F // ps
# shape becomes: (Batch, Hidden_Dim, H_ps, W_ps) e.g., (B, dim, 64, 8)
patch_features = patch_tokens.reshape(B, H_ps, W_ps, -1).permute(0, 3, 1, 2).contiguous()
# compute relative patch features (z_f = x_patch - x_cls)
B, C, H, W = patch_features.shape
x_patch = patch_features.permute(0, 2, 3, 1).reshape(B, H * W, C)
z_f = x_patch - cls_token.unsqueeze(1)
probe_input_features = z_f.permute(0, 2, 1).reshape(B, C, H, W)
conda create -n probing python=3.11.9 -y
pip install -r requirements.txt
The workflow consists of three main steps:
Note: Before running the workflow, make sure to adjust the
data_pathin thepaths/cluster.yamlorpaths/workstation.yamlfile to the path where you want to store the data etc.
Pre-extract features from backbone models to speed up hyperparameter optimization by avoiding repeated feature extraction during HPO trials.
python precompute_features.py \
paths=cluster \
backbone=audio/eat_base \
dataset=audio/urban_sed
We used slurm to precompute features for all backbones on all datasets. See the configs/slurm/features directory for the slurm scripts. An example is given below.
sbatch configs/slurm/features/urban_sed.sh
Note: It could be easier to save the dataset to disk and then load it from disk as a separate step. See the
configs/dataset/audio/urban_sed.yamlfile for the configuration.
Features are precomputed using the precompute.yaml config:
.pth files in {data_path}/precache/{dataset_name}/{backbone_name}/train.pth, test.pth, valid.pth (if validation split exists)Use Optuna with hybrid sampling (Sobol + TPE) to find optimal learning rates and weight decay values for different probing methods.
python optimize_hparams.py \
optimization=twoway_sobol_prot \
optimization.reset_study=True \
trainer.logger=null \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base
Example:
sbatch configs/slurm/hpo/urban_sed/eat_base.sh
twoway_sobol: Standard HPO for most probing methodstwoway_sobol_prot: Different search space for prototypical methodsn_trials: 50: Number of optimization trialsexploration_ratio: 0.50: Fraction of trials using Sobol samplingreeval_topk: 3: Number of top configurations to re-evaluatereeval_seeds: [0,1,2,3,4]: Seeds for final evaluationsearch_space:
optimizer:
lr: [2e-3, 8e-2] # Learning rate range (log scale)
weight_decay: [1e-5, 5e-4] # Weight decay range (log scale)
Train models using the optimized hyperparameters across multiple random seeds for robust performance evaluation.
From the re-evaluation JSON file, identify the best performing configuration. For instance:
{
"rank": 1,
"params": {
"optimizer.lr": 0.0,
"optimizer.weight_decay": 0.0
},
"mean": 0.0,
"std": 0.0
}
python main.py \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base \
optimizer.lr=0.00 \
optimizer.weight_decay=0.0 \
seed=0
# Run across different seeds for statistical significance
for seed in 0 1 2 3 4; do
python main.py \
paths=workstation \
head=prototypical \
dataset=audio/eat_base \
backbone=audio/urban_sed \
optimizer.lr=0.0 \
optimizer.weight_decay=0.0 \
seed=$seed \
experiment_name="final_eval_${seed}"
done
Here's a complete example for the urban_sed dataset with EAT backbone:
# 1. Precompute features
python precompute_features.py \
paths=workstation \
backbone=audio/eat_base \
dataset=audio/urban_sed
# 2. Run hyperparameter optimization
python optimize_hparams.py \
optimization=twoway_sobol_prot \
optimization.reset_study=True \
trainer.logger=null \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base
# 3. Extract best hyperparameters from JSON output
# (manually inspect reeval_top3_*.json file)
# 4. Run final training with optimal hyperparameters
python main.py \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base \
optimizer.lr=0.00 \
optimizer.weight_decay=0.0 \
seed=0
313 commits
Shell
43.0%
Python
34.7%
Jupyter Notebook
22.3%
This is the official GitHub repository for the paper: Unmute the Patch Tokens: Rethinking Probing in Multi-Label Audio Classification, accepted at ICLR 2026.
If you want to directly use the probing methods, not the complete pipeline.
Because the naming in the codebase differs slightly from the simplified names used in the paper, please refer to the mapping below:
| Paper Name | Code class name | File location |
|---|---|---|
| ProtoBin | Prototypical_multi_binarized_simple | heads/prototypical.py |
| ProtoFloat | Prototypical_multi_simple | heads/prototypical.py |
| Prototypical (from Bird-MAE) | prototypical_multi | heads/prototypical.py |
Here is an example of how the input is extracted from the EAT model, reshaped, and processed before being fed into the probing head.
In this implementation, the probes utilize the full patch tokens and subtract the class (cls) features to compute the relative features ($z_f$).
# extract features from EAT (normalization is handled internally)
features = model.extract_features(images)
cls_token = features[:, 0]
patch_tokens = features[:, 1:]
# calculate dimensions and reshape patch tokens
B, _, T, F = images.shape
ps = model.model.local_encoder.proj.kernel_size[0]
H_ps, W_ps = T // ps, F // ps
# shape becomes: (Batch, Hidden_Dim, H_ps, W_ps) e.g., (B, dim, 64, 8)
patch_features = patch_tokens.reshape(B, H_ps, W_ps, -1).permute(0, 3, 1, 2).contiguous()
# compute relative patch features (z_f = x_patch - x_cls)
B, C, H, W = patch_features.shape
x_patch = patch_features.permute(0, 2, 3, 1).reshape(B, H * W, C)
z_f = x_patch - cls_token.unsqueeze(1)
probe_input_features = z_f.permute(0, 2, 1).reshape(B, C, H, W)
conda create -n probing python=3.11.9 -y
pip install -r requirements.txt
The workflow consists of three main steps:
Note: Before running the workflow, make sure to adjust the
data_pathin thepaths/cluster.yamlorpaths/workstation.yamlfile to the path where you want to store the data etc.
Pre-extract features from backbone models to speed up hyperparameter optimization by avoiding repeated feature extraction during HPO trials.
python precompute_features.py \
paths=cluster \
backbone=audio/eat_base \
dataset=audio/urban_sed
We used slurm to precompute features for all backbones on all datasets. See the configs/slurm/features directory for the slurm scripts. An example is given below.
sbatch configs/slurm/features/urban_sed.sh
Note: It could be easier to save the dataset to disk and then load it from disk as a separate step. See the
configs/dataset/audio/urban_sed.yamlfile for the configuration.
Features are precomputed using the precompute.yaml config:
.pth files in {data_path}/precache/{dataset_name}/{backbone_name}/train.pth, test.pth, valid.pth (if validation split exists)Use Optuna with hybrid sampling (Sobol + TPE) to find optimal learning rates and weight decay values for different probing methods.
python optimize_hparams.py \
optimization=twoway_sobol_prot \
optimization.reset_study=True \
trainer.logger=null \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base
Example:
sbatch configs/slurm/hpo/urban_sed/eat_base.sh
twoway_sobol: Standard HPO for most probing methodstwoway_sobol_prot: Different search space for prototypical methodsn_trials: 50: Number of optimization trialsexploration_ratio: 0.50: Fraction of trials using Sobol samplingreeval_topk: 3: Number of top configurations to re-evaluatereeval_seeds: [0,1,2,3,4]: Seeds for final evaluationsearch_space:
optimizer:
lr: [2e-3, 8e-2] # Learning rate range (log scale)
weight_decay: [1e-5, 5e-4] # Weight decay range (log scale)
Train models using the optimized hyperparameters across multiple random seeds for robust performance evaluation.
From the re-evaluation JSON file, identify the best performing configuration. For instance:
{
"rank": 1,
"params": {
"optimizer.lr": 0.0,
"optimizer.weight_decay": 0.0
},
"mean": 0.0,
"std": 0.0
}
python main.py \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base \
optimizer.lr=0.00 \
optimizer.weight_decay=0.0 \
seed=0
# Run across different seeds for statistical significance
for seed in 0 1 2 3 4; do
python main.py \
paths=workstation \
head=prototypical \
dataset=audio/eat_base \
backbone=audio/urban_sed \
optimizer.lr=0.0 \
optimizer.weight_decay=0.0 \
seed=$seed \
experiment_name="final_eval_${seed}"
done
Here's a complete example for the urban_sed dataset with EAT backbone:
# 1. Precompute features
python precompute_features.py \
paths=workstation \
backbone=audio/eat_base \
dataset=audio/urban_sed
# 2. Run hyperparameter optimization
python optimize_hparams.py \
optimization=twoway_sobol_prot \
optimization.reset_study=True \
trainer.logger=null \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base
# 3. Extract best hyperparameters from JSON output
# (manually inspect reeval_top3_*.json file)
# 4. Run final training with optimal hyperparameters
python main.py \
paths=workstation \
head=prototypical \
dataset=audio/urban_sed \
backbone=audio/eat_base \
optimizer.lr=0.00 \
optimizer.weight_decay=0.0 \
seed=0
313 commits
Shell
43.0%
Python
34.7%
Jupyter Notebook
22.3%