{"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 os\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport pandas as pd\nfrom PIL import Image\nimport torchvision.transforms as transforms\n\n# Define the dataset class\nclass CustomDataset(Dataset):\n    def __init__(self, csv_file, root_dir, transform=None, is_test = False):\n        super().__init__()\n        self.data = csv_file\n        self.root_dir = root_dir\n        self.transform = transform\n        self.is_test = is_test\n        \n    @property\n    def classes(self):\n        return self.data.iloc[:, 1].unique().tolist()\n    \n    def __len__(self):\n        return len(self.data)\n    \n    def __getitem__(self, idx):\n        #path example: /kaggle/input/classify-leaves/images/0.jpg\n        img_path = os.path.join(self.root_dir, self.data.iloc[idx, 0])\n        image = Image.open(img_path)\n        if self.transform:\n            image = self.transform(image)\n        if self.is_test:\n            return image\n        label = self.data.iloc[idx, 2]\n        label = torch.tensor(label)\n        \n        \n        return image, label","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:27:48.395786Z","iopub.execute_input":"2023-09-22T06:27:48.396147Z","iopub.status.idle":"2023-09-22T06:27:48.408581Z","shell.execute_reply.started":"2023-09-22T06:27:48.396120Z","shell.execute_reply":"2023-09-22T06:27:48.407335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#load the dataset and data augment,preprocessing\ndef load_dataset(batch_size,img_size):\n    train_transforms = transforms.Compose([\n            transforms.Resize(img_size),\n            transforms.RandomHorizontalFlip(),\n            transforms.RandomVerticalFlip(),\n            transforms.ToTensor(),\n            ])\n    test_transforms = transforms.Compose([\n            transforms.Resize(img_size),\n            transforms.ToTensor(),\n    ])\n    \n    # Read the data set\n    root_folder = \"/kaggle/input/classify-leaves\"\n    train_csv = pd.read_csv(\"/kaggle/input/classify-leaves/train.csv\")\n    test_csv = pd.read_csv(\"/kaggle/input/classify-leaves/test.csv\")\n    \n    #label encoder, str to int\n    leaves_labels = train_csv.iloc[:, 1].unique()\n    n_classes = len(leaves_labels)\n    class_to_num = dict(zip(leaves_labels, range(n_classes)))\n    train_csv['labelEncoded'] = train_csv.iloc[:, 1].map(class_to_num)\n    \n    full_dataset = CustomDataset(train_csv, root_folder,transform=train_transforms)\n    predict_dataset = CustomDataset(test_csv, root_folder,transform=train_transforms, is_test = True)\n    \n    # split the dataset\n    train_size = int(0.9 * len(full_dataset))\n    test_size = len(full_dataset) - train_size\n    train_dataset, test_dataset = torch.utils.data.random_split(full_dataset, [train_size, test_size])\n     # dataloader\n    train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n    test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)\n    dataloaders = {'train':train_dataloader,'test':test_dataloader}\n    \n    print(f\"train size:{train_size},test size:{test_size}\")\n    print(full_dataset.classes)\n    return dataloaders,full_dataset.classes,predict_dataset","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:27:48.990794Z","iopub.execute_input":"2023-09-22T06:27:48.991190Z","iopub.status.idle":"2023-09-22T06:27:49.002337Z","shell.execute_reply.started":"2023-09-22T06:27:48.991160Z","shell.execute_reply":"2023-09-22T06:27:49.001128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\ndef display_data(dataloader,class_names):\n    # Get a batch of images and labels from the dataloader\n    images, labels = next(iter(dataloader[\"train\"]))\n    # Display the first 5 images\n    fig, axes = plt.subplots(1, 5, figsize=(15, 3))\n    for i in range(5):\n        axes[i].imshow(images[i].permute(1, 2, 0))# change the dimension order from (C, H, W) to (H, W, C),\n        axes[i].set_title(class_names[labels[i]])\n        axes[i].axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:09:18.937260Z","iopub.execute_input":"2023-09-22T06:09:18.938380Z","iopub.status.idle":"2023-09-22T06:09:18.954366Z","shell.execute_reply.started":"2023-09-22T06:09:18.938341Z","shell.execute_reply":"2023-09-22T06:09:18.953030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torch import nn\nfrom torch.nn import functional as F\n\nclass Residual(nn.Module):# Basic Residual for ResNet\n    def __init__(self, input_channels, num_channels,\n                 use_1x1conv=False, strides=1):\n        super().__init__()\n        self.conv1 = nn.Conv2d(input_channels, num_channels,\n                               kernel_size=3, padding=1, stride=strides)\n        self.conv2 = nn.Conv2d(num_channels, num_channels,\n                               kernel_size=3, padding=1)\n        if use_1x1conv:\n            self.conv3 = nn.Conv2d(input_channels, num_channels,\n                                   kernel_size=1, stride=strides)\n        else:\n            self.conv3 = None\n        self.bn1 = nn.BatchNorm2d(num_channels)\n        self.bn2 = nn.BatchNorm2d(num_channels)\n\n    def forward(self, X):\n        Y = F.relu(self.bn1(self.conv1(X)))\n        Y = self.bn2(self.conv2(Y))\n        if self.conv3:\n            X = self.conv3(X)\n        Y += X  #residual\n        return F.relu(Y)\n\ndef resnet_block(input_channels, num_channels, num_residuals,\n                 first_block=False):\n    block = []\n    for i in range(num_residuals):\n        if i == 0 and not first_block:\n            block.append(Residual(input_channels, num_channels,\n                                use_1x1conv=True, strides=2))\n        else:\n            block.append(Residual(num_channels, num_channels))\n    return block\ndef resNet_18(n_classes):\n    #full ResNet-18\n    b1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),\n                       nn.BatchNorm2d(64), nn.ReLU(),\n                       nn.MaxPool2d(kernel_size=3, stride=2, padding=1))\n    b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))\n    b3 = nn.Sequential(*resnet_block(64, 128, 2))\n    b4 = nn.Sequential(*resnet_block(128, 256, 2))\n    b5 = nn.Sequential(*resnet_block(256, 512, 2))\n    return nn.Sequential(b1, b2, b3, b4, b5,\n                        nn.AdaptiveAvgPool2d((1,1)),\n                        nn.Flatten(), nn.Linear(512, n_classes))\nnet = resNet_18(n_classes=100)\nX = torch.rand(size=(1, 3, 256, 256)) \nfor layer in net:\n    X = layer(X)\n    print(layer.__class__.__name__,'output shape:\\t', X.shape)","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:09:18.957078Z","iopub.execute_input":"2023-09-22T06:09:18.957857Z","iopub.status.idle":"2023-09-22T06:09:19.195982Z","shell.execute_reply.started":"2023-09-22T06:09:18.957819Z","shell.execute_reply":"2023-09-22T06:09:19.193731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calculate_accuracy(model, data_loader, device):\n    correct = 0\n    total = 0\n    #model.eval()  # Put model in evaluation mode\n    \n    with torch.no_grad():\n        for data, target in data_loader:\n            data, target = data.to(device), target.to(device)\n            output = model(data)\n            _, predicted = torch.max(output.data, 1)\n            total += target.size(0)\n            correct += (predicted == target).sum().item()\n    \n    return correct/total","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:09:19.197864Z","iopub.execute_input":"2023-09-22T06:09:19.198286Z","iopub.status.idle":"2023-09-22T06:09:19.206854Z","shell.execute_reply.started":"2023-09-22T06:09:19.198245Z","shell.execute_reply":"2023-09-22T06:09:19.205429Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#define the train function\nimport torch.optim as optim\ndef train(model,dataloaders,epochs,criterion,optimizer):\n    for epoch in range(epochs):\n        for batch_idx, (data, target) in enumerate(dataloaders['train']):      \n            data, target = data.to(device), target.to(device)\n            optimizer.zero_grad()\n            output = model(data)\n            loss = criterion(output, target)\n            loss.backward()\n            optimizer.step()\n            #scheduler.step()\n            \n            if (batch_idx) % 100 == 0:\n                train_accuracy = calculate_accuracy(model, dataloaders['train'], device)\n                test_accuracy  = calculate_accuracy(model, dataloaders['test'], device)\n                print(f\"epoch: {epoch} \",\n                      f\"[{batch_idx * batch_size}/{len(dataloaders['train'].dataset)} ({100. * batch_idx / len(dataloaders['train']):.0f}%)]\\t\"\n                      f\"loss: {loss.item():.6f}\\t \",\n                      f\"train accuracy: {100. * test_accuracy :.2f}%\\t\",\n                      f\"test accuracy:  {100.  * train_accuracy:.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:09:19.210121Z","iopub.execute_input":"2023-09-22T06:09:19.211572Z","iopub.status.idle":"2023-09-22T06:09:19.221947Z","shell.execute_reply.started":"2023-09-22T06:09:19.211529Z","shell.execute_reply":"2023-09-22T06:09:19.221040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# GPU training\ntrain_on_gpu = torch.cuda.is_available()\nif not train_on_gpu:\n    print('Training on CPU')\nelse:\n    print('Training on GPU')\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:09:19.223419Z","iopub.execute_input":"2023-09-22T06:09:19.224122Z","iopub.status.idle":"2023-09-22T06:09:19.238163Z","shell.execute_reply.started":"2023-09-22T06:09:19.224082Z","shell.execute_reply":"2023-09-22T06:09:19.236729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#resnet18\nbatch_size = 128\nimg_size  = 48\nepochs = 50\ndataloaders,class_names,predict_dataset = load_dataset(batch_size=128,img_size=256)\nmodel  = resNet_18(len(class_names))\nmodel.to(device)\ndisplay_data(dataloaders,class_names)\ncriterion = nn.CrossEntropyLoss() #nn.CrossEntropyLoss function includes a softmax\noptimizer = optim.Adam(model.parameters(), lr=0.001) #sdg\ntrain(model,dataloaders,epochs,criterion,optimizer)","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:09:19.240196Z","iopub.execute_input":"2023-09-22T06:09:19.241084Z","iopub.status.idle":"2023-09-22T06:12:19.916978Z","shell.execute_reply.started":"2023-09-22T06:09:19.241021Z","shell.execute_reply":"2023-09-22T06:12:19.915826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#submission\ndataloaders,class_names,predict_dataset = load_dataset(batch_size=128,img_size=256)\nnet, preds = model, []\ntest_loader = DataLoader(predict_dataset, batch_size=batch_size, shuffle=False)  \nfor X in test_loader:\n    y_hat = net(X.to(device))\n    preds.extend(y_hat.argmax(dim=1).type(torch.int32).cpu().numpy())\n#label encoder, str to int\ntrain_csv = pd.read_csv(\"/kaggle/input/classify-leaves/train.csv\")\nleaves_labels = train_csv.iloc[:, 1].unique()\nn_classes = len(leaves_labels)\nclass_to_num = dict(zip(leaves_labels, range(n_classes)))\nnum_to_class = dict(zip( range(n_classes),leaves_labels))\n\nresult = []\nfor i in preds:\n    result.append(num_to_class[i])\n\ntest_data = pd.read_csv(\"/kaggle/input/classify-leaves/test.csv\")\ntest_data['label'] = pd.Series(result)\nsubmission = pd.concat([test_data['image'], test_data['label']], axis=1)\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"Done!!!!!!!!!!!!!!!!!!!!!!!!!!!\")","metadata":{"execution":{"iopub.status.busy":"2023-09-22T06:39:49.329658Z","iopub.execute_input":"2023-09-22T06:39:49.330011Z","iopub.status.idle":"2023-09-22T06:39:49.418294Z","shell.execute_reply.started":"2023-09-22T06:39:49.329984Z","shell.execute_reply":"2023-09-22T06:39:49.417279Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}