e414d9a3-2169-4455-af6c-ac540bbdc2e0/AcousticBench

0

stars

0

commits

Python

primary language

May 7, 2026

updated

README

AcousticBench

AcousticBench is an audio-perception benchmark for Large Audio-Language Models (LALMs). This repository contains the evaluation harness, Dockerized model servers, and reference results for reproducing every number in the paper.

Sub-taskQuestionsFormat
RAD (Relative Acoustic Discrimination)1,2002-clip A/B
RSQ (Relative Speech Quality)1,0002-clip A/B
SER-Classify (Emotion Classification)6001-clip A/B
SER-Intensity (Emotion Intensity)4002-clip A/B
SER-Classify-Text (transcript diagnostic)600text-only A/B

3,200 scored + 600 diagnostic = 3,800 questions total.


Required for all steps below

Two API keys are needed regardless of which models you evaluate:

VariableWhy it's neededHow to get
OPENAI_API_KEYThe LLM judge (gpt-4o-mini) extracts A/B labels from every model response. Called on every run.py invocation, even for open-weight models.platform.openai.com/api-keys
HF_TOKENDownloads open-weight model weights from HuggingFace on first Docker run.huggingface.co/settings/tokens

Save them:

# OpenAI key — put in .env (auto-loaded by run.py)
cp example.env .env
# Edit .env and set OPENAI_API_KEY=sk-...

# HuggingFace token — save where Docker containers can find it
mkdir -p ~/.cache/huggingface
echo "hf_YOUR_TOKEN" > ~/.cache/huggingface/token

Additional keys (GEMINI_API_KEY) are only needed if you want to run Gemini models specifically.


Prerequisites

RequirementDetails
Python3.11+
OSLinux x86_64 (Ubuntu 22.04+)
GPUNVIDIA A100-80GB (paper config). Smaller GPUs work for smaller models — see VRAM column below
Docker24.0+ with NVIDIA Container Toolkit
Disk~80 GB (5 GB archive + model weights cache)
nvidia-smi
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi

API models (Gemini, GPT-4o, Cascade) need no GPU — just API keys and internet.


Setup

git clone <repo-url> && cd acousticbench-public
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[all]"

# Set up API keys (see "Required for all steps below" above)
cp example.env .env
# Edit .env and set OPENAI_API_KEY=sk-...

# Extract benchmark data (use the actual filename you received)
python3 -c "import zipfile; zipfile.ZipFile('YOUR_ARCHIVE.zip').extractall('archive')"

# Verify extraction
python run.py --verify-checksums --task all
# Expected: "All 3800 questions passed checksum verification."

Important: Run source .venv/bin/activate in every new terminal session before using run.py or any scripts.


Level 1 — Run the models yourself

Run any model on any task and get accuracy numbers.

API model

export GEMINI_API_KEY=your_key
python run.py --model Gemini-3.1-Pro --task rad --max-samples 3 --seed 42

Open-weight model on your GPU

# Start the model server (builds Docker image on first run, downloads weights from HuggingFace)
./scripts/docker_serve.sh voxtral_mini_3b

# Export the endpoint (printed by the script)
export ACOUSTICBENCH_VOXTRAL_MINI_3B_ENDPOINT=http://localhost:8009

# Run the evaluation (--max-samples 3 for a quick test; omit for the full task)
python run.py --model Voxtral-Mini-3B --task rad --max-samples 3 --seed 42

# Stop when done
./scripts/docker_serve.sh voxtral_mini_3b --stop

CLI flags

FlagWhat it doesPaper setting
--model NAMEWhich model to evaluateSee Models below
--task TASKWhich task: rad, rsq, ser_classify, ser_classify_text, ser_intensity, or allall
--runs NNumber of independent runs3
--seed SStarting seed. With --runs 3, produces seeds S, S+1, S+242 (seeds 42, 43, 44)
--concurrency NParallel inference threads8 for API, 1 for Docker
--split all|train|evalData split. all = full set (main leaderboard), eval = held-out (LoRA lift table)all
--max-samples NLimit to N questions (for quick testing)omit
--compare-referenceAfter running, compare results against reference_trajectories/ and print match rate-

Where results go

results/<Model>-<task>-<backend>-seed<N>-<timestamp>/
  responses.jsonl    # one JSON line per question
  config.json        # run configuration
  metrics.json       # aggregate accuracy

