Spaces:
Sleeping
Sleeping
janwinkler1
commited on
Commit
•
7235148
1
Parent(s):
40fa82b
eda jan, second push, adapted to wav files (#2)
Browse files- README.md +19 -11
- docs/docker-setup.md +8 -2
- docs/huggingface-spaces.md +7 -1
- format +7 -0
- python/eda_jan.py +148 -62
- python/requirements.txt +2 -0
README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
# Source of truth
|
2 |
|
3 |
## welcome and initial setup
|
4 |
-
|
|
|
5 |
i think when we start with the EDA, it suffices if anyone just uses what they are used to (f.e. conda or whatever). However, afterwards, i think it could be helpful that everyone, always has exactly the same environment, same package/python versions, which is why i propose working with docker to minimize headaches and "but it works on my machine" issues. I think with this minimal setup below, we can fully focus on hacking while not having pain with painful stuff.
|
6 |
|
7 |
please feel free to add / change / challenge things!
|
@@ -11,35 +12,39 @@ please feel free to add / change / challenge things!
|
|
11 |
- read how to setup docker for mac [here](https://docs.docker.com/desktop/install/mac-install/)
|
12 |
|
13 |
### how docker compose works
|
14 |
-
|
|
|
15 |
|
16 |
1. navigate to dc/dev and run:
|
17 |
|
18 |
```
|
19 |
-
docker compose up -d --build
|
20 |
```
|
21 |
|
22 |
only use the `--build` flag the first time around, or if you want to rebuild the container (e.g. when having added a package you need in the container). **NOTE:** the `-d` flag stands for `detach` which means that your docker container runs in the background and does not log everything into your console.
|
23 |
|
24 |
-
2. then, to check whether everything worked hit:
|
25 |
|
26 |
```
|
27 |
docker ps
|
28 |
```
|
29 |
|
30 |
-
3. for this specific setup, you can head to `localhost:8888` where jupyterlab is running.
|
31 |
|
32 |
-
4. to create a new file (using jupytext, see below), just create a new .ipynb file, the .py file will be created automatically. all the changes you make in the notebook, will be reflected in the .py files which you then can use for your commits.
|
33 |
|
34 |
-
now you shoold see the running docker containers.
|
|
|
|
|
35 |
|
36 |
-
### what about huggingface spaces:
|
37 |
- [here](./docs/huggingface-spaces.md), you can see what huggingface spaces is and how we can complement our github repo with it (credits to chat-gpt)
|
38 |
|
39 |
### jupytext - nice versioning of jupyter notebooks
|
|
|
40 |
since we are likely be working with jupyter notebooks alot, lets use jupytext. It automatically maps .ipynb to .py files with some magic. The .ipynb are in the gitignore, so we only have .py files nicely versioned in the repo. read more about it [here](https://jupytext.readthedocs.io/en/latest/)
|
41 |
|
42 |
### trunk based development
|
|
|
43 |
lets stick to trunk based. if you dont know what it is, read all about it [here](https://trunkbaseddevelopment.com/)
|
44 |
|
45 |
key take aways:
|
@@ -49,7 +54,7 @@ key take aways:
|
|
49 |
1. **Single Main Branch**: All developers commit to the trunk or main branch.
|
50 |
2. **Short-Lived Branches**: Branches, if used, are short-lived and quickly merged back.
|
51 |
3. **Frequent Integrations**: Code changes are integrated frequently, often multiple times a day.
|
52 |
-
4.
|
53 |
|
54 |
#### Benefits
|
55 |
|
@@ -70,6 +75,9 @@ key take aways:
|
|
70 |
- **Feature Flags**: Manage incomplete or experimental features.
|
71 |
- **Code Reviews**: Maintain quality and knowledge sharing.
|
72 |
|
|
|
73 |
|
74 |
-
|
75 |
-
|
|
|
|
|
|
1 |
# Source of truth
|
2 |
|
3 |
## welcome and initial setup
|
4 |
+
|
5 |
+
hi all,
|
6 |
i think when we start with the EDA, it suffices if anyone just uses what they are used to (f.e. conda or whatever). However, afterwards, i think it could be helpful that everyone, always has exactly the same environment, same package/python versions, which is why i propose working with docker to minimize headaches and "but it works on my machine" issues. I think with this minimal setup below, we can fully focus on hacking while not having pain with painful stuff.
|
7 |
|
8 |
please feel free to add / change / challenge things!
|
|
|
12 |
- read how to setup docker for mac [here](https://docs.docker.com/desktop/install/mac-install/)
|
13 |
|
14 |
### how docker compose works
|
15 |
+
|
16 |
+
essentially, you just have to build the container with the services you want. if you're interested in it i can go into more detail just let me know.
|
17 |
|
18 |
1. navigate to dc/dev and run:
|
19 |
|
20 |
```
|
21 |
+
docker compose up -d --build
|
22 |
```
|
23 |
|
24 |
only use the `--build` flag the first time around, or if you want to rebuild the container (e.g. when having added a package you need in the container). **NOTE:** the `-d` flag stands for `detach` which means that your docker container runs in the background and does not log everything into your console.
|
25 |
|
26 |
+
2. then, to check whether everything worked hit:
|
27 |
|
28 |
```
|
29 |
docker ps
|
30 |
```
|
31 |
|
32 |
+
3. for this specific setup, you can head to `localhost:8888` where jupyterlab is running.
|
33 |
|
34 |
+
4. to create a new file (using jupytext, see below), just create a new .ipynb file, the .py file will be created automatically. all the changes you make in the notebook, will be reflected in the .py files which you then can use for your commits.
|
35 |
|
36 |
+
now you shoold see the running docker containers.
|
37 |
+
|
38 |
+
### what about huggingface spaces:
|
39 |
|
|
|
40 |
- [here](./docs/huggingface-spaces.md), you can see what huggingface spaces is and how we can complement our github repo with it (credits to chat-gpt)
|
41 |
|
42 |
### jupytext - nice versioning of jupyter notebooks
|
43 |
+
|
44 |
since we are likely be working with jupyter notebooks alot, lets use jupytext. It automatically maps .ipynb to .py files with some magic. The .ipynb are in the gitignore, so we only have .py files nicely versioned in the repo. read more about it [here](https://jupytext.readthedocs.io/en/latest/)
|
45 |
|
46 |
### trunk based development
|
47 |
+
|
48 |
lets stick to trunk based. if you dont know what it is, read all about it [here](https://trunkbaseddevelopment.com/)
|
49 |
|
50 |
key take aways:
|
|
|
54 |
1. **Single Main Branch**: All developers commit to the trunk or main branch.
|
55 |
2. **Short-Lived Branches**: Branches, if used, are short-lived and quickly merged back.
|
56 |
3. **Frequent Integrations**: Code changes are integrated frequently, often multiple times a day.
|
57 |
+
4. **Feature Flags**: Incomplete features are managed with feature flags to maintain trunk stability.
|
58 |
|
59 |
#### Benefits
|
60 |
|
|
|
75 |
- **Feature Flags**: Manage incomplete or experimental features.
|
76 |
- **Code Reviews**: Maintain quality and knowledge sharing.
|
77 |
|
78 |
+
### code format
|
79 |
|
80 |
+
- lets stick to black for python and prettier for .md and other formats
|
81 |
+
- using docker for the purpose of formatting is really easy
|
82 |
+
- just `chmod +x format` so that the `format` is executable
|
83 |
+
- then simply use `./format` before adding your changes and all the files will be autoformatted
|
docs/docker-setup.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1 |
# DockerSetup
|
2 |
|
3 |
This is a short version of howto install Docker on Ubuntu 20.04. It is basically a summary of the following source:\
|
4 |
-
|
|
|
5 |
|
6 |
## Install Docker
|
|
|
7 |
```bash
|
8 |
sudo apt update
|
9 |
sudo apt-get install \
|
@@ -24,15 +26,19 @@ sudo apt install docker-ce
|
|
24 |
```
|
25 |
|
26 |
## Add user to "docker" group & re-login
|
|
|
27 |
Add yourself to the docker group (to get access to the docker deamon socket)\
|
28 |
note: beeing member of docker gives you root access via the docker deamon
|
29 |
-
|
|
|
30 |
sudo usermod -a -G docker `whoami`
|
31 |
```
|
|
|
32 |
Logout / Login to load the new group rights\
|
33 |
Using Ubuntu Gnome it may be required to restart
|
34 |
|
35 |
## Install Docker-Compose
|
|
|
36 |
```bash
|
37 |
sudo apt install python3-pip
|
38 |
sudo pip3 install docker-compose
|
|
|
1 |
# DockerSetup
|
2 |
|
3 |
This is a short version of howto install Docker on Ubuntu 20.04. It is basically a summary of the following source:\
|
4 |
+
|
5 |
+
- https://docs.docker.com/install/linux/docker-ce/ubuntu/#os-requirements
|
6 |
|
7 |
## Install Docker
|
8 |
+
|
9 |
```bash
|
10 |
sudo apt update
|
11 |
sudo apt-get install \
|
|
|
26 |
```
|
27 |
|
28 |
## Add user to "docker" group & re-login
|
29 |
+
|
30 |
Add yourself to the docker group (to get access to the docker deamon socket)\
|
31 |
note: beeing member of docker gives you root access via the docker deamon
|
32 |
+
|
33 |
+
```bash
|
34 |
sudo usermod -a -G docker `whoami`
|
35 |
```
|
36 |
+
|
37 |
Logout / Login to load the new group rights\
|
38 |
Using Ubuntu Gnome it may be required to restart
|
39 |
|
40 |
## Install Docker-Compose
|
41 |
+
|
42 |
```bash
|
43 |
sudo apt install python3-pip
|
44 |
sudo pip3 install docker-compose
|
docs/huggingface-spaces.md
CHANGED
@@ -3,6 +3,7 @@ Hugging Face Spaces and GitHub repositories serve different but complementary pu
|
|
3 |
### Comparison with GitHub Repositories
|
4 |
|
5 |
- **GitHub Repository**:
|
|
|
6 |
- **Purpose**: Primarily used for version control, collaboration, and sharing of code and projects.
|
7 |
- **Capabilities**: Stores code, tracks changes, manages issues, and supports CI/CD pipelines.
|
8 |
- **Usage**: Developers collaborate on software development projects, manage codebases, and deploy applications.
|
@@ -17,12 +18,15 @@ Hugging Face Spaces and GitHub repositories serve different but complementary pu
|
|
17 |
You can import a GitHub repository into Hugging Face Spaces to deploy an application hosted on GitHub. Here’s how to do it:
|
18 |
|
19 |
1. **Create a Space on Hugging Face**:
|
|
|
20 |
- Go to the Hugging Face Spaces website and create a new Space.
|
21 |
|
22 |
2. **Link to GitHub Repository**:
|
|
|
23 |
- During the setup of the new Space, you can link it to a GitHub repository. This allows Hugging Face Spaces to pull the code from your GitHub repo.
|
24 |
|
25 |
3. **Configure Your Space**:
|
|
|
26 |
- Ensure your repository contains the necessary files for the framework you are using (Streamlit, Gradio, or HTML/CSS/JS).
|
27 |
- For example, if you are using Streamlit, ensure you have a `requirements.txt` file for dependencies and a main Python script that runs the Streamlit app.
|
28 |
|
@@ -34,15 +38,17 @@ You can import a GitHub repository into Hugging Face Spaces to deploy an applica
|
|
34 |
|
35 |
1. **Create a New Space**:
|
36 |
- Navigate to Hugging Face Spaces and click on “New Space”.
|
37 |
-
|
38 |
2. **Set Up Space**:
|
|
|
39 |
- Choose a name for your Space, select the appropriate SDK (e.g., Streamlit, Gradio, or HTML), and choose the visibility (public or private).
|
40 |
|
41 |
3. **Connect GitHub Repository**:
|
|
|
42 |
- In the Space settings, you will find an option to link a GitHub repository. Provide the URL of your GitHub repository.
|
43 |
- Hugging Face Spaces will clone your GitHub repository to use it as the source code for your Space.
|
44 |
|
45 |
4. **Configure and Deploy**:
|
|
|
46 |
- Make sure your GitHub repository is set up correctly for the chosen framework. For example, a Streamlit app should have a `requirements.txt` and an entry-point script like `app.py`.
|
47 |
- Once everything is set up, your Space will be deployed and can be accessed via a URL provided by Hugging Face.
|
48 |
|
|
|
3 |
### Comparison with GitHub Repositories
|
4 |
|
5 |
- **GitHub Repository**:
|
6 |
+
|
7 |
- **Purpose**: Primarily used for version control, collaboration, and sharing of code and projects.
|
8 |
- **Capabilities**: Stores code, tracks changes, manages issues, and supports CI/CD pipelines.
|
9 |
- **Usage**: Developers collaborate on software development projects, manage codebases, and deploy applications.
|
|
|
18 |
You can import a GitHub repository into Hugging Face Spaces to deploy an application hosted on GitHub. Here’s how to do it:
|
19 |
|
20 |
1. **Create a Space on Hugging Face**:
|
21 |
+
|
22 |
- Go to the Hugging Face Spaces website and create a new Space.
|
23 |
|
24 |
2. **Link to GitHub Repository**:
|
25 |
+
|
26 |
- During the setup of the new Space, you can link it to a GitHub repository. This allows Hugging Face Spaces to pull the code from your GitHub repo.
|
27 |
|
28 |
3. **Configure Your Space**:
|
29 |
+
|
30 |
- Ensure your repository contains the necessary files for the framework you are using (Streamlit, Gradio, or HTML/CSS/JS).
|
31 |
- For example, if you are using Streamlit, ensure you have a `requirements.txt` file for dependencies and a main Python script that runs the Streamlit app.
|
32 |
|
|
|
38 |
|
39 |
1. **Create a New Space**:
|
40 |
- Navigate to Hugging Face Spaces and click on “New Space”.
|
|
|
41 |
2. **Set Up Space**:
|
42 |
+
|
43 |
- Choose a name for your Space, select the appropriate SDK (e.g., Streamlit, Gradio, or HTML), and choose the visibility (public or private).
|
44 |
|
45 |
3. **Connect GitHub Repository**:
|
46 |
+
|
47 |
- In the Space settings, you will find an option to link a GitHub repository. Provide the URL of your GitHub repository.
|
48 |
- Hugging Face Spaces will clone your GitHub repository to use it as the source code for your Space.
|
49 |
|
50 |
4. **Configure and Deploy**:
|
51 |
+
|
52 |
- Make sure your GitHub repository is set up correctly for the chosen framework. For example, a Streamlit app should have a `requirements.txt` and an entry-point script like `app.py`.
|
53 |
- Once everything is set up, your Space will be deployed and can be accessed via a URL provided by Hugging Face.
|
54 |
|
format
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#! /bin/sh
|
2 |
+
|
3 |
+
# Run as root, otherwise the container cannot modify the mounted files.
|
4 |
+
docker run --rm --user root --volume $(pwd):/work tmknom/prettier prettier --loglevel warn --write .
|
5 |
+
|
6 |
+
# Format Python files using Black
|
7 |
+
docker run --rm --user root --volume $(pwd):/data cytopia/black:latest .
|
python/eda_jan.py
CHANGED
@@ -20,7 +20,7 @@ import librosa.display
|
|
20 |
import matplotlib.pyplot as plt
|
21 |
from sklearn.cluster import KMeans
|
22 |
from sklearn.decomposition import PCA
|
23 |
-
from IPython.display import Audio, display
|
24 |
|
25 |
# %%
|
26 |
# Load the entire audio file
|
@@ -32,7 +32,7 @@ y, sr = librosa.load(file_path, sr=44100)
|
|
32 |
# %%
|
33 |
# split soundfile in to 10s chunks
|
34 |
window_size = 10 # window size in seconds
|
35 |
-
hop_size = 10
|
36 |
|
37 |
# Convert window and hop size to samples
|
38 |
window_samples = int(window_size * sr)
|
@@ -47,13 +47,13 @@ print(f"Total number of windows: {num_windows}")
|
|
47 |
# %%
|
48 |
# Define frequency bands (in Hz)
|
49 |
bands = {
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
}
|
58 |
|
59 |
# Initialize a list to hold the features
|
@@ -67,7 +67,7 @@ for i in range(num_windows):
|
|
67 |
# Compute STFT
|
68 |
S = librosa.stft(y_window)
|
69 |
S_db = librosa.amplitude_to_db(np.abs(S))
|
70 |
-
|
71 |
# Compute features for each band
|
72 |
features = []
|
73 |
for band, (low_freq, high_freq) in bands.items():
|
@@ -75,7 +75,7 @@ for i in range(num_windows):
|
|
75 |
high_bin = int(np.ceil(high_freq * (S.shape[0] / sr)))
|
76 |
band_energy = np.mean(S_db[low_bin:high_bin, :], axis=0)
|
77 |
features.append(band_energy)
|
78 |
-
|
79 |
# Flatten the feature array and add to all_features
|
80 |
features_flat = np.concatenate(features)
|
81 |
all_features.append(features_flat)
|
@@ -95,11 +95,13 @@ clusters = kmeans.fit_predict(features_reduced)
|
|
95 |
|
96 |
# Plot the clusters
|
97 |
plt.figure(figsize=(10, 6))
|
98 |
-
scatter = plt.scatter(
|
99 |
-
|
100 |
-
|
101 |
-
plt.
|
102 |
-
plt.
|
|
|
|
|
103 |
plt.show()
|
104 |
|
105 |
|
@@ -108,12 +110,12 @@ plt.show()
|
|
108 |
for cluster_label in np.unique(clusters):
|
109 |
# Find the first data point in the cluster
|
110 |
representative_index = np.where(clusters == cluster_label)[0][0]
|
111 |
-
|
112 |
# Use the original audio window at the representative index
|
113 |
start_sample = representative_index * hop_samples
|
114 |
end_sample = start_sample + window_samples
|
115 |
y_representative = y[start_sample:end_sample]
|
116 |
-
|
117 |
print(f"Cluster {cluster_label} representative audio:")
|
118 |
display(Audio(data=y_representative, rate=sr))
|
119 |
|
@@ -127,23 +129,36 @@ import numpy as np
|
|
127 |
import librosa
|
128 |
from sklearn.preprocessing import StandardScaler
|
129 |
import joblib
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
|
|
131 |
# Directory containing the audio files
|
132 |
-
audio_dir = "data/soundscape_data"
|
|
|
|
|
|
|
133 |
|
134 |
# Parameters for windowing
|
135 |
window_size = 10 # window size in seconds
|
136 |
-
hop_size = 10
|
137 |
|
138 |
# Define frequency bands (in Hz)
|
139 |
bands = {
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
}
|
148 |
|
149 |
# Directory to save features
|
@@ -152,10 +167,10 @@ os.makedirs(features_dir, exist_ok=True)
|
|
152 |
|
153 |
# Iterate over each audio file in the directory
|
154 |
for filename in os.listdir(audio_dir):
|
155 |
-
if filename.endswith(".
|
156 |
file_path = os.path.join(audio_dir, filename)
|
157 |
y, sr = librosa.load(file_path, sr=44100)
|
158 |
-
|
159 |
# Convert window and hop size to samples
|
160 |
window_samples = int(window_size * sr)
|
161 |
hop_samples = int(hop_size * sr)
|
@@ -194,19 +209,17 @@ for filename in os.listdir(audio_dir):
|
|
194 |
all_features = scaler.fit_transform(all_features)
|
195 |
|
196 |
# Save features to disk
|
197 |
-
feature_file = os.path.join(
|
|
|
|
|
198 |
joblib.dump((all_features, scaler), feature_file)
|
199 |
|
200 |
|
201 |
# %%
|
202 |
-
import numpy as np
|
203 |
-
import joblib
|
204 |
-
from sklearn.cluster import KMeans
|
205 |
-
from sklearn.decomposition import PCA
|
206 |
-
import matplotlib.pyplot as plt
|
207 |
-
|
208 |
# Directory to load features
|
209 |
features_dir = "features"
|
|
|
|
|
210 |
|
211 |
# Load all features
|
212 |
all_features = []
|
@@ -223,53 +236,50 @@ pca = PCA(n_components=2)
|
|
223 |
features_pca = pca.fit_transform(all_features)
|
224 |
|
225 |
# Perform k-means clustering
|
226 |
-
kmeans = KMeans(n_clusters=
|
227 |
clusters = kmeans.fit_predict(all_features)
|
228 |
|
229 |
# Plot the PCA-reduced features with cluster labels
|
230 |
plt.figure(figsize=(10, 6))
|
231 |
-
scatter = plt.scatter(
|
232 |
-
|
233 |
-
|
234 |
-
plt.
|
235 |
-
plt.
|
|
|
|
|
236 |
plt.show()
|
237 |
|
238 |
# Save clustering results
|
239 |
-
clustering_results = {
|
240 |
-
|
241 |
-
'kmeans': kmeans,
|
242 |
-
'pca': pca
|
243 |
-
}
|
244 |
-
joblib.dump(clustering_results, 'clustering_results.pkl')
|
245 |
|
246 |
# Plot the clusters
|
247 |
plt.figure(figsize=(10, 6))
|
248 |
-
for i in range(
|
249 |
-
plt.plot(all_features[clusters == i].mean(axis=0), label=f
|
250 |
plt.legend()
|
251 |
-
plt.title(
|
|
|
|
|
252 |
plt.show()
|
253 |
|
254 |
# %%
|
255 |
-
import os
|
256 |
-
import numpy as np
|
257 |
-
import librosa
|
258 |
-
from IPython.display import Audio, display
|
259 |
-
import joblib
|
260 |
-
|
261 |
# Directory containing the audio files
|
262 |
-
audio_dir = "data/soundscape_data"
|
|
|
|
|
|
|
263 |
# Directory to load features
|
264 |
features_dir = "features"
|
265 |
|
266 |
# Parameters for windowing
|
267 |
window_size = 10 # window size in seconds
|
268 |
-
hop_size = 10
|
269 |
|
270 |
# Load clustering results
|
271 |
-
clustering_results = joblib.load(
|
272 |
-
clusters = clustering_results[
|
273 |
|
274 |
# Load all features
|
275 |
all_features = []
|
@@ -278,7 +288,7 @@ audio_segments = []
|
|
278 |
for feature_file in os.listdir(features_dir):
|
279 |
if feature_file.endswith("_features.npy"):
|
280 |
features, scaler = joblib.load(os.path.join(features_dir, feature_file))
|
281 |
-
filename = feature_file.replace(
|
282 |
file_path = os.path.join(audio_dir, filename)
|
283 |
y, sr = librosa.load(file_path, sr=44100)
|
284 |
|
@@ -318,3 +328,79 @@ for cluster_label in np.unique(clusters):
|
|
318 |
|
319 |
|
320 |
# %%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
import matplotlib.pyplot as plt
|
21 |
from sklearn.cluster import KMeans
|
22 |
from sklearn.decomposition import PCA
|
23 |
+
from IPython.display import Audio, display
|
24 |
|
25 |
# %%
|
26 |
# Load the entire audio file
|
|
|
32 |
# %%
|
33 |
# split soundfile in to 10s chunks
|
34 |
window_size = 10 # window size in seconds
|
35 |
+
hop_size = 10 # hop size in seconds
|
36 |
|
37 |
# Convert window and hop size to samples
|
38 |
window_samples = int(window_size * sr)
|
|
|
47 |
# %%
|
48 |
# Define frequency bands (in Hz)
|
49 |
bands = {
|
50 |
+
"Sub-bass": (20, 60),
|
51 |
+
"Bass": (60, 250),
|
52 |
+
"Low Midrange": (250, 500),
|
53 |
+
"Midrange": (500, 2000),
|
54 |
+
"Upper Midrange": (2000, 4000),
|
55 |
+
"Presence": (4000, 6000),
|
56 |
+
"Brilliance": (6000, 20000),
|
57 |
}
|
58 |
|
59 |
# Initialize a list to hold the features
|
|
|
67 |
# Compute STFT
|
68 |
S = librosa.stft(y_window)
|
69 |
S_db = librosa.amplitude_to_db(np.abs(S))
|
70 |
+
|
71 |
# Compute features for each band
|
72 |
features = []
|
73 |
for band, (low_freq, high_freq) in bands.items():
|
|
|
75 |
high_bin = int(np.ceil(high_freq * (S.shape[0] / sr)))
|
76 |
band_energy = np.mean(S_db[low_bin:high_bin, :], axis=0)
|
77 |
features.append(band_energy)
|
78 |
+
|
79 |
# Flatten the feature array and add to all_features
|
80 |
features_flat = np.concatenate(features)
|
81 |
all_features.append(features_flat)
|
|
|
95 |
|
96 |
# Plot the clusters
|
97 |
plt.figure(figsize=(10, 6))
|
98 |
+
scatter = plt.scatter(
|
99 |
+
features_reduced[:, 0], features_reduced[:, 1], c=clusters, cmap="viridis"
|
100 |
+
)
|
101 |
+
plt.title("Clustered Frequency Band Features")
|
102 |
+
plt.xlabel("Principal Component 1")
|
103 |
+
plt.ylabel("Principal Component 2")
|
104 |
+
plt.colorbar(scatter, label="Cluster")
|
105 |
plt.show()
|
106 |
|
107 |
|
|
|
110 |
for cluster_label in np.unique(clusters):
|
111 |
# Find the first data point in the cluster
|
112 |
representative_index = np.where(clusters == cluster_label)[0][0]
|
113 |
+
|
114 |
# Use the original audio window at the representative index
|
115 |
start_sample = representative_index * hop_samples
|
116 |
end_sample = start_sample + window_samples
|
117 |
y_representative = y[start_sample:end_sample]
|
118 |
+
|
119 |
print(f"Cluster {cluster_label} representative audio:")
|
120 |
display(Audio(data=y_representative, rate=sr))
|
121 |
|
|
|
129 |
import librosa
|
130 |
from sklearn.preprocessing import StandardScaler
|
131 |
import joblib
|
132 |
+
import numpy as np
|
133 |
+
from sklearn.cluster import KMeans
|
134 |
+
from sklearn.decomposition import PCA
|
135 |
+
import matplotlib.pyplot as plt
|
136 |
+
import librosa
|
137 |
+
from IPython.display import Audio, display
|
138 |
+
from sklearn.model_selection import cross_val_score
|
139 |
+
from sklearn.ensemble import RandomForestClassifier
|
140 |
+
|
141 |
|
142 |
+
# %%
|
143 |
# Directory containing the audio files
|
144 |
+
# audio_dir = "data/soundscape_data"
|
145 |
+
audio_dir = (
|
146 |
+
"data/SoundMeters_Ingles_Primary-20240519T132658Z-002/SoundMeters_Ingles_Primary"
|
147 |
+
)
|
148 |
|
149 |
# Parameters for windowing
|
150 |
window_size = 10 # window size in seconds
|
151 |
+
hop_size = 10 # hop size in seconds
|
152 |
|
153 |
# Define frequency bands (in Hz)
|
154 |
bands = {
|
155 |
+
"Sub-bass": (20, 60),
|
156 |
+
"Bass": (60, 250),
|
157 |
+
"Low Midrange": (250, 500),
|
158 |
+
"Midrange": (500, 2000),
|
159 |
+
"Upper Midrange": (2000, 4000),
|
160 |
+
"Presence": (4000, 6000),
|
161 |
+
"Brilliance": (6000, 20000),
|
162 |
}
|
163 |
|
164 |
# Directory to save features
|
|
|
167 |
|
168 |
# Iterate over each audio file in the directory
|
169 |
for filename in os.listdir(audio_dir):
|
170 |
+
if filename.endswith(".wav"):
|
171 |
file_path = os.path.join(audio_dir, filename)
|
172 |
y, sr = librosa.load(file_path, sr=44100)
|
173 |
+
|
174 |
# Convert window and hop size to samples
|
175 |
window_samples = int(window_size * sr)
|
176 |
hop_samples = int(hop_size * sr)
|
|
|
209 |
all_features = scaler.fit_transform(all_features)
|
210 |
|
211 |
# Save features to disk
|
212 |
+
feature_file = os.path.join(
|
213 |
+
features_dir, f"{os.path.splitext(filename)[0]}_features.npy"
|
214 |
+
)
|
215 |
joblib.dump((all_features, scaler), feature_file)
|
216 |
|
217 |
|
218 |
# %%
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
# Directory to load features
|
220 |
features_dir = "features"
|
221 |
+
n_clusters = 5
|
222 |
+
|
223 |
|
224 |
# Load all features
|
225 |
all_features = []
|
|
|
236 |
features_pca = pca.fit_transform(all_features)
|
237 |
|
238 |
# Perform k-means clustering
|
239 |
+
kmeans = KMeans(n_clusters=n_clusters) # Example: 5 clusters
|
240 |
clusters = kmeans.fit_predict(all_features)
|
241 |
|
242 |
# Plot the PCA-reduced features with cluster labels
|
243 |
plt.figure(figsize=(10, 6))
|
244 |
+
scatter = plt.scatter(
|
245 |
+
features_pca[:, 0], features_pca[:, 1], c=clusters, cmap="viridis"
|
246 |
+
)
|
247 |
+
plt.title("PCA of Clustered Frequency Band Features")
|
248 |
+
plt.xlabel("Principal Component 1")
|
249 |
+
plt.ylabel("Principal Component 2")
|
250 |
+
plt.colorbar(scatter, label="Cluster")
|
251 |
plt.show()
|
252 |
|
253 |
# Save clustering results
|
254 |
+
clustering_results = {"clusters": clusters, "kmeans": kmeans, "pca": pca}
|
255 |
+
joblib.dump(clustering_results, "clustering_results.pkl")
|
|
|
|
|
|
|
|
|
256 |
|
257 |
# Plot the clusters
|
258 |
plt.figure(figsize=(10, 6))
|
259 |
+
for i in range(n_clusters):
|
260 |
+
plt.plot(all_features[clusters == i].mean(axis=0), label=f"Cluster {i}")
|
261 |
plt.legend()
|
262 |
+
plt.title("Clustered Frequency Band Features")
|
263 |
+
plt.xlabel("Feature Index (Frequency Bands)")
|
264 |
+
plt.ylabel("Mean Feature Value (Energy in dB)")
|
265 |
plt.show()
|
266 |
|
267 |
# %%
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
# Directory containing the audio files
|
269 |
+
# audio_dir = "data/soundscape_data"
|
270 |
+
audio_dir = (
|
271 |
+
"data/SoundMeters_Ingles_Primary-20240519T132658Z-002/SoundMeters_Ingles_Primary"
|
272 |
+
)
|
273 |
# Directory to load features
|
274 |
features_dir = "features"
|
275 |
|
276 |
# Parameters for windowing
|
277 |
window_size = 10 # window size in seconds
|
278 |
+
hop_size = 10 # hop size in seconds
|
279 |
|
280 |
# Load clustering results
|
281 |
+
clustering_results = joblib.load("clustering_results.pkl")
|
282 |
+
clusters = clustering_results["clusters"]
|
283 |
|
284 |
# Load all features
|
285 |
all_features = []
|
|
|
288 |
for feature_file in os.listdir(features_dir):
|
289 |
if feature_file.endswith("_features.npy"):
|
290 |
features, scaler = joblib.load(os.path.join(features_dir, feature_file))
|
291 |
+
filename = feature_file.replace("_features.npy", ".wav")
|
292 |
file_path = os.path.join(audio_dir, filename)
|
293 |
y, sr = librosa.load(file_path, sr=44100)
|
294 |
|
|
|
328 |
|
329 |
|
330 |
# %%
|
331 |
+
|
332 |
+
# Fit PCA
|
333 |
+
pca = PCA().fit(all_features_scaled)
|
334 |
+
|
335 |
+
# Method 1: Variance Explained
|
336 |
+
explained_variance = pca.explained_variance_ratio_
|
337 |
+
cumulative_explained_variance = np.cumsum(explained_variance)
|
338 |
+
|
339 |
+
# Plot the cumulative explained variance
|
340 |
+
plt.figure(figsize=(10, 6))
|
341 |
+
plt.plot(cumulative_explained_variance, marker="o")
|
342 |
+
plt.xlabel("Number of Principal Components")
|
343 |
+
plt.ylabel("Cumulative Explained Variance")
|
344 |
+
plt.title("Explained Variance vs. Number of Principal Components")
|
345 |
+
plt.grid(True)
|
346 |
+
plt.show()
|
347 |
+
|
348 |
+
|
349 |
+
# %%
|
350 |
+
# Method 2: Scree Plot
|
351 |
+
plt.figure(figsize=(10, 6))
|
352 |
+
plt.plot(np.arange(1, len(explained_variance) + 1), explained_variance, marker="o")
|
353 |
+
plt.xlabel("Principal Component")
|
354 |
+
plt.ylabel("Explained Variance")
|
355 |
+
plt.title("Scree Plot")
|
356 |
+
plt.grid(True)
|
357 |
+
plt.show()
|
358 |
+
|
359 |
+
|
360 |
+
# %%
|
361 |
+
# Method 3: Kaiser Criterion
|
362 |
+
eigenvalues = pca.explained_variance_
|
363 |
+
kaiser_criterion = np.sum(eigenvalues > 1)
|
364 |
+
|
365 |
+
|
366 |
+
# IMO this doesnt make sense at the moment, we need to extract more features
|
367 |
+
print(f"Number of components selected by Kaiser Criterion: {kaiser_criterion}")
|
368 |
+
|
369 |
+
|
370 |
+
# %%
|
371 |
+
# Method 4: Cross-Validation
|
372 |
+
# Evaluate a classifier with different numbers of principal components
|
373 |
+
|
374 |
+
## do not run if you dont have time, this takes forever.
|
375 |
+
# scores = []
|
376 |
+
# for n_components in range(1, len(explained_variance) + 1):
|
377 |
+
# pca = PCA(n_components=n_components)
|
378 |
+
# features_pca = pca.fit_transform(all_features_scaled)
|
379 |
+
# classifier = RandomForestClassifier() # Use your preferred model here
|
380 |
+
# score = np.mean(cross_val_score(classifier, features_pca, clusters, cv=n_clusters)) # Assuming `clusters` are your labels
|
381 |
+
# scores.append(score)
|
382 |
+
|
383 |
+
# # Plot cross-validation scores
|
384 |
+
# plt.figure(figsize=(10, 6))
|
385 |
+
# plt.plot(range(1, len(explained_variance) + 1), scores, marker='o')
|
386 |
+
# plt.xlabel('Number of Principal Components')
|
387 |
+
# plt.ylabel('Cross-Validation Score')
|
388 |
+
# plt.title('Cross-Validation Score vs. Number of Principal Components')
|
389 |
+
# plt.grid(True)
|
390 |
+
# plt.show()
|
391 |
+
|
392 |
+
# # Choosing the number of components that explain at least 95% of the variance
|
393 |
+
# n_components_variance = np.argmax(cumulative_explained_variance >= 0.95) + 1
|
394 |
+
# print(f"Number of components to retain 95% variance: {n_components_variance}")
|
395 |
+
|
396 |
+
# # Choose the optimal number of components based on your analysis
|
397 |
+
# optimal_n_components = n_components_variance # or based on the scree plot, cross-validation, etc.
|
398 |
+
# print(f"Optimal number of components: {optimal_n_components}")
|
399 |
+
|
400 |
+
# # Perform PCA with the selected number of components
|
401 |
+
# pca = PCA(n_components=optimal_n_components)
|
402 |
+
# features_pca = pca.fit_transform(all_features_scaled)
|
403 |
+
|
404 |
+
# %%
|
405 |
+
|
406 |
+
# %%
|
python/requirements.txt
CHANGED
@@ -8,3 +8,5 @@ numpy
|
|
8 |
opencv-python
|
9 |
scipy
|
10 |
librosa
|
|
|
|
|
|
8 |
opencv-python
|
9 |
scipy
|
10 |
librosa
|
11 |
+
plotly
|
12 |
+
ipywidgets
|