{"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":"code","source":"\"\"\"\nANIP - Facial Recognition, Age Estimation & OCR\nComplete Solution for All Three Tasks\n\"\"\"\n\nimport os\nimport json\nimport numpy as np\nimport pandas as pd\nimport cv2\nfrom pathlib import Path\nfrom tqdm import tqdm\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nfrom torchvision import models\nfrom PIL import Image\n\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score\nfrom sklearn.metrics.pairwise import cosine_similarity\nimport matplotlib.pyplot as plt\n\n# Set device\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"Using device: {device}\")\n\n# Base directory\nBASE_DIR = \"/kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr\"\n\n# Directory paths\nTASK1_TRAIN = os.path.join(BASE_DIR, \"dataset_tache_1/dataset_tache_1/train\")\nTASK1_TEST = os.path.join(BASE_DIR, \"dataset_tache_1/dataset_tache_1/test\")\n\nTASK2_TRAIN = os.path.join(BASE_DIR, \"dataset_tache_2/dataset_tache_2/train\")\nTASK2_TEST = os.path.join(BASE_DIR, \"dataset_tache_2/dataset_tache_2/test\")\n\nTASK3_TRAIN = os.path.join(BASE_DIR, \"dataset_tache_3/dataset_tache_3/train\")\nTASK3_TEST = os.path.join(BASE_DIR, \"dataset_tache_3/dataset_tache_3/test\")\n\nprint(\"=\" * 80)\nprint(\"ANIP CHALLENGE - COMPLETE SOLUTION\")\nprint(\"=\" * 80)\n\n# ============================================================================\n# TASK 1: FACIAL RECOGNITION - Face Matching\n# ============================================================================\nprint(\"\\n\" + \"=\" * 80)\nprint(\"TASK 1: FACIAL RECOGNITION\")\nprint(\"=\" * 80)\n\nclass FaceRecognitionDataset(Dataset):\n    \"\"\"Dataset for face recognition task\"\"\"\n    def __init__(self, image_dir, transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        \n        # Check if directory exists\n        if not os.path.exists(image_dir):\n            raise ValueError(f\"Directory does not exist: {image_dir}\")\n        \n        all_files = os.listdir(image_dir)\n        self.image_files = sorted([f for f in all_files if f.lower().endswith(('.jpg', '.png', '.jpeg', '.bmp', '.tiff'))])\n        \n        print(f\"Found {len(self.image_files)} images in {image_dir}\")\n        if len(self.image_files) == 0:\n            raise ValueError(f\"No image files found in {image_dir}\")\n        \n    def __len__(self):\n        return len(self.image_files)\n    \n    def __getitem__(self, idx):\n        img_name = self.image_files[idx]\n        img_path = os.path.join(self.image_dir, img_name)\n        image = Image.open(img_path).convert('RGB')\n        \n        if self.transform:\n            image = self.transform(image)\n            \n        return image, img_name\n\nclass FaceEmbeddingModel(nn.Module):\n    \"\"\"Face embedding model using ResNet50\"\"\"\n    def __init__(self, embedding_dim=512):\n        super(FaceEmbeddingModel, self).__init__()\n        self.backbone = models.resnet50(pretrained=True)\n        in_features = self.backbone.fc.in_features\n        self.backbone.fc = nn.Sequential(\n            nn.Linear(in_features, embedding_dim),\n            nn.BatchNorm1d(embedding_dim)\n        )\n        \n    def forward(self, x):\n        return self.backbone(x)\n\n# Data transforms for Task 1\ntransform_task1 = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Load training data for Task 1\nprint(\"\\n[Task 1] Loading training data...\")\ntrain_dataset_task1 = FaceRecognitionDataset(TASK1_TRAIN, transform=transform_task1)\ntrain_loader_task1 = DataLoader(train_dataset_task1, batch_size=32, shuffle=False, num_workers=0, pin_memory=True)\n\n# Initialize model for Task 1\nprint(\"[Task 1] Initializing face embedding model...\")\nmodel_task1 = FaceEmbeddingModel(embedding_dim=512).to(device)\nmodel_task1.eval()\n\n# Extract embeddings for training set\nprint(\"[Task 1] Extracting embeddings from training images...\")\ntrain_embeddings = {}\ntrain_identities = {}\n\nwith torch.no_grad():\n    for images, img_names in tqdm(train_loader_task1, desc=\"Training embeddings\"):\n        images = images.to(device)\n        embeddings = model_task1(images).cpu().numpy()\n        \n        for i, img_name in enumerate(img_names):\n            train_embeddings[img_name] = embeddings[i]\n            # Extract identity (XXXX) and shot number (0 or 1)\n            person_id = img_name.split('_')[0]\n            train_identities[img_name] = person_id\n\n# Load test data for Task 1\nprint(\"[Task 1] Loading test data...\")\ntest_dataset_task1 = FaceRecognitionDataset(TASK1_TEST, transform=transform_task1)\ntest_loader_task1 = DataLoader(test_dataset_task1, batch_size=32, shuffle=False, num_workers=0, pin_memory=True)\n\n# Extract embeddings for test set\nprint(\"[Task 1] Extracting embeddings from test images...\")\ntest_embeddings = {}\n\nwith torch.no_grad():\n    for images, img_names in tqdm(test_loader_task1, desc=\"Test embeddings\"):\n        images = images.to(device)\n        embeddings = model_task1(images).cpu().numpy()\n        \n        for i, img_name in enumerate(img_names):\n            test_embeddings[img_name] = embeddings[i]\n\n# Match faces using cosine similarity\nprint(\"[Task 1] Matching faces...\")\nresults_task1 = []\n\ntest_img_list = list(test_embeddings.keys())\ntrain_img_list = list(train_embeddings.keys())\n\ntrain_emb_matrix = np.array([train_embeddings[img] for img in train_img_list])\ntest_emb_matrix = np.array([test_embeddings[img] for img in test_img_list])\n\n# Calculate cosine similarity\nsimilarities = cosine_similarity(test_emb_matrix, train_emb_matrix)\n\nfor i, test_img in enumerate(tqdm(test_img_list, desc=\"Creating matches\")):\n    best_match_idx = np.argmax(similarities[i])\n    best_match = train_img_list[best_match_idx]\n    similarity_score = similarities[i][best_match_idx]\n    person_id = train_identities[best_match]\n    \n    results_task1.append({\n        'test_image': test_img,\n        'matched_train_image': best_match,\n        'person_id': person_id,\n        'similarity_score': similarity_score\n    })\n\n# Save results for Task 1\ndf_task1 = pd.DataFrame(results_task1)\ndf_task1.to_csv('task1_results.csv', index=False)\nprint(f\"[Task 1] Results saved to task1_results.csv\")\nprint(f\"[Task 1] Matched {len(results_task1)} test images\")\n\n# Save model weights\ntorch.save(model_task1.state_dict(), 'task1_model_weights.pth')\nprint(\"[Task 1] Model weights saved to task1_model_weights.pth\")\n\n# ============================================================================\n# TASK 2: AGE ESTIMATION\n# ============================================================================\nprint(\"\\n\" + \"=\" * 80)\nprint(\"TASK 2: AGE ESTIMATION\")\nprint(\"=\" * 80)\n\nclass AgeEstimationDataset(Dataset):\n    \"\"\"Dataset for age estimation task\"\"\"\n    def __init__(self, image_dir, transform=None, is_train=True):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.is_train = is_train\n        \n        # Check if directory exists\n        if not os.path.exists(image_dir):\n            raise ValueError(f\"Directory does not exist: {image_dir}\")\n        \n        # Get all image files with various extensions\n        all_files = os.listdir(image_dir)\n        self.image_files = sorted([f for f in all_files if f.lower().endswith(('.jpg', '.png', '.jpeg', '.bmp', '.tiff'))])\n        \n        print(f\"Found {len(self.image_files)} images in {image_dir}\")\n        if len(self.image_files) > 0:\n            print(f\"Sample filenames: {self.image_files[:3]}\")\n        \n        if len(self.image_files) == 0:\n            raise ValueError(f\"No image files found in {image_dir}\")\n        \n        if is_train:\n            self.ages = self._extract_ages()\n        \n    def _extract_ages(self):\n        \"\"\"Extract ages from filename: XXXXXX_YZWW or other formats\"\"\"\n        ages = []\n        for fname in self.image_files:\n            # Remove extension\n            name_without_ext = os.path.splitext(fname)[0]\n            \n            # Try different parsing strategies\n            try:\n                # Format: XXXXXX_YZWW (e.g., 000001_0M25.jpg)\n                if '_' in name_without_ext:\n                    parts = name_without_ext.split('_')\n                    if len(parts) >= 2:\n                        # Get the last part after underscore\n                        last_part = parts[-1]\n                        \n                        # Extract age (last 2 digits)\n                        age_str = ''.join(filter(str.isdigit, last_part))\n                        if len(age_str) >= 2:\n                            age = int(age_str[-2:])\n                        elif len(age_str) == 1:\n                            age = int(age_str)\n                        else:\n                            age = 25  # Default age\n                        \n                        ages.append(age)\n                    else:\n                        ages.append(25)\n                else:\n                    # If no underscore, try to extract any numbers\n                    digits = ''.join(filter(str.isdigit, name_without_ext))\n                    if len(digits) >= 2:\n                        age = int(digits[-2:])\n                    else:\n                        age = 25\n                    ages.append(age)\n            except Exception as e:\n                print(f\"Warning: Could not extract age from {fname}, using default age 25\")\n                ages.append(25)\n        \n        print(f\"Age range: {min(ages)} - {max(ages)}\")\n        return ages\n    \n    def __len__(self):\n        return len(self.image_files)\n    \n    def __getitem__(self, idx):\n        img_name = self.image_files[idx]\n        img_path = os.path.join(self.image_dir, img_name)\n        image = Image.open(img_path).convert('RGB')\n        \n        if self.transform:\n            image = self.transform(image)\n        \n        if self.is_train:\n            age = self.ages[idx]\n            return image, torch.tensor(age, dtype=torch.float32), img_name\n        else:\n            return image, img_name\n\nclass AgeEstimationModel(nn.Module):\n    \"\"\"Age estimation model using ResNet50\"\"\"\n    def __init__(self):\n        super(AgeEstimationModel, self).__init__()\n        self.backbone = models.resnet50(pretrained=True)\n        in_features = self.backbone.fc.in_features\n        self.backbone.fc = nn.Sequential(\n            nn.Linear(in_features, 512),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n            nn.Linear(512, 128),\n            nn.ReLU(),\n            nn.Dropout(0.2),\n            nn.Linear(128, 1)\n        )\n        \n    def forward(self, x):\n        return self.backbone(x)\n\n# Data transforms for Task 2\ntransform_task2_train = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\ntransform_task2_test = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Load datasets for Task 2\nprint(\"\\n[Task 2] Loading datasets...\")\ntry:\n    train_dataset_task2 = AgeEstimationDataset(TASK2_TRAIN, transform=transform_task2_train, is_train=True)\n    train_loader_task2 = DataLoader(train_dataset_task2, batch_size=32, shuffle=True, num_workers=0, pin_memory=True)\n    \n    test_dataset_task2 = AgeEstimationDataset(TASK2_TEST, transform=transform_task2_test, is_train=False)\n    test_loader_task2 = DataLoader(test_dataset_task2, batch_size=32, shuffle=False, num_workers=0, pin_memory=True)\n    \n    print(f\"[Task 2] Training samples: {len(train_dataset_task2)}\")\n    print(f\"[Task 2] Test samples: {len(test_dataset_task2)}\")\nexcept Exception as e:\n    print(f\"[Task 2] Error loading dataset: {e}\")\n    print(f\"[Task 2] Checking directory: {TASK2_TRAIN}\")\n    if os.path.exists(TASK2_TRAIN):\n        print(f\"[Task 2] Directory exists. Contents: {os.listdir(TASK2_TRAIN)[:10]}\")\n    else:\n        print(f\"[Task 2] Directory does not exist!\")\n    raise\n\n# Initialize model for Task 2\nprint(\"[Task 2] Initializing age estimation model...\")\nmodel_task2 = AgeEstimationModel().to(device)\ncriterion_task2 = nn.L1Loss()\noptimizer_task2 = optim.Adam(model_task2.parameters(), lr=0.001)\nscheduler_task2 = optim.lr_scheduler.ReduceLROnPlateau(optimizer_task2, mode='min', patience=2)\n\n# Training Task 2\nprint(\"[Task 2] Training model...\")\nnum_epochs_task2 = 10\nbest_loss = float('inf')\n\nfor epoch in range(num_epochs_task2):\n    model_task2.train()\n    train_loss = 0.0\n    \n    pbar = tqdm(train_loader_task2, desc=f\"Epoch {epoch+1}/{num_epochs_task2}\")\n    for images, ages, _ in pbar:\n        images = images.to(device)\n        ages = ages.to(device)\n        \n        optimizer_task2.zero_grad()\n        outputs = model_task2(images).squeeze()\n        loss = criterion_task2(outputs, ages)\n        loss.backward()\n        optimizer_task2.step()\n        \n        train_loss += loss.item()\n        pbar.set_postfix({'loss': loss.item()})\n    \n    avg_loss = train_loss / len(train_loader_task2)\n    scheduler_task2.step(avg_loss)\n    print(f\"[Task 2] Epoch {epoch+1}/{num_epochs_task2}, Loss: {avg_loss:.4f}\")\n    \n    if avg_loss < best_loss:\n        best_loss = avg_loss\n        torch.save(model_task2.state_dict(), 'task2_model_weights.pth')\n\n# Inference on test set for Task 2\nprint(\"[Task 2] Running inference on test set...\")\nmodel_task2.eval()\npredictions_task2 = []\n\nwith torch.no_grad():\n    for images, img_names in tqdm(test_loader_task2, desc=\"Predicting ages\"):\n        images = images.to(device)\n        outputs = model_task2(images).squeeze()\n        ages_pred = outputs.cpu().numpy()\n        \n        for i, img_name in enumerate(img_names):\n            predicted_age = max(0, int(round(ages_pred[i] if ages_pred.ndim > 0 else ages_pred.item())))\n            predictions_task2.append({\n                'image': img_name,\n                'predicted_age': predicted_age\n            })\n\n# Save results for Task 2\ndf_task2 = pd.DataFrame(predictions_task2)\ndf_task2.to_csv('task2_results.csv', index=False)\nprint(f\"[Task 2] Results saved to task2_results.csv\")\nprint(f\"[Task 2] Model weights saved to task2_model_weights.pth\")\n\n# ============================================================================\n# TASK 3: OCR AND FRAUD DETECTION\n# ============================================================================\nprint(\"\\n\" + \"=\" * 80)\nprint(\"TASK 3: OCR AND FRAUD DETECTION\")\nprint(\"=\" * 80)\n\nclass DocumentDataset(Dataset):\n    \"\"\"Dataset for document OCR and fraud detection\"\"\"\n    def __init__(self, base_dir, countries, transform=None, is_train=True):\n        self.base_dir = base_dir\n        self.transform = transform\n        self.is_train = is_train\n        self.samples = []\n        \n        for country in countries:\n            country_dir = os.path.join(base_dir, country)\n            if not os.path.exists(country_dir):\n                print(f\"Warning: Country directory not found: {country_dir}\")\n                continue\n                \n            if is_train:\n                # Load from all categories\n                categories = ['normal', 'forgery_1', 'forgery_2', 'forgery_3', 'forgery_4']\n                for category in categories:\n                    cat_dir = os.path.join(country_dir, category)\n                    if os.path.exists(cat_dir):\n                        files = [f for f in os.listdir(cat_dir) if f.lower().endswith(('.jpg', '.png', '.jpeg', '.bmp', '.tiff'))]\n                        for img_file in files:\n                            self.samples.append({\n                                'path': os.path.join(cat_dir, img_file),\n                                'country': country,\n                                'category': category,\n                                'filename': img_file\n                            })\n                        print(f\"Found {len(files)} images in {country}/{category}\")\n            else:\n                # Test images are directly in country folder\n                if os.path.exists(country_dir):\n                    files = [f for f in os.listdir(country_dir) if f.lower().endswith(('.jpg', '.png', '.jpeg', '.bmp', '.tiff'))]\n                    for img_file in files:\n                        self.samples.append({\n                            'path': os.path.join(country_dir, img_file),\n                            'country': country,\n                            'category': None,\n                            'filename': img_file\n                        })\n                    print(f\"Found {len(files)} test images in {country}\")\n        \n        print(f\"Total samples loaded: {len(self.samples)}\")\n        if len(self.samples) == 0:\n            raise ValueError(f\"No samples found in {base_dir}\")\n    \n    def __len__(self):\n        return len(self.samples)\n    \n    def __getitem__(self, idx):\n        sample = self.samples[idx]\n        image = Image.open(sample['path']).convert('RGB')\n        \n        if self.transform:\n            image = self.transform(image)\n        \n        if self.is_train:\n            # Encode category as label\n            categories = ['normal', 'forgery_1', 'forgery_2', 'forgery_3', 'forgery_4']\n            label = categories.index(sample['category'])\n            return image, label, sample['filename'], sample['country']\n        else:\n            return image, sample['filename'], sample['country']\n\nclass FraudDetectionModel(nn.Module):\n    \"\"\"Fraud detection model using ResNet50\"\"\"\n    def __init__(self, num_classes=5):\n        super(FraudDetectionModel, self).__init__()\n        self.backbone = models.resnet50(pretrained=True)\n        in_features = self.backbone.fc.in_features\n        self.backbone.fc = nn.Sequential(\n            nn.Linear(in_features, 512),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(512, 256),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n            nn.Linear(256, num_classes)\n        )\n        \n    def forward(self, x):\n        return self.backbone(x)\n\n# Data transforms for Task 3\ntransform_task3_train = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomRotation(5),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\ntransform_task3_test = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Countries list\ncountries = ['arizona_dl', 'esp', 'est', 'rus']\n\n# Load datasets for Task 3\nprint(\"\\n[Task 3] Loading datasets...\")\ntrain_dataset_task3 = DocumentDataset(TASK3_TRAIN, countries, transform=transform_task3_train, is_train=True)\ntrain_loader_task3 = DataLoader(train_dataset_task3, batch_size=16, shuffle=True, num_workers=0, pin_memory=True)\n\ntest_dataset_task3 = DocumentDataset(TASK3_TEST, countries, transform=transform_task3_test, is_train=False)\ntest_loader_task3 = DataLoader(test_dataset_task3, batch_size=16, shuffle=False, num_workers=0, pin_memory=True)\n\nprint(f\"[Task 3] Training samples: {len(train_dataset_task3)}\")\nprint(f\"[Task 3] Test samples: {len(test_dataset_task3)}\")\n\n# Initialize model for Task 3\nprint(\"[Task 3] Initializing fraud detection model...\")\nmodel_task3 = FraudDetectionModel(num_classes=5).to(device)\ncriterion_task3 = nn.CrossEntropyLoss()\noptimizer_task3 = optim.Adam(model_task3.parameters(), lr=0.0001)\nscheduler_task3 = optim.lr_scheduler.StepLR(optimizer_task3, step_size=3, gamma=0.5)\n\n# Training Task 3\nprint(\"[Task 3] Training model...\")\nnum_epochs_task3 = 8\nbest_acc = 0.0\n\nfor epoch in range(num_epochs_task3):\n    model_task3.train()\n    train_loss = 0.0\n    correct = 0\n    total = 0\n    \n    pbar = tqdm(train_loader_task3, desc=f\"Epoch {epoch+1}/{num_epochs_task3}\")\n    for images, labels, _, _ in pbar:\n        images = images.to(device)\n        labels = labels.to(device)\n        \n        optimizer_task3.zero_grad()\n        outputs = model_task3(images)\n        loss = criterion_task3(outputs, labels)\n        loss.backward()\n        optimizer_task3.step()\n        \n        train_loss += loss.item()\n        _, predicted = outputs.max(1)\n        total += labels.size(0)\n        correct += predicted.eq(labels).sum().item()\n        \n        pbar.set_postfix({'loss': loss.item(), 'acc': 100.*correct/total})\n    \n    accuracy = 100. * correct / total\n    scheduler_task3.step()\n    print(f\"[Task 3] Epoch {epoch+1}/{num_epochs_task3}, Loss: {train_loss/len(train_loader_task3):.4f}, Accuracy: {accuracy:.2f}%\")\n    \n    if accuracy > best_acc:\n        best_acc = accuracy\n        torch.save(model_task3.state_dict(), 'task3_model_weights.pth')\n\n# Inference on test set for Task 3\nprint(\"[Task 3] Running inference on test set...\")\nmodel_task3.eval()\npredictions_task3 = []\ncategories = ['normal', 'forgery_1', 'forgery_2', 'forgery_3', 'forgery_4']\n\nwith torch.no_grad():\n    for images, img_names, countries_batch in tqdm(test_loader_task3, desc=\"Predicting fraud\"):\n        images = images.to(device)\n        outputs = model_task3(images)\n        _, predicted = outputs.max(1)\n        \n        for i, img_name in enumerate(img_names):\n            pred_category = categories[predicted[i].item()]\n            predictions_task3.append({\n                'image': img_name,\n                'country': countries_batch[i],\n                'predicted_class': pred_category\n            })\n\n# Save results for Task 3\ndf_task3 = pd.DataFrame(predictions_task3)\ndf_task3.to_csv('task3_results.csv', index=False)\nprint(f\"[Task 3] Results saved to task3_results.csv\")\nprint(f\"[Task 3] Model weights saved to task3_model_weights.pth\")\n\n# ============================================================================\n# SUMMARY\n# ============================================================================\nprint(\"\\n\" + \"=\" * 80)\nprint(\"COMPLETION SUMMARY\")\nprint(\"=\" * 80)\nprint(\"\\nAll tasks completed successfully!\")\nprint(\"\\nGenerated files:\")\nprint(\"  Task 1:\")\nprint(\"    - task1_results.csv (face matching results)\")\nprint(\"    - task1_model_weights.pth (model weights)\")\nprint(\"  Task 2:\")\nprint(\"    - task2_results.csv (age predictions)\")\nprint(\"    - task2_model_weights.pth (model weights)\")\nprint(\"  Task 3:\")\nprint(\"    - task3_results.csv (fraud detection results)\")\nprint(\"    - task3_model_weights.pth (model weights)\")\nprint(\"\\n\" + \"=\" * 80)\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-14T07:24:47.515087Z","iopub.execute_input":"2025-10-14T07:24:47.515535Z","iopub.status.idle":"2025-10-14T09:51:39.494016Z","shell.execute_reply.started":"2025-10-14T07:24:47.515513Z","shell.execute_reply":"2025-10-14T09:51:39.493206Z"}},"outputs":[{"name":"stdout","text":"Using device: cuda\n================================================================================\nANIP CHALLENGE - COMPLETE SOLUTION\n================================================================================\n\n================================================================================\nTASK 1: FACIAL RECOGNITION\n================================================================================\n\n[Task 1] Loading training data...\nFound 4000 images in /kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_1/dataset_tache_1/train\n[Task 1] Initializing face embedding model...\n","output_type":"stream"},{"name":"stderr","text":"Downloading: \"https://download.pytorch.org/models/resnet50-0676ba61.pth\" to /root/.cache/torch/hub/checkpoints/resnet50-0676ba61.pth\n100%|██████████| 97.8M/97.8M [00:00<00:00, 189MB/s] \n","output_type":"stream"},{"name":"stdout","text":"[Task 1] Extracting embeddings from training images...\n","output_type":"stream"},{"name":"stderr","text":"Training embeddings: 100%|██████████| 125/125 [00:39<00:00,  3.19it/s]\n","output_type":"stream"},{"name":"stdout","text":"[Task 1] Loading test data...\nFound 2000 images in /kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_1/dataset_tache_1/test\n[Task 1] Extracting embeddings from test images...\n","output_type":"stream"},{"name":"stderr","text":"Test embeddings: 100%|██████████| 63/63 [00:19<00:00,  3.26it/s]\n","output_type":"stream"},{"name":"stdout","text":"[Task 1] Matching faces...\n","output_type":"stream"},{"name":"stderr","text":"Creating matches: 100%|██████████| 2000/2000 [00:00<00:00, 134164.06it/s]\n","output_type":"stream"},{"name":"stdout","text":"[Task 1] Results saved to task1_results.csv\n[Task 1] Matched 2000 test images\n[Task 1] Model weights saved to task1_model_weights.pth\n\n================================================================================\nTASK 2: AGE ESTIMATION\n================================================================================\n\n[Task 2] Loading datasets...\nFound 40012 images in /kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_2/dataset_tache_2/train\nSample filenames: ['00013_00M19.JPG', '00013_01M19.JPG', '00013_02M19.JPG']\nAge range: 16 - 77\nFound 200 images in /kaggle/input/anip-reconnaissance-faciale-estimation-ages-ocr/dataset_tache_2/dataset_tache_2/test\nSample filenames: ['0.JPG', '1.JPG', '10.JPG']\n[Task 2] Training samples: 40012\n[Task 2] Test samples: 200\n[Task 2] Initializing age estimation model...\n[Task 2] Training model...\n","output_type":"stream"},{"name":"stderr","text":"Epoch 1/10: 100%|██████████| 1251/1251 [15:20<00:00,  1.36it/s, loss=5.77]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 1/10, Loss: 5.8960\n","output_type":"stream"},{"name":"stderr","text":"Epoch 2/10: 100%|██████████| 1251/1251 [10:37<00:00,  1.96it/s, loss=4.47]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 2/10, Loss: 4.9322\n","output_type":"stream"},{"name":"stderr","text":"Epoch 3/10: 100%|██████████| 1251/1251 [10:33<00:00,  1.98it/s, loss=5.08]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 3/10, Loss: 4.7408\n","output_type":"stream"},{"name":"stderr","text":"Epoch 4/10: 100%|██████████| 1251/1251 [10:32<00:00,  1.98it/s, loss=3.01]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 4/10, Loss: 4.5222\n","output_type":"stream"},{"name":"stderr","text":"Epoch 5/10: 100%|██████████| 1251/1251 [10:36<00:00,  1.97it/s, loss=5.29]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 5/10, Loss: 4.3896\n","output_type":"stream"},{"name":"stderr","text":"Epoch 6/10: 100%|██████████| 1251/1251 [10:37<00:00,  1.96it/s, loss=2.78]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 6/10, Loss: 4.2532\n","output_type":"stream"},{"name":"stderr","text":"Epoch 7/10: 100%|██████████| 1251/1251 [10:35<00:00,  1.97it/s, loss=4.97]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 7/10, Loss: 4.1577\n","output_type":"stream"},{"name":"stderr","text":"Epoch 8/10: 100%|██████████| 1251/1251 [10:34<00:00,  1.97it/s, loss=2.59]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 8/10, Loss: 4.1542\n","output_type":"stream"},{"name":"stderr","text":"Epoch 9/10: 100%|██████████| 1251/1251 [10:31<00:00,  1.98it/s, loss=3]   \n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 9/10, Loss: 4.0135\n","output_type":"stream"},{"name":"stderr","text":"Epoch 10/10: 100%|██████████| 1251/1251 [10:33<00:00,  1.97it/s, loss=6.66]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Epoch 10/10, Loss: 3.9571\n[Task 2] Running inference on test set...\n","output_type":"stream"},{"name":"stderr","text":"Predicting ages: 100%|██████████| 7/7 [00:02<00:00,  2.44it/s]\n","output_type":"stream"},{"name":"stdout","text":"[Task 2] Results saved to task2_results.csv\n[Task 2] Model weights saved to task2_model_weights.pth\n\n================================================================================\nTASK 3: OCR AND FRAUD DETECTION\n================================================================================\n\n[Task 3] Loading datasets...\nFound 500 images in arizona_dl/normal\nFound 500 images in arizona_dl/forgery_1\nFound 500 images in arizona_dl/forgery_2\nFound 500 images in arizona_dl/forgery_3\nFound 500 images in arizona_dl/forgery_4\nFound 500 images in esp/normal\nFound 500 images in esp/forgery_1\nFound 500 images in esp/forgery_2\nFound 500 images in esp/forgery_3\nFound 500 images in esp/forgery_4\nFound 500 images in est/normal\nFound 500 images in est/forgery_1\nFound 500 images in est/forgery_2\nFound 500 images in est/forgery_3\nFound 500 images in est/forgery_4\nFound 500 images in rus/normal\nFound 500 images in rus/forgery_1\nFound 500 images in rus/forgery_2\nFound 500 images in rus/forgery_3\nFound 500 images in rus/forgery_4\nTotal samples loaded: 10000\nFound 50 test images in arizona_dl\nFound 50 test images in esp\nFound 50 test images in est\nFound 50 test images in rus\nTotal samples loaded: 200\n[Task 3] Training samples: 10000\n[Task 3] Test samples: 200\n[Task 3] Initializing fraud detection model...\n[Task 3] Training model...\n","output_type":"stream"},{"name":"stderr","text":"Epoch 1/8: 100%|██████████| 625/625 [05:47<00:00,  1.80it/s, loss=0.695, acc=51.5]\n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 1/8, Loss: 0.9670, Accuracy: 51.55%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 2/8: 100%|██████████| 625/625 [04:13<00:00,  2.47it/s, loss=0.53, acc=62.4] \n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 2/8, Loss: 0.6733, Accuracy: 62.43%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 3/8: 100%|██████████| 625/625 [04:10<00:00,  2.50it/s, loss=0.574, acc=65.2]\n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 3/8, Loss: 0.6418, Accuracy: 65.18%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 4/8: 100%|██████████| 625/625 [04:08<00:00,  2.52it/s, loss=0.496, acc=73.9]\n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 4/8, Loss: 0.5349, Accuracy: 73.86%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 5/8: 100%|██████████| 625/625 [04:08<00:00,  2.51it/s, loss=0.524, acc=79.4]\n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 5/8, Loss: 0.4636, Accuracy: 79.40%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 6/8: 100%|██████████| 625/625 [04:07<00:00,  2.52it/s, loss=0.399, acc=82.2]\n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 6/8, Loss: 0.4095, Accuracy: 82.25%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 7/8: 100%|██████████| 625/625 [04:08<00:00,  2.51it/s, loss=0.492, acc=86.5] \n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 7/8, Loss: 0.3296, Accuracy: 86.47%\n","output_type":"stream"},{"name":"stderr","text":"Epoch 8/8: 100%|██████████| 625/625 [04:09<00:00,  2.50it/s, loss=0.214, acc=88]   \n","output_type":"stream"},{"name":"stdout","text":"[Task 3] Epoch 8/8, Loss: 0.3035, Accuracy: 87.99%\n[Task 3] Running inference on test set...\n","output_type":"stream"},{"name":"stderr","text":"Predicting fraud: 100%|██████████| 13/13 [00:04<00:00,  2.61it/s]","output_type":"stream"},{"name":"stdout","text":"[Task 3] Results saved to task3_results.csv\n[Task 3] Model weights saved to task3_model_weights.pth\n\n================================================================================\nCOMPLETION SUMMARY\n================================================================================\n\nAll tasks completed successfully!\n\nGenerated files:\n  Task 1:\n    - task1_results.csv (face matching results)\n    - task1_model_weights.pth (model weights)\n  Task 2:\n    - task2_results.csv (age predictions)\n    - task2_model_weights.pth (model weights)\n  Task 3:\n    - task3_results.csv (fraud detection results)\n    - task3_model_weights.pth (model weights)\n\n================================================================================\n","output_type":"stream"},{"name":"stderr","text":"\n","output_type":"stream"}],"execution_count":1},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}