Level 2 — Compare your results to our reference JSONLs

This verifies that your local GPU produces the same answers we reported. Add --compare-reference to any run.py command and it will automatically compare each run against the matching file in reference_trajectories/.

Quick check (5 minutes)

./scripts/docker_serve.sh voxtral_mini_3b
export ACOUSTICBENCH_VOXTRAL_MINI_3B_ENDPOINT=http://localhost:8009

python run.py --model Voxtral-Mini-3B --task rad --max-samples 10 --seed 42 --compare-reference
# Expected output: "Reference comparison: 10/10 (100.0%) match ..."

Expected match rates

ScenarioExpected
Same GPU type as ours (A100-80GB)100%
Different GPU (e.g. H100, A6000)90-100% (greedy decoding + flash-attention FP nondeterminism flips ~0-2% of near-50/50 items)
API models (Gemini, GPT-4o)95-100% (provider-side nondeterminism even at temp 0)

Reference trajectories layout

reference_trajectories/
  <Model>/
    <task>/
      run_1.jsonl       # seed 42
      run_2.jsonl       # seed 43
      run_3.jsonl       # seed 44
      summary.json      # mean accuracy, std, per-run breakdown

Models

API models (no GPU needed)

Model--model flagRequired env var
Gemini-3.1-ProGemini-3.1-ProGEMINI_API_KEY
Gemini-3-FlashGemini-3-FlashGEMINI_API_KEY
Gemini-2.5-ProGemini-2.5-ProGEMINI_API_KEY
Gemini-2.5-Flash-AudioGemini-2.5-Flash-AudioGEMINI_API_KEY
GPT-4oGPT-4oOPENAI_API_KEY
Cascade (ASR baseline)Cascade-GPT4oTranscribe-GPT5.4OPENAI_API_KEY

Open-weight models (GPU + Docker)

Model--model flagDocker nameVRAMPort
Qwen3-OmniQwen3-Omniqwen3_omni~70 GB8001
Voxtral-Small-24BVoxtral-Small-24Bvoxtral_small_24b~50 GB8008
Kimi-AudioKimi-Audiokimi_audio~20 GB8002
MiniCPM-o-4.5MiniCPM-o-4.5minicpm_o~20 GB8005
Step-Audio-2-miniStep-Audio-2-ministep_audio2~20 GB8020
MiMo-Audio-7BMiMo-Audio-7Bmimo_audio~20 GB8019
Audio-Flamingo-3Audio-Flamingo-3audio_flamingo3~20 GB8010
Qwen2-Audio-7BQwen2-Audio-7B-Instructqwen2_audio~16 GB8004
Phi-4-MultimodalPhi-4-Multimodalphi4mm~12 GB8006
Voxtral-Mini-3BVoxtral-Mini-3Bvoxtral_mini_3b~8 GB8009

Each model's endpoint env var is printed by docker_serve.sh when starting. See ./scripts/docker_serve.sh --list for the full list.

Kimi LoRA finetunes (paper §4.2)

Model--model flagDocker name
Kimi-Audio-LoRA-RADKimi-Audio-LoRA-RADkimi_lora_rad
Kimi-Audio-LoRA-RSQKimi-Audio-LoRA-RSQkimi_lora_rsq
Kimi-Audio-LoRA-SER-ClassifyKimi-Audio-LoRA-SER-Classifykimi_lora_ser_classify
Kimi-Audio-LoRA-SER-IntensityKimi-Audio-LoRA-SER-Intensitykimi_lora_ser_intensity
Kimi-Audio-LoRA-Simple-AudioQAKimi-Audio-LoRA-Simple-AudioQAkimi_lora_simple_audioqa

Requires Kimi LoRA adapter weights extracted into ./archive/. Download from Kaggle:

pip install kagglehub
python3 -c "
import kagglehub, shutil
path = kagglehub.dataset_download('blueberrystonekitten/acousticbench-kimi-rap-finetunes')
shutil.copytree(path, 'archive', dirs_exist_ok=True)
print('Adapter weights extracted to ./archive/')
"

Important: LoRA reference trajectories were run with --split eval. Use --split eval when comparing against them. The LoRA Docker container needs ~60 GB of free disk on first boot to export the merged model (cached for subsequent runs).


JSONL schema

Each run_*.jsonl (and each responses.jsonl from your own runs) has one JSON line per question:

