From 9bf8b6375d7306a678e944bc03fa6fa4257e1430 Mon Sep 17 00:00:00 2001 From: RawCooked Date: Mon, 5 May 2025 11:31:38 +0200 Subject: [PATCH 1/2] changed html in django --- .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 213 bytes .../__pycache__/admin.cpython-313.pyc | Bin 0 -> 257 bytes .../__pycache__/apps.cpython-313.pyc | Bin 0 -> 601 bytes .../__pycache__/models.cpython-313.pyc | Bin 0 -> 254 bytes .../__pycache__/views.cpython-313.pyc | Bin 0 -> 1178 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 224 bytes .../templates/chat_interface.html | 2 +- .../__pycache__/settings.cpython-313.pyc | Bin 2752 -> 3021 bytes .../prj_api/__pycache__/urls.cpython-313.pyc | Bin 1167 -> 613 bytes 9 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/__init__.cpython-313.pyc create mode 100644 Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/admin.cpython-313.pyc create mode 100644 Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/apps.cpython-313.pyc create mode 100644 Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/models.cpython-313.pyc create mode 100644 Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/views.cpython-313.pyc create mode 100644 Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/migrations/__pycache__/__init__.cpython-313.pyc diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/__init__.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37ae2ed41fa6735c9aa57c8480dd179ee139c5be GIT binary patch literal 213 zcmey&%ge<81V5W4GC=fW5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa|LJvsFxJacWU< zOkrkDW?qa-esXDUYFF^Y!wq)oLW>IQ<#~PnHS@d zpIn-onpaXBJT6H78ua}!H4lkC%v?=dJ8u>m;%z9UIz literal 0 HcmV?d00001 diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/apps.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/apps.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f865577ddb1ab9d872288d411e6973feddb76a3 GIT binary patch literal 601 zcmZWm&ubJh6i#Mlw`=R7ZB?4oY+@3bgv6#r64NePX}j*dV{XD{%!y1%Rfvqq=EbYTi_aeAQ&twLpO5-8m2+wP zhoTr%PQ4Ud=JnP;>bH&h3pz>H>JC83W*nei2k^>D27D9Xv|@6Vxdkv5#yTlVUMip7 z%K4a8(gE`y_+0oQ3FP`NfOVlpV9psasvNffrsGRogl21f^o)M6+*o=l{Cjk$vTDXl zXX&wUlWIhd6@kGkcyH8{XO0g19da$zJh1kd*7T5NANPjKcBwW~U|P`s+oPUp`+9D| z;+7`N$#%W@gf8zNd`s?KZah98n%md;lQgb3R$~le6IR*CL;VeL)1$icyqVMsv+cvM aMSI7apE1VxJ9_e~9pRnN^WVt3rRpy^jHzt^ literal 0 HcmV?d00001 diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/models.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/models.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b9908075ea47a66242dfe04eb1b860a6914c446 GIT binary patch literal 254 zcmey&%ge<81V5W4GHihKV-N=hn4pZ$0zk%8hG2$ZMsEf$#v(=qhIA%P=9eI8O~zYn zx%nxnImLdOOt&~wvJ&&s^Yv1aikN|tD;Yk6)Z8j^wu%WYPAw{qDa_2t%!_f!PcF?( z%_}L6anCHtC{2oS&kv4w^o$QE%FjwoE{SmjVwco{ocv0VD&53_f*7a76yuiIWZ8Y=oM7n;;;d-OLJ1~ia3ByU8mBPZ%#%C6*;9 z>>%PuLvO(}zIb%dU*V@bk`zi7XbI#kGG*f`0Pq0-93SO>&8C%kO&N-&(ir9nWm63m zGZU)UvLm}zZX~_pCxE3`swJCQQ>!Uv?qfO3See$K6R)g<^x;s2$9YAWR`E?#XpP~~ zdn?;#>W$$oLTR~d=6Q^yk^PgsTbkJ}&20EPrTKL|Eg51vzOFwXpMG@y=kps= zY3W!xSxG0SUuf#Q{sO2I`Ssjh0Td=4E<9XF%cp*C{@VO)dAD5OF4zCkx6WBRcosdh>by;E!jvrf1XKp~oNWDe`=_59ETj z2jq;_=hcF$N)B?y4s-@ruf;AV)JbSOn9AU4e*iMgO~?^pmpjMDkof2mBK|1iqm9Lz V-%}(>dII)81t>P{wB#AY&>+I)f&o-%5reCLr%KNa|L-vsFxJacWU< zOkrkDW?qa-esXDUYF
-

