spyroskantarelis/chordonomicon

Chordonomicon: A Dataset of 666,000 Chord Progressions

Python

165

42 commits

updated May 7, 2026

See the code

README

Chordonomicon

Chordonomicon: A Dataset of 666,000 Chord Progressions

Chordonomicon is a very large scale dataset containing containing over 666,000 song-level symbolic chord progressions, annotated with structural parts (verse, chorus, bridge, etc.), genre, and release date, created by scraping various sources of user-generated progressions and associated metadata, showing strong similarity to well-established prior datasets. Beyond the dataset itself, we propose a reproducible benchmark suite for next chord prediction, evaluating three sequence modeling architectures (RNN, GRU, LSTM) across multiple context window sizes and data scales under strict exact-match evaluation. Our experiments reveal that structural part annotations consistently improve prediction performance. Chordonomicon is released as an open benchmark, providing split methodology, baselines, and evaluation protocols to enable fair and reproducible comparison for future work on chord prediction, classification, generation, and beyond. All code and information for replicating our next chord prediction benchmark is in Chord_Prediction branch.

Next Chord Prediction Benchmark

A next chord prediction system trained on the Chordonomicon dataset. Given a sequence of chords, the model predicts the next chord. Three chord representations are supported — flat token, triad (root + qualex + bass), and tetrad (root + quality + extensions + bass) — and three recurrent architectures — RNN, GRU, LSTM.


Project structure

.
├── Chord_Embeddings.py   # Data preprocessing and vocabulary building
├── Helpers.py            # Dataset, model, and split utilities
├── Model_Training.py     # Training script
├── Model_Evaluation.py   # Evaluation script
├── Run.py                # Entry point — configure and launch train/eval
├── data/
│   ├── chordonomicon_v2.csv
│   ├── filtered_1token.pkl      # all songs, 1-token encoding
│   ├── filtered_3tokens.pkl     # all songs, 3-token encoding
│   ├── filtered_4tokens.pkl     # all songs, 4-token encoding
│   ├── labeled_1token.pkl       # labeled songs (labels stripped), 1-token
│   ├── labeled_3tokens.pkl
│   ├── labeled_4tokens.pkl
│   ├── segmented_1token.pkl     # labeled songs split into sections, 1-token
│   ├── segmented_3tokens.pkl
│   ├── segmented_4tokens.pkl
│   └── vocabs/
│       ├── vocabs.pkl           # all vocabulary and mapping dicts
│       ├── vocab_chords.csv
│       ├── vocab_roots.csv
│       ├── vocab_qualities.csv
│       ├── vocab_extensions.csv
│       ├── vocab_basses.csv
│       └── vocab_qualexes.csv
├── models/
│   ├── best_LSTM_model.pth
│   ├── best_LSTM_model_metrics.json
│   ├── LSTM/
│   │   └── json/
│   ├── GRU/
│   │   └── json/
│   └── RNN/
│       └── json/
└── results/

Step 1 — Preprocess the dataset

Run Chord_Embeddings.py once to build all vocabularies and encoded sequence files.