FieldTypeDescription
example_idstringStable ID matching archive/questions/acousticbench_<task>.jsonl
response_textstringRaw model output (empty if error)
response_status"ok" / "error"Whether the model responded
chosen"A" / "B" / nullAnswer extracted by the judge. null = unparseable or refusal
correct"A" / "B"Gold answer
is_correctboolchosen == correct (false when chosen is null)
extraction_sourcestring"deterministic" (regex), "rerun-attempt-N" (refusal retry), or "llm" (LLM re-judge)
wall_time_sfloatInference latency in seconds
metaobjectQuestion metadata: dimension, category, task, etc.

Handling refusals and errors

A small fraction of responses are abstentions or verbose text the judge can't parse. If you see null values in chosen:

# Retry refusals up to 3 times
python scripts/rerun_nones.py --model MODEL_NAME --concurrency 8 --max-retries 3 \
    results/MODEL_NAME-*-seed42-*/responses.jsonl

# Re-judge remaining unparseable responses via LLM
python scripts/rejudge.py results/MODEL_NAME-*/responses.jsonl

Notes

Greedy decoding. All open-weight models use temperature=0, do_sample=False. Run-to-run variance is zero or near-zero. Small differences across GPU types come from flash-attention floating-point nondeterminism, not sampling.

Paper configuration. All reference trajectories were produced on A100-80GB GPUs, with 3 runs (seeds 42, 43, 44) per (model, task).

Train/eval splits. Each task has train and eval halves. Main leaderboard: --split all. LoRA lift table (paper Table 2): --split eval.

MiniCPM-o-4.5 merges paired audio clips with a 1-second silence gap for 2-clip tasks because its chat interface accepts only single audio input.

LLM judge. The harness uses gpt-4o-mini to extract A/B labels from free-text responses. Requires OPENAI_API_KEY.

Zip format. The benchmark archive uses Zip64. System unzip on many Linux distributions can't handle this — use the Python zipfile command shown above.

First Docker run. Downloads model weights from HuggingFace (8-70 GB depending on model). Weights cache at ~/.cache/huggingface and reuse on subsequent runs.

e414d9a3-2169-4455-af6c-ac540bbdc2e0/AcousticBench

0

stars

0

commits

Python

primary language

May 7, 2026

updated

README

AcousticBench

AcousticBench is an audio-perception benchmark for Large Audio-Language Models (LALMs). This repository contains the evaluation harness, Dockerized model servers, and reference results for reproducing every number in the paper.

Sub-taskQuestionsFormat
RAD (Relative Acoustic Discrimination)1,2002-clip A/B
RSQ (Relative Speech Quality)1,0002-clip A/B
SER-Classify (Emotion Classification)6001-clip A/B
SER-Intensity (Emotion Intensity)4002-clip A/B
SER-Classify-Text (transcript diagnostic)600text-only A/B

3,200 scored + 600 diagnostic = 3,800 questions total.


Required for all steps below

Two API keys are needed regardless of which models you evaluate:

VariableWhy it's neededHow to get
OPENAI_API_KEYThe LLM judge (gpt-4o-mini) extracts A/B labels from every model response. Called on every run.py invocation, even for open-weight models.platform.openai.com/api-keys
HF_TOKENDownloads open-weight model weights from HuggingFace on first Docker run.huggingface.co/settings/tokens

Save them:

# OpenAI key — put in .env (auto-loaded by run.py)
cp example.env .env
# Edit .env and set OPENAI_API_KEY=sk-...

# HuggingFace token — save where Docker containers can find it
mkdir -p ~/.cache/huggingface
echo "hf_YOUR_TOKEN" > ~/.cache/huggingface/token

Additional keys (GEMINI_API_KEY) are only needed if you want to run Gemini models specifically.


Prerequisites

RequirementDetails
Python3.11+
OSLinux x86_64 (Ubuntu 22.04+)
GPUNVIDIA A100-80GB (paper config). Smaller GPUs work for smaller models — see VRAM column below
Docker24.0+ with NVIDIA Container Toolkit
Disk~80 GB (5 GB archive + model weights cache)
nvidia-smi
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi

API models (Gemini, GPT-4o, Cascade) need no GPU — just API keys and internet.


Setup

git clone <repo-url> && cd acousticbench-public
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[all]"

