{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"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":"none","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30635,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Kaggle link: https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition","metadata":{}},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.status.busy":"2024-01-15T16:34:23.390591Z","iopub.execute_input":"2024-01-15T16:34:23.392426Z","iopub.status.idle":"2024-01-15T16:34:23.410422Z","shell.execute_reply.started":"2024-01-15T16:34:23.392374Z","shell.execute_reply":"2024-01-15T16:34:23.409296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Import everything needed","metadata":{}},{"cell_type":"code","source":"import zipfile\nimport glob\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import train_test_split\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import datasets, transforms\nnp.random.seed(0)\ntorch.manual_seed(0)\ntorch.cuda.manual_seed(0)","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:23.412258Z","iopub.execute_input":"2024-01-15T16:34:23.412739Z","iopub.status.idle":"2024-01-15T16:34:23.419679Z","shell.execute_reply.started":"2024-01-15T16:34:23.412715Z","shell.execute_reply":"2024-01-15T16:34:23.418901Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Unzip datasets","metadata":{}},{"cell_type":"code","source":"train_dir = 'train'\ntest_dir = 'test'\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip') as train_zip:\n    train_zip.extractall('')\n    \nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip') as test_zip:\n    test_zip.extractall('')\ntrain_list = glob.glob(os.path.join(train_dir,'*.jpg'))\ntest_list = glob.glob(os.path.join(test_dir, '*.jpg'))\nprint(f\"Train Data: {len(train_list)}\")\nprint(f\"Test Data: {len(test_list)}\")","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:23.420959Z","iopub.execute_input":"2024-01-15T16:34:23.421234Z","iopub.status.idle":"2024-01-15T16:34:39.214121Z","shell.execute_reply.started":"2024-01-15T16:34:23.421206Z","shell.execute_reply":"2024-01-15T16:34:39.212865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = [path.split('/')[-1].split('.')[0] for path in train_list]","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:39.216780Z","iopub.execute_input":"2024-01-15T16:34:39.217188Z","iopub.status.idle":"2024-01-15T16:34:39.231544Z","shell.execute_reply.started":"2024-01-15T16:34:39.217157Z","shell.execute_reply":"2024-01-15T16:34:39.230501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Plot random image with their label","metadata":{}},{"cell_type":"code","source":"random_idx = np.random.randint(1, len(train_list), size=9)\nfig, axes = plt.subplots(3, 3, figsize=(16, 12))\n\nfor idx, ax in enumerate(axes.ravel()):\n    img = Image.open(train_list[idx])\n    ax.set_title(labels[idx])\n    ax.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:39.232747Z","iopub.execute_input":"2024-01-15T16:34:39.233069Z","iopub.status.idle":"2024-01-15T16:34:42.182151Z","shell.execute_reply.started":"2024-01-15T16:34:39.233044Z","shell.execute_reply":"2024-01-15T16:34:42.181223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Use Sklearn to split the training data","metadata":{}},{"cell_type":"code","source":"train_list, valid_list = train_test_split(train_list, \n                                          test_size=0.2,\n                                          stratify=labels,\n                                          random_state=0)","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.183197Z","iopub.execute_input":"2024-01-15T16:34:42.183603Z","iopub.status.idle":"2024-01-15T16:34:42.205626Z","shell.execute_reply.started":"2024-01-15T16:34:42.183575Z","shell.execute_reply":"2024-01-15T16:34:42.204424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Train Data: {len(train_list)}\")\nprint(f\"Validation Data: {len(valid_list)}\")\nprint(f\"Test Data: {len(test_list)}\")","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.206762Z","iopub.execute_input":"2024-01-15T16:34:42.207012Z","iopub.status.idle":"2024-01-15T16:34:42.213455Z","shell.execute_reply.started":"2024-01-15T16:34:42.206990Z","shell.execute_reply":"2024-01-15T16:34:42.211849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will discuss this in more detail in a near future...","metadata":{}},{"cell_type":"code","source":"train_transforms = transforms.Compose([\n    transforms.RandomResizedCrop(224),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(degrees=15),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) \n])\n\ntest_transforms = transforms.Compose([\n    transforms.Resize(256),\n    transforms.CenterCrop(224),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.214592Z","iopub.execute_input":"2024-01-15T16:34:42.214922Z","iopub.status.idle":"2024-01-15T16:34:42.227607Z","shell.execute_reply.started":"2024-01-15T16:34:42.214867Z","shell.execute_reply":"2024-01-15T16:34:42.226604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Define the dataset using PIL to read image","metadata":{}},{"cell_type":"code","source":"class CatsDogsDataset(Dataset):\n    def __init__(self, file_list, transform=None):\n        self.file_list = file_list\n        self.transform = transform\n        self.filelength = len(file_list)\n\n    def __len__(self):\n        return self.filelength\n\n    def __getitem__(self, idx):\n        img_path = self.file_list[idx]\n        img = Image.open(img_path)\n        img_transformed = self.transform(img)\n        label = img_path.split(\"/\")[-1].split(\".\")[0]\n        label = 1 if label == \"dog\" else 0\n        return img_transformed, label","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.229050Z","iopub.execute_input":"2024-01-15T16:34:42.230215Z","iopub.status.idle":"2024-01-15T16:34:42.237478Z","shell.execute_reply.started":"2024-01-15T16:34:42.230168Z","shell.execute_reply":"2024-01-15T16:34:42.236643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = CatsDogsDataset(train_list, transform=train_transforms)\nvalid_data = CatsDogsDataset(valid_list, transform=test_transforms)\ntest_data = CatsDogsDataset(test_list, transform=test_transforms)","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.240245Z","iopub.execute_input":"2024-01-15T16:34:42.240604Z","iopub.status.idle":"2024-01-15T16:34:42.249708Z","shell.execute_reply.started":"2024-01-15T16:34:42.240579Z","shell.execute_reply":"2024-01-15T16:34:42.248662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Create dataloader, you can modify the batch size if needed","metadata":{}},{"cell_type":"code","source":"batch_size = 32\ntrain_loader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)\nvalid_loader = DataLoader(dataset=valid_data, batch_size=batch_size, shuffle=False)\ntest_loader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.251128Z","iopub.execute_input":"2024-01-15T16:34:42.251658Z","iopub.status.idle":"2024-01-15T16:34:42.261320Z","shell.execute_reply.started":"2024-01-15T16:34:42.251632Z","shell.execute_reply":"2024-01-15T16:34:42.260239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO: define a convolutional neural network, train it and output the log ","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.262241Z","iopub.execute_input":"2024-01-15T16:34:42.262489Z","iopub.status.idle":"2024-01-15T16:34:42.270979Z","shell.execute_reply.started":"2024-01-15T16:34:42.262467Z","shell.execute_reply":"2024-01-15T16:34:42.270227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nimport torch.optim as optim\n\n\nclass SimpleCNN(nn.Module):\n    def __init__(self):\n        super(SimpleCNN, self).__init__()\n        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)\n        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)\n        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)\n        self.fc1 = nn.Linear(32 * 56 * 56, 256)\n        self.fc2 = nn.Linear(256, 2)  # 2 classes: cat and dog\n\n    def forward(self, x):\n        x = self.pool(F.relu(self.conv1(x)))\n        x = self.pool(F.relu(self.conv2(x)))\n        x = x.view(-1, 32 * 56 * 56)\n        x = F.relu(self.fc1(x))\n        x = self.fc2(x)\n        return x\n\n\nmodel = SimpleCNN()\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\n\nnum_epochs = 5\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n    for images, labels in train_loader:\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item()\n    \n    \n    average_loss = running_loss / len(train_loader)\n    print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {average_loss:.4f}')\n\n\nmodel.eval()\ncorrect = 0\ntotal = 0\nwith torch.no_grad():\n    for images, labels in valid_loader:\n        outputs = model(images)\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n\naccuracy = correct / total\nprint(f'Validation Accuracy: {accuracy * 100:.2f}%')\n\n","metadata":{"execution":{"iopub.status.busy":"2024-01-15T16:34:42.272065Z","iopub.execute_input":"2024-01-15T16:34:42.272363Z","iopub.status.idle":"2024-01-15T17:20:00.922672Z","shell.execute_reply.started":"2024-01-15T16:34:42.272335Z","shell.execute_reply":"2024-01-15T17:20:00.921469Z"},"trusted":true},"execution_count":null,"outputs":[]}]}