kangourous commited on
Commit
5d82932
·
verified ·
1 Parent(s): 275cdc6

Upload 2 files

Browse files
notebooks/CNN_training.ipynb ADDED
@@ -0,0 +1,582 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 14,
6
+ "id": "f27bc33e-2451-4ef3-80e9-f3081e7db8c5",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "import numpy as np\n",
11
+ "import torch\n",
12
+ "import torch.nn as nn\n",
13
+ "import torch.optim as optim\n",
14
+ "from torch.utils.data import DataLoader, Dataset\n",
15
+ "import torchaudio\n",
16
+ "import torchvision\n",
17
+ "import matplotlib.pyplot as plt\n",
18
+ "from preprocess import get_raw_data, get_batch_generator\n",
19
+ "from datasets import load_from_disk\n",
20
+ "import os\n",
21
+ "import csv\n",
22
+ "import torch\n",
23
+ "from tqdm import tqdm"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": 2,
29
+ "id": "f62a5ab8-0ac3-4543-9496-1c2cfca92e66",
30
+ "metadata": {},
31
+ "outputs": [],
32
+ "source": [
33
+ "dataset = load_from_disk(\"audio\")"
34
+ ]
35
+ },
36
+ {
37
+ "cell_type": "code",
38
+ "execution_count": 3,
39
+ "id": "314a5450-4881-40c4-995a-b01fcc31e536",
40
+ "metadata": {},
41
+ "outputs": [],
42
+ "source": [
43
+ "SR = 12000\n",
44
+ "\n",
45
+ "signals_train, labels_train, sizes_train = get_raw_data(dataset[\"train\"])\n",
46
+ "signals_test, labels_test, sizes_test = get_raw_data(dataset[\"test\"])\n"
47
+ ]
48
+ },
49
+ {
50
+ "cell_type": "code",
51
+ "execution_count": 4,
52
+ "id": "6b0e9608-5a49-4183-9273-8f2e72e4f9a3",
53
+ "metadata": {},
54
+ "outputs": [],
55
+ "source": [
56
+ "# **Dataset to load audio file. Implement mixup transform**\n",
57
+ "class AudioDataset(Dataset):\n",
58
+ " def __init__(self, X, y, mean, std, n_mels, n_fft, hop_length, mixup=False):\n",
59
+ " \n",
60
+ " self.X = X\n",
61
+ " self.labels = y\n",
62
+ " self.sample_rate = 12000\n",
63
+ " self.mel_transform = torchaudio.transforms.MelSpectrogram(\n",
64
+ " sample_rate=self.sample_rate,\n",
65
+ " n_fft=n_fft,\n",
66
+ " hop_length=hop_length,\n",
67
+ " n_mels=n_mels\n",
68
+ " )\n",
69
+ "\n",
70
+ " self.env_idx = np.where(self.labels == 1)[0]\n",
71
+ " self.mixup = mixup\n",
72
+ " self.mean = mean\n",
73
+ " self.std = std\n",
74
+ " \n",
75
+ " def __len__(self):\n",
76
+ " return len(self.X)\n",
77
+ " \n",
78
+ " def __getitem__(self, idx):\n",
79
+ " waveform = self.X[idx]\n",
80
+ " if self.mixup:\n",
81
+ " r = np.random.random()\n",
82
+ " if r > 0.5:\n",
83
+ " idx_to_add = np.random.choice(self.env_idx)\n",
84
+ " to_add = self.X[idx_to_add]\n",
85
+ " #r *= 2\n",
86
+ " assert (r <= 1)\n",
87
+ " waveform = r*waveform + (1-r)*to_add\n",
88
+ "\n",
89
+ " waveform = torch.as_tensor(waveform).unsqueeze(0)\n",
90
+ "\n",
91
+ " mel_spectrogram = self.mel_transform(waveform)\n",
92
+ " mel_spectrogram = torch.log10(1+mel_spectrogram)\n",
93
+ " \n",
94
+ " # Normaliser le spectrogramme\n",
95
+ " mel_spectrogram = (mel_spectrogram - self.mean)/self.std\n",
96
+ " \n",
97
+ " return mel_spectrogram, self.labels[idx]\n",
98
+ "\n",
99
+ "def train_model(\n",
100
+ " model, \n",
101
+ " dataloaders, \n",
102
+ " criterion, \n",
103
+ " optimizer, \n",
104
+ " num_epochs, \n",
105
+ " device, \n",
106
+ " save_dir=\"checkpoints\", \n",
107
+ " csv_file=\"validation_accuracy.csv\"\n",
108
+ "):\n",
109
+ " # Préparer le dossier de sauvegarde\n",
110
+ " os.makedirs(save_dir, exist_ok=True)\n",
111
+ "\n",
112
+ " # Préparer le fichier CSV\n",
113
+ " if not os.path.exists(csv_file):\n",
114
+ " with open(csv_file, mode=\"w\", newline=\"\") as file:\n",
115
+ " writer = csv.writer(file)\n",
116
+ " writer.writerow([\"epoch\", \"val_accuracy\"]) # En-têtes du CSV\n",
117
+ "\n",
118
+ " model = model.to(device)\n",
119
+ "\n",
120
+ " for epoch in range(num_epochs):\n",
121
+ " print(f\"Epoch {epoch + 1}/{num_epochs}\")\n",
122
+ " print(\"-\" * 10)\n",
123
+ "\n",
124
+ " for phase in ['train', 'val']:\n",
125
+ " if phase == 'train':\n",
126
+ " model.train()\n",
127
+ " else:\n",
128
+ " model.eval()\n",
129
+ "\n",
130
+ " running_loss = 0.0\n",
131
+ " running_corrects = 0\n",
132
+ " \n",
133
+ " for inputs, labels in dataloaders[phase]:\n",
134
+ " inputs = inputs.to(device, dtype=torch.float)\n",
135
+ " labels = labels.to(device, dtype=torch.float).view(-1) # Labels en 1D pour BCEWithLogitsLoss\n",
136
+ "\n",
137
+ " optimizer.zero_grad()\n",
138
+ "\n",
139
+ " with torch.set_grad_enabled(phase == 'train'):\n",
140
+ " outputs = model(inputs).view(-1) # Sorties en 1D pour BCEWithLogitsLoss\n",
141
+ " loss = criterion(outputs, labels) # Calcul de la perte\n",
142
+ " \n",
143
+ " if phase == 'train':\n",
144
+ " loss.backward()\n",
145
+ " optimizer.step()\n",
146
+ " \n",
147
+ " running_loss += loss.item() * inputs.size(0)\n",
148
+ "\n",
149
+ " # Calcul des prédictions binaires (sigmoid + seuil 0.5)\n",
150
+ " preds = torch.sigmoid(outputs) > 0.5\n",
151
+ " running_corrects += torch.sum(preds == labels.bool()) # Comparaison binaire\n",
152
+ " #print(running_corrects, len(dataloaders[phase].dataset))\n",
153
+ " \n",
154
+ " epoch_loss = running_loss / len(dataloaders[phase].dataset)\n",
155
+ " epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)\n",
156
+ " \n",
157
+ " print(f\"{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}\")\n",
158
+ "\n",
159
+ " # Sauvegarde du modèle et de l'accuracy si en phase de validation\n",
160
+ " if phase == 'val':\n",
161
+ " # Sauvegarder le modèle\n",
162
+ " model_save_path = os.path.join(save_dir, f\"model_epoch_{epoch + 1}.pth\")\n",
163
+ " torch.save(model.state_dict(), model_save_path)\n",
164
+ " print(f\"Model saved to {model_save_path}\")\n",
165
+ "\n",
166
+ " # Écrire l'accuracy dans le fichier CSV\n",
167
+ " with open(csv_file, mode=\"a\", newline=\"\") as file:\n",
168
+ " writer = csv.writer(file)\n",
169
+ " writer.writerow([epoch + 1, epoch_acc.item()]) # Ajouter l'epoch et l'accuracy\n",
170
+ "\n",
171
+ " print(\"Training complete.\")\n",
172
+ " return model\n"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": 5,
178
+ "id": "d8d813e0-a445-4b65-b9e3-68e8bee28e8d",
179
+ "metadata": {},
180
+ "outputs": [],
181
+ "source": [
182
+ "X_train = signals_train\n",
183
+ "X_test = signals_test\n",
184
+ "y_train = labels_train\n",
185
+ "y_test = labels_test"
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "code",
190
+ "execution_count": 6,
191
+ "id": "c17f7b65-03cc-4eda-892e-0cfee758257c",
192
+ "metadata": {},
193
+ "outputs": [],
194
+ "source": [
195
+ "# Paramètres dataset\n",
196
+ "\n",
197
+ "SAMPLE_RATE = 12000\n",
198
+ "N_FFT = 2048 \n",
199
+ "HOP_LENGTH = 512 \n",
200
+ "N_MELS = 100 \n",
201
+ "BATCH_SIZE = 64\n",
202
+ "MEAN = -24.443264\n",
203
+ "STD = 8.27237\n",
204
+ "\n",
205
+ "\n",
206
+ "MEAN = 0.17555018\n",
207
+ "STD = 0.19079028\n",
208
+ "MEAN=0.18522209\n",
209
+ "STD=0.20916936\n",
210
+ "\n",
211
+ "\n",
212
+ "\n",
213
+ "# Créer les datasets et dataloaders\n",
214
+ "train_dataset = AudioDataset(X_train,\n",
215
+ " y_train,\n",
216
+ " mean=MEAN,\n",
217
+ " std=STD,\n",
218
+ " n_mels=N_MELS,\n",
219
+ " n_fft=N_FFT,\n",
220
+ " hop_length=HOP_LENGTH,\n",
221
+ " mixup=True)\n",
222
+ "val_dataset = AudioDataset(X_test,\n",
223
+ " y_test,\n",
224
+ " mean=MEAN,\n",
225
+ " std=STD,\n",
226
+ " n_mels=N_MELS,\n",
227
+ " n_fft=N_FFT,\n",
228
+ " hop_length=HOP_LENGTH,\n",
229
+ " mixup=False)\n",
230
+ "\n",
231
+ "dataloaders = {\n",
232
+ " \"train\": DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=4),\n",
233
+ " \"val\": DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=4)\n",
234
+ "}"
235
+ ]
236
+ },
237
+ {
238
+ "cell_type": "code",
239
+ "execution_count": 7,
240
+ "id": "11bbd974-9065-487c-a7db-ee6e7c66c5e5",
241
+ "metadata": {},
242
+ "outputs": [
243
+ {
244
+ "data": {
245
+ "text/plain": [
246
+ "<matplotlib.image.AxesImage at 0x7fd388f59e90>"
247
+ ]
248
+ },
249
+ "execution_count": 7,
250
+ "metadata": {},
251
+ "output_type": "execute_result"
252
+ },
253
+ {
254
+ "data": {
255
+ "image/png": "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hZ7QTsAXBYSQUsFBjRBSKpp2UGtra5MPf/jD0tbWdqqb0tSwn+YG+2lulKGfmu5FASGELISmfVIjhJD5wEGNEFIqOKgRQkoFBzVCSKngoEYIKRVNO6jdfvvtctZZZ0l7e7tceuml8vDDD5/qJp0ytm3bJhdffLF0dXXJihUr5KqrrpJdu3aZbY4fPy6bNm2Svr4+Wbx4sVxzzTUyNDR0ilrcHHz84x+XJElky5Yt9b+xn2Z49tln5e1vf7v09fVJR0eHXHDBBfLII4/U1zvn5Oabb5aVK1dKR0eHbNy4UZ588slT2OK505SD2te//nW58cYb5cMf/rA8+uij8qpXvUquuOIKOXDgwKlu2inh/vvvl02bNsmDDz4o9913n0xNTcmb3/xmGR8fr29zww03yHe+8x2555575P7775d9+/bJ1VdffQpbfWr52c9+Jp/97Gflla98pfk7+0nk8OHDctlll0lLS4t8//vfl8cff1z+9V//VZYsWVLf5pZbbpHbbrtN7rzzTnnooYeks7NTrrjiCjl+/PgpbPkccU3IJZdc4jZt2lRfrtVqbtWqVW7btm2nsFXNw4EDB5yIuPvvv98559zw8LBraWlx99xzT32b3/zmN05E3I4dO05VM08ZY2Nj7pxzznH33Xef+5M/+RP3vve9zznHfjrBBz7wAff617++4fosy9zAwID7l3/5l/rfhoeHXVtbm/vqV7/6h2jigmi6J7XJyUnZuXOnbNy4sf63NE1l48aNsmPHjlPYsuZhZGRERESWLl0qIiI7d+6Uqakp02fr1q2TNWvWnJZ9tmnTJnnLW95i+kOE/XSCb3/727J+/Xp561vfKitWrJALL7xQPv/5z9fX7969WwYHB00/9fT0yKWXXvqS6KemG9QOHjwotVpN+vv7zd/7+/tlcHDwFLWqeciyTLZs2SKXXXaZnH/++SIiMjg4KK2trdLb22u2PR377Gtf+5o8+uijsm3bNm8d+2mGp556Su644w4555xz5Ac/+IG8613vkve+971y9913i4jU++Kl+htsOushEmbTpk3y2GOPyQMPPHCqm9J07N27V973vvfJfffdJ+3t7ae6OU1LlmWyfv16+djHPiYiIhdeeKE89thjcuedd8p11113ilu3cJruSW3ZsmVSqVS8N1JDQ0MyMDBwilrVHGzevFm++93vyo9+9CM588wz638fGBiQyclJGR4eNtufbn22c+dOOXDggLzmNa+RarUq1WpV7r//frntttukWq1Kf38/+0lEVq5cKa94xSvM384991zZs2ePiEi9L16qv8GmG9RaW1vloosuku3bt9f/lmWZbN++XTZs2HAKW3bqcM7J5s2b5Rvf+Ib88Ic/lLVr15r1F110kbS0tJg+27Vrl+zZs+e06rPLL79cfvWrX8nPf/7z+r/169fLtddeW//MfhK57LLLvJCgJ554Ql72speJiMjatWtlYGDA9NPo6Kg89NBDL41+OtVvKmbja1/7mmtra3Nf/OIX3eOPP+7e+c53ut7eXjc4OHiqm3ZKeNe73uV6enrcj3/8Y7d///76v6NHj9a3+bu/+zu3Zs0a98Mf/tA98sgjbsOGDW7Dhg2nsNXNgX776Rz7yTnnHn74YVetVt1HP/pR9+STT7ovf/nLbtGiRe7f/u3f6tt8/OMfd729ve5b3/qW++Uvf+muvPJKt3btWnfs2LFT2PK50ZSDmnPOffrTn3Zr1qxxra2t7pJLLnEPPvjgqW7SKUNm6mp5/+666676NseOHXPvfve73ZIlS9yiRYvcn//5n7v9+/efukY3CTiosZ9m+M53vuPOP/9819bW5tatW+c+97nPmfVZlrmbbrrJ9ff3u7a2Nnf55Ze7Xbt2naLWFoN+aoSQUtF0mhohhCwEDmqEkFLBQY0QUio4qBFCSgUHNUJIqeCgRggpFRzUCCGlgoMaIaRUcFAjhJQKDmqEkFLBQY0QUir+f7OSPL7BW8HQAAAAAElFTkSuQmCC",
256
+ "text/plain": [
257
+ "<Figure size 640x480 with 1 Axes>"
258
+ ]
259
+ },
260
+ "metadata": {},
261
+ "output_type": "display_data"
262
+ }
263
+ ],
264
+ "source": [
265
+ "plt.imshow((train_dataset[5][0][0]))"
266
+ ]
267
+ },
268
+ {
269
+ "cell_type": "code",
270
+ "execution_count": 8,
271
+ "id": "eba16b15-b762-4b65-9386-e64ad666e41e",
272
+ "metadata": {},
273
+ "outputs": [],
274
+ "source": [
275
+ "class ConvLayer(nn.Module):\n",
276
+ " def __init__(self, in_channels, out_channels):\n",
277
+ " super(ConvLayer, self).__init__()\n",
278
+ " self.conv_layers = nn.Sequential(\n",
279
+ " nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False),\n",
280
+ " nn.BatchNorm2d(out_channels),\n",
281
+ " nn.ReLU(),\n",
282
+ " nn.MaxPool2d(kernel_size=2, stride=2),\n",
283
+ " )\n",
284
+ "\n",
285
+ " def forward(self, x):\n",
286
+ " x = self.conv_layers(x)\n",
287
+ " return x\n",
288
+ "\n",
289
+ "\n",
290
+ "class AudioClassifierCNN(nn.Module):\n",
291
+ " def __init__(self):\n",
292
+ " super(AudioClassifierCNN, self).__init__()\n",
293
+ " \n",
294
+ " self.conv_layers = nn.Sequential(\n",
295
+ " ConvLayer(1, 16),\n",
296
+ " ConvLayer(16, 32),\n",
297
+ " ConvLayer(32, 64),\n",
298
+ " ConvLayer(64, 128),\n",
299
+ " ConvLayer(128, 256),\n",
300
+ " ConvLayer(256, 256)\n",
301
+ " )\n",
302
+ "\n",
303
+ "\n",
304
+ " self.fc_layers = nn.Sequential(\n",
305
+ " nn.Flatten(),\n",
306
+ " nn.Linear(256, 32),\n",
307
+ " nn.ReLU(),\n",
308
+ " nn.Dropout(0.4),\n",
309
+ " nn.Linear(32, 1)\n",
310
+ " )\n",
311
+ "\n",
312
+ " def forward(self, x):\n",
313
+ " x = self.conv_layers(x)\n",
314
+ " x = self.fc_layers(x)\n",
315
+ " return x.squeeze(1)"
316
+ ]
317
+ },
318
+ {
319
+ "cell_type": "code",
320
+ "execution_count": 9,
321
+ "id": "37214be6-cf2a-472f-8c59-8a57d4efb7a1",
322
+ "metadata": {},
323
+ "outputs": [
324
+ {
325
+ "data": {
326
+ "text/plain": [
327
+ "tensor([0.4159], grad_fn=<SqueezeBackward1>)"
328
+ ]
329
+ },
330
+ "execution_count": 9,
331
+ "metadata": {},
332
+ "output_type": "execute_result"
333
+ }
334
+ ],
335
+ "source": [
336
+ "model = AudioClassifierCNN()\n",
337
+ "a, b = train_dataset[3]\n",
338
+ "model(a.unsqueeze(0))"
339
+ ]
340
+ },
341
+ {
342
+ "cell_type": "code",
343
+ "execution_count": 10,
344
+ "id": "93a17a9d-203b-4c61-ba2c-63deebe6c42e",
345
+ "metadata": {},
346
+ "outputs": [],
347
+ "source": [
348
+ "# (To find mean and std for normalization)\n",
349
+ "if 0:\n",
350
+ " mean = []\n",
351
+ " std = []\n",
352
+ " mean_b = []\n",
353
+ " std_b = []\n",
354
+ " for a, b in train_dataset:\n",
355
+ " mean.append(a.mean((-1,-2)))\n",
356
+ " std.append(a.std((-1,-2)))\n",
357
+ " print(np.mean(mean, 0))\n",
358
+ " print(np.mean(std, 0))"
359
+ ]
360
+ },
361
+ {
362
+ "cell_type": "code",
363
+ "execution_count": 11,
364
+ "id": "9d74c1d8-0f3d-4802-9a15-5c62464a3fcc",
365
+ "metadata": {},
366
+ "outputs": [
367
+ {
368
+ "name": "stdout",
369
+ "output_type": "stream",
370
+ "text": [
371
+ "Epoch 1/50\n",
372
+ "----------\n",
373
+ "train Loss: 0.2585 Acc: 0.9038\n",
374
+ "val Loss: 0.2161 Acc: 0.9196\n",
375
+ "Model saved to checkpoints2/model_epoch_1.pth\n",
376
+ "Epoch 2/50\n",
377
+ "----------\n",
378
+ "train Loss: 0.2139 Acc: 0.9247\n",
379
+ "val Loss: 0.1747 Acc: 0.9382\n",
380
+ "Model saved to checkpoints2/model_epoch_2.pth\n",
381
+ "Epoch 3/50\n",
382
+ "----------\n",
383
+ "train Loss: 0.1972 Acc: 0.9321\n",
384
+ "val Loss: 0.1415 Acc: 0.9491\n",
385
+ "Model saved to checkpoints2/model_epoch_3.pth\n",
386
+ "Epoch 4/50\n",
387
+ "----------\n",
388
+ "train Loss: 0.1855 Acc: 0.9351\n",
389
+ "val Loss: 0.1346 Acc: 0.9515\n",
390
+ "Model saved to checkpoints2/model_epoch_4.pth\n",
391
+ "Epoch 5/50\n",
392
+ "----------\n",
393
+ "train Loss: 0.1786 Acc: 0.9380\n",
394
+ "val Loss: 0.1483 Acc: 0.9521\n",
395
+ "Model saved to checkpoints2/model_epoch_5.pth\n",
396
+ "Epoch 6/50\n",
397
+ "----------\n"
398
+ ]
399
+ },
400
+ {
401
+ "ename": "KeyboardInterrupt",
402
+ "evalue": "",
403
+ "output_type": "error",
404
+ "traceback": [
405
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
406
+ "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
407
+ "Cell \u001b[0;32mIn[11], line 12\u001b[0m\n\u001b[1;32m 9\u001b[0m optimizer \u001b[38;5;241m=\u001b[39m optim\u001b[38;5;241m.\u001b[39mAdam(model\u001b[38;5;241m.\u001b[39mparameters(), lr\u001b[38;5;241m=\u001b[39mLEARNING_RATE)\n\u001b[1;32m 11\u001b[0m \u001b[38;5;66;03m# Entraîner le modèle\u001b[39;00m\n\u001b[0;32m---> 12\u001b[0m model \u001b[38;5;241m=\u001b[39m \u001b[43mtrain_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdataloaders\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcriterion\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnum_epochs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m50\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdevice\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcuda\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msave_dir\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcheckpoints2\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcsv_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mvalid2.csv\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
408
+ "Cell \u001b[0;32mIn[4], line 89\u001b[0m, in \u001b[0;36mtrain_model\u001b[0;34m(model, dataloaders, criterion, optimizer, num_epochs, device, save_dir, csv_file)\u001b[0m\n\u001b[1;32m 86\u001b[0m loss \u001b[38;5;241m=\u001b[39m criterion(outputs, labels) \u001b[38;5;66;03m# Calcul de la perte\u001b[39;00m\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m phase \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtrain\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[0;32m---> 89\u001b[0m \u001b[43mloss\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbackward\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 90\u001b[0m optimizer\u001b[38;5;241m.\u001b[39mstep()\n\u001b[1;32m 92\u001b[0m running_loss \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m loss\u001b[38;5;241m.\u001b[39mitem() \u001b[38;5;241m*\u001b[39m inputs\u001b[38;5;241m.\u001b[39msize(\u001b[38;5;241m0\u001b[39m)\n",
409
+ "File \u001b[0;32m~/.local/share/virtualenvs/kangourou-v5SGOwnr/lib/python3.11/site-packages/torch/_tensor.py:626\u001b[0m, in \u001b[0;36mTensor.backward\u001b[0;34m(self, gradient, retain_graph, create_graph, inputs)\u001b[0m\n\u001b[1;32m 616\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m has_torch_function_unary(\u001b[38;5;28mself\u001b[39m):\n\u001b[1;32m 617\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m handle_torch_function(\n\u001b[1;32m 618\u001b[0m Tensor\u001b[38;5;241m.\u001b[39mbackward,\n\u001b[1;32m 619\u001b[0m (\u001b[38;5;28mself\u001b[39m,),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 624\u001b[0m inputs\u001b[38;5;241m=\u001b[39minputs,\n\u001b[1;32m 625\u001b[0m )\n\u001b[0;32m--> 626\u001b[0m \u001b[43mtorch\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mautograd\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbackward\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 627\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgradient\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mretain_graph\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreate_graph\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minputs\u001b[49m\n\u001b[1;32m 628\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
410
+ "File \u001b[0;32m~/.local/share/virtualenvs/kangourou-v5SGOwnr/lib/python3.11/site-packages/torch/autograd/__init__.py:347\u001b[0m, in \u001b[0;36mbackward\u001b[0;34m(tensors, grad_tensors, retain_graph, create_graph, grad_variables, inputs)\u001b[0m\n\u001b[1;32m 342\u001b[0m retain_graph \u001b[38;5;241m=\u001b[39m create_graph\n\u001b[1;32m 344\u001b[0m \u001b[38;5;66;03m# The reason we repeat the same comment below is that\u001b[39;00m\n\u001b[1;32m 345\u001b[0m \u001b[38;5;66;03m# some Python versions print out the first line of a multi-line function\u001b[39;00m\n\u001b[1;32m 346\u001b[0m \u001b[38;5;66;03m# calls in the traceback and some print out the last line\u001b[39;00m\n\u001b[0;32m--> 347\u001b[0m \u001b[43m_engine_run_backward\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 348\u001b[0m \u001b[43m \u001b[49m\u001b[43mtensors\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 349\u001b[0m \u001b[43m \u001b[49m\u001b[43mgrad_tensors_\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 350\u001b[0m \u001b[43m \u001b[49m\u001b[43mretain_graph\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 351\u001b[0m \u001b[43m \u001b[49m\u001b[43mcreate_graph\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 352\u001b[0m \u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 353\u001b[0m \u001b[43m \u001b[49m\u001b[43mallow_unreachable\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 354\u001b[0m \u001b[43m \u001b[49m\u001b[43maccumulate_grad\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 355\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
411
+ "File \u001b[0;32m~/.local/share/virtualenvs/kangourou-v5SGOwnr/lib/python3.11/site-packages/torch/autograd/graph.py:823\u001b[0m, in \u001b[0;36m_engine_run_backward\u001b[0;34m(t_outputs, *args, **kwargs)\u001b[0m\n\u001b[1;32m 821\u001b[0m unregister_hooks \u001b[38;5;241m=\u001b[39m _register_logging_hooks_on_whole_graph(t_outputs)\n\u001b[1;32m 822\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 823\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mVariable\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execution_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_backward\u001b[49m\u001b[43m(\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Calls into the C++ engine to run the backward pass\u001b[39;49;00m\n\u001b[1;32m 824\u001b[0m \u001b[43m \u001b[49m\u001b[43mt_outputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m 825\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# Calls into the C++ engine to run the backward pass\u001b[39;00m\n\u001b[1;32m 826\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m 827\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m attach_logging_hooks:\n",
412
+ "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
413
+ ]
414
+ }
415
+ ],
416
+ "source": [
417
+ "# Paramètre apprentissage\n",
418
+ "EPOCHS = 20\n",
419
+ "LEARNING_RATE = 0.001\n",
420
+ "\n",
421
+ "# Initialiser le modèle, la loss, et l'optimiseur\n",
422
+ "num_classes = 2 # Ajustez selon vos besoins\n",
423
+ "model = AudioClassifierCNN()\n",
424
+ "criterion = nn.BCEWithLogitsLoss()\n",
425
+ "optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)\n",
426
+ "\n",
427
+ "# Entraîner le modèle\n",
428
+ "model = train_model(model, dataloaders, criterion, optimizer, num_epochs=50, device=\"cuda\", save_dir=\"checkpoints2\", csv_file=\"valid2.csv\")\n"
429
+ ]
430
+ },
431
+ {
432
+ "cell_type": "code",
433
+ "execution_count": 12,
434
+ "id": "7e854804-ae5e-46e1-88fb-53f5acfd9429",
435
+ "metadata": {},
436
+ "outputs": [
437
+ {
438
+ "name": "stderr",
439
+ "output_type": "stream",
440
+ "text": [
441
+ "[codecarbon WARNING @ 01:53:44] Multiple instances of codecarbon are allowed to run at the same time.\n",
442
+ "[codecarbon INFO @ 01:53:44] [setup] RAM Tracking...\n",
443
+ "[codecarbon INFO @ 01:53:44] [setup] CPU Tracking...\n",
444
+ "[codecarbon WARNING @ 01:53:44] No CPU tracking mode found. Falling back on CPU constant mode. \n",
445
+ " Linux OS detected: Please ensure RAPL files exist at \\sys\\class\\powercap\\intel-rapl to measure CPU\n",
446
+ "\n",
447
+ "[codecarbon INFO @ 01:53:45] CPU Model on constant consumption mode: AMD Ryzen 9 5900X 12-Core Processor\n",
448
+ "[codecarbon INFO @ 01:53:45] [setup] GPU Tracking...\n",
449
+ "[codecarbon INFO @ 01:53:45] Tracking Nvidia GPU via pynvml\n",
450
+ "[codecarbon INFO @ 01:53:45] >>> Tracker's metadata:\n",
451
+ "[codecarbon INFO @ 01:53:45] Platform system: Linux-6.1.0-26-amd64-x86_64-with-glibc2.36\n",
452
+ "[codecarbon INFO @ 01:53:45] Python version: 3.11.2\n",
453
+ "[codecarbon INFO @ 01:53:45] CodeCarbon version: 2.8.3\n",
454
+ "[codecarbon INFO @ 01:53:45] Available RAM : 31.259 GB\n",
455
+ "[codecarbon INFO @ 01:53:45] CPU count: 24\n",
456
+ "[codecarbon INFO @ 01:53:45] CPU model: AMD Ryzen 9 5900X 12-Core Processor\n",
457
+ "[codecarbon INFO @ 01:53:45] GPU count: 1\n",
458
+ "[codecarbon INFO @ 01:53:45] GPU model: 1 x NVIDIA GeForce RTX 3080\n",
459
+ "[codecarbon INFO @ 01:53:49] Saving emissions data to file /home/kangourou/frugal/emissions.csv\n"
460
+ ]
461
+ }
462
+ ],
463
+ "source": [
464
+ "from codecarbon import EmissionsTracker\n",
465
+ "tracker = EmissionsTracker(allow_multiple_runs=True)"
466
+ ]
467
+ },
468
+ {
469
+ "cell_type": "code",
470
+ "execution_count": 19,
471
+ "id": "f23a1000-90e0-4777-825f-38d270128ae7",
472
+ "metadata": {},
473
+ "outputs": [
474
+ {
475
+ "name": "stderr",
476
+ "output_type": "stream",
477
+ "text": [
478
+ "[codecarbon WARNING @ 01:55:10] Already started tracking\n",
479
+ "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 119/119 [00:00<00:00, 173.09it/s]\n",
480
+ "[codecarbon INFO @ 01:55:10] Energy consumed for RAM : 0.000160 kWh. RAM Power : 11.722217559814453 W\n",
481
+ "[codecarbon INFO @ 01:55:10] Energy consumed for all CPUs : 0.000717 kWh. Total CPU Power : 52.5 W\n",
482
+ "[codecarbon INFO @ 01:55:10] Energy consumed for all GPUs : 0.001315 kWh. Total GPU Power : 238.54231240370862 W\n",
483
+ "[codecarbon INFO @ 01:55:10] 0.002192 kWh of electricity used since the beginning.\n"
484
+ ]
485
+ },
486
+ {
487
+ "name": "stdout",
488
+ "output_type": "stream",
489
+ "text": [
490
+ "0.05850168950330892\n"
491
+ ]
492
+ }
493
+ ],
494
+ "source": [
495
+ "mel_transform = torchaudio.transforms.MelSpectrogram(\n",
496
+ " sample_rate=SAMPLE_RATE,\n",
497
+ " n_fft=2048,\n",
498
+ " hop_length=512,\n",
499
+ " n_mels=100\n",
500
+ ").cuda()\n",
501
+ "X_train\n",
502
+ "model.cuda()\n",
503
+ "preds = []\n",
504
+ "\n",
505
+ "tracker.start()\n",
506
+ "tracker.start_task(\"inference\")\n",
507
+ "with torch.inference_mode():\n",
508
+ " bs=128\n",
509
+ " for i in tqdm(range(0, X_test.shape[0], bs)):\n",
510
+ " batch = X_test[i:i+bs]\n",
511
+ " mel = mel_transform(torch.as_tensor(batch).cuda())\n",
512
+ " mel = torch.log10(1+mel)\n",
513
+ " #mel_spectrogram = mel_spectrogram[:,:50]\n",
514
+ " #mfcc = self.mfcc_transform(waveform).mean(-1).squeeze(0)\n",
515
+ " \n",
516
+ "\n",
517
+ " # Normaliser le spectrogramme\n",
518
+ " mel = (mel - MEAN)/STD\n",
519
+ " mel = mel.unsqueeze(1)\n",
520
+ " #pred = np.argmax(model(mel).cpu().numpy(), -1)\n",
521
+ " pred = torch.sigmoid(model(mel)).cpu().numpy()\n",
522
+ " preds.append(pred)\n",
523
+ "preds = np.concatenate(preds)\n",
524
+ "\n",
525
+ "emissions_data = tracker.stop_task()\n",
526
+ "print(emissions_data.energy_consumed * 1000)"
527
+ ]
528
+ },
529
+ {
530
+ "cell_type": "code",
531
+ "execution_count": 20,
532
+ "id": "bc710afc-392d-4591-b129-07d3419f8696",
533
+ "metadata": {},
534
+ "outputs": [
535
+ {
536
+ "data": {
537
+ "text/plain": [
538
+ "np.float64(0.9478174603174603)"
539
+ ]
540
+ },
541
+ "execution_count": 20,
542
+ "metadata": {},
543
+ "output_type": "execute_result"
544
+ }
545
+ ],
546
+ "source": [
547
+ "((preds>0.5)==labels_test).sum()/preds.size"
548
+ ]
549
+ },
550
+ {
551
+ "cell_type": "code",
552
+ "execution_count": null,
553
+ "id": "d6f3d8e7-3315-4f78-b7a4-789d75eb1eac",
554
+ "metadata": {},
555
+ "outputs": [],
556
+ "source": [
557
+ "np.save(\"preds_nn.npy\", preds)"
558
+ ]
559
+ }
560
+ ],
561
+ "metadata": {
562
+ "kernelspec": {
563
+ "display_name": "Python 3 (ipykernel)",
564
+ "language": "python",
565
+ "name": "python3"
566
+ },
567
+ "language_info": {
568
+ "codemirror_mode": {
569
+ "name": "ipython",
570
+ "version": 3
571
+ },
572
+ "file_extension": ".py",
573
+ "mimetype": "text/x-python",
574
+ "name": "python",
575
+ "nbconvert_exporter": "python",
576
+ "pygments_lexer": "ipython3",
577
+ "version": "3.11.2"
578
+ }
579
+ },
580
+ "nbformat": 4,
581
+ "nbformat_minor": 5
582
+ }
notebooks/XGBoost_train.ipynb ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "d3e9ed94-07af-482e-a610-03eb8eec8608",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "from datasets import load_from_disk\n",
11
+ "from IPython.display import Audio\n",
12
+ "import matplotlib.pyplot as plt\n",
13
+ "import librosa\n",
14
+ "import numpy as np\n",
15
+ "import torchaudio\n",
16
+ "import torch\n",
17
+ "\n",
18
+ "from preprocess import get_raw_data, basic_stats_dataset, get_batch_generator\n",
19
+ "from sklearn.decomposition import PCA\n",
20
+ "from tqdm import tqdm"
21
+ ]
22
+ },
23
+ {
24
+ "cell_type": "code",
25
+ "execution_count": 2,
26
+ "id": "a786f85c-649d-4c5f-8677-1e2aaff1717f",
27
+ "metadata": {},
28
+ "outputs": [],
29
+ "source": [
30
+ "dataset = load_from_disk(\"audio\")\n",
31
+ "SR = 12000"
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "code",
36
+ "execution_count": 3,
37
+ "id": "f55a78dd-2946-4b74-8c6d-8c9d9ba125a7",
38
+ "metadata": {},
39
+ "outputs": [],
40
+ "source": [
41
+ "signals_train, labels_train, sizes_train = get_raw_data(dataset[\"train\"], pad=\"reflect\")\n",
42
+ "signals_test, labels_test, sizes_test = get_raw_data(dataset[\"test\"], pad=\"reflect\")"
43
+ ]
44
+ },
45
+ {
46
+ "cell_type": "code",
47
+ "execution_count": 4,
48
+ "id": "543acf10-a35b-4ba0-bbfc-e72264e54242",
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "import scipy\n",
53
+ "def get_mfcc_features(signals, labels, bs, do_mixup=False, n_mels=50, nfft = 512, hop=128):\n",
54
+ " features = np.zeros((signals.shape[0], n_mels*2), dtype=np.float32)\n",
55
+ " transform = torchaudio.transforms.MFCC(\n",
56
+ " sample_rate=SR,\n",
57
+ " n_mfcc=n_mels,\n",
58
+ " log_mels=True,\n",
59
+ " melkwargs={\"n_fft\": nfft, \"hop_length\": hop, \"n_mels\": n_mels}#\"f_min\":0, \"f_max\":4000},\n",
60
+ " ).cuda()\n",
61
+ " \n",
62
+ " for i in tqdm(range(0, signals.shape[0], bs)):\n",
63
+ " batch = signals[i:i+bs]\n",
64
+ " batch_tensor = torch.as_tensor(batch).cuda()\n",
65
+ " mfcc_batch = transform(batch_tensor)\n",
66
+ "\n",
67
+ " features[i:i+bs,:n_mels] = mfcc_batch.mean(-1).cpu().numpy()\n",
68
+ " features[i:i+bs,n_mels:n_mels*2] = mfcc_batch.std(-1).cpu().numpy()\n",
69
+ " \n",
70
+ " return features\n",
71
+ "\n",
72
+ "\n",
73
+ "def get_mel_features(signals, bs):\n",
74
+ " features = np.zeros((signals.shape[0], 55*3), dtype=np.float32)\n",
75
+ " \n",
76
+ " transform = torchaudio.transforms.MelSpectrogram(\n",
77
+ " sample_rate=12000,\n",
78
+ " n_fft=1024,\n",
79
+ " hop_length=512,\n",
80
+ " n_mels=55\n",
81
+ " ).cuda()\n",
82
+ "\n",
83
+ " for i in tqdm(range(0, signals.shape[0], bs)):\n",
84
+ " batch = signals[i:i+bs]\n",
85
+ "\n",
86
+ " batch_tensor = torch.as_tensor(batch).cuda()\n",
87
+ " \n",
88
+ " mel_batch = transform(batch_tensor)\n",
89
+ " mel_batch_delta = torchaudio.functional.compute_deltas(mel_batch)\n",
90
+ " mel_batch_delta_delta = torchaudio.functional.compute_deltas(mel_batch_delta)\n",
91
+ "\n",
92
+ " feat_all = np.hstack((\n",
93
+ " mel_batch.mean(-1).cpu(),\n",
94
+ " mel_batch.std(-1).cpu(),\n",
95
+ " #mel_batch_delta.mean(-1).cpu(),\n",
96
+ " mel_batch_delta.std(-1).cpu(),\n",
97
+ " #scipy.stats.skew(mel_batch_delta.cpu().numpy(), -1),\n",
98
+ " #mel_batch_delta_delta.mean(-1).cpu(),\n",
99
+ " #mel_batch_delta_delta.std(-1).cpu(),\n",
100
+ " ))\n",
101
+ " features[i:i+bs, :] = feat_all\n",
102
+ " return features\n",
103
+ "\n",
104
+ "\n",
105
+ "\n",
106
+ "def get_spectral_features(signals, bs):\n",
107
+ " features = []\n",
108
+ " for i in tqdm(range(0, signals.shape[0], bs)):\n",
109
+ " batch = signals[i:i+bs]\n",
110
+ "\n",
111
+ " a = librosa.feature.spectral_contrast(y=batch, sr=12000, fmin=50, n_bands=3)\n",
112
+ " #b = librosa.feature.spectral_bandwidth(y=batch, sr=12000).mean((-1))\n",
113
+ " #c = librosa.feature.spectral_centroid(y=batch, sr=12000).mean((-1))\n",
114
+ " #d = librosa.feature.spectral_flatness(y=batch).mean((-1))\n",
115
+ " #e = librosa.feature.spectral_rolloff(y=batch, sr=12000).mean((-1))\n",
116
+ " #f = librosa.feature.chroma_cens(y=batch, sr=12000).mean(-1)\n",
117
+ " #g = librosa.feature.tonnetz(y=batch, sr=12000).mean(-1)\n",
118
+ " #features.append(np.hstack((a, b, c, d, e, f, g)))\n",
119
+ " features.append(a.mean(-1))\n",
120
+ " #features.append(np.hstack((a.mean(-1))))\n",
121
+ " #features.append(np.hstack((a, b, c, d, e, f, g)))\n",
122
+ " features = np.concatenate(features)\n",
123
+ " return features"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": 5,
129
+ "id": "cc7e6fc1-db81-4a68-a5dc-9e33105098e6",
130
+ "metadata": {},
131
+ "outputs": [
132
+ {
133
+ "name": "stderr",
134
+ "output_type": "stream",
135
+ "text": [
136
+ "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 552/552 [00:01<00:00, 488.45it/s]\n",
137
+ "100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 35/35 [00:00<00:00, 57.30it/s]\n"
138
+ ]
139
+ }
140
+ ],
141
+ "source": [
142
+ "train_mfcc = get_mfcc_features(signals_train, labels_train, 64, do_mixup=False, n_mels=55, nfft=1024, hop=256)\n",
143
+ "train_mels = get_mel_features(signals_train, 1024)\n",
144
+ "#train_pitch =get_pitch_features(signals_train, 2048)\n",
145
+ "#train_spectral_features = get_spectral_features(signals_train, 1024)"
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "code",
150
+ "execution_count": 6,
151
+ "id": "37fcb3f8-5984-48fd-9cff-f6430ac45269",
152
+ "metadata": {},
153
+ "outputs": [
154
+ {
155
+ "name": "stderr",
156
+ "output_type": "stream",
157
+ "text": [
158
+ "[codecarbon WARNING @ 02:00:34] Multiple instances of codecarbon are allowed to run at the same time.\n",
159
+ "[codecarbon INFO @ 02:00:34] [setup] RAM Tracking...\n",
160
+ "[codecarbon INFO @ 02:00:34] [setup] CPU Tracking...\n",
161
+ "[codecarbon WARNING @ 02:00:34] No CPU tracking mode found. Falling back on CPU constant mode. \n",
162
+ " Linux OS detected: Please ensure RAPL files exist at \\sys\\class\\powercap\\intel-rapl to measure CPU\n",
163
+ "\n",
164
+ "[codecarbon INFO @ 02:00:35] CPU Model on constant consumption mode: AMD Ryzen 9 5900X 12-Core Processor\n",
165
+ "[codecarbon INFO @ 02:00:35] [setup] GPU Tracking...\n",
166
+ "[codecarbon INFO @ 02:00:35] Tracking Nvidia GPU via pynvml\n",
167
+ "[codecarbon INFO @ 02:00:35] >>> Tracker's metadata:\n",
168
+ "[codecarbon INFO @ 02:00:35] Platform system: Linux-6.1.0-26-amd64-x86_64-with-glibc2.36\n",
169
+ "[codecarbon INFO @ 02:00:35] Python version: 3.11.2\n",
170
+ "[codecarbon INFO @ 02:00:35] CodeCarbon version: 2.8.3\n",
171
+ "[codecarbon INFO @ 02:00:35] Available RAM : 31.259 GB\n",
172
+ "[codecarbon INFO @ 02:00:35] CPU count: 24\n",
173
+ "[codecarbon INFO @ 02:00:35] CPU model: AMD Ryzen 9 5900X 12-Core Processor\n",
174
+ "[codecarbon INFO @ 02:00:35] GPU count: 1\n",
175
+ "[codecarbon INFO @ 02:00:35] GPU model: 1 x NVIDIA GeForce RTX 3080\n",
176
+ "[codecarbon INFO @ 02:00:38] Saving emissions data to file /home/kangourou/frugal/emissions.csv\n"
177
+ ]
178
+ }
179
+ ],
180
+ "source": [
181
+ "from codecarbon import EmissionsTracker\n",
182
+ "tracker = EmissionsTracker(allow_multiple_runs=True)"
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "code",
187
+ "execution_count": 7,
188
+ "id": "3880dbe6-16ad-4143-a296-92339b723d81",
189
+ "metadata": {},
190
+ "outputs": [
191
+ {
192
+ "name": "stderr",
193
+ "output_type": "stream",
194
+ "text": [
195
+ "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 237/237 [00:00<00:00, 649.63it/s]\n",
196
+ "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 237/237 [00:00<00:00, 727.40it/s]\n",
197
+ "[codecarbon INFO @ 02:00:39] Energy consumed for RAM : 0.000002 kWh. RAM Power : 11.722217559814453 W\n",
198
+ "[codecarbon INFO @ 02:00:39] Energy consumed for all CPUs : 0.000010 kWh. Total CPU Power : 52.5 W\n",
199
+ "[codecarbon INFO @ 02:00:39] Energy consumed for all GPUs : 0.000036 kWh. Total GPU Power : 182.93542388234846 W\n",
200
+ "[codecarbon INFO @ 02:00:39] 0.000048 kWh of electricity used since the beginning.\n"
201
+ ]
202
+ },
203
+ {
204
+ "name": "stdout",
205
+ "output_type": "stream",
206
+ "text": [
207
+ "0.04825051408887344\n"
208
+ ]
209
+ }
210
+ ],
211
+ "source": [
212
+ "tracker.start()\n",
213
+ "tracker.start_task(\"inference\")\n",
214
+ "test_mfcc = get_mfcc_features(signals_test, labels_test, 64, do_mixup=False, n_mels=55, nfft=1024, hop=256)\n",
215
+ "test_mels = get_mel_features(signals_test, 64)\n",
216
+ "#test_pitch =get_pitch_features(signals_test, 2048)\n",
217
+ "#test_spectral_features = get_spectral_features(signals_test, 1024)\n",
218
+ "emissions_data = tracker.stop_task()\n",
219
+ "print(emissions_data.energy_consumed * 1000)"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": 8,
225
+ "id": "c609655a-e4f2-4450-970a-e9a813c9c349",
226
+ "metadata": {},
227
+ "outputs": [],
228
+ "source": [
229
+ "X_train = np.hstack((train_mfcc, train_mels))\n",
230
+ "X_test = np.hstack((test_mfcc, test_mels))\n",
231
+ "\n",
232
+ "Y_train = labels_train\n",
233
+ "Y_test = labels_test"
234
+ ]
235
+ },
236
+ {
237
+ "cell_type": "code",
238
+ "execution_count": 9,
239
+ "id": "d3314f22-c8ed-4480-a513-462528e9a837",
240
+ "metadata": {},
241
+ "outputs": [
242
+ {
243
+ "name": "stdout",
244
+ "output_type": "stream",
245
+ "text": [
246
+ "0.9536375661375661\n"
247
+ ]
248
+ },
249
+ {
250
+ "name": "stderr",
251
+ "output_type": "stream",
252
+ "text": [
253
+ "/home/kangourou/.local/share/virtualenvs/kangourou-v5SGOwnr/lib/python3.11/site-packages/xgboost/core.py:158: UserWarning: [02:01:00] WARNING: /workspace/src/common/error_msg.cc:58: Falling back to prediction using DMatrix due to mismatched devices. This might lead to higher memory usage and slower performance. XGBoost is running on: cuda:0, while the input data is on: cpu.\n",
254
+ "Potential solutions:\n",
255
+ "- Use a data structure that matches the device ordinal in the booster.\n",
256
+ "- Set the device for booster before call to inplace_predict.\n",
257
+ "\n",
258
+ "This warning will only be shown once.\n",
259
+ "\n",
260
+ " warnings.warn(smsg, UserWarning)\n"
261
+ ]
262
+ }
263
+ ],
264
+ "source": [
265
+ "from xgboost import XGBClassifier, XGBRegressor\n",
266
+ "\n",
267
+ "model = XGBRegressor(n_estimators=5000,\n",
268
+ " learning_rate=0.02,\n",
269
+ " device=\"cuda\",\n",
270
+ " tree_method=\"hist\",\n",
271
+ " subsample=0.5,\n",
272
+ " objective='binary:logistic',\n",
273
+ " #colsample_bytree=0.5,\n",
274
+ " #reg_alpha=0,\n",
275
+ " #max_depth=5\n",
276
+ " )\n",
277
+ "\n",
278
+ "model.fit((X_train), Y_train)\n",
279
+ "pred1 = model.predict(X_test)\n",
280
+ "print((labels_test == (pred1>0.5)).sum()/labels_test.size)"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": 10,
286
+ "id": "c283f121-e9c1-450d-8527-2334477f9346",
287
+ "metadata": {},
288
+ "outputs": [],
289
+ "source": [
290
+ "model.save_model(\"xgboost_params.json\")"
291
+ ]
292
+ },
293
+ {
294
+ "cell_type": "code",
295
+ "execution_count": 11,
296
+ "id": "97c19677-00ec-4e23-8b5c-5916078c420e",
297
+ "metadata": {},
298
+ "outputs": [
299
+ {
300
+ "data": {
301
+ "image/png": "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",
302
+ "text/plain": [
303
+ "<Figure size 640x480 with 1 Axes>"
304
+ ]
305
+ },
306
+ "metadata": {},
307
+ "output_type": "display_data"
308
+ }
309
+ ],
310
+ "source": [
311
+ "plt.plot(model.feature_importances_)\n",
312
+ "for i in range(1,5):\n",
313
+ " plt.axvline(i*55, c=\"r\")\n",
314
+ "#plt.axhline(0,c=\"r\")\n",
315
+ "#plt.axvline(30, c=\"g\")\n",
316
+ "#plt.axvline(30+130, c=\"g\")"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": 12,
322
+ "id": "22fb4073-ec59-4157-bef9-15902e1698d5",
323
+ "metadata": {},
324
+ "outputs": [
325
+ {
326
+ "name": "stdout",
327
+ "output_type": "stream",
328
+ "text": [
329
+ "(array([0.95674822, 0.95139442]), array([0.93418619, 0.96825765]), array([0.94533261, 0.95975197]), array([6488, 8632]))\n",
330
+ "0.9536375661375661\n"
331
+ ]
332
+ }
333
+ ],
334
+ "source": [
335
+ "import sklearn\n",
336
+ "pred1 = model.predict(X_test)\n",
337
+ "#pred=pred<0.5\n",
338
+ "\n",
339
+ "print(sklearn.metrics.precision_recall_fscore_support(labels_test, pred1>0.5))\n",
340
+ "print((labels_test == (pred1>0.5)).sum()/labels_test.size)"
341
+ ]
342
+ }
343
+ ],
344
+ "metadata": {
345
+ "kernelspec": {
346
+ "display_name": "Python 3 (ipykernel)",
347
+ "language": "python",
348
+ "name": "python3"
349
+ },
350
+ "language_info": {
351
+ "codemirror_mode": {
352
+ "name": "ipython",
353
+ "version": 3
354
+ },
355
+ "file_extension": ".py",
356
+ "mimetype": "text/x-python",
357
+ "name": "python",
358
+ "nbconvert_exporter": "python",
359
+ "pygments_lexer": "ipython3",
360
+ "version": "3.11.2"
361
+ }
362
+ },
363
+ "nbformat": 4,
364
+ "nbformat_minor": 5
365
+ }