# Set up API keys (see "Required for all steps below" above)
cp example.env .env
# Edit .env and set OPENAI_API_KEY=sk-...

# Extract benchmark data (use the actual filename you received)
python3 -c "import zipfile; zipfile.ZipFile('YOUR_ARCHIVE.zip').extractall('archive')"

# Verify extraction
python run.py --verify-checksums --task all
# Expected: "All 3800 questions passed checksum verification."

Important: Run source .venv/bin/activate in every new terminal session before using run.py or any scripts.


Level 1 — Run the models yourself

Run any model on any task and get accuracy numbers.

API model

export GEMINI_API_KEY=your_key
python run.py --model Gemini-3.1-Pro --task rad --max-samples 3 --seed 42

Open-weight model on your GPU

# Start the model server (builds Docker image on first run, downloads weights from HuggingFace)
./scripts/docker_serve.sh voxtral_mini_3b

# Export the endpoint (printed by the script)
export ACOUSTICBENCH_VOXTRAL_MINI_3B_ENDPOINT=http://localhost:8009

# Run the evaluation (--max-samples 3 for a quick test; omit for the full task)
python run.py --model Voxtral-Mini-3B --task rad --max-samples 3 --seed 42

# Stop when done
./scripts/docker_serve.sh voxtral_mini_3b --stop

CLI flags

FlagWhat it doesPaper setting
--model NAMEWhich model to evaluateSee Models below
--task TASKWhich task: rad, rsq, ser_classify, ser_classify_text, ser_intensity, or allall
--runs NNumber of independent runs3
--seed SStarting seed. With --runs 3, produces seeds S, S+1, S+242 (seeds 42, 43, 44)
--concurrency NParallel inference threads8 for API, 1 for Docker
--split all|train|evalData split. all = full set (main leaderboard), eval = held-out (LoRA lift table)all
--max-samples NLimit to N questions (for quick testing)omit
--compare-referenceAfter running, compare results against reference_trajectories/ and print match rate-

Where results go

results/<Model>-<task>-<backend>-seed<N>-<timestamp>/
  responses.jsonl    # one JSON line per question
  config.json        # run configuration
  metrics.json       # aggregate accuracy

Level 2 — Compare your results to our reference JSONLs

This verifies that your local GPU produces the same answers we reported. Add --compare-reference to any run.py command and it will automatically compare each run against the matching file in reference_trajectories/.

Quick check (5 minutes)

./scripts/docker_serve.sh voxtral_mini_3b
export ACOUSTICBENCH_VOXTRAL_MINI_3B_ENDPOINT=http://localhost:8009

python run.py --model Voxtral-Mini-3B --task rad --max-samples 10 --seed 42 --compare-reference
# Expected output: "Reference comparison: 10/10 (100.0%) match ..."

Expected match rates

ScenarioExpected
Same GPU type as ours (A100-80GB)100%
Different GPU (e.g. H100, A6000)90-100% (greedy decoding + flash-attention FP nondeterminism flips ~0-2% of near-50/50 items)
API models (Gemini, GPT-4o)95-100% (provider-side nondeterminism even at temp 0)

Reference trajectories layout

reference_trajectories/
  <Model>/
    <task>/
      run_1.jsonl       # seed 42
      run_2.jsonl       # seed 43
      run_3.jsonl       # seed 44
      summary.json      # mean accuracy, std, per-run breakdown

Models

API models (no GPU needed)

Model--model flagRequired env var
Gemini-3.1-ProGemini-3.1-ProGEMINI_API_KEY
Gemini-3-FlashGemini-3-FlashGEMINI_API_KEY
Gemini-2.5-ProGemini-2.5-ProGEMINI_API_KEY
Gemini-2.5-Flash-AudioGemini-2.5-Flash-AudioGEMINI_API_KEY
GPT-4oGPT-4oOPENAI_API_KEY
Cascade (ASR baseline)Cascade-GPT4oTranscribe-GPT5.4OPENAI_API_KEY

Open-weight models (GPU + Docker)

