Skip to main content

Frechet Music Distance

License: MIT arXiv

Table of Contents

Introduction

A library for calculating Frechet Music Distance (FMD). This is an official implementation of the paper Frechet Music Distance: A Metric For Generative Symbolic Music Evaluation.

Features

  • Calculating FMD and FMD-Inf scores between two datasets for evaluation
  • Caching extracted features and distribution parameters to speedup subsequent computations
  • Support for various symbolic music representations (MIDI and ABC)
  • Support for various embedding models (CLaMP 2, CLaMP 1)
  • Support for various methods of estimating embedding distribution parameters (MLE, Leodit Wolf, Shrinkage, OAS, Bootstrap)
  • Computation of per-song FMD to find outliers in the dataset

Installation

The library can be installed from from PyPi using pip:

pip install frechet-music-distance

Note: If it doesn't work try updating pip:

pip install --upgrade pip

You can also install from source by cloning the repository and installing it locally:

git clone https://github.com/jryban/frechet-music-distance.git
cd frechet-music-distance
pip install -e .

The library was tested on Linux and MacOS, but it should work on Windows as well.

Note: If you encounter NotOpenSSLWarning please downgrade your urllib3 version to 1.26.6:

pip install urllib3==1.26.6

or use a different version of Python that supports OpenSSL, by following the instructions provided in this urllib3 GitHub issue

Usage

The library currently supports MIDI and ABC symbolic music representations.

Note: When using ABC Notation please ensure that each song is located in a separate file.

Command Line

fmd score [-h] [--model {clamp2,clamp}] [--estimator {mle,bootstrap,oas,shrinkage,leodit_wolf}] [--inf] [--steps STEPS] [--min_n MIN_N] [--clear-cache] [reference_dataset] [test_dataset]

Positional arguments:

  • reference_dataset: Path to the reference dataset
  • test_dataset: Path to the test dataset

Options:

  • --model {clamp2,clamp}, -m {clamp2,clamp} Embedding model name
  • --estimator {mle,bootstrap,oas,shrinkage,leodit_wolf}, -e {mle,bootstrap,oas,shrinkage,leodit_wolf} Gaussian estimator for mean and covariance
  • --inf Use FMD-Inf extrapolation
  • --steps STEPS, -s STEPS Number of steps when calculating FMD-Inf
  • --min_n MIN_N, -n MIN_N Mininum sample size when calculating FMD-Inf (Must be smaller than the size of the test dataset)
  • --clear-cache Clear the pre-computed cache before FMD calculation

Cleanup

Additionaly the pre-computed cache can be cleared by executing:

fmd clear

Python API

Initialization

You can initialize the metric like so:

from frechet_music_distance import FrechetMusicDistance

metric = FrechetMusicDistance(feature_extractor='<model_name>', gaussian_estimator='<esimator_name>', verbose=True)

Valid values for <model_name> are: clamp2 (default), clamp Valid values for <esimator_name> are: mle (default), bootstrap, shrinkage, leodit_wolf, oas

If you want more control over feature extraction models and gaussian estimators, you can instantiate the object outside and pass it to the constructor directly like so:

from frechet_music_distance import FrechetMusicDistance
from frechet_music_distance.gaussian_estimators import LeoditWolfEstimator, MaxLikelihoodEstimator, OASEstimator, BootstrappingEstimator, ShrinkageEstimator
from frechet_music_distance.models import CLaMP2Extractor, CLaMPExtractor

extractor = CLaMP2Extractor(verbose=True)
estimator = ShrinkageEstimator(shrinkage=0.1)
fmd = FrechetMusicDistance(feature_extractor=extractor, gaussian_estimator=estimator, verbose=True)

Standard FMD score

score = metric.score(
    reference_dataset="<reference_dataset_path>",
    test_dataset="<test_dataset_path>"
)

FMD-Inf score

result = metric.score_inf(
    reference_dataset="<reference_dataset_path>",
    test_dataset="<test_dataset_path>",
    steps=<num_steps> # default=25
    min_n=<minumum_sample_size> # default=500
)

