kechenadobe commited on
Commit
480718e
·
verified ·
1 Parent(s): 7e7b8dd

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +235 -1
README.md CHANGED
@@ -1,3 +1,237 @@
1
  ---
2
  license: other
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: other
3
+ ---
4
+
5
+ # OpenFLAM
6
+ <p align="center">
7
+ <img src="https://raw.githubusercontent.com/adobe-research/openflam/main/assets/FLAM_SLOGAN.png" alt="Framewise Language-Audio Modeling" width="75%"/>
8
+ </p>
9
+ <p align="center">
10
+ <a href="https://arxiv.org/abs/2505.05335"><img src="https://img.shields.io/badge/arXiv-2505.05335-brightgreen.svg?logo=arxiv&logoColor=red"/></a>
11
+ <a href="https://pypi.org/project/openflam"><img src="https://badge.fury.io/py/openflam.svg?icon=si%3Apython&icon_color=%232add51"/></a>
12
+ <a href="./LICENSE"><img alt="Static Badge" src="https://img.shields.io/badge/License-Adobe_Research-yellow?logo=bookstack&logoColor=yellow"></a>
13
+ <a href="https://flam-model.github.io/"><img alt="Static Badge" src="https://img.shields.io/badge/FLAM%20Website-8A2BE2?logo=wolfram"></a>
14
+ </p>
15
+
16
+ ### Joint Audio and Text Embeddings via Framewise Language-Audio Modeling (FLAM)
17
+
18
+ FLAM is a cutting-edge language–audio model that supports both zero-shot sound even detection and large-scale audio retrieval via free-form text.
19
+
20
+ This code accompanies the following ICML 2025 publication:
21
+ ```
22
+ @inproceedings{flam2025,
23
+ title={{FLAM}: Frame-Wise Language-Audio Modeling},
24
+ author={Yusong Wu and Christos Tsirigotis and Ke Chen and Cheng-Zhi Anna Huang and Aaron Courville and Oriol Nieto and Prem Seetharaman and Justin Salamon},
25
+ booktitle={Forty-second International Conference on Machine Learning (ICML)},
26
+ year={2025},
27
+ url={https://openreview.net/forum?id=7fQohcFrxG}
28
+ }
29
+ ```
30
+
31
+ ## Architecture
32
+
33
+ FLAM is based on contrastive language-audio pretraining, known as CLAP, and improve its capability by supporting the frame-wise event localization via learnable text and audio biases and scales.
34
+ <p align="center">
35
+ <img src="https://raw.githubusercontent.com/adobe-research/openflam/main/assets/FLAM_ARCH.png" alt="FLAM Architecture" width="100%"/>
36
+ </p>
37
+
38
+ ## Quick Start
39
+
40
+ Install FLAM via PyPi:
41
+
42
+ ```bash
43
+ pip install openflam
44
+ ```
45
+
46
+ Two examples are provided:
47
+
48
+ 1. [global_example.py](./test/global_example.py): to obtain audio and text embeddings and do clip-wise similarity.
49
+ 2. [local_example.py](./test/local_example.py) to do sound event localization and plot the results.
50
+
51
+ For the API documentation, please refer to [hook.py](./src/openflam/hook.py).
52
+
53
+
54
+ ### Global Example: To obtain clip-wise similarity between audio and text embeddings
55
+
56
+ Please refer to [global_example.py](./test/global_example.py):
57
+
58
+ ```python
59
+ import librosa
60
+ import torch
61
+
62
+ import openflam
63
+
64
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
65
+ SR = 48000 # Sampling Rate (FLAM requires 48kHz)
66
+
67
+ flam = openflam.OpenFLAM(model_name="v1-base", default_ckpt_path="/tmp/openflam").to(
68
+ DEVICE
69
+ )
70
+
71
+ # Sanity Check (Optional)
72
+ flam.sanity_check()
73
+
74
+ # load audio
75
+ audio, sr = librosa.load("test/test_data/test_example.wav", sr=SR)
76
+ audio = audio[: int(10 * sr)]
77
+ audio_samples = torch.tensor(audio).unsqueeze(0).to(DEVICE) # [B, 480000 = 10 sec]
78
+
79
+ # Define text
80
+ text_samples = [
81
+ "breaking bones",
82
+ "metallic creak",
83
+ "tennis ball",
84
+ "troll scream",
85
+ "female speaker",
86
+ ]
87
+
88
+ # Get Global Audio Features (10sec = 0.1Hz embeddings)
89
+ audio_global_feature = flam.get_global_audio_features(audio_samples) # [B, 512]
90
+
91
+ # Get Text Features
92
+ text_feature = flam.get_text_features(text_samples) # [B, 512]
93
+
94
+ # Calculate similarity (dot product)
95
+ global_similarities = (text_feature @ audio_global_feature.T).squeeze(1)
96
+
97
+ print("\nGlobal Cosine Similarities:")
98
+ for text, score in zip(text_samples, global_similarities):
99
+ print(f"{text}: {score.item():.4f}")
100
+ ```
101
+
102
+ ### Local Example: To perform sound event localization and plot the diagram
103
+
104
+ Please refer to [local_example.py](./test/local_example.py).
105
+
106
+ The following plot will be generated by running the code below:
107
+
108
+ <p align="center">
109
+ <img src="https://raw.githubusercontent.com/adobe-research/openflam/main/assets/sed_heatmap.png" alt="FLAM Architecture" width="100%"/>
110
+ </p>
111
+
112
+
113
+ ```python
114
+ from pathlib import Path
115
+
116
+ import librosa
117
+ import numpy as np
118
+ import scipy
119
+ import torch
120
+
121
+ import openflam
122
+ from openflam.module.plot_utils import plot_sed_heatmap
123
+
124
+ # Configuration
125
+ OUTPUT_DIR = Path("sed_output") # Directory to save output figures
126
+
127
+ # Define target sound events
128
+ TEXTS = [
129
+ "breaking bones",
130
+ "metallic creak",
131
+ "tennis ball",
132
+ "troll scream",
133
+ "female speaker",
134
+ ]
135
+
136
+ # Define negative class (sounds that shouldn't be in the audio)
137
+ NEGATIVE_CLASS = [
138
+ "female speaker"
139
+ ]
140
+
141
+ SR = 48000
142
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
143
+
144
+ flam = openflam.OpenFLAM(model_name="v1-base", default_ckpt_path="/tmp/openflam")
145
+ flam.to(DEVICE)
146
+
147
+ # Load and prepare audio
148
+ audio, sr = librosa.load("test/test_data/test_example.wav", sr=SR)
149
+ audio = audio[: int(10 * sr)]
150
+
151
+ # Convert to tensor and move to device
152
+ audio_tensor = torch.tensor(audio).unsqueeze(0).to(DEVICE)
153
+
154
+ # Run inference
155
+ with torch.no_grad():
156
+ # Get local similarity using the wrapper's built-in method
157
+ # This uses the unbiased method (Eq. 9 in the paper)
158
+ act_map_cross = (
159
+ flam.get_local_similarity(
160
+ audio_tensor,
161
+ TEXTS,
162
+ method="unbiased",
163
+ cross_product=True,
164
+ )
165
+ .cpu()
166
+ .numpy()
167
+ )
168
+
169
+ # Apply median filtering for smoother results
170
+ act_map_filter = []
171
+ for i in range(act_map_cross.shape[0]):
172
+ act_map_filter.append(scipy.ndimage.median_filter(act_map_cross[i], (1, 3)))
173
+ act_map_filter = np.array(act_map_filter)
174
+
175
+ # Prepare similarity dictionary for plotting
176
+ similarity = {f"{TEXTS[i]}": act_map_filter[0][i] for i in range(len(TEXTS))}
177
+
178
+ # Prepare audio for plotting (resample to 32kHz)
179
+ target_sr = 32000
180
+ audio_plot = librosa.resample(audio, orig_sr=SR, target_sr=target_sr)
181
+
182
+ # Create output directory if it doesn't exist
183
+ OUTPUT_DIR.mkdir(exist_ok=True)
184
+
185
+ # Generate and save visualization
186
+ output_path = OUTPUT_DIR / "sed_heatmap.png"
187
+ plot_sed_heatmap(
188
+ audio_plot,
189
+ target_sr,
190
+ post_similarity=similarity,
191
+ duration=10.0,
192
+ negative_class=NEGATIVE_CLASS,
193
+ figsize=(14, 8),
194
+ save_path=output_path,
195
+ )
196
+
197
+ print(f"Plot saved: {output_path}")
198
+ ```
199
+
200
+ ## License
201
+
202
+ Both **code** and **models** for OpenFLAM are released under a non-commercial [Adobe Research License](./LICENSE). Please, review it carefully before using this technology.
203
+
204
+ ## Pretrained Models
205
+
206
+ The pretrained checkpoints can be found [here](https://huggingface.co/kechenadobe/OpenFLAM/blob/main/open_flam_oct17.pth).
207
+
208
+ OpenFLAM automatically handles the downloading of the checkpoint. Please, refer to the previous section for more details.
209
+
210
+ ## Datasets
211
+
212
+ The original experimental results reported in [our paper](https://arxiv.org/abs/2505.05335) were obtained by the model trained on internal datasets that are not publicly shareable.
213
+
214
+ OpenFLAM is trained **on all publicly available datasets**, including:
215
+
216
+ 1. Datasets with coarse (aka, global or weak) labels: AudioSet-ACD (a LLM-based captioning for AudioSet), FreeSound, WavCaps, AudioCaps, Clotho;
217
+ 2. Datasets with fine-grained (aka, local or strong) labels: AudioSet Strong, UrbanSED, DESED, Maestro, and Simulation data from AudioSet-ACD & FreeSound.
218
+
219
+ We report a comparison of the OpenFLAM performance to the original paper report (the global retrieval metrics --ie, A2T and T2A-- are R@1 / R@5):
220
+ <p align="center">
221
+ <img src="https://raw.githubusercontent.com/adobe-research/openflam/main/assets/Exp.png" alt="FLAM Exp" width="100%"/>
222
+ </p>
223
+
224
+
225
+ ## Citation
226
+
227
+ If you use OpenFLAM, please cite our main work:
228
+
229
+ ```
230
+ @inproceedings{flam2025,
231
+ title={{FLAM}: Frame-Wise Language-Audio Modeling},
232
+ author={Yusong Wu and Christos Tsirigotis and Ke Chen and Cheng-Zhi Anna Huang and Aaron Courville and Oriol Nieto and Prem Seetharaman and Justin Salamon},
233
+ booktitle={Forty-second International Conference on Machine Learning (ICML)},
234
+ year={2025},
235
+ url={https://openreview.net/forum?id=7fQohcFrxG}
236
+ }
237
+ ```