-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPJT_partie_Joris.py
483 lines (375 loc) · 15.9 KB
/
PJT_partie_Joris.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# -*- coding: utf-8 -*-
"""Copie de ProjetAudio
Automatically generated by Colaboratory.
Original file is located at
https://colab.research.google.com/drive/1HwhjlIGTzxMxlEHPYbmknsy97qDpiGbf
#Configuration de l'environnement de travail
"""
#!rm -rf /content/melspectrogram/ #supprime le dossier melspectrogram si problèmes
!pip install librosa # installation de la librairie librosa
!git clone https://github.com/Jakobovski/free-spoken-digit-dataset #téléchargement du jeu de données
!mkdir /content/melspectrogram #création du dossier qui contiendra les mel-spectrogrammes
"""###Chargement des chemins de fichiers
Pour éviter d'avoir à recalculer constamment les mel-spectrogrammes, on les calcule une fois et on les sauvegarde dans le dossier melspectrogram. On commence par charger les chemins de fichiers.
"""
import glob # librairie spécialisée dans la recherche de chemin
list_of_files = glob.glob("free-spoken-digit-dataset/recordings/*") #permet d'obtenir le chemin relatif de tous les fichiers du dossier recordings
print(list_of_files[:2])
n_files = len(list_of_files) # nombres de fichiers audios
print(n_files)
"""###Exemple librairie librosa
On peut charger les fichiers audio au format .wav
"""
import librosa
y, sr = librosa.load(list_of_files[3], sr= 8000) #y est le signal sous forme d'array numpy, sr est le taux d'échantillonage (vaut 8khz d'après les indications github)
print(y, sr)
"""On peut calculer certaines caractéristiques des signaux audios, ici le melspectrogramme"""
import numpy as np
sp = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128) # calcul du melspectrogramme
s_dB = librosa.power_to_db(sp, ref=np.max) #conversion de l'amplitude en dB pour une meilleure vi
print(type(s_dB))
"""Vous pouvez écouter un signal audio via la commande suivante"""
from IPython.display import Audio
Audio(y,rate=sr) # permet de lire un fichier audio sous forme d'array numpy dans un notebook jupyter ou dans colab
"""###Exemple d'affichage de mel-spectrogramme"""
import matplotlib.pyplot as plt
import librosa.display
import numpy as np
def plot_spec(S_dB):
plt.figure(figsize=(10, 4))
librosa.display.specshow(S_dB, x_axis='time',
y_axis='mel', sr=sr)
plt.colorbar(format='%+2.0f dB')
plt.title('Mel-frequency spectrogram')
plt.tight_layout()
plt.show()
plot_spec(s_dB)
"""###Prétraitement et enregistrement des fichiers audios en mel-spectrogramme
Définition des fonctions utilisées pour le prétraitement
"""
n_mels=128
sr = 8000
def compute_spectrogram(path):
"Calcule le melspectrogramme du fichier audio situé à path dans le repertoire de fichiers"
file_name = os.path.basename(path)
s , _ = librosa.load(path, sr= sr) # sr est le taux d'échantillonnage du signal.
melspec = librosa.feature.melspectrogram(y=s, sr=sr, n_mels=n_mels)
melspec_db = librosa.power_to_db(melspec, ref=np.max)
melspec_db_image = melspec_db.reshape(melspec_db.shape[0],melspec_db.shape[1],1) # on rajoute la dimension 1 à la fin pour forcer la représentation en tant qu'image (hauteur, largeur, nombre de couleurs ici égale à 1)
return (path,melspec_db_image)
def get_duration(spec):
"Renvoie la dimension correspondant à l'axe temporel d'un melspectrogramme"
return spec.shape[1]
def get_longest_duration(list_path_spec):
"Renvoie la dimension temporelle du melspectrogramme le plus long"
list_time = [get_duration(spec) for path, spec in list_path_spec ]
return max(list_time)
def save_melspec(path_melspec):
"""
Permet d'enregistrer les spectrogrammes dans le dossier melspectrogram
"""
path, melspec = path_melspec
file_name = os.path.basename(path)
melspec_path = os.path.join("/content/melspectrogram", os.path.splitext(file_name)[0])
np.save(melspec_path, melspec)
#print("{} saved".format(melspec_path))
"""Le prétraitement et l'enregistrement des melspectrogrammes prend quelques minutes"""
import os
from tqdm.autonotebook import tqdm # bar de remplissage pour visualiser l'évolution du calcul et de l'enregistrement des spectrogrammes
import sys
import tensorflow as tf
n=n_files
print("Conversion des fichiers audio en melspectrogrammes")
list_spec = []
for path, spec in tqdm(map(compute_spectrogram, list_of_files[:n]), total=n):
list_spec.append((path, spec))
max_time = get_longest_duration(list_spec)
print("La plus longue dimension temporelle est {}".format(max_time))
def spec_padding(path_data):
path, spec = path_data
min_spec = np.min(spec)
spec_padded = np.pad(spec, ((0,0),(0,max_time-spec.shape[1]),(0,0)),"constant",constant_values=((min_spec,min_spec),(min_spec,min_spec),(min_spec,min_spec)))
return (path, spec_padded)
print("Traitement des melspectrogrammes pour qu'ils aient la même durée")
list_padded_spec = []
for path, spec_padded in tqdm(map(spec_padding, list_spec[:n]), total=n):
list_padded_spec.append((path,spec_padded))
print("Traitement des melspectrogrammes pour qu'ils aient la même durée")
for spec in tqdm(map(save_melspec, list_padded_spec[:n]), total=n):
pass
"""# Votre travail
## Importation des fichiers
"""
import os
import random
noms_fichiers = os.listdir('melspectrogram/')
def importer(nom):
data = np.load('melspectrogram/'+nom)
infos = nom[0:-4]
infos = infos.split("_")
infos[0] = int(infos[0]) # Conversion des strings en nombres
infos[2] = int(infos[2])
if infos[1] == 'jackson':
infos[1] = [1,0,0,0]
elif infos[1] == 'nicolas':
infos[1] = [0,1,0,0]
elif infos[1] == 'theo':
infos[1] = [0,0,1,0]
elif infos[1] == 'yweweler':
infos[1] = [0,0,0,1]
return data, infos
"""## Création du modèle
### Fonctions de calcul appelées dans la fonction d'optimisation
"""
# Fonction calculant la moyenne de la dérivée de la variation de précision (vitesse d'évolution moyenne)
def atteinte_90(history):
if history.history['acc'][-1] < 0.9:
return
i = len(history.history['acc'])-1
while history.history['acc'][i] > 0.9:
i -= 1
return i
# Fonction qui affiche le nombre d'éléments dans chaque classe (on veut 1/4 des données)
# Inutilisée par la suite (mais peut être utile)
def verif_repartition(y_train):
un = 0
deux = 0
trois = 0
quatre = 0
for i in range(len(y_train)):
if y_train[i][0] == 1:
un += 1
elif y_train[i][1] == 1:
deux += 1
elif y_train[i][2] == 1:
trois += 1
elif y_train[i][3] == 1:
quatre += 1
print('REPARTITION DES CLASSES')
print ('1 :'+str(un)+'\n2 :'+str(deux)+'\n3 :'+str(trois)+'\n4 :'+str(quatre))
# Création des données d'entrainement
def creer_X_Y(noms_fichiers):
X,Y = [],[]
for i in range(len(noms_fichiers)):
data,infos = importer(noms_fichiers[i])
X.append(data)
Y.append(infos[1])
return np.asarray(X),np.asarray(Y)
"""### Fonction qui crée un modèle avec des paramètres"""
import keras
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.models import Sequential
from keras.layers import Dense, Activation, Flatten, Dropout
from keras.optimizers import SGD
from sklearn.model_selection import train_test_split
def nouveau_modele(nb_conv2D,epoques,BS,pourcentage_test):
X,Y = creer_X_Y(noms_fichiers)
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=pourcentage_test)
# create model
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(128, 36, 1)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# Convolutions
for i in range(nb_conv2D):
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(lr=0.01), metrics=['accuracy'])
history = model.fit(np.asarray(x_train), np.asarray(y_train), epochs=epoques, batch_size=BS, verbose = 1)
evaluate = model.evaluate(np.asarray(x_test),np.asarray(y_test))
prediction = model.predict(x_test)
dernier_atteinte_90 = atteinte_90(history)
# Dans le return il y a un _ à la place de xtest, ytest et prediction, version précédente qui était trop gourmande
# je n'ai pas eu le temps de changer la suite donc cette solution de fortune est moins gourmande mais inutile (histoire d'index appelées dans la suite)
return _, _, model, history.history, evaluate, _, dernier_atteinte_90
"""## Test itératif des critères"""
import numpy as np
from google.colab import files
def opti_gourmand(iteration):
max_conv2D = 4 # doit rester inférieur à 8 (experience)
max_epoques = 300
max_BS = 0.9
max_pourcentage_test = 0.8 # Valeurs sur le site de M.Gibaru : [0.6,0.8]
resultats = []
i = -1
compteur = 0
for nb_conv2D in np.arange(2,max_conv2D,2):
i += 1
j = -1
resultats.append([])
for epoques in np.arange(50,max_epoques,(max_epoques-50)//3):
j += 1
k = -1
resultats[i].append([])
for BS in np.arange(0.04,max_BS,(max_BS-0.01)/4):
k += 1
resultats[i][j].append([])
for pourcentage_test in np.arange(0.6,max_pourcentage_test,(max_pourcentage_test-0.1)/3):
resultats[i][j][k].append(nouveau_modele(int(nb_conv2D),int(epoques),int(BS*pourcentage_test*2000),pourcentage_test))
return resultats
resultats = opti_gourmand(3)
def opti_simple():
ntest = 4
max_conv2D = 7
max_epoques = 200
max_BS = 0.9
max_pourcentage_test = 0.95
res_conv2D = []
res_epoques = []
res_BS =[]
res_pourcentage_test = []
for i in np.arange(1,max_epoques,200//6):
res_epoques.append(nouveau_modele(4,i,32,0.8))
print(str(i))
return res_epoques
# resultats = opti_simple()
"""# Recherche d'un optimum en fonction de différents critères"""
def convergence_la_plus_rapide_gour():
index = []
min_dernier_atteinte_90 = resultats[0][0][0][0][6]
for a in range(len(resultats)):
for b in range(len(resultats[a])):
for c in range(len(resultats[a][b])):
for d in range(len(resultats[a][b][c])):
if resultats[a][b][c][d][6] < min_dernier_atteinte_90: # Si la valeur de dernier_atteinte_90 pour le jeu de paramètres choisis est la plus basse, on conserve l'index correspondant de la liste resultats (il indique le jeu optimal pour ce critère)
index = [(a,b,c,d)]
min_dernier_atteinte_90 = resultats[a][b][c][d][6]
elif resultats[a][b][c][d][6] == min_dernier_atteinte_90: # On peut trouver plusieurs possibilités
index.append((a,b,c,d))
print('On obtient la convergence la plus rapide avec le(s) jeu(x) de paramètres : '+str(index))
print('Avec la dernière atteinte de 90% de précision au bout de '+str(min_dernier_atteinte_90)+' époques !')
return
# convergence_la_plus_rapide_gour()
print('')
def meilleur_acc_gour(): # Fonction qui affiche l'index du jeu de paramètre idéal et la valeur maximale de précision atteinte
index = []
meilleur_acc = 0
for a in range(len(resultats)):
for b in range(len(resultats[a])):
for c in range(len(resultats[a][b])):
for d in range(len(resultats[a][b][c])):
if resultats[a][b][c][d][4][1] > meilleur_acc:
index = [(a,b,c,d)]
meilleur_acc = resultats[a][b][c][d][4][1]
elif resultats[a][b][c][d][4][1] == meilleur_acc: # On peut trouver plusieurs possibilités
index.append((a,b,c,d))
print('On obtient la meilleure précision avec le(s) jeu(x) de paramètres : '+str(index))
print('Avec une précision de '+str(meilleur_acc)+' !')
return
print('On obtient la meilleure précision avec le(s) jeu(x) de paramètres : '+str(index))
print('Avec une précision de '+str(meilleur_acc)+' !')
return
meilleur_acc_sim()
# meilleur_acc_gour()
print('')
def meilleur_loss():
index = []
meilleur_loss = 100
for a in range(len(resultats)):
for b in range(len(resultats[a])):
for c in range(len(resultats[a][b])):
for d in range(len(resultats[a][b][c])):
if resultats[a][b][c][d][4][0] < meilleur_loss:
index = [(a,b,c,d)]
meilleur_loss = resultats[a][b][c][d][4][1]
elif resultats[a][b][c][d][4][1] == meilleur_loss: # On peut trouver plusieurs possibilités
index.append((a,b,c,d))
print('On obtient le meilleur loss avec le(s) jeu(x) de paramètres : '+str(index))
print('Avec un loss de '+str(meilleur_loss)+' !')
return
# meilleur_loss_gour()
print('')
def le_plus_overfit_gour():
index = []
max_overfit = 0
for a in range(len(resultats)):
for b in range(len(resultats[a])):
for c in range(len(resultats[a][b])):
for d in range(len(resultats[a][b][c])):
overfit = abs(resultats[a][b][c][d][3]['acc'][-1]-resultats[a][b][c][d][4][1])
if overfit > max_overfit:
index = [(a,b,c,d)]
max_overfit = overfit
elif overfit == max_overfit: # On peut trouver plusieurs possibilités
index.append((a,b,c,d))
print('On obtient le plus grand overfitting avec le(s) jeu(x) de paramètres : '+str(index))
print("Avec un critère d'overfitting de "+str(max_overfit)+' !')
return
# le_plus_overfit_gour()
"""### Graphiques"""
import matplotlib.pyplot as plt
# Tracés des effets des différentes variations des 4 paramètres avec la meilleure config de précision
# Variation du nombre d'époques (cf avant : C2D=2 ; epochs = 148 idéalement ? ; BS = 0,27 ; %test = 0.2)
epoques = []
accuracy = []
for i in range(len(resultats[0])):
accuracy.append(resultats[0][i][1][0][4][1]) # Valeur de la précision
epoques.append(50+i*(200-1)//3)
plt.plot(epoques,accuracy)
plt.xlabel("nombre d'époques")
plt.ylabel('accuracy')
plt.show()
# Variation du Batch Size (cf avant : C2D=2 ; epochs = 148 ; BS = 0,27 ? ; %test = 0.2)
batchsize = []
accuracy = []
for i in range(len(resultats[0][2])):
accuracy.append(resultats[0][2][i][0][4][1]) # Valeur de la précision
batchsize.append((0.01+i*(0.8-0.01)/3)*0.2*2000)
plt.plot(batchsize,accuracy)
plt.xlabel('Batch Size')
plt.ylabel('accuracy')
plt.show()
# Variation du %test (cf avant : C2D=2 ; epochs = 148 ; BS = 0,27 ; %test = 0.2 ?)
pourc_test = []
accuracy = []
for i in range(len(resultats[0][2][1])):
accuracy.append(resultats[0][2][1][i][4][1]) # Valeur de la précision
pourc_test.append(0.2+i*(0.9-0.2)/3)
plt.plot(pourc_test,accuracy)
plt.xlabel('pourcentage utilisé pour tester')
plt.ylabel('accuracy')
plt.show()
"""## Matrice de confusion
### Fonction qui crée la matrice de confusion
"""
import seaborn as sn
import pandas as pd
import matplotlib.pyplot as plt
def mat_conf(cm):
df_cm = pd.DataFrame(cm, index = [i for i in ["jackson","nicolas","theo","yweweler"]],
columns = [i for i in ["jackson","nicolas","theo","yweweler"]])
plt.figure(figsize = (10,7))
return sn.heatmap(df_cm, annot=True,fmt='g')
"""### Adaptation des arrays de prédiction retournés par le modèle au bon format pour la matrice de confusion"""
# Fonction qui prend la liste sous la forme [[0.000001,0.000001,0.9999,0.0001],...] et qui retourne [[0,0,1,0],...]
def adapter_Y_pred(Y_pred):
for i in range(len(Y_pred)):
imax = list(Y_pred[i]).index(max(list(Y_pred[i])))
Y_pred[i][imax]= 1
for k in range(len(Y_pred[i])):
if Y_pred[i][k] != 1:
Y_pred[i][k]=0
# Fonction qui prend un array de résultats prédits sous la forme [[0,0,1,0],...] et qui retourne [3,...]
def adapter(L):
LS = []
for i in range(len(L)):
LS.append(list(L[i]).index(max(list(L[i]))))
return LS
Y_test_mat = adapter(y_test)
Y_pred_mat = adapter(prediction)
"""### Création de la matrice de confusion"""
from sklearn import metrics
cm = confusion_matrix(Y_test_mat,Y_pred_mat)
mat_conf(cm)
mat_conf(matrice)
"""## Schéma du modèle"""
from keras.utils import plot_model
plot_model(model, to_file='model.png',show_shapes=True)