{"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":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os, shutil, random, zipfile\n\ninput_path = \"/kaggle/input/dogs-vs-cats\"   # adjust if your folder name is different\nwork_path = \"/kaggle/working\"\n\nwith zipfile.ZipFile(os.path.join(input_path, \"train.zip\"), 'r') as z:\n    z.extractall(work_path)\n\nwith zipfile.ZipFile(os.path.join(input_path, \"test1.zip\"), 'r') as z:\n    z.extractall(work_path)\n\nprint(\"Extraction completed!\")\n\noriginal_dataset_dir = \"/kaggle/working/train\"     # <-- where extracted images are\nbase_dir = \"/kaggle/working/cats_and_dogs_small\"   # <-- new dataset folder\n\nif not os.path.exists(base_dir):\n    os.mkdir(base_dir)\n\ntrain_dir = os.path.join(base_dir, \"train\")\nvalid_dir = os.path.join(base_dir, \"valid\")\n\nfor d in [train_dir, valid_dir]:\n    if not os.path.exists(d):\n        os.mkdir(d)\n\ntrain_cats = os.path.join(train_dir, \"cats\")\ntrain_dogs = os.path.join(train_dir, \"dogs\")\nvalid_cats = os.path.join(valid_dir, \"cats\")\nvalid_dogs = os.path.join(valid_dir, \"dogs\")\n\nfor d in [train_cats, train_dogs, valid_cats, valid_dogs]:\n    if not os.path.exists(d):\n        os.mkdir(d)\n\nfnames = os.listdir(original_dataset_dir)\nrandom.shuffle(fnames)\n\nvalid_files = fnames[:2000]\ntrain_files = fnames[2000:4000]\n\n# Copy validation images\nfor fname in valid_files:\n    src = os.path.join(original_dataset_dir, fname)\n    if \"cat\" in fname:\n        shutil.copy(src, valid_cats)\n    else:\n        shutil.copy(src, valid_dogs)\n\n# Copy training images\nfor fname in train_files:\n    src = os.path.join(original_dataset_dir, fname)\n    if \"cat\" in fname:\n        shutil.copy(src, train_cats)\n    else:\n        shutil.copy(src, train_dogs)\n\nprint(\"Dataset split completed!\")\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:44.691611Z","iopub.execute_input":"2025-12-03T13:47:44.691936Z","iopub.status.idle":"2025-12-03T13:47:54.120718Z","shell.execute_reply.started":"2025-12-03T13:47:44.691912Z","shell.execute_reply":"2025-12-03T13:47:54.120103Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import transforms, datasets\nimport torch\n\ndata_transforms = {\n    'train': transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406], \n                             [0.229, 0.224, 0.225])\n    ]),\n    'valid': transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406], \n                             [0.229, 0.224, 0.225])\n    ]),\n}\n\ntrain_dataset = datasets.ImageFolder(train_dir, data_transforms['train'])\nvalid_dataset = datasets.ImageFolder(valid_dir, data_transforms['valid'])\n\nprint(train_dataset.class_to_idx)\nprint(train_dataset.classes)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:54.121848Z","iopub.execute_input":"2025-12-03T13:47:54.122064Z","iopub.status.idle":"2025-12-03T13:47:54.137509Z","shell.execute_reply.started":"2025-12-03T13:47:54.122046Z","shell.execute_reply":"2025-12-03T13:47:54.136957Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2)\nvalid_loader = DataLoader(valid_dataset, batch_size=32, shuffle=True, num_workers=2)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:54.13834Z","iopub.execute_input":"2025-12-03T13:47:54.138615Z","iopub.status.idle":"2025-12-03T13:47:54.142512Z","shell.execute_reply.started":"2025-12-03T13:47:54.138598Z","shell.execute_reply":"2025-12-03T13:47:54.14197Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import models\nimport torch.nn as nn\n\nmodel_ft = models.resnet18(pretrained=True)\n\n# Replace last layer: 512 → 2 classes (cat/dog)\nnum_ftrs = model_ft.fc.in_features\nmodel_ft.fc = nn.Linear(num_ftrs, 2)\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel_ft = model_ft.to(device)\n\nprint(model_ft)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:54.143886Z","iopub.execute_input":"2025-12-03T13:47:54.144087Z","iopub.status.idle":"2025-12-03T13:47:54.61999Z","shell.execute_reply.started":"2025-12-03T13:47:54.144072Z","shell.execute_reply":"2025-12-03T13:47:54.619272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.optim as optim\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)\nscheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:54.620653Z","iopub.execute_input":"2025-12-03T13:47:54.621193Z","iopub.status.idle":"2025-12-03T13:47:54.625736Z","shell.execute_reply.started":"2025-12-03T13:47:54.621173Z","shell.execute_reply":"2025-12-03T13:47:54.624938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time\nimport copy\n\ndef train_model(model, criterion, optimizer, scheduler, num_epochs=25):\n    since = time.time()\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n    \n    for epoch in range(num_epochs):\n        print(f\"Epoch {epoch}/{num_epochs-1}\")\n        print(\"-\" * 20)\n        \n        for phase in [\"train\", \"valid\"]:\n            if phase == \"train\":\n                model.train()\n                dataloader = train_loader\n            else:\n                model.eval()\n                dataloader = valid_loader\n            \n            running_loss = 0.0\n            running_corrects = 0\n            \n            for inputs, labels in dataloader:\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n                \n                optimizer.zero_grad()\n                \n                with torch.set_grad_enabled(phase == \"train\"):\n                    outputs = model(inputs)\n                    _, preds = torch.max(outputs, 1)\n                    loss = criterion(outputs, labels)\n                    \n                    if phase == \"train\":\n                        loss.backward()\n                        optimizer.step()\n                \n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n            \n            if phase == \"train\":\n                scheduler.step()\n            \n            epoch_loss = running_loss / len(dataloader.dataset)\n            epoch_acc = running_corrects.double() / len(dataloader.dataset)\n            \n            print(f\"{phase} Loss: {epoch_loss:.4f}  Acc: {epoch_acc:.4f}\")\n            \n            # Save best model\n            if phase == \"valid\" and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n        \n        print()\n    \n    total_time = time.time() - since\n    print(f\"Training complete in {total_time//60:.0f}m {total_time%60:.0f}s\")\n    print(f\"Best validation accuracy: {best_acc:.4f}\")\n    \n    model.load_state_dict(best_model_wts)\n    return model\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:54.627434Z","iopub.execute_input":"2025-12-03T13:47:54.627655Z","iopub.status.idle":"2025-12-03T13:47:54.637622Z","shell.execute_reply.started":"2025-12-03T13:47:54.62764Z","shell.execute_reply":"2025-12-03T13:47:54.63711Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_ft = train_model(model_ft, criterion, optimizer, scheduler, num_epochs=5)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-03T13:47:54.638246Z","iopub.execute_input":"2025-12-03T13:47:54.638463Z","iopub.status.idle":"2025-12-03T13:48:47.88084Z","shell.execute_reply.started":"2025-12-03T13:47:54.638447Z","shell.execute_reply":"2025-12-03T13:48:47.879927Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}