{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":117193,"databundleVersionId":14001224,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## INSTALLATION DES DÉPENDANCES","metadata":{}},{"cell_type":"code","source":"# Installation des packages requis\n#!pip install torch torchvision\n!pip install facenet-pytorch\n!pip install pillow\n!pip install numpy pandas\n!pip install matplotlib seaborn\n!pip install scikit-learn\n!pip install tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:07:38.238959Z","iopub.execute_input":"2025-10-17T21:07:38.23952Z","iopub.status.idle":"2025-10-17T21:10:27.89016Z","shell.execute_reply.started":"2025-10-17T21:07:38.239497Z","shell.execute_reply":"2025-10-17T21:10:27.88908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom tqdm import tqdm\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom facenet_pytorch import MTCNN, InceptionResnetV1\nfrom sklearn.metrics.pairwise import cosine_similarity\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:10:40.134871Z","iopub.execute_input":"2025-10-17T21:10:40.13518Z","iopub.status.idle":"2025-10-17T21:10:40.631526Z","shell.execute_reply.started":"2025-10-17T21:10:40.135155Z","shell.execute_reply":"2025-10-17T21:10:40.63089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Configuration\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"Device utilisé: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:10:54.870458Z","iopub.execute_input":"2025-10-17T21:10:54.870705Z","iopub.status.idle":"2025-10-17T21:10:54.875714Z","shell.execute_reply.started":"2025-10-17T21:10:54.870688Z","shell.execute_reply":"2025-10-17T21:10:54.875021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls /kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:11:02.869761Z","iopub.execute_input":"2025-10-17T21:11:02.870036Z","iopub.status.idle":"2025-10-17T21:11:03.014722Z","shell.execute_reply.started":"2025-10-17T21:11:02.870018Z","shell.execute_reply":"2025-10-17T21:11:03.013741Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Chemins des données\nTRAIN_PATH = './ANI'\nTRAIN_PATH = '/kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_1/dataset_tache_1/train'\nTEST_PATH = '/kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_1/dataset_tache_1/test'\nOUTPUT_CSV = 'tache1_predictions.csv'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:11:06.26746Z","iopub.execute_input":"2025-10-17T21:11:06.267745Z","iopub.status.idle":"2025-10-17T21:11:06.272254Z","shell.execute_reply.started":"2025-10-17T21:11:06.267722Z","shell.execute_reply":"2025-10-17T21:11:06.271421Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Initialisation de MTCNN pour la détection de visages\nmtcnn = MTCNN(\n    image_size=160,\n    margin=20,\n    min_face_size=20,\n    thresholds=[0.6, 0.7, 0.7],\n    factor=0.709,\n    post_process=True,\n    device=device\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:11:20.975677Z","iopub.execute_input":"2025-10-17T21:11:20.976414Z","iopub.status.idle":"2025-10-17T21:11:21.207059Z","shell.execute_reply.started":"2025-10-17T21:11:20.976383Z","shell.execute_reply":"2025-10-17T21:11:21.206116Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def detect_and_crop_face(image_path, mtcnn):\n    \"\"\"\n    Détecte et extrait le visage d'une image\n    \"\"\"\n    try:\n        img = Image.open(image_path).convert('RGB')\n        face = mtcnn(img)\n        if face is not None:\n            return face\n        else:\n            # Si pas de visage détecté, utiliser l'image complète redimensionnée\n            transform = transforms.Compose([\n                transforms.Resize((160, 160)),\n                transforms.ToTensor(),\n                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])\n            ])\n            return transform(img)\n    except Exception as e:\n        print(f\"Erreur lors du traitement de {image_path}: {e}\")\n        return None\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:11:42.747614Z","iopub.execute_input":"2025-10-17T21:11:42.748203Z","iopub.status.idle":"2025-10-17T21:11:42.753606Z","shell.execute_reply.started":"2025-10-17T21:11:42.748179Z","shell.execute_reply":"2025-10-17T21:11:42.75275Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Test de détection\nsample_image = os.path.join(TRAIN_PATH, os.listdir(TRAIN_PATH)[0])\nface = detect_and_crop_face(sample_image, mtcnn)\nif face is not None:\n    print(f\"✓ Détection de visage réussie! Shape: {face.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:12:06.506393Z","iopub.execute_input":"2025-10-17T21:12:06.507026Z","iopub.status.idle":"2025-10-17T21:12:07.511384Z","shell.execute_reply.started":"2025-10-17T21:12:06.507009Z","shell.execute_reply":"2025-10-17T21:12:07.510571Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Chargement du modèle FaceNet pré-entraîné\nresnet = InceptionResnetV1(pretrained='vggface2').eval().to(device)\n\ndef extract_embedding(face_tensor, model):\n    \"\"\"\n    Extrait l'embedding d'un visage avec FaceNet\n    \"\"\"\n    if face_tensor is None:\n        return None\n    \n    with torch.no_grad():\n        if len(face_tensor.shape) == 3:\n            face_tensor = face_tensor.unsqueeze(0)\n        embedding = model(face_tensor.to(device))\n        return embedding.cpu().numpy().flatten()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:12:28.809008Z","iopub.execute_input":"2025-10-17T21:12:28.809695Z","iopub.status.idle":"2025-10-17T21:12:30.068622Z","shell.execute_reply.started":"2025-10-17T21:12:28.809655Z","shell.execute_reply":"2025-10-17T21:12:30.068046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Test d'extraction d'embedding\nif face is not None:\n    embedding = extract_embedding(face, resnet)\n    print(f\"✓ Embedding extrait! Shape: {embedding.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:12:46.194017Z","iopub.execute_input":"2025-10-17T21:12:46.19464Z","iopub.status.idle":"2025-10-17T21:12:46.328565Z","shell.execute_reply.started":"2025-10-17T21:12:46.194618Z","shell.execute_reply":"2025-10-17T21:12:46.327761Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def process_train_dataset(train_path, mtcnn, model):\n    \"\"\"\n    Traite toutes les images d'entraînement et extrait les embeddings\n    \"\"\"\n    train_embeddings = {}\n    train_files = sorted([f for f in os.listdir(train_path) if f.endswith(('.jpg', '.png'))])\n    \n    print(\"Traitement du dataset d'entraînement...\")\n    for filename in tqdm(train_files):\n        img_path = os.path.join(train_path, filename)\n        \n        # Extraction de l'ID de la personne (ex: 0000 de 0000_0.jpg)\n        person_id = filename.split('_')[0]\n        \n        # Détection et extraction du visage\n        face = detect_and_crop_face(img_path, mtcnn)\n        \n        # Extraction de l'embedding\n        embedding = extract_embedding(face, model)\n        \n        if embedding is not None:\n            if person_id not in train_embeddings:\n                train_embeddings[person_id] = []\n            train_embeddings[person_id].append(embedding)\n    \n    # Moyenne des embeddings pour chaque personne (2 photos par personne)\n    avg_embeddings = {}\n    for person_id, embeddings in train_embeddings.items():\n        avg_embeddings[person_id] = np.mean(embeddings, axis=0)\n    \n    return avg_embeddings\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:13:09.740465Z","iopub.execute_input":"2025-10-17T21:13:09.741352Z","iopub.status.idle":"2025-10-17T21:13:09.747153Z","shell.execute_reply.started":"2025-10-17T21:13:09.741323Z","shell.execute_reply":"2025-10-17T21:13:09.746232Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_embeddings = process_train_dataset(TRAIN_PATH, mtcnn, resnet)\nprint(f\"\\n✓ Nombre de personnes dans le dataset d'entraînement: {len(train_embeddings)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:13:25.150036Z","iopub.execute_input":"2025-10-17T21:13:25.150328Z","iopub.status.idle":"2025-10-17T21:16:59.287346Z","shell.execute_reply.started":"2025-10-17T21:13:25.150308Z","shell.execute_reply":"2025-10-17T21:16:59.286648Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def process_test_dataset(test_path, mtcnn, model):\n    \"\"\"\n    Traite toutes les images de test et extrait les embeddings\n    \"\"\"\n    test_embeddings = {}\n    test_files = sorted([f for f in os.listdir(test_path) if f.endswith(('.jpg', '.png'))])\n    \n    print(\"\\nTraitement du dataset de test...\")\n    for filename in tqdm(test_files):\n        img_path = os.path.join(test_path, filename)\n        \n        # Détection et extraction du visage\n        face = detect_and_crop_face(img_path, mtcnn)\n        \n        # Extraction de l'embedding\n        embedding = extract_embedding(face, model)\n        \n        if embedding is not None:\n            test_embeddings[filename] = embedding\n    \n    return test_embeddings\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:17:07.754138Z","iopub.execute_input":"2025-10-17T21:17:07.754435Z","iopub.status.idle":"2025-10-17T21:17:07.760319Z","shell.execute_reply.started":"2025-10-17T21:17:07.754415Z","shell.execute_reply":"2025-10-17T21:17:07.759521Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Exécution du traitement\ntest_embeddings = process_test_dataset(TEST_PATH, mtcnn, resnet)\nprint(f\"\\n✓ Nombre d'images de test traitées: {len(test_embeddings)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:17:23.024349Z","iopub.execute_input":"2025-10-17T21:17:23.024941Z","iopub.status.idle":"2025-10-17T21:19:19.879211Z","shell.execute_reply.started":"2025-10-17T21:17:23.024913Z","shell.execute_reply":"2025-10-17T21:19:19.878513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def match_faces(test_embeddings, train_embeddings, threshold=0.6):\n    \"\"\"\n    Apparie chaque image de test avec la personne la plus similaire\n    \"\"\"\n    predictions = []\n    \n    print(\"\\nAppariement des visages...\")\n    for test_filename, test_emb in tqdm(test_embeddings.items()):\n        best_match_id = None\n        min_distance = float('inf')\n        \n        # Calcul de la distance avec chaque personne du train\n        for person_id, train_emb in train_embeddings.items():\n            # Distance euclidienne\n            distance = np.linalg.norm(test_emb - train_emb)\n            \n            # Alternative: Distance cosinus\n            # distance = 1 - cosine_similarity([test_emb], [train_emb])[0][0]\n            \n            if distance < min_distance:\n                min_distance = distance\n                best_match_id = person_id\n        \n        # Vérification du seuil\n        if min_distance > threshold:\n            best_match_id = \"UNKNOWN\"\n        \n        predictions.append({\n            'test_image': test_filename,\n            'predicted_id': best_match_id,\n            'confidence': min_distance\n        })\n    \n    return predictions\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:19:26.221516Z","iopub.execute_input":"2025-10-17T21:19:26.221769Z","iopub.status.idle":"2025-10-17T21:19:26.227656Z","shell.execute_reply.started":"2025-10-17T21:19:26.221753Z","shell.execute_reply":"2025-10-17T21:19:26.226915Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = match_faces(test_embeddings, train_embeddings, threshold=0.8)\nprint(f\"\\n✓ Appariement terminé!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:19:43.21064Z","iopub.execute_input":"2025-10-17T21:19:43.211111Z","iopub.status.idle":"2025-10-17T21:20:02.461893Z","shell.execute_reply.started":"2025-10-17T21:19:43.211092Z","shell.execute_reply":"2025-10-17T21:20:02.461071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Création du DataFrame\ndf_predictions = pd.DataFrame(predictions)\n\n# Affichage des premières prédictions\nprint(\"\\nPremières prédictions:\")\nprint(df_predictions.head(10))\n\n# Statistiques\nprint(f\"\\nNombre d'images appariées: {len(df_predictions[df_predictions['predicted_id'] != 'UNKNOWN'])}\")\nprint(f\"Nombre d'images non appariées: {len(df_predictions[df_predictions['predicted_id'] == 'UNKNOWN'])}\")\n\n# Sauvegarde en CSV\ndf_predictions.to_csv(OUTPUT_CSV, index=False)\nprint(f\"\\n✓ Prédictions sauvegardées dans: {OUTPUT_CSV}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:20:42.9633Z","iopub.execute_input":"2025-10-17T21:20:42.963592Z","iopub.status.idle":"2025-10-17T21:20:43.004042Z","shell.execute_reply.started":"2025-10-17T21:20:42.963574Z","shell.execute_reply":"2025-10-17T21:20:43.003336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Distribution des distances de confiance\nplt.figure(figsize=(12, 5))\n\nplt.subplot(1, 2, 1)\nplt.hist(df_predictions['confidence'], bins=50, edgecolor='black')\nplt.xlabel('Distance (Confidence)')\nplt.ylabel('Fréquence')\nplt.title('Distribution des Distances de Matching')\nplt.grid(True, alpha=0.3)\n\nplt.subplot(1, 2, 2)\nmatched = len(df_predictions[df_predictions['predicted_id'] != 'UNKNOWN'])\nunmatched = len(df_predictions[df_predictions['predicted_id'] == 'UNKNOWN'])\nplt.pie([matched, unmatched], labels=['Matched', 'Unmatched'], autopct='%1.1f%%')\nplt.title('Proportion des Appariements')\n\nplt.tight_layout()\nplt.savefig('tache1_results_visualization.png', dpi=300)\nplt.show()\n\nprint(\"✓ Visualisation sauvegardée!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:21:26.223661Z","iopub.execute_input":"2025-10-17T21:21:26.224336Z","iopub.status.idle":"2025-10-17T21:21:27.189733Z","shell.execute_reply.started":"2025-10-17T21:21:26.224313Z","shell.execute_reply":"2025-10-17T21:21:27.188807Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Si vous avez les vrais labels pour évaluation\ndef calculate_metrics(predictions, true_labels):\n    \"\"\"\n    Calcule les métriques de performance\n    \"\"\"\n    correct = 0\n    total = len(predictions)\n    \n    for pred, true in zip(predictions, true_labels):\n        if pred == true:\n            correct += 1\n    \n    accuracy = correct / total\n    return {\n        'accuracy': accuracy,\n        'correct': correct,\n        'total': total\n    }\n\n# Utilisation (à adapter selon vos données)\nmetrics = calculate_metrics(df_predictions['predicted_id'], true_labels)\nprint(f\"Accuracy: {metrics['accuracy']:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:23:36.447611Z","iopub.execute_input":"2025-10-17T21:23:36.447946Z","iopub.status.idle":"2025-10-17T21:23:36.495795Z","shell.execute_reply.started":"2025-10-17T21:23:36.447923Z","shell.execute_reply":"2025-10-17T21:23:36.494811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Les poids de FaceNet sont déjà pré-entraînés\n# Sauvegarder les embeddings pour accélérer les prédictions futures\nimport pickle\n\n# Sauvegarde des embeddings\nwith open('train_embeddings.pkl', 'wb') as f:\n    pickle.dump(train_embeddings, f)\n\nwith open('test_embeddings.pkl', 'wb') as f:\n    pickle.dump(test_embeddings, f)\n\nprint(\"✓ Embeddings sauvegardés!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-17T21:24:24.506406Z","iopub.execute_input":"2025-10-17T21:24:24.506959Z","iopub.status.idle":"2025-10-17T21:24:24.538496Z","shell.execute_reply.started":"2025-10-17T21:24:24.506938Z","shell.execute_reply":"2025-10-17T21:24:24.537809Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}