Talk to Mistral 7B

+

Talk to BeeBay !

{% csrf_token %} diff --git a/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/settings.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/settings.cpython-313.pyc index 53ca889198428257f4f10555ea0dbd597826137a..5ae0918b31a797d8338cc139eec8e939dce21c9c 100644 GIT binary patch delta 606 zcmZWlJ#W)c6n)RJWBbK+?Zip!B$V)>ihvp?m0Cd&NT^LhL_n%<%T%?53bjE%s+UYz zYKfJhktMpaz{Hl3g+GAg!V;OKe*no!CpKPMma12}_voB^?$goxp8kva8z>; zkTpza7$z9%pn%GB12me18FsDDClGQlh%dolrsNu~U`UmD_E-u`YC;+^%$A+nz$$YU zOw(XPj=5~epUuMAyi&mqPctw}vv8GKEQHNE2SqBuHJaazm9CG9_#vKqHjtcNzuoWb zI0O4>yTAA9?UZy|-QCVk`_2EIzs1#3A-+9Os`nPk)up@TYI$j~MEuX(H#1CLz8k%W zeZW}u|M2^nLE-Y=>5n#q=NKEKuklsPl?wi;_+Xyv_Cf;dkJg(j+Z%2xc7lJka`>-JyMY7Vvj^|B&(iqVwi_pfqv6dCnS;NJZ+LA8pqZ-BoxMcJ`!RU7a%ht nNT2l-24)S94Lc|-9~;Yoet&FQCrWXGgd1Aq&ykP3!{Yn{;_8<( delta 306 zcmW-cKTE?<6vf|7()@YpOVT85Qnj-NF$wMpq7?)ww6|`8V|A132QWB_OL*VF-6^As zUqH}B9NkF32}+sAZ1K^~dH{zXP!3ZR@g0%@Kg# z%&Y^@M_DQ#>>ZgpFD}RF-t=hy>|}B*Kb@Lys+yp570MgFJ(zpUn?S|qCUZp9`Ut{G cEI1Ff%3GxJhYxI<#Y1=xLb>kV8=1QN1L9{x;{X5v diff --git a/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/urls.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/urls.cpython-313.pyc index 94cc4c305be9f4f850b5222e9425cbc60e2a3d5a..747406770ce33d8a8b478aa2f0efbe7836972250 100644 GIT binary patch delta 451 zcmeC@e9BV)nU|M~0SJCJOJwLUGB7*_abSQ0%J{qt$e79y%n;1z&EUmY#HavbGkG(4 zF&8m=u@td@`OMy|UTj5d3JfvKN({j)F^oZcFoO_ukN|=WWYvRtrc4k)utwGxwjd!C zMPN=aTQIvNGgt*j3=7Z#PE(+BK>(&(pSg%DolBGZB}h<{@fK@hN^WMJCetmJg2a-H zTkM&6$vLGdsUVrM%+&JYDz?NFL!b)%TMV~2lQR-a;z7bdX_mai+|(*I{oMSN)SN1A zUl3KSS6Y-)?5D{+xq(?%Q^*%+Vrp(;NoI1sPkwr4a$-&q8_?EUEXA26skc}_YKuUj zH+cthTa+-60di}x2ax!{%*e=imqFn^gX&!dm5*!;tehPZ6HKRDO|+VBKhgd&i}Fnt tjt-%Y(Ej+&_yyJ%S@dsm@N`5>ET2((SzPxrhu#NvR(_^N?jk{;VE}4aV$c8p literal 1167 zcmb7EO;6N77@l@pcIgTjN(ohipttbPhYuzVpuWKF>QdJ)4-&03WBHF9&ZM0DKpJ z>d~yg***s!K@SknlX~)ov@R1F3f$OetSdw*uu|f6m8cNd%5~6FZF%!TO?EzSPM+f$ zb>$Kj`^IdQ?{0RbGFGpdGHDH4`nda!Cu>`q521&XK{(8a%R-#M0VXgdJC2)%e8xM- zV}_9*#|vm|bJuWH=2yYKml&m#3z7|BV}SE^28jS>hFv zi?Rjjya5+|AG!$);}jESK{y~dhVd@oa=bUL$@uK>qr z7A9_t?sNq1=-N``Qaab?#{3c1zp211Ktu>J3dOaY2b}AF)QEh;rH&w((f?4imUvO- zhslsPp{OUUi4(5-vsN?)aw+_HL@t`q;h<`zRko`<4ns7&7Fp%a7ESqQwfzVWP2Rw| zQbz;|-j1$oKg7+{rCfFWI7~QDM8|cRC_J7wt4(`j#j=@$z4jyQqlgv+kM;4q={WrQ zI8HuUDdt8Q3HyYMi}AMO`D^ z&0Du)>}L_WOD^)N;*rt?{&UihB Date: Mon, 12 May 2025 00:22:12 +0100 Subject: [PATCH 2/2] add XIA to the notebook --- .../Notebooks/gos_s_cnn_lstm.py | 570 ++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 Act/Singing-talent-detection/Notebooks/gos_s_cnn_lstm.py diff --git a/Act/Singing-talent-detection/Notebooks/gos_s_cnn_lstm.py b/Act/Singing-talent-detection/Notebooks/gos_s_cnn_lstm.py new file mode 100644 index 0000000..b1773cb --- /dev/null +++ b/Act/Singing-talent-detection/Notebooks/gos_s_cnn_lstm.py @@ -0,0 +1,570 @@ +# -*- coding: utf-8 -*- +"""GOS-S-CNN-LSTM.ipynb + +Automatically generated by Colab. + +Original file is located at + https://colab.research.google.com/drive/14XFNU3HBngF5j3a97y7SFmBYDy6pPxrw + +**CNN V2** +""" + +# -------------------------------------------------------------------------------- +# 📌 MONTAGE & IMPORTS +# -------------------------------------------------------------------------------- +from google.colab import drive +drive.mount('/content/drive', force_remount=True) + +# Installer les dépendances nécessaires +!pip install librosa==0.10.1 +!pip install numpy --upgrade --force-reinstall +!pip install -U scikit-learn +!pip install librosa +!pip install matplotlib +!pip install tensorflow==2.4.0 # Version stable pour compatibilité + +import os +import numpy as np +import librosa +import matplotlib.pyplot as plt +import tensorflow as tf +from sklearn.model_selection import train_test_split +from sklearn.utils import class_weight +from tensorflow.keras import layers, models +from tensorflow.keras.optimizers import Adam +from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau +from collections import Counter +from imblearn.over_sampling import RandomOverSampler + +# -------------------------------------------------------------------------------- +# 📂 PARAMÈTRES +# -------------------------------------------------------------------------------- +DATA_PATH = "/content/drive/MyDrive" +SAMPLE_RATE = 22050 +DURATION = 3 +SAMPLES_PER_TRACK = SAMPLE_RATE * DURATION +FIXED_TIME_STEPS = 130 +N_MELS = 128 +MODEL_PATH = "/content/drive/MyDrive/model_belle_voix_simplified.h5" +X_TEST_PATH = "/content/drive/MyDrive/X_test.npy" +Y_TEST_PATH = "/content/drive/MyDrive/y_test.npy" + +# -------------------------------------------------------------------------------- +# 🎵 EXTRACTION MEL AVEC AUGMENTATION +# -------------------------------------------------------------------------------- +def extract_features_with_augmentation(file_path, max_len=SAMPLES_PER_TRACK, fixed_time_steps=FIXED_TIME_STEPS): + try: + y, sr = librosa.load(file_path, sr=SAMPLE_RATE, duration=DURATION) + if len(y) < max_len: + y = np.pad(y, (0, max_len - len(y)), mode='constant') + else: + y = y[:max_len] + + noise = y + 0.005 * np.random.randn(len(y)) + features = [] + for y_aug in [y, noise]: + mel = librosa.feature.melspectrogram(y=y_aug, sr=sr, n_mels=N_MELS) + mel_db = librosa.power_to_db(mel, ref=np.max).astype(np.float32) + if mel_db.shape[1] < fixed_time_steps: + mel_db = np.pad(mel_db, ((0, 0), (0, fixed_time_steps - mel_db.shape[1])), mode='constant') + else: + mel_db = mel_db[:, :fixed_time_steps] + if not np.isnan(mel_db).any(): + features.append(mel_db) + return features if features else None + except Exception as e: + print(f"Erreur lors du traitement de {file_path}: {e}") + return None + +# -------------------------------------------------------------------------------- +# 📅 CHARGEMENT DES DONNÉES +# -------------------------------------------------------------------------------- +def load_data(fixed_time_steps=FIXED_TIME_STEPS, max_files_per_class=None): + X, y = [], [] + label_map = {'non_belle_voix': 0, 'belle_voix': 1} + for label_name, label in label_map.items(): + folder = os.path.join(DATA_PATH, label_name) + file_count = 0 + for fname in os.listdir(folder): + if fname.endswith(".wav"): + if max_files_per_class is not None and file_count >= max_files_per_class: + break + fpath = os.path.join(folder, fname) + feats = extract_features_with_augmentation(fpath, fixed_time_steps=fixed_time_steps) + if feats: + for feat in feats: + if feat.shape == (N_MELS, fixed_time_steps): + X.append(feat) + y.append(label) + else: + print(f"Ignore {fpath}: forme inattendue {feat.shape}") + file_count += 1 + X = np.array(X, dtype=np.float32) + y = np.array(y) + print(f"Données chargées avec X shape: {X.shape}, y shape: {y.shape}") + return X, y + +# -------------------------------------------------------------------------------- +# ⚖️ ÉQUILIBRAGE DES DONNÉES +# -------------------------------------------------------------------------------- +def balance(X, y): + X_flat = X.reshape((X.shape[0], -1)) + ros = RandomOverSampler(random_state=42) + X_res, y_res = ros.fit_resample(X_flat, y) + X_res = X_res.reshape((-1, X.shape[1], X.shape[2])).astype(np.float32) + return X_res, y_res + +# -------------------------------------------------------------------------------- +# 🧼 PRÉTRAITEMENT +# -------------------------------------------------------------------------------- +def preprocess(X, y): + for i in range(X.shape[0]): + X[i] = (X[i] - X[i].min()) / (X[i].max() - X[i].min() + 1e-8) + X = X[..., np.newaxis] + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42) + class_weights = class_weight.compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) + return X_train, X_test, y_train, y_test, dict(enumerate(class_weights)) + +# -------------------------------------------------------------------------------- +# 🧐 CONSTRUCTION DU MODÈLE CNN (SANS GRU) +# -------------------------------------------------------------------------------- +def build_advanced_cnn(input_shape): + model = models.Sequential([ + layers.Input(shape=input_shape), + layers.Conv2D(64, (3,3), activation='relu', padding='same', name='conv1'), + layers.BatchNormalization(), + layers.MaxPooling2D((2,2)), + layers.Conv2D(128, (3,3), activation='relu', padding='same', name='conv2'), + layers.BatchNormalization(), + layers.MaxPooling2D((2,2)), + layers.Conv2D(256, (3,3), activation='relu', padding='same', name='conv3'), + layers.BatchNormalization(), + layers.MaxPooling2D((2,2)), + layers.Flatten(), + layers.Dense(256, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01)), + layers.Dropout(0.4), + layers.Dense(1, activation='sigmoid', name='output') + ]) + model.compile(optimizer=Adam(learning_rate=0.0005), + loss='binary_crossentropy', + metrics=['accuracy', tf.keras.metrics.Precision(name='precision'), + tf.keras.metrics.Recall(name='recall'), + tf.keras.metrics.AUC(name='auc')]) + return model + +# -------------------------------------------------------------------------------- +# 🚀 PIPELINE D'ENTRAÎNEMENT +# -------------------------------------------------------------------------------- +print("🔄 Chargement des données...") +X, y = load_data(fixed_time_steps=FIXED_TIME_STEPS, max_files_per_class=1000) +print(f"🔎 Avant équilibrage : {Counter(y)}") +X, y = balance(X, y) +print(f"✅ Après équilibrage : {Counter(y)}") +X_train, X_test, y_train, y_test, class_weights = preprocess(X, y) +print(f"📀 Shape train: {X_train.shape}, test: {X_test.shape}") + +# Entraînement du modèle +model = build_advanced_cnn(X_train.shape[1:]) +early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) +lr_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5, verbose=1) + +history = model.fit( + X_train, y_train, + validation_split=0.3, + epochs=50, + batch_size=16, + class_weight=class_weights, + callbacks=[early_stop, lr_scheduler], + shuffle=True +) + +# Sauvegarder le modèle et les données de test +model.save(MODEL_PATH) +np.save(X_TEST_PATH, X_test) +np.save(Y_TEST_PATH, y_test) +print(f"✅ Modèle sauvegardé à {MODEL_PATH}") +print(f"✅ Données de test sauvegardées à {X_TEST_PATH} et {Y_TEST_PATH}") + +# -------------------------------------------------------------------------------- +# 📊 ÉVALUATION DU MODÈLE +# -------------------------------------------------------------------------------- +test_metrics = model.evaluate(X_test, y_test, return_dict=True) +print(f"🎯 Test metrics: Accuracy: {test_metrics['accuracy']:.4f}, " + f"Precision: {test_metrics['precision']:.4f}, " + f"Recall: {test_metrics['recall']:.4f}, " + f"AUC: {test_metrics['auc']:.4f}") + +# Analyse des erreurs +y_pred = (model.predict(X_test) > 0.5).astype(int) +errors = np.where(y_pred.flatten() != y_test)[0] +print(f"Indices des échantillons mal classés dans l'ensemble de test : {errors}") +print(f"Nombre total d'erreurs : {len(errors)}") + +# -------------------------------------------------------------------------------- +# 📈 VISUALISATION DES MÉTRIQUES D'ENTRAÎNEMENT +# -------------------------------------------------------------------------------- +plt.figure(figsize=(12, 5)) +plt.subplot(1, 2, 1) +plt.plot(history.history['accuracy'], label='Train Accuracy') +plt.plot(history.history['val_accuracy'], label='Validation Accuracy') +plt.title('Model Accuracy') +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.legend() +plt.subplot(1, 2, 2) +plt.plot(history.history['loss'], label='Train Loss') +plt.plot(history.history['val_loss'], label='Validation Loss') +plt.title('Model Loss') +plt.xlabel('Epoch') +plt.ylabel('Loss') +plt.legend() +plt.tight_layout() +plt.show() + +"""xIA""" + +# -------------------------------------------------------------------------------- +# 📌 IMPORTS POUR XAI +# -------------------------------------------------------------------------------- +from google.colab import drive +drive.mount('/content/drive', force_remount=True) + +# Installer les dépendances nécessaires +!pip install opencv-python shap seaborn +!pip install tensorflow==2.4.0 # Assurer la même version que Code 1 + +import numpy as np +import matplotlib.pyplot as plt +import tensorflow as tf +import cv2 +import shap +import seaborn as sns +import os + +# Désactiver le GPU pour éviter les erreurs +os.environ["CUDA_VISIBLE_DEVICES"] = "" + +# Configuration pour des visualisations +plt.style.use('ggplot') +sns.set_palette("deep") +plt.rcParams['font.size'] = 12 +plt.rcParams['axes.titlesize'] = 14 +plt.rcParams['axes.labelsize'] = 12 +plt.rcParams['xtick.labelsize'] = 10 +plt.rcParams['ytick.labelsize'] = 10 +plt.rcParams['legend.fontsize'] = 10 + +# -------------------------------------------------------------------------------- +# 📂 PARAMÈTRES +# -------------------------------------------------------------------------------- +MODEL_PATH = "/content/drive/MyDrive/model_belle_voix_simplified.h5" +X_TEST_PATH = "/content/drive/MyDrive/X_test.npy" +Y_TEST_PATH = "/content/drive/MyDrive/y_test.npy" +N_MELS = 128 +FIXED_TIME_STEPS = 130 + +# -------------------------------------------------------------------------------- +# 🧠 XAI : GRAD-CAM +# -------------------------------------------------------------------------------- +def get_gradcam_heatmap(model, img_array, conv_layer_name): + try: + conv_layer = model.get_layer(conv_layer_name) + except ValueError: + raise ValueError(f"Couche '{conv_layer_name}' introuvable. Couches disponibles : {[layer.name for layer in model.layers]}") + + grad_model = tf.keras.models.Model( + [model.inputs], [conv_layer.output, model.output] + ) + + with tf.GradientTape() as tape: + conv_output, predictions = grad_model(img_array) + class_channel = predictions[:, 0] # Classification binaire (sigmoid) + + grads = tape.gradient(class_channel, conv_output) + pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) + + conv_output = conv_output[0] + heatmap = conv_output @ pooled_grads[..., tf.newaxis] + heatmap = tf.squeeze(heatmap) + + heatmap = tf.maximum(heatmap, 0) / (tf.math.reduce_max(heatmap) + 1e-8) + return heatmap.numpy() + +def superimpose_heatmap(heatmap, img, alpha=0.4): + heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) + heatmap = np.uint8(255 * heatmap) + heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) + + img = img - img.min() + img = img / (img.max() + 1e-8) + img = np.uint8(255 * img) + + superimposed_img = heatmap * alpha + img * (1 - alpha) + superimposed_img = np.uint8(superimposed_img) + return superimposed_img + +# -------------------------------------------------------------------------------- +# 🧠 CHARGEMENT DES DONNÉES ET DU MODÈLE +# -------------------------------------------------------------------------------- +print("🔄 Chargement du modèle et des données...") +model = tf.keras.models.load_model(MODEL_PATH) +X_test = np.load(X_TEST_PATH) +y_test = np.load(Y_TEST_PATH) +print(f"✅ Données chargées : X_test shape {X_test.shape}, y_test shape {y_test.shape}") + +# Recompiler le modèle pour initialiser les métriques +model.compile( + optimizer=tf.keras.optimizers.Adam(learning_rate=0.0005), + loss='binary_crossentropy', + metrics=['accuracy', tf.keras.metrics.Precision(name='precision'), + tf.keras.metrics.Recall(name='recall'), tf.keras.metrics.AUC(name='auc')] +) + +# Initialisation robuste pour Grad-CAM +model.predict(X_test[:10]) # Prédire sur plusieurs échantillons pour forcer l'initialisation +print("✅ Modèle initialisé pour Grad-CAM") + +# Vérifier les couches disponibles +print("Couches du modèle :", [layer.name for layer in model.layers]) + +# -------------------------------------------------------------------------------- +# 🧠 VISUALISATION GRAD-CAM +# -------------------------------------------------------------------------------- +num_samples_to_visualize = 5 +conv_layer_name = 'conv3' +indices_to_visualize = [18] + [np.random.randint(0, len(X_test)) for _ in range(num_samples_to_visualize - 1)] # Inclure l'index 18 + +plt.figure(figsize=(15, num_samples_to_visualize * 3)) +for i, idx in enumerate(indices_to_visualize): + img = X_test[idx, :, :, 0] + img_array = np.expand_dims(X_test[idx], axis=0) + + pred = model.predict(img_array)[0][0] + label_pred = 'belle_voix' if pred > 0.5 else 'non_belle_voix' + label_true = 'belle_voix' if y_test[idx] == 1 else 'non_belle_voix' + + try: + heatmap = get_gradcam_heatmap(model, img_array, conv_layer_name) + superimposed_img = superimpose_heatmap(heatmap, img) + + plt.subplot(num_samples_to_visualize, 2, 2 * i + 1) + plt.imshow(img, cmap='magma', aspect='auto') + plt.title(f"Vérité: {label_true}\nPrédit: {label_pred} ({pred:.2f})", pad=10) + plt.xlabel('Temps (pas)') + plt.ylabel('Fréquence (Mels)') + plt.colorbar(label='Amplitude (dB)') + + plt.subplot(num_samples_to_visualize, 2, 2 * i + 2) + plt.imshow(superimposed_img, aspect='auto') + plt.title("Grad-CAM", pad=10) + plt.xlabel('Temps (pas)') + plt.ylabel('Fréquence (Mels)') + plt.colorbar(label='Importance') + + except Exception as e: + print(f"Erreur lors de la visualisation Grad-CAM pour l'échantillon {idx}: {e}") + +plt.suptitle("Visualisation Grad-CAM : Régions Influençant les Prédictions", fontsize=16, y=1.02) +plt.tight_layout() +plt.show() + +# -------------------------------------------------------------------------------- +# 🧠 VISUALISATION SHAP +# -------------------------------------------------------------------------------- +X_test_flat = X_test.reshape(X_test.shape[0], -1) +background = shap.sample(X_test_flat, 10, random_state=42) # Réduire pour stabilité + +def model_predict(data): + data = data.reshape(-1, N_MELS, FIXED_TIME_STEPS, 1) + return model.predict(data).flatten() # Aplatir pour sortie binaire + +print("🔄 Calcul des valeurs SHAP...") +explainer = shap.KernelExplainer(model_predict, background, l1_reg="num_features(5)") +shap_values = explainer.shap_values(X_test_flat[:5], nsamples=200) # Réduire échantillons, augmenter nsamples + +# Vérifier la forme des shap_values +print(f"Shape de shap_values: {np.array(shap_values).shape}") +print(f"Shape de X_test_flat[:5]: {X_test_flat[:5].shape}") + +plt.figure(figsize=(10, 6)) +shap.summary_plot(shap_values, X_test_flat[:5], + feature_names=[f'Mel_{i}_{t}' for i in range(N_MELS) for t in range(FIXED_TIME_STEPS)], + plot_type="bar", max_display=10) +plt.title("SHAP : Contributions des Caractéristiques aux Prédictions", pad=15) +plt.show() + +sample_idx = 0 +plt.figure(figsize=(12, 4)) +shap.force_plot(explainer.expected_value, shap_values[sample_idx], + X_test_flat[sample_idx], + feature_names=[f'Mel_{i}_{t}' for i in range(N_MELS) for t in range(FIXED_TIME_STEPS)], + matplotlib=True, contribution_threshold=0.05) +plt.title(f"SHAP Force Plot pour l'Échantillon {sample_idx}", pad=15) +plt.show() + +plt.figure(figsize=(10, 4)) +sns.heatmap(shap_values[sample_idx].reshape(N_MELS, FIXED_TIME_STEPS), + cmap='coolwarm', cbar_kws={'label': 'Valeur SHAP'}) +plt.title(f"SHAP Heatmap pour l'Échantillon {sample_idx}", pad=15) +plt.xlabel('Temps (pas)') +plt.ylabel('Fréquence (Mels)') +plt.show() + +# Analyse spécifique de l'échantillon mal classé (index 18) +print("🔍 Analyse SHAP pour l'échantillon mal classé (index 18)...") +shap_values_18 = explainer.shap_values(X_test_flat[18:19], nsamples=200) +plt.figure(figsize=(12, 4)) +shap.force_plot(explainer.expected_value, shap_values_18[0], + X_test_flat[18], + feature_names=[f'Mel_{i}_{t}' for i in range(N_MELS) for t in range(FIXED_TIME_STEPS)], + matplotlib=True, contribution_threshold=0.05) +plt.title("SHAP Force Plot pour l'Échantillon Mal Classé (Index 18)", pad=15) +plt.show() + +plt.figure(figsize=(10, 4)) +sns.heatmap(shap_values_18[0].reshape(N_MELS, FIXED_TIME_STEPS), + cmap='coolwarm', cbar_kws={'label': 'Valeur SHAP'}) +plt.title("SHAP Heatmap pour l'Échantillon Mal Classé (Index 18)", pad=15) +plt.xlabel('Temps (pas)') +plt.ylabel('Fréquence (Mels)') +plt.show() + +"""**LSTM**""" + +# 📦 Imports +import os +import numpy as np +import librosa +import matplotlib.pyplot as plt +from sklearn.model_selection import train_test_split +from sklearn.metrics import classification_report, confusion_matrix +from tensorflow.keras.preprocessing.sequence import pad_sequences +from tensorflow.keras import layers, models +from tensorflow.keras.callbacks import EarlyStopping +import seaborn as sns + +# 🔧 Configuration +SAMPLE_RATE = 22050 +DURATION = 3 +SAMPLES_PER_TRACK = SAMPLE_RATE * DURATION +DATA_PATH = "/content/drive/MyDrive" # à adapter si besoin + +# 🎵 Extraction MFCC +def extract_mfcc(file_path, max_len=SAMPLES_PER_TRACK): + try: + audio, sr = librosa.load(file_path, sr=SAMPLE_RATE) + if len(audio) < max_len: + audio = np.pad(audio, (0, max_len - len(audio))) + else: + audio = audio[:max_len] + mfcc = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=40) + return mfcc.T + except Exception as e: + print(f"❌ Erreur MFCC : {file_path} : {e}") + return None + +# 📂 Chargement des données +def load_mfcc_data(): + X, y = [], [] + labels_map = {"belle_voix": 1, "non_belle_voix": 0} + for folder_name, label in labels_map.items(): + folder_path = os.path.join(DATA_PATH, folder_name) + if not os.path.exists(folder_path): + print(f"⚠️ Dossier introuvable : {folder_path}") + continue + for file_name in os.listdir(folder_path): + if file_name.endswith(".wav"): + path = os.path.join(folder_path, file_name) + mfcc_data = extract_mfcc(path) + if mfcc_data is not None: + X.append(mfcc_data) + y.append(label) + return np.array(X, dtype=object), np.array(y) + +# ✅ Chargement et padding +X_mfcc, y_mfcc = load_mfcc_data() +print(f"✅ Chargé : {len(X_mfcc)} fichiers") + +max_length = max([x.shape[0] for x in X_mfcc]) +X_mfcc_padded = pad_sequences(X_mfcc, maxlen=max_length, dtype='float32', padding='post') +X_mfcc_padded = X_mfcc_padded[..., np.newaxis] # ajout canal + +# ✂️ Split +X_train, X_test, y_train, y_test = train_test_split( + X_mfcc_padded, y_mfcc, test_size=0.2, stratify=y_mfcc, random_state=42 +) + +# 🧠 Modèle LSTM +def create_lstm_model(input_shape): + model = models.Sequential([ + layers.Masking(mask_value=0., input_shape=input_shape), + layers.LSTM(64, return_sequences=True), + layers.LSTM(32), + layers.Dense(32, activation='relu'), + layers.Dense(1, activation='sigmoid') + ]) + model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) + return model + +# 🚀 Entraînement +lstm_model = create_lstm_model((X_train.shape[1], X_train.shape[2])) +early_stop = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True) + +history = lstm_model.fit( + X_train, y_train, + epochs=15, + batch_size=32, + validation_split=0.2, + callbacks=[early_stop] +) + +# 📈 Courbes +plt.figure(figsize=(12, 5)) +plt.subplot(1, 2, 1) +plt.plot(history.history['accuracy'], label='Train Acc') +plt.plot(history.history['val_accuracy'], label='Val Acc') +plt.title('Accuracy') +plt.legend() + +plt.subplot(1, 2, 2) +plt.plot(history.history['loss'], label='Train Loss') +plt.plot(history.history['val_loss'], label='Val Loss') +plt.title('Loss') +plt.legend() +plt.tight_layout() +plt.show() + +# 📊 Évaluation +y_pred = (lstm_model.predict(X_test) > 0.5).astype("int32") +print("\n🧾 Rapport de classification :\n") +print(classification_report(y_test, y_pred)) + +# 🔍 Matrice de confusion +cm = confusion_matrix(y_test, y_pred) +plt.figure(figsize=(5, 4)) +sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=["non_belle_voix", "belle_voix"], yticklabels=["non_belle_voix", "belle_voix"]) +plt.xlabel("Prédit") +plt.ylabel("Réel") +plt.title("Matrice de confusion") +plt.show() + +# 💾 Sauvegarde +model_path = '/content/drive/MyDrive/lstm_belle_voix_model.h5' +lstm_model.save(model_path) +print(f"✅ Modèle sauvegardé : {model_path}") + +# 🔮 Prédiction sur fichier .wav +def predict_voice(file_path): + mfcc = extract_mfcc(file_path) + if mfcc is None: + print("❌ MFCC non valide") + return + mfcc_padded = pad_sequences([mfcc], maxlen=max_length, dtype='float32', padding='post') + mfcc_padded = mfcc_padded[..., np.newaxis] + proba = lstm_model.predict(mfcc_padded)[0][0] + classe = "belle_voix" if proba > 0.5 else "non_belle_voix" + print(f"🔍 Fichier : {os.path.basename(file_path)}") + print(f"🔊 Classe prédite : {classe} (probabilité : {proba:.2f})") + +# Exemple : prediction sur un fichier +# predict_voice("/content/drive/MyDrive/belle_voix/exemple.wav") \ No newline at end of file