{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":74704,"databundleVersionId":8152167,"sourceType":"competition"}],"dockerImageVersionId":30684,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\nimport cv2\nimport numpy as np\nimport os\nimport random\nimport pandas as pd\nfrom PIL import Image\n\nimport torch\nimport torchvision\nimport torchvision.transforms as transform\nfrom torchvision.datasets import ImageFolder\nfrom torch.utils.data import DataLoader, Dataset, ConcatDataset\nimport torch.nn as nn\nimport torchvision.models as models\nfrom torchvision.utils import make_grid\nimport torch.nn.functional as F\nimport torch.optim as optim\nimport math\nimport copy\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils.class_weight import compute_class_weight","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:00:20.722422Z","iopub.execute_input":"2024-04-22T02:00:20.722768Z","iopub.status.idle":"2024-04-22T02:00:29.090972Z","shell.execute_reply.started":"2024-04-22T02:00:20.722739Z","shell.execute_reply":"2024-04-22T02:00:29.090055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label_names = ['dandelion', 'daisy','tulip','sunflower','rose']\nimg_size = 224\ntrain_transform = transform.Compose([\n    transform.Resize((img_size, img_size)),\n    transform.ToTensor(),\n    transform.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\ntrain_dataset = ImageFolder('../input/ece379k-hw4-flower-classification-24spring/train', transform=train_transform)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:00:29.092849Z","iopub.execute_input":"2024-04-22T02:00:29.093663Z","iopub.status.idle":"2024-04-22T02:00:30.413648Z","shell.execute_reply.started":"2024-04-22T02:00:29.093625Z","shell.execute_reply":"2024-04-22T02:00:30.412638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y = [i[1] for i in train_dataset]\nclass_weights = compute_class_weight(class_weight=\"balanced\", classes=np.unique(y), y=y)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:00:30.414941Z","iopub.execute_input":"2024-04-22T02:00:30.415677Z","iopub.status.idle":"2024-04-22T02:00:58.960751Z","shell.execute_reply.started":"2024-04-22T02:00:30.415641Z","shell.execute_reply":"2024-04-22T02:00:58.959916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"my_train, my_test = train_test_split(train_dataset, test_size=0.1, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:00:58.962494Z","iopub.execute_input":"2024-04-22T02:00:58.962783Z","iopub.status.idle":"2024-04-22T02:01:14.149404Z","shell.execute_reply.started":"2024-04-22T02:00:58.962757Z","shell.execute_reply":"2024-04-22T02:01:14.148563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"my_train_transform = transform.Compose([\n    transform.RandomRotation(30),\n    transform.RandomHorizontalFlip(p=0.5)])\nmy_train = [(my_train_transform(i[0]), i[1]) for i in my_train]","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:01:14.150948Z","iopub.execute_input":"2024-04-22T02:01:14.151383Z","iopub.status.idle":"2024-04-22T02:01:23.028391Z","shell.execute_reply.started":"2024-04-22T02:01:14.151345Z","shell.execute_reply":"2024-04-22T02:01:23.027553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 32\ntrain_loader = torch.utils.data.DataLoader(my_train, batch_size=batch_size, shuffle=True)\ntest_loader = torch.utils.data.DataLoader(my_test, batch_size=batch_size, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:02:20.798585Z","iopub.execute_input":"2024-04-22T02:02:20.799453Z","iopub.status.idle":"2024-04-22T02:02:20.804306Z","shell.execute_reply.started":"2024-04-22T02:02:20.799416Z","shell.execute_reply":"2024-04-22T02:02:20.803339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FlowerModel(nn.Module):\n    def __init__(self, num_classes=1000):\n        super().__init__()\n        self.cnn = nn.Sequential(\n            nn.Conv2d(3, 32, kernel_size=3, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Dropout(0.2),\n            \n            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Dropout(0.1),\n        \n            nn.Conv2d(64, 96, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Dropout(0.1),\n            \n            nn.Conv2d(96, 96, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Dropout(0.2),\n            \n            nn.Flatten(),\n            nn.Linear(18816, 1024),\n            nn.ReLU(),\n            \n            nn.Linear(1024, 512),\n            nn.ReLU(),\n            \n            nn.Linear(512, num_classes)\n        )\n    \n    def validation_step(self, batch, loss_fn):\n        images, labels = batch \n        out = self(images)                    # Generate predictions\n        loss = loss_fn(out, labels)           # Calculate loss\n        acc = accuracy(out, labels)           # Calculate accuracy\n        return {'val_loss': loss.detach(), 'val_acc': acc}\n        \n    def validation_epoch_end(self, outputs):\n        batch_losses = [x['val_loss'] for x in outputs]\n        epoch_loss = torch.stack(batch_losses).mean()   # Combine losses\n        batch_accs = [x['val_acc'] for x in outputs]\n        epoch_acc = torch.stack(batch_accs).mean()      # Combine accuracies\n        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}\n    \n    def epoch_end(self, epoch, result):\n        print(\"Epoch [{}], train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}\".format(\n            epoch, result['train_loss'], result['val_loss'], result['val_acc']))\n    \n    def forward(self, x):\n        return self.cnn(x)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:07:37.554158Z","iopub.execute_input":"2024-04-22T02:07:37.554784Z","iopub.status.idle":"2024-04-22T02:07:37.567264Z","shell.execute_reply.started":"2024-04-22T02:07:37.554753Z","shell.execute_reply":"2024-04-22T02:07:37.566297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def accuracy(outputs, labels):\n    _, preds = torch.max(outputs, dim=1)\n    return torch.tensor(torch.sum(preds == labels).item() / len(preds))\n\n@torch.no_grad()\ndef evaluate(model, test_loader, loss_fn):\n    model.eval()\n    outputs = [model.validation_step((inputs.to(device), labels.to(device)), loss_fn) for inputs, labels in test_loader]\n    return model.validation_epoch_end(outputs)\n\ndef train_model(model, train_loader, test_loader, n_epochs=20, loss_fn=None, optimizer=None, device=None):\n    if device is None:\n        device = torch.device(\"cpu\")\n    if loss_fn is None:\n        loss_fn = nn.CrossEntropyLoss(weight=torch.tensor(class_weights, dtype=torch.float).to(device), reduction=\"mean\")\n    if optimizer is None:\n        optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-3)\n    scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode=\"min\", patience=2, verbose=True)\n    for epoch in range(n_epochs):\n        model.train()\n        train_loss = []\n        for inputs, labels in train_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            # forward, backward, and then weight update\n            optimizer.zero_grad()\n            y_pred = model(inputs)\n            loss = loss_fn(y_pred, labels)\n            train_loss.append(loss)\n            loss.backward()\n            optimizer.step()\n            \n        result = evaluate(model, test_loader, loss_fn)\n        result[\"train_loss\"] = torch.stack(train_loss).mean().item()\n        model.epoch_end(epoch, result)\n        scheduler.step(result[\"val_loss\"])","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:20:07.174145Z","iopub.execute_input":"2024-04-22T02:20:07.174941Z","iopub.status.idle":"2024-04-22T02:20:07.186931Z","shell.execute_reply.started":"2024-04-22T02:20:07.174907Z","shell.execute_reply":"2024-04-22T02:20:07.186034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nmodel = FlowerModel(num_classes=5).to(device)\n\ntrain_model(model, train_loader, test_loader, n_epochs=20, device=device)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:20:07.890595Z","iopub.execute_input":"2024-04-22T02:20:07.891493Z","iopub.status.idle":"2024-04-22T02:21:38.739076Z","shell.execute_reply.started":"2024-04-22T02:20:07.891457Z","shell.execute_reply":"2024-04-22T02:21:38.738144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check the model's training accuracy for overfitting\n\nacc = 0\ncount = 0\nfor inputs, labels in train_loader:\n    inputs, labels = inputs.to(device), labels.to(device)\n    y_pred = model(inputs)\n    acc += (torch.argmax(y_pred, 1) == labels).float().sum()\n    count += len(labels)\nacc /= count\nprint(\"Model train accuracy %.2f%%\" % (acc * 100))","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:21:47.553925Z","iopub.execute_input":"2024-04-22T02:21:47.554575Z","iopub.status.idle":"2024-04-22T02:21:48.957904Z","shell.execute_reply.started":"2024-04-22T02:21:47.554541Z","shell.execute_reply":"2024-04-22T02:21:48.956964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folder = '../input/ece379k-hw4-flower-classification-24spring/test'\n\ntest_transform = transform.Compose([\n    transform.Resize((img_size, img_size)),\n    transform.ToTensor(),\n    transform.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\ntest_images = []\ntest_image_names = []\nfor filename in os.listdir(folder):\n    test_image_names.append(filename)\n    test_images.append(test_transform(Image.open(os.path.join(folder, filename))).to(device))\n        \ntest_images = torch.stack(test_images)\ntest_image_names = np.array(test_image_names)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:10:00.472263Z","iopub.execute_input":"2024-04-22T02:10:00.473099Z","iopub.status.idle":"2024-04-22T02:10:05.377335Z","shell.execute_reply.started":"2024-04-22T02:10:00.473057Z","shell.execute_reply":"2024-04-22T02:10:05.376365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\n\nwith torch.no_grad():\n    y_pred = torch.argmax(model(test_images), 1)","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:21:57.000093Z","iopub.execute_input":"2024-04-22T02:21:57.000950Z","iopub.status.idle":"2024-04-22T02:21:57.007828Z","shell.execute_reply.started":"2024-04-22T02:21:57.000915Z","shell.execute_reply":"2024-04-22T02:21:57.007052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig,ax=plt.subplots(5,2)\nfig.set_size_inches(15,15)\nfor i in range(5):\n    for j in range (2):\n        l=random.randint(0,len(test_images))\n        ax[i,j].imshow(test_images[l].cpu().numpy().transpose(1, 2, 0))\n        ax[i,j].set_title('Flower: '+label_names[y_pred[l]])\nplt.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:22:07.541647Z","iopub.execute_input":"2024-04-22T02:22:07.542353Z","iopub.status.idle":"2024-04-22T02:22:09.878991Z","shell.execute_reply.started":"2024-04-22T02:22:07.542320Z","shell.execute_reply":"2024-04-22T02:22:09.878141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame({'A' : [1,3,5]})\n\nv = [0, 1, 0, 1, 0, 1]\n\ndf['B'] = df['A'].apply(lambda x: v[x])\n\nsubmission = pd.DataFrame(np.column_stack([test_image_names, np.array(label_names)[y_pred.cpu()]]), columns=['Id', 'Category']).to_csv(\"submission6.csv\", index=False)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-22T02:22:37.490002Z","iopub.execute_input":"2024-04-22T02:22:37.490617Z","iopub.status.idle":"2024-04-22T02:22:37.512719Z","shell.execute_reply.started":"2024-04-22T02:22:37.490584Z","shell.execute_reply":"2024-04-22T02:22:37.511934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}