| --- |
| license: apache-2.0 |
| language: |
| - en |
| tags: |
| - hearing loss |
| - challenge |
| - intelligibility |
| - prediction |
| - lyrics |
| - music |
| --- |
| |
| # Baseline for the Second Cadenza Lyric Intelligibility Prediction (CLIP2) challenge |
|
|
| The baseline model for the CLIP2 Cadenza challenge consisting of a regression |
| model that predicts a scalar in `[0, 1]` representing how intelligible a |
| song's lyrics are. Built on a partially fine-tuned Whisper encoder as front-end |
| and a small MLP regression head. |
|
|
| The `lyric_intelligibility_model.py` is self-contained: it has the model |
| (`WhisperIntelligibilityModel`, with `save_pretrained()`/`from_pretrained()` |
| mirroring the standard HF API) and a ready-to-use inference wrapper |
| (`IntelligibilityPredictor`) in one file. |
|
|
| ## Files in this repo |
|
|
| | File | Purpose | |
| |----------------------------------|----------------------------------------------------------------------------------------------------------| |
| | `config.json` | Model hyperparameters (backbone, hidden_dim, layer selection) | |
| | `model.safetensors` | Trained weights (state_dict) | |
| | `lyric_intelligibility_model.py` | `WhisperIntelligibilityModel` + `IntelligibilityPredictor` β everything needed to load and run the model | |
| | `inference.py` | Optional CLI wrapper around `IntelligibilityPredictor` that writes results to a CSV file | |
|
|
| ## Loading and using the model |
|
|
| ```python |
| from lyric_intelligibility_model import IntelligibilityPredictor |
| |
| predictor = IntelligibilityPredictor.from_pretrained( |
| "cadenzachallenge/CLIP2-BaselineBetterEar" |
| ) |
| result = predictor.predict("path/to/song.wav") |
| print(result["score"]) # e.g. 0.83 |
| print(result["channel"]) # "mono", or "left"/"right" for stereo (better-ear) |
| ``` |
|
|
| `predict()` also accepts a directory: it scores every audio file at the top |
| level (not recursive) and returns `{filename: result}` instead of a single |
| result dict. |
|
|
| ```python |
| results = predictor.predict("path/to/songs_dir") |
| for filename, r in results.items(): |
| print(filename, r["score"]) |
| ``` |
|
|
| Stereo audio is automatically scored per-channel and combined via the |
| **better-ear strategy** (`max(score_left, score_right)`) by default |
| β pass `better_ear=False` to downmix to mono instead. |
| Audio is resampled to 16 kHz internally using `soxr` (SoX HQ). |
|
|
| If you just want the raw model (e.g. for further fine-tuning) without the |
| audio-loading wrapper: |
|
|
| ```python |
| from lyric_intelligibility_model import WhisperIntelligibilityModel |
| from transformers import WhisperProcessor |
| |
| model = WhisperIntelligibilityModel.from_pretrained( |
| "cadenzachallenge/CLIP2-BaselineBetterEar" |
| ) |
| processor = WhisperProcessor.from_pretrained( |
| model.SUPPORTED_MODELS['whisper-large-v3'] |
| ) |
| |
| # unfreeze some encoder layers for fine-tuning |
| model.unfreeze_backbone(num_top_layers=4, context_layers=2) |
| |
| # preprocess audio -> log-mel features |
| inputs = processor(waveform, sampling_rate=16000, return_tensors="pt") |
| scores = model(inputs.input_features) # forward pass, then compute your loss |
| ``` |
|
|
| ## Command-line usage |
|
|
| `inference.py` is a thin CLI wrapper around `IntelligibilityPredictor` that |
| writes a `results.csv` (columns: filename stem, score β no header) instead |
| of returning a dict: |
|
|
| ```bash |
| pip install torch transformers huggingface_hub safetensors soundfile soxr |
| |
| python inference.py \ |
| --repo_id cadenzachallenge/CLIP2-BaselineBetterEar \ |
| --audio path/to/song.wav # or a directory |
| |
| # options: |
| # --no-better-ear downmix stereo to mono instead of left/right max |
| # --max-100 scale scores to [0, 100] instead of [0, 1] |
| # --output FILE custom CSV path (default: results.csv) |
| ``` |
|
|
| ## Model details |
|
|
| - **Backbone:** Whisper encoder (size set by `config.json`, default `whisper-large-v3`) |
| - **Layer fusion:** mean-pooled encoder layer(s) β learned per-layer weights β |
| optional cross-layer attention (when multiple layers are selected) |
| - **Head:** 2-layer MLP + sigmoid β score in `(0, 1)` |
| - **Output:** single scalar intelligibility score per input |
|
|
| - Data: The model was trained in CLIP2 train dataset. |
|
|
| ## More Information |
|
|
| For more information, please see the [Cadenza Challenge](https://cadenzachallenge.org/) website. |