TobiasLogic commited on
Commit
e0fb310
·
verified ·
1 Parent(s): a3994c1

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +198 -0
README.md ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ pipeline_tag: text-to-audio
4
+ language:
5
+ - en
6
+ tags:
7
+ - audio
8
+ - text-to-audio
9
+ - diffusion
10
+ - rectified-flow
11
+ - spectrogram
12
+ - clap
13
+ - custom-code
14
+ - tiny
15
+ ---
16
+
17
+ # AudioModel v1 🔊
18
+
19
+ <p>
20
+ <audio controls src="samples/rain_falling_on_a_roof.wav"></audio> "rain falling on a roof"
21
+ </p>
22
+ <p>
23
+ <audio controls src="samples/footsteps_on_gravel.wav"></audio> "footsteps on gravel"
24
+ </p>
25
+ <p>
26
+ <audio controls src="samples/a_dog_barking.wav"></audio> "a dog barking"
27
+ </p>
28
+ <p>
29
+ <audio controls src="samples/a_car_engine_starting.wav"></audio> "a car engine starting"
30
+ </p>
31
+
32
+ A tiny text-to-audio diffusion model. You give it a sentence, it gives you 17.8
33
+ seconds of sound. It is 40,296,844 trained parameters and it trained in under four
34
+ hours on a single H100.
35
+
36
+ This is the PixelModel line moving into a third modality. v1 through v6 were tiny
37
+ latent diffusion for images, VoxelModel did 3D occupancy grids, and this one treats
38
+ a mel spectrogram as a grayscale image and runs the same DiT plus rectified flow
39
+ recipe on it. Same argument every time: low resolution as a deliberate aesthetic,
40
+ applied to a new kind of output.
41
+
42
+ ## Why this combination didn't already exist
43
+
44
+ Riffusion proved that treating a spectrogram as an image and running image
45
+ diffusion on it works, including inverting it back to audio. But Riffusion is a
46
+ fine-tune of Stable Diffusion v1.5, not trained from scratch, and not tiny.
47
+ tiny-audio-diffusion is from scratch and genuinely small, but it diffuses raw
48
+ waveforms, not spectrograms, and isn't built for free-text conditioning.
49
+ AudioLDM and Make-An-Audio are the real text-to-audio research lineage, but both
50
+ are full-scale systems with a VAE-compressed latent space and a separately trained
51
+ vocoder, not something you train from scratch on a rented GPU in an afternoon.
52
+
53
+ Nothing combined from-scratch, hobbyist scale, spectrogram-as-image, rectified
54
+ flow, and free-text CLAP conditioning in one place. That's the gap this fills.
55
+
56
+ ## The one honest result
57
+
58
+ FAD (Frechet Audio Distance, PANN embeddings) on 300 held-out Clotho evaluation
59
+ clips, comparing three things against real audio:
60
+
61
+ ![FAD comparison](audiomodel-v1-fad.png)
62
+
63
+ Text conditioning clearly helps: 67.0 with a real prompt against 87.1 with no
64
+ prompt at all. And the model is not that far from the ceiling a Griffin-Lim
65
+ vocoder allows in the first place: taking real audio, converting it to our exact
66
+ mel spectrogram, and inverting it right back with Griffin-Lim already costs 60.5
67
+ FAD against the original file, before the model has generated anything. Most of
68
+ the remaining distance between the model and real audio is the vocoder, not the
69
+ model.
70
+
71
+ Worth knowing if you use this number: PANN embeddings are 2048-dimensional and our
72
+ full held-out evaluation split is only 1,045 clips, so the covariance estimate
73
+ behind FAD is structurally rank-deficient here. Scipy warns about it
74
+ (`LinAlgWarning: Matrix is singular`) and it would still warn even using every
75
+ single held-out clip we have, since 1,045 is still under 2,048. The relative
76
+ ordering of the three numbers is the trustworthy part, not their precision to one
77
+ decimal place.
78
+
79
+ We also found a real bug while computing this: the `frechet_audio_distance`
80
+ library's PANN path concatenates each clip's flat 2048-length embedding with
81
+ `np.concatenate` instead of stacking them, which silently collapses 300 separate
82
+ embeddings into one 614,400-length vector and breaks the statistics downstream.
83
+ Their own README admits PANN isn't covered by CI. `eval_fad.py` reshapes the
84
+ embeddings back to `(n, 2048)` before computing FAD, which is the whole fix.
85
+
86
+ ## Training
87
+
88
+ ![training loss](audiomodel-v1-loss.png)
89
+
90
+ | | |
91
+ |---|---|
92
+ | clips | 3,839 train (development split), 1,045 held out (validation split) |
93
+ | pairs | 19,195, since each clip carries 5 independent captions |
94
+ | steps | 90,000 at batch 256 |
95
+ | hardware | one H100 SXM 80GB, 6.51 steps/s, 28.3 GiB |
96
+ | wall clock | 3.85 hours |
97
+ | optimizer | AdamW 2e-4, betas (0.9, 0.99), grad clip 1.0 |
98
+ | schedule | cosine to 1e-6, 500 step warmup |
99
+ | EMA | 0.9999 |
100
+ | CFG dropout | 10% |
101
+
102
+ Held-out loss bottomed at **0.06961 at step 54,000** and drifted up to 0.07078 by
103
+ step 90,000. That's a real overfitting inflection, and it arrives earlier than it
104
+ did on VoxelModel (step 64,000 of 90,000 there), which makes sense: Clotho's
105
+ development split has 3,839 unique clips against VoxelModel's 28,415 unique
106
+ meshes, so the same step budget means a lot more repetition per unique example
107
+ here. The shipped weights are the step 54,000 EMA checkpoint, not the step 90,000
108
+ final one, because this run saves the best validation checkpoint separately as it
109
+ trains. VoxelModel v1 didn't do this and lost its own best checkpoint to an
110
+ overwrite bug. That was worth fixing before this run, not after.
111
+
112
+ ## No VAE, but not zero baggage either
113
+
114
+ AudioModel diffuses directly on the mel spectrogram image. There's no autoencoder
115
+ compressing it first, which is the same "no asterisk" choice VoxelModel made for
116
+ voxels instead of copying AudioLDM's VAE step. Total trained footprint is 40.30M.
117
+
118
+ Conditioning is frozen CLAP (`laion/clap-htsat-unfused`), cross-attention on the
119
+ RoBERTa text tower's last hidden state (768 dim, 32 tokens) plus adaLN-zero from
120
+ the projected pooled embedding (512 dim). Loading `ClapModel` pulls in the whole
121
+ 153.49M-parameter checkpoint, audio tower included, but only the text tower and
122
+ projection, 125.30M of it, ever runs a forward pass here. The HTSAT audio encoder
123
+ just sits there unused. If you're adapting this code, swapping in a text-only CLAP
124
+ checkpoint would trim that dead weight; we didn't bother for a single training run.
125
+
126
+ ## Architecture
127
+
128
+ `AudioDiT` patchifies a 384x256 mel spectrogram at patch size 16, giving a 24x16
129
+ grid, 384 tokens, dim 384, depth 12, heads 6. Positional encoding is a 2D sincos
130
+ over that grid. Objective is rectified flow with `target = x1 - x0` and
131
+ logit-normal timestep sampling, `t = sigmoid(randn)`, identical to VoxelModel's
132
+ objective on a different kind of image.
133
+
134
+ ## Data
135
+
136
+ Clotho v2.1 (Drossos, Lipping and Virtanen, DCASE 2020), from Zenodo, not from an
137
+ HF mirror since none of the official kind exists. Development split for training,
138
+ validation split for the held-out loss during training, evaluation split reserved
139
+ untouched for the FAD numbers above. Each clip carries 5 independent crowdsourced
140
+ captions, and all 5 get used as separate training pairs against the same
141
+ spectrogram rather than picking one, which is a free 5x on the text side without
142
+ touching the audio side.
143
+
144
+ Spectrograms come from `diffusers.pipelines.deprecated.audio_diffusion.mel.Mel`
145
+ at `x_res=384, hop_length=1024`, both bumped from the library's defaults
146
+ (`x_res=256, hop_length=512`) to cover 17.8 seconds instead of 5.9. `y_res=256`
147
+ mel bins is the library default, left alone. The `Mel` class already pads short
148
+ clips with silence and only reads the first slice of longer ones, so every clip
149
+ in the 15 to 30 second Clotho range ends up as a fixed 17.8 second window starting
150
+ at the beginning of the clip, no custom windowing logic needed.
151
+
152
+ Griffin-Lim, 32 iterations, is the inversion back to audio. It's the zero-training
153
+ default and it's known to sound phasey and metallic compared to a learned vocoder
154
+ like BigVGAN-v2. We didn't swap one in for v1: the FAD numbers above suggest the
155
+ vocoder actually is the dominant source of remaining distance from real audio, so
156
+ that's the correct place to spend effort on a v2, not on the diffusion model
157
+ itself.
158
+
159
+ ## Usage
160
+
161
+ ```bash
162
+ python sample.py "a dog barking" "rain falling on a roof" --cfg 4.0 --steps 50
163
+ ```
164
+
165
+ Writes 17.8 second WAVs at 22,050 Hz to `--out-dir`.
166
+
167
+ ## What v1 does not do
168
+
169
+ **A learned vocoder.** Griffin-Lim is what's shipped. The FAD breakdown above is
170
+ the argument for why that's a defensible v1 choice and not just laziness.
171
+
172
+ **More than 300 clips of FAD signal.** The evaluation split only has 1,045 clips
173
+ total and PANN embeddings are 2048-dimensional, so the covariance estimate behind
174
+ every FAD number in this card is on the edge of what's estimable at all. Treat the
175
+ ordering as real and the decimal places as decoration.
176
+
177
+ **Augmentation.** 90,000 steps over 3,839 unique clips is a lot of repetition with
178
+ nothing to break it up. Time-shift or pitch-shift augmentation on the waveform
179
+ before spectrogram conversion is the obvious next lever, same shape of fix as the
180
+ yaw-and-mirror augmentation flagged as unbuilt on VoxelModel v1.
181
+
182
+ ## Files
183
+
184
+ | file | what |
185
+ |---|---|
186
+ | `model.safetensors` | EMA weights at step 90,000 |
187
+ | `model_best.safetensors` | EMA weights at step 54,000, the shipped checkpoint |
188
+ | `audio_dit.py` | the model |
189
+ | `train.py` | training loop |
190
+ | `sample.py` | inference |
191
+ | `eval_fad.py` | FAD evaluation against held-out real audio |
192
+ | `fetch_clotho.py` | Zenodo download and extraction |
193
+ | `build_data.py` | mel spectrogram and CLAP embedding precompute |
194
+ | `benchmark_throughput.py` | the throughput check this run's batch size came from |
195
+ | `config.json` | architecture and training config |
196
+ | `fad_results.json` | the raw numbers behind the FAD chart |
197
+ | `requirements.txt` | what you need installed to run any of the above |
198
+ | `samples/` | the four clips embedded at the top of this card |