{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!unzip -q /kaggle/input/dogs-vs-cats/train.zip","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":false,"scrolled":true,"execution":{"iopub.status.busy":"2025-04-02T14:03:39.338901Z","iopub.execute_input":"2025-04-02T14:03:39.339175Z","iopub.status.idle":"2025-04-02T14:03:50.864631Z","shell.execute_reply.started":"2025-04-02T14:03:39.339155Z","shell.execute_reply":"2025-04-02T14:03:50.862982Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport shutil\nimport random\n\n# Define paths\nBASE_DIR = \"/kaggle/working\"\nSOURCE_DIR = os.path.join(BASE_DIR, \"train\")  # Folder with all images\nDATA_DIR = os.path.join(BASE_DIR, \"data\")\nTRAIN_DIR = os.path.join(DATA_DIR, \"train\")\nVAL_DIR = os.path.join(DATA_DIR, \"val\")\n\n# Ensure required directories exist\nfor category in [\"cat\", \"dog\"]:\n    os.makedirs(os.path.join(TRAIN_DIR, category), exist_ok=True)\n    os.makedirs(os.path.join(VAL_DIR, category), exist_ok=True)\n\n# Organize images into \"cat/\" and \"dog/\" folders\nfor filename in os.listdir(SOURCE_DIR):\n    if filename.startswith(\"cat\"):\n        shutil.move(os.path.join(SOURCE_DIR, filename), os.path.join(TRAIN_DIR, \"cat\", filename))\n    elif filename.startswith(\"dog\"):\n        shutil.move(os.path.join(SOURCE_DIR, filename), os.path.join(TRAIN_DIR, \"dog\", filename))\n\nprint(\"Dataset structured successfully!\")\n\n# Split function\ndef split_data(category, train_ratio=0.8):\n    source_path = os.path.join(TRAIN_DIR, category)\n    images = [f for f in os.listdir(source_path) if f.endswith(\".jpg\")]\n    random.shuffle(images)\n\n    train_count = int(train_ratio * len(images))\n    train_images = images[:train_count]\n    val_images = images[train_count:]\n\n    # Move images to train and val folders\n    for img in val_images:\n        shutil.move(os.path.join(source_path, img), os.path.join(VAL_DIR, category, img))\n\n# Apply split for both categories\nsplit_data(\"cat\")\nsplit_data(\"dog\")\n\nprint(\"Dataset split successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-02T14:03:50.866659Z","iopub.execute_input":"2025-04-02T14:03:50.867082Z","iopub.status.idle":"2025-04-02T14:03:51.830086Z","shell.execute_reply.started":"2025-04-02T14:03:50.867044Z","shell.execute_reply":"2025-04-02T14:03:51.829164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nimport torchvision.datasets as datasets\nimport torchvision.models as models\nfrom torch.utils.data import DataLoader\nfrom tqdm import tqdm  # Import tqdm for progress bars\n\n# Paths\nTRAIN_PATH = \"./data/train\"\nVAL_PATH = \"./data/val\"\n\n# Training parameters\nNUM_BATCH = 32\nEPOCHS = 5\nLEARNING_RATE = 1e-3\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\n# Define data transformations\ntransform = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Resize((224, 224)),\n])\n\n# Load datasets\ntrain_dataset = datasets.ImageFolder(root=TRAIN_PATH, transform=transform)\nval_dataset = datasets.ImageFolder(root=VAL_PATH, transform=transform)\n\n# Create DataLoaders\ntrain_loader = DataLoader(train_dataset, batch_size=NUM_BATCH, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=NUM_BATCH, shuffle=False)\n\n# Load pre-trained ResNet18 model\nmodel = models.resnet18(pretrained=True)\nprint(model.fc.in_features)\n\n# Freeze all layers\nfor param in model.parameters():\n    param.requires_grad = False\n\n# Replace the fully connected layer\nmodel.fc = nn.Linear(in_features=512, out_features=2)\n\n# Ensure the new `fc` layer is trainable\nfor param in model.fc.parameters():\n    param.requires_grad = True\n\n# Move model to device\nmodel = model.to(DEVICE)\n\n# Define loss function and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.fc.parameters(), lr=LEARNING_RATE)\n\n# Training and validation loop\nfor epoch in range(EPOCHS):\n    # Training\n    model.train()\n    train_loss, correct, total = 0, 0, 0\n    loop = tqdm(train_loader, desc=f\"Epoch [{epoch+1}/{EPOCHS}] Training\", leave=True)\n    \n    for images, labels in loop:\n        images, labels = images.to(DEVICE), labels.to(DEVICE)\n\n        # Forward pass\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n\n        # Backpropagation\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        # Track loss and accuracy\n        train_loss += loss.item()\n        _, predicted = torch.max(outputs, 1)\n        correct += (predicted == labels).sum().item()\n        total += labels.size(0)\n\n        # Update tqdm progress bar\n        loop.set_postfix(loss=loss.item(), acc=100 * correct / total)\n\n    train_acc = 100 * correct / total\n    print(f\"Epoch [{epoch+1}/{EPOCHS}], Train Loss: {train_loss/len(train_loader):.4f}, Train Acc: {train_acc:.2f}%\")\n\n    # Validation\n    model.eval()\n    val_loss, correct, total = 0, 0, 0\n    loop = tqdm(val_loader, desc=f\"Epoch [{epoch+1}/{EPOCHS}] Validation\", leave=True)\n\n    with torch.no_grad():\n        for images, labels in loop:\n            images, labels = images.to(DEVICE), labels.to(DEVICE)\n\n            # Forward pass\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n            # Track loss and accuracy\n            val_loss += loss.item()\n            _, predicted = torch.max(outputs, 1)\n            correct += (predicted == labels).sum().item()\n            total += labels.size(0)\n\n            # Update tqdm progress bar\n            loop.set_postfix(loss=loss.item(), acc=100 * correct / total)\n\n    val_acc = 100 * correct / total\n    print(f\"Epoch [{epoch+1}/{EPOCHS}], Val Loss: {val_loss/len(val_loader):.4f}, Val Acc: {val_acc:.2f}%\")\n\nprint(\"Training complete!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-02T15:21:15.006962Z","iopub.execute_input":"2025-04-02T15:21:15.007282Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"ResNet18_CatDog_224_Norm.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-02T14:11:54.891900Z","iopub.execute_input":"2025-04-02T14:11:54.892141Z","iopub.status.idle":"2025-04-02T14:11:54.962455Z","shell.execute_reply.started":"2025-04-02T14:11:54.892119Z","shell.execute_reply":"2025-04-02T14:11:54.961794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}