Model--model flagDocker nameVRAMPort
Qwen3-OmniQwen3-Omniqwen3_omni~70 GB8001
Voxtral-Small-24BVoxtral-Small-24Bvoxtral_small_24b~50 GB8008
Kimi-AudioKimi-Audiokimi_audio~20 GB8002
MiniCPM-o-4.5MiniCPM-o-4.5minicpm_o~20 GB8005
Step-Audio-2-miniStep-Audio-2-ministep_audio2~20 GB8020
MiMo-Audio-7BMiMo-Audio-7Bmimo_audio~20 GB8019
Audio-Flamingo-3Audio-Flamingo-3audio_flamingo3~20 GB8010
Qwen2-Audio-7BQwen2-Audio-7B-Instructqwen2_audio~16 GB8004
Phi-4-MultimodalPhi-4-Multimodalphi4mm~12 GB8006
Voxtral-Mini-3BVoxtral-Mini-3Bvoxtral_mini_3b~8 GB8009

Each model's endpoint env var is printed by docker_serve.sh when starting. See ./scripts/docker_serve.sh --list for the full list.

Kimi LoRA finetunes (paper §4.2)

Model--model flagDocker name
Kimi-Audio-LoRA-RADKimi-Audio-LoRA-RADkimi_lora_rad
Kimi-Audio-LoRA-RSQKimi-Audio-LoRA-RSQkimi_lora_rsq
Kimi-Audio-LoRA-SER-ClassifyKimi-Audio-LoRA-SER-Classifykimi_lora_ser_classify
Kimi-Audio-LoRA-SER-IntensityKimi-Audio-LoRA-SER-Intensitykimi_lora_ser_intensity
Kimi-Audio-LoRA-Simple-AudioQAKimi-Audio-LoRA-Simple-AudioQAkimi_lora_simple_audioqa

Requires Kimi LoRA adapter weights extracted into ./archive/. Download from Kaggle:

pip install kagglehub
python3 -c "
import kagglehub, shutil
path = kagglehub.dataset_download('blueberrystonekitten/acousticbench-kimi-rap-finetunes')
shutil.copytree(path, 'archive', dirs_exist_ok=True)
print('Adapter weights extracted to ./archive/')
"

Important: LoRA reference trajectories were run with --split eval. Use --split eval when comparing against them. The LoRA Docker container needs ~60 GB of free disk on first boot to export the merged model (cached for subsequent runs).


JSONL schema

Each run_*.jsonl (and each responses.jsonl from your own runs) has one JSON line per question:

FieldTypeDescription
example_idstringStable ID matching archive/questions/acousticbench_<task>.jsonl
response_textstringRaw model output (empty if error)
response_status"ok" / "error"Whether the model responded
chosen"A" / "B" / nullAnswer extracted by the judge. null = unparseable or refusal
correct"A" / "B"Gold answer
is_correctboolchosen == correct (false when chosen is null)
extraction_sourcestring"deterministic" (regex), "rerun-attempt-N" (refusal retry), or "llm" (LLM re-judge)
wall_time_sfloatInference latency in seconds
metaobjectQuestion metadata: dimension, category, task, etc.

Handling refusals and errors

A small fraction of responses are abstentions or verbose text the judge can't parse. If you see null values in chosen:

# Retry refusals up to 3 times
python scripts/rerun_nones.py --model MODEL_NAME --concurrency 8 --max-retries 3 \
    results/MODEL_NAME-*-seed42-*/responses.jsonl

# Re-judge remaining unparseable responses via LLM
python scripts/rejudge.py results/MODEL_NAME-*/responses.jsonl

Notes

Greedy decoding. All open-weight models use temperature=0, do_sample=False. Run-to-run variance is zero or near-zero. Small differences across GPU types come from flash-attention floating-point nondeterminism, not sampling.

Paper configuration. All reference trajectories were produced on A100-80GB GPUs, with 3 runs (seeds 42, 43, 44) per (model, task).

Train/eval splits. Each task has train and eval halves. Main leaderboard: --split all. LoRA lift table (paper Table 2): --split eval.

MiniCPM-o-4.5 merges paired audio clips with a 1-second silence gap for 2-clip tasks because its chat interface accepts only single audio input.

LLM judge. The harness uses gpt-4o-mini to extract A/B labels from free-text responses. Requires OPENAI_API_KEY.

Zip format. The benchmark archive uses Zip64. System unzip on many Linux distributions can't handle this — use the Python zipfile command shown above.

First Docker run. Downloads model weights from HuggingFace (8-70 GB depending on model). Weights cache at ~/.cache/huggingface and reuse on subsequent runs.

Languages

Python

94.0%

Dockerfile

4.3%

Shell

1.7%