{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nfrom torch import nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom torchvision.transforms import Resize, ToTensor, CenterCrop, Normalize\nfrom torchvision.datasets import ImageFolder\nfrom PIL import Image\nfrom pathlib import Path\nimport pandas as pd\nimport numpy as np\nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-output":false,"execution":{"iopub.status.busy":"2023-10-16T12:43:42.343022Z","iopub.execute_input":"2023-10-16T12:43:42.343351Z","iopub.status.idle":"2023-10-16T12:43:46.013734Z","shell.execute_reply.started":"2023-10-16T12:43:42.343323Z","shell.execute_reply":"2023-10-16T12:43:46.012736Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.manual_seed(42)\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\ndevice","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:43:46.015625Z","iopub.execute_input":"2023-10-16T12:43:46.016123Z","iopub.status.idle":"2023-10-16T12:43:46.053644Z","shell.execute_reply.started":"2023-10-16T12:43:46.016090Z","shell.execute_reply":"2023-10-16T12:43:46.052507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform = transforms.Compose([\n    Resize(256),\n    CenterCrop(224),\n    ToTensor(),\n    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:43:47.850835Z","iopub.execute_input":"2023-10-16T12:43:47.851769Z","iopub.status.idle":"2023-10-16T12:43:47.857132Z","shell.execute_reply.started":"2023-10-16T12:43:47.851738Z","shell.execute_reply":"2023-10-16T12:43:47.855921Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset_path = Path('/', 'kaggle', 'input', 'dog-vs-cat-classification')","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:43:48.963881Z","iopub.execute_input":"2023-10-16T12:43:48.964423Z","iopub.status.idle":"2023-10-16T12:43:48.968886Z","shell.execute_reply.started":"2023-10-16T12:43:48.964394Z","shell.execute_reply":"2023-10-16T12:43:48.967978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset_path = Path(dataset_path, 'train', 'train')\ntest_dataset_path = Path(dataset_path, 'test', 'test')","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:43:49.623563Z","iopub.execute_input":"2023-10-16T12:43:49.623964Z","iopub.status.idle":"2023-10-16T12:43:49.629051Z","shell.execute_reply.started":"2023-10-16T12:43:49.623932Z","shell.execute_reply":"2023-10-16T12:43:49.627541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = ImageFolder(root=train_dataset_path, transform=transform, target_transform=lambda x: torch.tensor([x]).float())\ntrain_dataset.class_to_idx","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:43:50.281671Z","iopub.execute_input":"2023-10-16T12:43:50.282029Z","iopub.status.idle":"2023-10-16T12:44:32.588627Z","shell.execute_reply.started":"2023-10-16T12:43:50.282004Z","shell.execute_reply":"2023-10-16T12:44:32.587733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:34.603257Z","iopub.execute_input":"2023-10-16T12:44:34.603624Z","iopub.status.idle":"2023-10-16T12:44:34.608876Z","shell.execute_reply.started":"2023-10-16T12:44:34.603575Z","shell.execute_reply":"2023-10-16T12:44:34.607959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomVGG11(nn.Module):\n    def __init__(self, hidden_units):\n        super().__init__()\n\n        in_ch, out_ch = 3, hidden_units\n        conv1_block = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n        )\n\n        in_ch, out_ch = out_ch, 2 * out_ch\n        conv2_block = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n        )\n\n        in_ch, out_ch = out_ch, 2 * out_ch\n        conv3_block = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.Conv2d(out_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n        )\n\n        in_ch, out_ch = out_ch, 2 * out_ch\n        conv4_block = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.Conv2d(out_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n        )\n\n        conv5_block = nn.Sequential(\n            nn.Conv2d(out_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.Conv2d(out_ch, out_ch, 3, 1, 1),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n        )\n\n        self.conv_layers = nn.Sequential(\n            conv1_block,\n            conv2_block,\n            conv3_block,\n            conv4_block,\n            conv5_block,\n        )\n\n        self.classifier = nn.Sequential(\n            nn.Linear(out_ch * 7 * 7, 4096),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(4096, 4096),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(4096, 1),\n        )\n\n    def forward(self, x):\n        batch_size = x.size(0)\n        y1 = self.conv_layers(x)\n        y2 = y1.view(batch_size, -1)\n        y3 = self.classifier(y2)\n        return y3","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:35.352441Z","iopub.execute_input":"2023-10-16T12:44:35.353544Z","iopub.status.idle":"2023-10-16T12:44:35.364108Z","shell.execute_reply.started":"2023-10-16T12:44:35.353503Z","shell.execute_reply":"2023-10-16T12:44:35.363138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = CustomVGG11(hidden_units=8)\nloss_fn = nn.BCELoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:36.140822Z","iopub.execute_input":"2023-10-16T12:44:36.141138Z","iopub.status.idle":"2023-10-16T12:44:36.443870Z","shell.execute_reply.started":"2023-10-16T12:44:36.141114Z","shell.execute_reply":"2023-10-16T12:44:36.442863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.to(device)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:37.327431Z","iopub.execute_input":"2023-10-16T12:44:37.327799Z","iopub.status.idle":"2023-10-16T12:44:40.699417Z","shell.execute_reply.started":"2023-10-16T12:44:37.327769Z","shell.execute_reply":"2023-10-16T12:44:40.697052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_step(model, dataloader, loss_fn, optimizer):\n    train_loss = 0\n    train_acc = 0\n    \n    model.train()\n    for batch, (x, y) in tqdm(enumerate(dataloader), total=len(dataloader), ncols=100, desc='train'):\n        x, y = x.to(device), y.to(device)\n\n        probs = torch.sigmoid(model(x))\n        loss = loss_fn(probs, y)\n        train_loss += loss.item()\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        preds = probs.round()\n        train_acc += y.eq(preds).float().mean().item()\n        \n    train_loss /= len(train_dataloader)\n    train_acc /= len(train_dataloader)\n    return train_loss, train_acc","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:47.099658Z","iopub.execute_input":"2023-10-16T12:44:47.100017Z","iopub.status.idle":"2023-10-16T12:44:47.107231Z","shell.execute_reply.started":"2023-10-16T12:44:47.099991Z","shell.execute_reply":"2023-10-16T12:44:47.105665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs = 10\ncolumns = ['train_loss', 'train_acc']\nhistory = pd.DataFrame(columns=columns)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:52.395809Z","iopub.execute_input":"2023-10-16T12:44:52.396427Z","iopub.status.idle":"2023-10-16T12:44:52.404033Z","shell.execute_reply.started":"2023-10-16T12:44:52.396400Z","shell.execute_reply":"2023-10-16T12:44:52.402804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(epochs):\n\n    print(f'epoch {epoch + 1} of {epochs}')\n    \n    train_loss, train_acc = train_step(model, train_dataloader, loss_fn, optimizer)\n\n    stat = [train_loss, train_acc]\n    print('train_loss: {:.4f} | train_acc: {:.4f}'.format(*stat))\n    history.loc[len(history)] = stat","metadata":{"execution":{"iopub.status.busy":"2023-10-16T12:44:55.845429Z","iopub.execute_input":"2023-10-16T12:44:55.846168Z","iopub.status.idle":"2023-10-16T13:10:40.520972Z","shell.execute_reply.started":"2023-10-16T12:44:55.846138Z","shell.execute_reply":"2023-10-16T13:10:40.519916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict(row):\n    image = Image.open(row.id)\n    x = transform(image).unsqueeze(0).to(device)\n    with torch.inference_mode():\n        y = torch.sigmoid(model(x))\n        label = y.cpu().squeeze().round().int().item()\n        return label","metadata":{"execution":{"iopub.status.busy":"2023-10-16T13:11:20.535038Z","iopub.execute_input":"2023-10-16T13:11:20.535374Z","iopub.status.idle":"2023-10-16T13:11:20.541419Z","shell.execute_reply.started":"2023-10-16T13:11:20.535347Z","shell.execute_reply":"2023-10-16T13:11:20.540348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output = pd.DataFrame({'id': test_dataset_path.iterdir()})\n\nmodel.eval()\noutput['labels'] = output.apply(predict, axis=1)\noutput['id'] = output.apply(lambda x: x.id.name, axis=1)\noutput.head()","metadata":{"execution":{"iopub.status.busy":"2023-10-16T13:11:23.083789Z","iopub.execute_input":"2023-10-16T13:11:23.084251Z","iopub.status.idle":"2023-10-16T13:13:21.804107Z","shell.execute_reply.started":"2023-10-16T13:11:23.084213Z","shell.execute_reply":"2023-10-16T13:13:21.803116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output.sort_values(by=['id']).to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T13:23:11.519545Z","iopub.execute_input":"2023-10-16T13:23:11.519977Z","iopub.status.idle":"2023-10-16T13:23:11.544581Z","shell.execute_reply.started":"2023-10-16T13:23:11.519949Z","shell.execute_reply":"2023-10-16T13:23:11.543609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}