--- license: cc-by-nc-4.0 library_name: mule-torch tags: - audio - music - music-information-retrieval - embeddings - representation-learning - feature-extraction - pytorch - onnx - nfnet pipeline_tag: feature-extraction --- # MULE (PyTorch) — `matteospanio/mule` Pretrained weights for an **unofficial PyTorch port** of **MULE** (Musicset Unsupervised Large Embedding), the SF-NFNet-F0 music-audio representation model from SiriusXM/Pandora: > *Supervised and Unsupervised Learning of Audio Representations for Music > Understanding*, M. C. McCallum, F. Korzeniowski, S. Oramas, F. Gouyon, > A. F. Ehmann. ISMIR 2022. These weights were **converted, not re-trained** — transferred from the original TensorFlow/Keras `model.keras` into the PyTorch implementation and verified to be numerically equivalent (end-to-end clip-embedding cosine **0.9999999** vs the original pipeline; ONNX backbone max-abs `< 1e-6`; 62.35 M params). Library / code: **** > ⚠️ **Unofficial.** This is an independent community port from TensorFlow to > PyTorch. It is **not affiliated with, endorsed by, or maintained by** SiriusXM, > Pandora, or the original authors. All credit for the model goes to them. ## Files | File | What | |---|---| | `model.safetensors` | Full model state dict (SF-NFNet-F0 backbone + mel filterbank buffer), ~267 MB. | | `config.json` | Architecture + frontend + slicing constants (rebuilds `MuleConfig`). | | `backbone.onnx` | Self-contained ONNX export of the backbone (`(N,1,96,300)` log-mel slice → `(N,1728)`), opset 17, dynamic batch. ~252 MB. | ## Usage ```bash pip install mule-torch # or: pip install git+https://github.com/matteospanio/mule-torch ``` ```python import torch from mule_torch import MuleModel # Downloads these weights from the Hub by default. model = MuleModel.from_pretrained() # == from_pretrained(hf_repo="matteospanio/mule") waveform = torch.randn(1, 16000 * 10) # (B, T) mono @ 16 kHz, in [-1, 1] emb = model(waveform) # (B, 1728) ``` ### ONNX (backbone only) The full waveform→embedding path includes a data-dependent number of 2-second slices, so the ONNX export covers the **backbone** (one standardized 96×300 log-mel slice → 1728-d). Do the mel front-end + slicing in torch/host, then run slices through `backbone.onnx`: ```python import onnxruntime as ort, numpy as np sess = ort.InferenceSession("backbone.onnx", providers=["CPUExecutionProvider"]) emb = sess.run(None, {"mel_slice": slices.astype(np.float32)})[0] # (N, 1728) ``` ## Input convention 16 kHz mono waveform in `[-1, 1]`. The model computes a 96-band log-mel spectrogram, slices it into 96×300 windows every ~2 s, runs the backbone, and mean-pools the per-slice 1728-d embeddings into one vector per clip. > The original `AudioFile` reader scales PCM16 by `1/2^16`; conventional `[-1,1]` > audio tracks the original closely but isn't bit-identical (the > `log10(10000·x+1)` mel compression is non-linear). ## License These weights are a derivative of the original MULE weights, released by Pandora/SiriusXM under **CC BY-NC 4.0**, and inherit that **non-commercial** license. The `mule-torch` source code is GPL-3.0-only. Please cite McCallum et al. (2022). ```bibtex @inproceedings{mccallum2022mule, title = {Supervised and Unsupervised Learning of Audio Representations for Music Understanding}, author = {McCallum, Matthew C. and Korzeniowski, Filip and Oramas, Sergio and Gouyon, Fabien and Ehmann, Andreas F.}, booktitle = {Proceedings of the 23rd International Society for Music Information Retrieval Conference (ISMIR)}, year = {2022}, url = {https://arxiv.org/abs/2210.03799} } ```