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 0000000..37ae2ed Binary files /dev/null and b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/__init__.cpython-313.pyc differ diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/admin.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/admin.cpython-313.pyc new file mode 100644 index 0000000..077c0bd Binary files /dev/null and b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/admin.cpython-313.pyc differ 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 0000000..6f86557 Binary files /dev/null and b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/apps.cpython-313.pyc differ 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 0000000..3b99080 Binary files /dev/null and b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/models.cpython-313.pyc differ diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/views.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/views.cpython-313.pyc new file mode 100644 index 0000000..9ab9262 Binary files /dev/null and b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/__pycache__/views.cpython-313.pyc differ diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/migrations/__pycache__/__init__.cpython-313.pyc b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/migrations/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..6e63f36 Binary files /dev/null and b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/migrations/__pycache__/__init__.cpython-313.pyc differ diff --git a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/templates/chat_interface.html b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/templates/chat_interface.html index 987f2c9..3141dfc 100644 --- a/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/templates/chat_interface.html +++ b/Act/Deployment-app/Back-Django/prj_api/MathematicoLogical/templates/chat_interface.html @@ -86,7 +86,7 @@
-

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 53ca889..5ae0918 100644 Binary files a/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/settings.cpython-313.pyc and b/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/settings.cpython-313.pyc differ 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 94cc4c3..7474067 100644 Binary files a/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/urls.cpython-313.pyc and b/Act/Deployment-app/Back-Django/prj_api/prj_api/__pycache__/urls.cpython-313.pyc differ 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