result.score   # To get the FMD-Inf score
result.r2      # To get the R^2 of FMD-Inf linear regression
result.slope   # To get the slope of the regression
result.points  # To get the point estimates used in FMD-Inf regression

Individual (per-song) score

result = metric.score_individual(
    reference_dataset="<reference_dataset_path>",
    test_song_path="<test_song_path>",
)

Cleanup

Additionaly the pre-computed cache can be cleared like so:

from frechet_music_distance.utils import clear_cache

clear_cache()

Extending FMD

Embedding Model

You can add your own model as a feature extractor like so:

from frechet_music_distance.models import FeatureExtractor

class MyExtractor(FeatureExtractor):

    def __init__(self, verbose: bool = True) -> None:
        super().__init__(verbose)
        """<My implementation>"""
        

    @torch.no_grad()
    def _extract_feature(self, data: Any) -> NDArray:
        """<My implementation>"""


    def extract_features(self, dataset_path: str | Path) -> NDArray:
        """<My implementation of loading data>"""

        return super()._extract_features(data)


    def extract_feature(self, filepath: str | Path) -> NDArray:
        """<My implementation of loading data>"""

        return self._extract_feature(data)

If your model uses the same data format as CLaMP2 or CLaMP you can use frechet_music_distance.dataset_loaders.ABCLoader or frechet_music_distance.dataset_loaders.MIDIasMTFLoader for loading music data.

Gaussian Estimator

You can add your own estimator like so:

from .gaussian_estimator import GaussianEstimator
from .max_likelihood_estimator import MaxLikelihoodEstimator


class BootstrappingEstimator(GaussianEstimator):

    def __init__(self, num_samples: int = 1000) -> None:
        super().__init__()
        """<My implementation>"""

    def estimate_parameters(self, features: NDArray) -> tuple[NDArray, NDArray]:
        """<My implementation>"""

        return mean, cov

Supported Embedding Models

Model Name in library Description Creator
CLaMP clamp CLaMP: Contrastive Language-Music Pre-training for Cross-Modal Symbolic Music Information Retrieval Microsoft Muzic
CLaMP2 clamp2 CLaMP 2: Multimodal Music Information Retrieval Across 101 Languages Using Large Language Models sanderwood

Citation

If you use Frecheet Music Distance in your research, please cite the following paper:

@article{retkowski2024frechet,
  title={Frechet Music Distance: A Metric For Generative Symbolic Music Evaluation},
  author={Retkowski, Jan and St{\k{e}}pniak, Jakub and Modrzejewski, Mateusz},
  journal={arXiv preprint arXiv:2412.07948},
  year={2024}
}

Acknowledgements

This library uses code from the following repositories for handling the embedding models:

License

This project is licensed under the MIT License. See the LICENSE file for details.


Metadata

Release files for frechet-music-distance 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for frechet-music-distance 1.0.0
File Size Uploaded
frechet_music_distance-1.0.0.tar.gz 24.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for frechet-music-distance 1.0.0
File Interpreter ABI Platform
frechet_music_distance-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 57.2 kB

Release files / frechet_music_distance-1.0.0.tar.gz

Download URL frechet_music_distance-1.0.0.tar.gz
Size 24.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a757fbc672dc47c34904778dbe2e8529ed8eb3efdb7bb7c093be1c4ceea0f89b
BLAKE2b-256 checksum
How to use checksums
f44b187e9729c2d3c9e41726edcd55671a0d355ea726a98f52572de6358621f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.3

Release files / frechet_music_distance-1.0.0-py3-none-any.whl

Download URL frechet_music_distance-1.0.0-py3-none-any.whl
Size 32.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
43c3538462a919b1fc8f408db4e59a83dbfe3cd338e8b482bb1b3b9fa0edaf48
BLAKE2b-256 checksum
How to use checksums
3fc70fa984c73d0de140c0f69fe00cfcb4b73073914c2ce073c1e38084937d2e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page