alberto chord recognizer (CRNN, triads and sevenths)
A small convolutional-recurrent network that labels guitar audio with one of 73 classes per frame: no chord, or a major, minor, dominant-7th, major-7th, minor-7th or half-diminished-7th chord on any of the 12 roots. It is the neural recognizer of alberto, a guitar songwriting helper that listens to a progression, estimates the key, and suggests what to play next.
- Parameters: 482,025 (checkpoint under 2.5 MB)
- Input: log-magnitude constant-Q transform, C2 upward, 6 octaves, 24 bins per octave,
hop 512 at 22.05 kHz (
config.jsonhas every value) - Output: per-frame logits over 73 classes (
config.jsonlists them in order) - Decoding: alberto runs Viterbi over the frame posteriors with a bigram transition matrix
stored in the checkpoint (
transitions, estimated from the training labels); plain argmax works too, at a small accuracy cost - Runs comfortably on CPU: ~16 ms for model + Viterbi on an 8-second window on an M-series Mac
Training
Trained on GuitarSet (Xi, Bittner, Ye, Bello, ISMIR 2018; CC BY 4.0), mono-mic recordings, using the performed chord annotation mapped to the 73-class vocabulary (references with other qualities — 9ths, 6ths, sus — reduce to the triad their third implies). Players 00–04 (300 excerpts, strummed and solo) were used for training with random pitch shifts of up to ±5 semitones applied by rolling CQT bins; player 05 (60 excerpts) was held out. 30 epochs, Adam 1e-3 with cosine decay, 8-second chunks, cross-entropy.
Evaluation (mir_eval, held-out player 05, 30 strummed excerpts)
| metric | this model, viterbi | this model, argmax | binary-template baseline |
|---|---|---|---|
| root | 0.729 | 0.724 | 0.541 |
| majmin | 0.689 | 0.675 | 0.516 |
| triads | 0.525 | 0.516 | 0.399 |
| sevenths | 0.575 | 0.566 | 0.400 |
| mirex | 0.721 | 0.721 | 0.506 |
Scored against the performed annotation. The previous 25-class version scored majmin 0.684 and sevenths 0.450, so the seventh vocabulary lifted sevenths by 12.5 points without costing majmin.
Usage
The model definition lives in the alberto repository (alberto/chords/model.py). With it
on your path:
from huggingface_hub import hf_hub_download
from alberto.chords.model import recognize
weights = hf_hub_download("shawon/alberto-chord-crnn", "crnn_majmin.pt")
segments = recognize(y, sr, weights=weights) # y: mono float32 numpy array
for seg in segments:
print(f"{seg.start:6.2f} {seg.end:6.2f} {seg.chord}")
Or load the raw checkpoint into your own copy of the architecture:
import torch
ckpt = torch.load("crnn_majmin.pt", map_location="cpu", weights_only=True)
model = ChordCRNN(n_bins=ckpt["n_bins"], n_classes=ckpt.get("n_classes", 25)).eval()
model.load_state_dict(ckpt["state_dict"])
logits = model(torch.from_numpy(features).unsqueeze(0)) # (1, n_frames, 73)
Frames whose RMS is below -60 dBFS should be treated as no-chord regardless of the
prediction; alberto decodes the posteriors with Viterbi (see transitions above).
Limitations
- Six qualities only; sus, diminished and augmented chords map to the nearest class by their third, and extended chords (9ths, 6ths, 11ths) likewise.
- Trained on one acoustic guitar recorded with one microphone. Expect lower accuracy on electric guitar, distortion, or full mixes.
- Assumes the root is the lowest note, as in ordinary guitar voicings.
- Downloads last month
- 43