{"metadata":{"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":63103,"databundleVersionId":6877691,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false},"colab":{"provenance":[],"gpuType":"T4"},"accelerator":"GPU"},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset, random_split\nfrom torchvision import transforms, models\nfrom PIL import Image\nimport os\nimport numpy as np\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom torchsummary import summary\nimport json\nimport seaborn as sns","metadata":{"id":"PMw_kMWu1CJx"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set random seeds\ntorch.manual_seed(42)\nnp.random.seed(42)","metadata":{"id":"SFbwfFVw1fm3"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define paths\ntrain_path = \"/kaggle/input/face-classification-deep-learning-cs-405/dataset/train\"\ntest_path = \"/kaggle/input/face-classification-deep-learning-cs-405/dataset\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Constants\nEPOCHS = 10\nBATCH_SIZE = 64\nIMG_SIZE = 224\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"id":"nVlg0fyu4dpp"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FaceDataset(Dataset):\n    def __init__(self, root_dir, transform=None):\n        self.root_dir = root_dir\n        self.transform = transform\n        self.classes = sorted(os.listdir(root_dir))\n        self.class_to_idx = {cls_name: i for i, cls_name in enumerate(self.classes)}\n        self.images = self._load_images()\n\n    def _load_images(self):\n        images = []\n        for class_name in self.classes:\n            class_dir = os.path.join(self.root_dir, class_name)\n            for img_name in os.listdir(class_dir):\n                img_path = os.path.join(class_dir, img_name)\n                images.append((img_path, self.class_to_idx[class_name]))\n        return images\n\n    def __len__(self):\n        return len(self.images)\n\n    def __getitem__(self, idx):\n        img_path, label = self.images[idx]\n        image = Image.open(img_path).convert('RGB')\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label","metadata":{"id":"UYKA5bWD4lDy"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training data generator\ntrain_transform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n\n# Validation data generator\nval_transform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])","metadata":{"id":"cf0uc-bx2GTv"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_dataset = FaceDataset(root_dir=train_path, transform=train_transform)","metadata":{"id":"Q02q5fsr4xBX"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset, val_dataset, test_dataset = random_split(\n    full_dataset, [train_size, val_size, test_size]\n)","metadata":{"id":"-0cErfoo48B7"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Apply different transform to validation and test sets\nval_dataset.dataset.transform = val_transform\ntest_dataset.dataset.transform = val_transform","metadata":{"id":"m4mq8TB34-pl"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Split into train (70%), validation (20%), and test (10%) sets\ntrain_size = int(0.7 * len(full_dataset))\nval_size = int(0.2 * len(full_dataset))\ntest_size = len(full_dataset) - train_size - val_size","metadata":{"id":"Zwh2zviT40C3"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create data loaders\ntrain_loader = DataLoader(\n    train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=4, pin_memory=True\n)\n\nval_loader = DataLoader(\n    val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=4, pin_memory=True\n)\n\ntest_loader = DataLoader(\n    test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=4, pin_memory=True\n)","metadata":{"id":"1HbKwImu5BDL"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FaceClassifier(nn.Module):\n    def __init__(self, num_classes):\n        super(FaceClassifier, self).__init__()\n        # Use ResNet50 as backbone\n        self.backbone = models.resnet50(pretrained=True)\n        in_features = self.backbone.fc.in_features\n        self.backbone.fc = nn.Identity()\n\n        # Custom classification head\n        self.classifier = nn.Sequential(\n            nn.Linear(in_features, 1024),\n            nn.BatchNorm1d(1024),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(1024, 512),\n            nn.BatchNorm1d(512),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n            nn.Linear(512, num_classes)\n        )\n\n    def forward(self, x):\n        features = self.backbone(x)\n        return self.classifier(features)","metadata":{"id":"6SckAH6s50jM"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Model Summary\")\nsummary(model, input_size=(3, IMG_SIZE, IMG_SIZE))","metadata":{"id":"2mHiPe09EzQx","outputId":"95304983-bca7-4f86-8699-123691e5db79"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Initialize model\nnum_classes = len(full_dataset.classes)\nmodel = FaceClassifier(num_classes=num_classes).to(DEVICE)","metadata":{"id":"DA-93iNs5L2N"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(model, train_loader, val_loader):\n    criterion = nn.CrossEntropyLoss()\n    optimizer = optim.Adam(model.parameters(), lr=1e-4)\n    best_acc = 0\n\n    train_losses, val_losses = [], []\n    train_accuracies, val_accuracies = [], []\n\n    for epoch in range(EPOCHS):\n        model.train()\n        running_loss, correct = 0.0, 0\n\n        for imgs, labels in tqdm(train_loader, desc=f\"Epoch {epoch+1}\"):\n            imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n            optimizer.zero_grad()\n            outputs = model(imgs)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item() * imgs.size(0)\n            correct += (outputs.argmax(1) == labels).sum().item()\n\n        train_acc = correct / len(train_loader.dataset)\n        train_loss = running_loss / len(train_loader.dataset)\n        train_losses.append(train_loss)\n        train_accuracies.append(train_acc)\n        print(f\"Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f}\")\n\n        # Validation\n        model.eval()\n        correct_val, val_loss_total = 0, 0.0\n        with torch.no_grad():\n            for imgs, labels in val_loader:\n                imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n                outputs = model(imgs)\n                loss = criterion(outputs, labels)\n                val_loss_total += loss.item() * imgs.size(0)\n                correct_val += (outputs.argmax(1) == labels).sum().item()\n        val_acc = correct_val / len(val_loader.dataset)\n        val_loss = val_loss_total / len(val_loader.dataset)\n        val_losses.append(val_loss)\n        val_accuracies.append(val_acc)\n\n        print(f\"Validation Loss: {val_loss:.4f}, Accuracy: {val_acc:.4f}\")\n        if val_acc > best_acc:\n            best_acc = val_acc\n            torch.save(model.state_dict(), \"best_model.pt\")\n            print(\"Best model saved\")\n\n    return train_losses, val_losses, train_accuracies, val_accuracies","metadata":{"id":"xuTmwtfw5Rki"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def test(model, loader):\n    model.eval()\n    correct = 0\n    with torch.no_grad():\n        for imgs, labels in loader:\n            imgs, labels = imgs.to(device), labels.to(device)\n            outputs = model(imgs)\n            correct += (outputs.argmax(1) == labels).sum().item()\n    print(f\"Test Accuracy: {correct / len(loader.dataset):.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T14:23:56.026410Z","iopub.execute_input":"2025-04-16T14:23:56.026676Z","iopub.status.idle":"2025-04-16T14:23:56.031127Z","shell.execute_reply.started":"2025-04-16T14:23:56.026656Z","shell.execute_reply":"2025-04-16T14:23:56.030539Z"},"id":"g0U16DR8yo0R"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_metrics(train_losses, val_losses, train_accuracies, val_accuracies):\n    plt.figure(figsize=(14, 5))\n\n    plt.subplot(1, 2, 1)\n    plt.plot(train_losses, label='Train Loss')\n    plt.plot(val_losses, label='Val Loss')\n    plt.xlabel(\"Epochs\")\n    plt.ylabel(\"Loss\")\n    plt.title(\"Loss Over Epochs\")\n    plt.legend()\n\n    plt.subplot(1, 2, 2)\n    plt.plot(train_accuracies, label='Train Acc')\n    plt.plot(val_accuracies, label='Val Acc')\n    plt.xlabel(\"Epochs\")\n    plt.ylabel(\"Accuracy\")\n    plt.title(\"Accuracy Over Epochs\")\n    plt.legend()\n\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T14:24:01.168856Z","iopub.execute_input":"2025-04-16T14:24:01.169425Z","iopub.status.idle":"2025-04-16T14:24:01.174006Z","shell.execute_reply.started":"2025-04-16T14:24:01.169399Z","shell.execute_reply":"2025-04-16T14:24:01.173234Z"},"id":"CYExoVpMyo0R"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if __name__ == \"__main__\":\n\n    train_losses, val_losses, train_accuracies, val_accuracies = train(model, train_loader, val_loader)\n\n    model.load_state_dict(torch.load(\"best_model.pt\"))\n    test(model, test_loader)\n    plot_metrics(train_losses, val_losses, train_accuracies, val_accuracies)","metadata":{"id":"8550cGXt8UHp","outputId":"fa4d01f0-4844-49cf-8b11-de20699a4675"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"####Plotting Graphs","metadata":{"id":"GfYmgcI4AHL2"}},{"cell_type":"code","source":"plot_metrics(train_losses, val_losses, train_accuracies, val_accuracies)","metadata":{"id":"PbzsfHtSAScr","outputId":"28426469-cb4d-4217-d09d-16f33ae7b8cf"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict_and_save(model, test_dir, output_csv_path, img_size=(224, 224), batch_size=32):\n    # Create test data generator\n    test_datagen = ImageDataGenerator(rescale=1./255)\n    test_generator = test_datagen.flow_from_directory(\n        test_dir,\n        target_size=img_size,\n        batch_size=batch_size,\n        class_mode=None,\n        shuffle=False\n    )\n\n    # Make predictions\n    predictions = model.predict(test_generator, verbose=1)\n    predicted_classes = np.argmax(predictions, axis=1)\n\n    # Map class indices back to class labels\n    class_indices = {v: k for k, v in test_generator.class_indices.items()}\n    predicted_labels = [class_indices[i] for i in predicted_classes]\n\n    # Get file names\n    filenames = test_generator.filenames\n    filenames = [f.split('/')[-1] for f in filenames]\n\n    # Create DataFrame and save\n    results_df = pd.DataFrame({\n        'filename': filenames,\n        'predicted_class': predicted_labels\n    })\n\n    results_df.to_csv(output_csv_path, index=False)\n    print(f\"Predictions saved to {output_csv_path}\")\n","metadata":{"id":"6boWLo0oDt0m"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_and_save(model, test_dir=test_path, output_csv_path='predictions.csv')","metadata":{"id":"jn30UcddDOUm","outputId":"dd40a405-ecff-449e-b3b2-4dca17a484f2"},"outputs":[],"execution_count":null}]}