Before running, make sure chordonomicon_v2.csv is placed in the data/ directory (create it manually if it doesn't exist yet).

python Chord_Embeddings.py

This reads data/chordonomicon_v2.csv and produces all data/*.pkl files and data/vocabs/ outputs. The data/ and data/vocabs/ directories are created automatically if they don't exist.


Step 2 — Train a model

python Model_Training.py \
    --representation triad \
    --model_type     lstm \
    --data_path      ./data/segmented_3tokens.pkl \
    --vocabs_path    ./data/vocabs/vocabs.pkl \
    --embed_dim      16 \
    --hidden_dim     256 \
    --num_layers     1 \
    --batch_size     4096 \
    --epochs         200 \
    --lr             5e-3 \
    --sample_size    200000 \
    --num            0

Arguments

ArgumentDefaultDescription
--representationchordChord encoding: chord, triad, or tetrad
--model_typernnRecurrent architecture: rnn, gru, or lstm
--data_pathsegmented_4tokens.pklPath to encoded sequence dataset
--vocabs_pathdata/vocabs/vocabs.pklPath to vocabs pickle
--embed_dim16Embedding dimension
--hidden_dim256RNN hidden dimension
--num_layers1Number of RNN layers
--batch_size4096Batch size
--epochs200Maximum training epochs
--lr5e-3Learning rate
--sample_size200000Total samples drawn (80% train, 10% val, 10% test)
--num0Run id, appended to saved filenames
--seedrandomRandom seed (saved in checkpoint for reproducibility)
--deviceautocuda or cpu

Data split

Songs are split by id — no song appears in more than one split. The split is stratified by section label. Early stopping triggers after 10 epochs of no improvement on validation loss. The learning rate is halved after 3 epochs of no improvement (ReduceLROnPlateau).

Outputs

Each run saves to models/<MODEL_TYPE>/ using a filename that encodes all hyperparameters. If the run achieves a new best validation loss, the checkpoint is also copied to models/best_<MODEL_TYPE>_model.pth.


Step 3 — Evaluate a model

python Model_Evaluation.py \
    --representation  triad \
    --model_type      lstm \
    --model_path      ./models/best_LSTM_model.pth \
    --model_name      LSTM_triad_baseline \
    --dataset_path    ./data/segmented_3tokens.pkl \
    --vocabs_path     ./data/vocabs/vocabs.pkl \
    --batch_size      4096 \
    --top_n           10

To evaluate on a held-out second dataset instead of the test split:

python Model_Evaluation.py \
    ... \
    --second_dataset_path ./data/labeled_3tokens.pkl \
    --full_dataset

Arguments

ArgumentDefaultDescription
--representationRequired. Must match the trained model
--model_typernnMust match the trained model
--model_pathRequired. Path to .pth checkpoint
--model_nameRequired. Human-readable name, used in output filename
--dataset_pathsegmented_4tokens.pklPrimary dataset (used to recreate splits)
--second_dataset_pathlabeled_4tokens.pklHeld-out dataset for --full_dataset
--vocabs_pathdata/vocabs/vocabs.pklPath to vocabs pickle
--save_dir./resultsDirectory for JSON results
--batch_size4096Batch size
--top_n10Number of top mismatches to print
--deviceautocuda or cpu
--full_datasetoffEvaluate on second_dataset_path instead of test split

Outputs

Results are saved to results/<model_name>_<representation>_<sample_size>.json containing metrics, per-length accuracy, and decoded mismatch tables. Evaluation is deterministic — the seed is restored from the checkpoint, giving identical results across runs.


Representations

NameEncodingDataset files
chordSingle chord id (0-indexed)*_1token.pkl
triad[root_id, qualex_id, bass_id]*_3tokens.pkl
tetrad[root_id, quality_id, extension_id, bass_id]*_4tokens.pkl

In triad mode, quality and extensions are combined into a single qualex token. In tetrad mode they are split. All part ids are 1-indexed in the vocabulary; the dataset shifts them to 0-indexed for the model.


Vocabularies

data/vocabs/vocabs.pkl contains 20 tables:

  • Encodingchord_to_idx, root_to_idx, quality_to_idx, extensions_to_idx, bass_to_idx, qualex_to_idx
  • Decodingidx_to_chord, idx_to_root, idx_to_quality, idx_to_extensions, idx_to_bass, idx_to_qualex
  • Text lookupschord_to_parts_3/4, parts_to_chord_3/4
  • Integer lookupspart_ids_to_chord_id_3/4, chord_id_to_part_ids_3/4

Human-readable CSV versions are saved alongside in data/vocabs/.


Approximate number of parameters

TokensRNNGRULSTM
11.12M1.26M1.33M
3449K605K683K
4354K518K600K

Using Run.py

Run.py is a convenience script — edit the cmd and cmd2 lists to configure training and evaluation, then run:

python Run.py

Additional Scripts

Using convert_mirex.ipynb you can convert the chord progressions into Harte syntax.

We offer three additional Python scripts: one for transposing chords into all tonalities (for data augmentation purposes), another for converting chords into their corresponding notes (e.g., A:7 → ['la','do#,'mi','sol']), and a third script that generates a binary 12-semitone list representation for each chord, commencing with the note C (e.g., C:maj7 → [1,0,0,0,1,0,0,1,0,0,0,1]) (all scripts are in convert_to_mappings.ipynb).

The full updated dataset (as of 12/3/2024) can be downloaded from here: https://huggingface.co/datasets/ailsntua/Chordonomicon

For a detailed description of the Chordonomicon Dataset, please see our paper on arXiv [https://doi.org/10.48550/arXiv.2410.22046]. If you use this dataset, kindly cite the paper to acknowledge the work.

Citation

@article{kantarelis2024chordonomicon, title={CHORDONOMICON: A Dataset of 666,000 Songs and their Chord Progressions}, author={Kantarelis, Spyridon and Thomas, Konstantinos and Lyberatos, Vassilis and Dervakos, Edmund and Stamou, Giorgos}, journal={arXiv preprint arXiv:2410.22046}, year={2024} }

Contributors

gliolits

11 commits

vaslyb

2 commits

notcarlybates

1 commits

spyroskantarelis/chordonomicon

Chordonomicon: A Dataset of 666,000 Chord Progressions

Python

165

42 commits

updated May 7, 2026

See the code

README

Chordonomicon

Chordonomicon: A Dataset of 666,000 Chord Progressions

Chordonomicon is a very large scale dataset containing containing over 666,000 song-level symbolic chord progressions, annotated with structural parts (verse, chorus, bridge, etc.), genre, and release date, created by scraping various sources of user-generated progressions and associated metadata, showing strong similarity to well-established prior datasets. Beyond the dataset itself, we propose a reproducible benchmark suite for next chord prediction, evaluating three sequence modeling architectures (RNN, GRU, LSTM) across multiple context window sizes and data scales under strict exact-match evaluation. Our experiments reveal that structural part annotations consistently improve prediction performance. Chordonomicon is released as an open benchmark, providing split methodology, baselines, and evaluation protocols to enable fair and reproducible comparison for future work on chord prediction, classification, generation, and beyond. All code and information for replicating our next chord prediction benchmark is in Chord_Prediction branch.

Next Chord Prediction Benchmark

A next chord prediction system trained on the Chordonomicon dataset. Given a sequence of chords, the model predicts the next chord. Three chord representations are supported — flat token, triad (root + qualex + bass), and tetrad (root + quality + extensions + bass) — and three recurrent architectures — RNN, GRU, LSTM.


Project structure

.
├── Chord_Embeddings.py   # Data preprocessing and vocabulary building
├── Helpers.py            # Dataset, model, and split utilities
├── Model_Training.py     # Training script
├── Model_Evaluation.py   # Evaluation script
├── Run.py                # Entry point — configure and launch train/eval
├── data/
│   ├── chordonomicon_v2.csv
│   ├── filtered_1token.pkl      # all songs, 1-token encoding
│   ├── filtered_3tokens.pkl     # all songs, 3-token encoding
│   ├── filtered_4tokens.pkl     # all songs, 4-token encoding
│   ├── labeled_1token.pkl       # labeled songs (labels stripped), 1-token
│   ├── labeled_3tokens.pkl
│   ├── labeled_4tokens.pkl
│   ├── segmented_1token.pkl     # labeled songs split into sections, 1-token
│   ├── segmented_3tokens.pkl
│   ├── segmented_4tokens.pkl
│   └── vocabs/
│       ├── vocabs.pkl           # all vocabulary and mapping dicts
│       ├── vocab_chords.csv
│       ├── vocab_roots.csv
│       ├── vocab_qualities.csv
│       ├── vocab_extensions.csv
│       ├── vocab_basses.csv
│       └── vocab_qualexes.csv
├── models/
│   ├── best_LSTM_model.pth
│   ├── best_LSTM_model_metrics.json
│   ├── LSTM/
│   │   └── json/
│   ├── GRU/
│   │   └── json/
│   └── RNN/
│       └── json/
└── results/

Step 1 — Preprocess the dataset

Run Chord_Embeddings.py once to build all vocabularies and encoded sequence files.

Before running, make sure chordonomicon_v2.csv is placed in the data/ directory (create it manually if it doesn't exist yet).

python Chord_Embeddings.py

This reads data/chordonomicon_v2.csv and produces all data/*.pkl files and data/vocabs/ outputs. The data/ and data/vocabs/ directories are created automatically if they don't exist.


Step 2 — Train a model

python Model_Training.py \
    --representation triad \
    --model_type     lstm \
    --data_path      ./data/segmented_3tokens.pkl \
    --vocabs_path    ./data/vocabs/vocabs.pkl \
    --embed_dim      16 \
    --hidden_dim     256 \
    --num_layers     1 \
    --batch_size     4096 \
    --epochs         200 \
    --lr             5e-3 \
    --sample_size    200000 \
    --num            0

Arguments

ArgumentDefaultDescription
--representationchordChord encoding: chord, triad, or tetrad
--model_typernnRecurrent architecture: rnn, gru, or lstm
--data_pathsegmented_4tokens.pklPath to encoded sequence dataset
--vocabs_pathdata/vocabs/vocabs.pklPath to vocabs pickle
--embed_dim16Embedding dimension
--hidden_dim256RNN hidden dimension
--num_layers1Number of RNN layers
--batch_size4096Batch size
--epochs200Maximum training epochs
--lr5e-3Learning rate
--sample_size200000Total samples drawn (80% train, 10% val, 10% test)
--num0Run id, appended to saved filenames
--seedrandomRandom seed (saved in checkpoint for reproducibility)
--deviceautocuda or cpu

Data split

Songs are split by id — no song appears in more than one split. The split is stratified by section label. Early stopping triggers after 10 epochs of no improvement on validation loss. The learning rate is halved after 3 epochs of no improvement (ReduceLROnPlateau).

Outputs

Each run saves to models/<MODEL_TYPE>/ using a filename that encodes all hyperparameters. If the run achieves a new best validation loss, the checkpoint is also copied to models/best_<MODEL_TYPE>_model.pth.


Step 3 — Evaluate a model

python Model_Evaluation.py \
    --representation  triad \
    --model_type      lstm \
    --model_path      ./models/best_LSTM_model.pth \
    --model_name      LSTM_triad_baseline \
    --dataset_path    ./data/segmented_3tokens.pkl \
    --vocabs_path     ./data/vocabs/vocabs.pkl \
    --batch_size      4096 \
    --top_n           10

To evaluate on a held-out second dataset instead of the test split:

python Model_Evaluation.py \
    ... \
    --second_dataset_path ./data/labeled_3tokens.pkl \
    --full_dataset

Arguments

ArgumentDefaultDescription
--representationRequired. Must match the trained model
--model_typernnMust match the trained model
--model_pathRequired. Path to .pth checkpoint
--model_nameRequired. Human-readable name, used in output filename
--dataset_pathsegmented_4tokens.pklPrimary dataset (used to recreate splits)
--second_dataset_pathlabeled_4tokens.pklHeld-out dataset for --full_dataset
--vocabs_pathdata/vocabs/vocabs.pklPath to vocabs pickle
--save_dir./resultsDirectory for JSON results
--batch_size4096Batch size
--top_n10Number of top mismatches to print
--deviceautocuda or cpu
--full_datasetoffEvaluate on second_dataset_path instead of test split

Outputs

Results are saved to results/<model_name>_<representation>_<sample_size>.json containing metrics, per-length accuracy, and decoded mismatch tables. Evaluation is deterministic — the seed is restored from the checkpoint, giving identical results across runs.


Representations

NameEncodingDataset files
chordSingle chord id (0-indexed)*_1token.pkl
triad[root_id, qualex_id, bass_id]*_3tokens.pkl
tetrad[root_id, quality_id, extension_id, bass_id]*_4tokens.pkl

In triad mode, quality and extensions are combined into a single qualex token. In tetrad mode they are split. All part ids are 1-indexed in the vocabulary; the dataset shifts them to 0-indexed for the model.


Vocabularies

data/vocabs/vocabs.pkl contains 20 tables:

  • Encodingchord_to_idx, root_to_idx, quality_to_idx, extensions_to_idx, bass_to_idx, qualex_to_idx
  • Decodingidx_to_chord, idx_to_root, idx_to_quality, idx_to_extensions, idx_to_bass, idx_to_qualex
  • Text lookupschord_to_parts_3/4, parts_to_chord_3/4
  • Integer lookupspart_ids_to_chord_id_3/4, chord_id_to_part_ids_3/4

Human-readable CSV versions are saved alongside in data/vocabs/.


Approximate number of parameters

TokensRNNGRULSTM
11.12M1.26M1.33M
3449K605K683K
4354K518K600K

Using Run.py

Run.py is a convenience script — edit the cmd and cmd2 lists to configure training and evaluation, then run:

python Run.py

Additional Scripts

Using convert_mirex.ipynb you can convert the chord progressions into Harte syntax.

We offer three additional Python scripts: one for transposing chords into all tonalities (for data augmentation purposes), another for converting chords into their corresponding notes (e.g., A:7 → ['la','do#,'mi','sol']), and a third script that generates a binary 12-semitone list representation for each chord, commencing with the note C (e.g., C:maj7 → [1,0,0,0,1,0,0,1,0,0,0,1]) (all scripts are in convert_to_mappings.ipynb).

The full updated dataset (as of 12/3/2024) can be downloaded from here: https://huggingface.co/datasets/ailsntua/Chordonomicon

For a detailed description of the Chordonomicon Dataset, please see our paper on arXiv [https://doi.org/10.48550/arXiv.2410.22046]. If you use this dataset, kindly cite the paper to acknowledge the work.

Citation

@article{kantarelis2024chordonomicon, title={CHORDONOMICON: A Dataset of 666,000 Songs and their Chord Progressions}, author={Kantarelis, Spyridon and Thomas, Konstantinos and Lyberatos, Vassilis and Dervakos, Edmund and Stamou, Giorgos}, journal={arXiv preprint arXiv:2410.22046}, year={2024} }

Contributors

gliolits

11 commits

vaslyb

2 commits

notcarlybates

1 commits

Languages

Python

79.4%

Jupyter Notebook

20.6%