Saxophone highlight
A soulful saxophone excerpt backed drums.
Welcome to ML Jazz! Over the past couple of years, I've been exploring ways in how machines can generate music. The journey ended up exploring autoregressive generation with transformers, diffusion models from bare bones, and adapting a pretrained diffusion model with LoRA.
Current approach
One of the key realizations that led to LoRA fine tuning was that training a diffusion model from scratch required an enormous scale of data.
I had originally expected large amounts of data would be needed, but I was willing to sacrifice some quality for less data. It turns out, before a certain threshold, the audio will simply sound like noise before you start to discern music (see below).
To get coherent music when training from scratch, one would need 100s of GB to TBs of audio data in order to turn random noise into somewhat pleasant music.
This was impractical for myself to implement and unnecessary - thinking cost wise, the amount of compute resources I had and the data I could effectively process.
On the other hand, using Low-Rank Adaptation (LoRA) fine tuning, only 3 GB to 6 GB is needed (this is about 10-20 hours of audio) to turn a general text-to-audio diffusion model to a model capable of generating jazz style music.
In essence, an adapter is attached to the output of the pretrained model, with pretrained model weights frozen, and only the adapter weights trainable.
The number of weights in the adapter is greatly smaller than the pretrained model (at only about 1-3% of the total weights).
This keeps the heavy lifting of what music sounds like handled by the pretrained model unaltered (things like pitch, instrument sounds, timbre), and having the adapter fine tuning focus only on capturing the style of jazz (swing feel, brushed drums, bending of notes on sax).
Although, LoRA fine tuning does not generally cover all the weights that full fine tuning achieves, the original LoRA paper research (Hu et al., 2021) shows that useful adaptations appear to have low dimensional structural changes than the total parameters in the original model.
Note that the data for training was hand selected to be around 10 hours of audio, all which resembled similar structures in style, phrasing, instrument sounds for training consistency.
Data cleansing was performed to pick out oddities that might cause the model to diverge.
A soulful saxophone excerpt backed drums.
A piano generation with a swing feel that transitions into straight time.
A saxophone sample with a swing-oriented prompt.
A slower, more spacious saxophone generation.
A blues-oriented saxophone generation.
A piano-focused generation.
Turn the source recordings into consistent clips, split them into training and holdout sets, and pair them with useful text captions.
Encode the training audio once with the pretrained variational autoencoder so training does not repeat this expensive step.
Optimize only the LoRA attention weights while keeping the pretrained AudioLDM2 model frozen.
Load an adapter checkpoint and synthesize music from jazz-focused text prompts.
Compare matched base and adapted generations through listening and measures such as Fréchet Audio Distance.
One of the major challenges in fine tuning was getting the scale of the data right, as well as picking out a quality dataset to train on. As I noticed, and also mentioned in the scaling laws paper (Kaplan et al., 2020), the number of trainable model parameters must scale proportionally with dataset size, or else there will be diminishing returns. In this project, when I tried fine tuning with a small dataset (even when the style was more similar), the quality of music at the best checkpoint before overfitting was less than what I achieved with a decently sized dataset (10 hours of audio, about 7 GB).
This relationship can be expressed by holding the ratio \(N^{0.74}/D\) approximately constant.
This project uses AudioLDM2 (Liu et al., 2024), a pretrained latent diffusion model designed for text-conditioned audio generation. It provides a strong general musical prior, which means the experiment can focus on adapting style and instrumentation rather than learning audio generation from scratch. LoRA adapters are attached to the attention layers of the diffusion network while the larger pretrained pipeline remains frozen.
This original AudioLDM2 sample was used as the baseline for comparison. The fine-tuned model produced a significant improvement.
A LoRA rank of 16 was selected as a practical balance: it offers enough capacity to learn the timbre and phrasing of the jazz dataset while keeping the adapter compact, reducing memory use, and limiting the tendency to overfit a comparatively focused collection of recordings.
The learning rate is tapered near the end of training. Early updates can make broader stylistic changes; the smaller late-stage updates help refine the adapter without abruptly disturbing musical structure that has already been learned. The final taper is also a useful safeguard against audible degradation or overfitting late in the run.
Learning from first principles
This trial explores learning diffusion (Ho et al., 2020) by injecting random noise into an original audio sample.
All diffusion training and ML architecture was written from the ground up in PyTorch.
gen_orig_4.wav is the original audio sample.
gen_4.wav is the sample with random noise injected while the model is in the process of learning diffusion.
DDPM defines a fixed forward process that gradually adds Gaussian noise, then learns a reverse process that removes that noise one step at a time (Ho et al., 2020). Here, x0 is the clean sample, xt is its noisy state at step t, and βt controls how much noise is added at that step.
Each step keeps most of the previous signal and adds a small amount of fresh Gaussian noise. After many steps, the original structure is replaced by something close to pure noise.
With αt = 1−βt and ᾱt equal to the product of all α values through step t, a noisy training example can be created at any chosen step without simulating every earlier step.
The model predicts the noise component εθ(xt, t), scales it according to the noise schedule, and subtracts it from xt. The σtz term adds the variance required for reverse diffusion, where z ~ 𝒩(0, I) for intermediate steps and z = 0 for the final step. Repeating this update produces xt−1, then xt−2, until the generated sample reaches x0.
First, separate the known noise from the model's predicted noise to form the residual:
Then calculate the expected squared size of that residual:
The expectation averages the loss over randomly selected timesteps, clean samples, and Gaussian noise. Training minimizes this prediction error; the actual removal of predicted noise from xt happens in the reverse-process update above.
Earlier and new experiments
The original idea was that music, specifically jazz, can be treated as a language, and if we could tokenize it, then like LLMs, we can perform next-token prediction to generate intelligent pieces of creation. Fortunately, there does exist a mechanism, audio to MIDI, that produces discrete pitches from wav audio, and through encoding the MIDI, I was able to train a autoregressive transformer to accomplish this task.
(The generated melody starts at 0:27)
Note that this was the very first initial experiement tinkering in trying to generate jazz music with ML models.
The result was with piano instrumentation was decent, however it was constrained to particular timbres enforced by MIDI (whereas diffusion on raw audio was more permissive).
Some samples to listen to below:
Notes & Notable Timestamps:
Notes & Notable Timestamps:
Notes & Notable Timestamps:
Ho, J., Jain, A., & Abbeel, P. (2020). Denoising Diffusion Probabilistic Models.
Hu et al. (2021). LoRA: Low-Rank Adaptation of Large Language Models.
Kaplan et al. (2020). Scaling Laws for Neural Language Models.
Liu et al. (2024). AudioLDM 2: Learning Holistic Audio Generation with Self-supervised Pretraining.