{"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":"tpu1vmV38","dataSources":[{"sourceId":29193,"databundleVersionId":2318453,"sourceType":"competition"}],"dockerImageVersionId":30664,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%config Completer.use_jedi = False\nimport 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\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":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-03-06T10:58:17.015132Z","iopub.execute_input":"2024-03-06T10:58:17.015417Z","iopub.status.idle":"2024-03-06T10:58:42.436292Z","shell.execute_reply.started":"2024-03-06T10:58:17.015388Z","shell.execute_reply":"2024-03-06T10:58:42.435154Z"},"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=test_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":"2024-03-06T10:58:42.437879Z","iopub.execute_input":"2024-03-06T10:58:42.438248Z","iopub.status.idle":"2024-03-06T10:58:42.446247Z","shell.execute_reply.started":"2024-03-06T10:58:42.43822Z","shell.execute_reply":"2024-03-06T10:58:42.445583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\ndef display_data(dataloader, class_names):\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))\n        axes[i].set_title(class_names[labels[i]])\n        axes[i].axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-06T10:58:42.447183Z","iopub.execute_input":"2024-03-06T10:58:42.447434Z","iopub.status.idle":"2024-03-06T10:58:43.290022Z","shell.execute_reply.started":"2024-03-06T10:58:42.44741Z","shell.execute_reply":"2024-03-06T10:58:43.289045Z"},"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        \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\n\ndef resNet_18(n_classes):\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))\n\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)\nnumpy_array = X.detach().numpy()\nprint(len(numpy_array))\nprint(f\"{numpy_array.argmax()}  + {numpy_array[0,numpy_array.argmax()]} +   + {numpy_array.max()}\")","metadata":{"execution":{"iopub.status.busy":"2024-03-06T10:58:43.292403Z","iopub.execute_input":"2024-03-06T10:58:43.292794Z","iopub.status.idle":"2024-03-06T10:58:43.464848Z","shell.execute_reply.started":"2024-03-06T10:58:43.292765Z","shell.execute_reply":"2024-03-06T10:58:43.463763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calcultate_accuracy(model, data_loader, device):\n    correct = 0\n    total = 0\n    model.eval()\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":"2024-03-06T10:58:43.466407Z","iopub.execute_input":"2024-03-06T10:58:43.467163Z","iopub.status.idle":"2024-03-06T10:58:43.47272Z","shell.execute_reply.started":"2024-03-06T10:58:43.467123Z","shell.execute_reply":"2024-03-06T10:58:43.471856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.optim as optim\n\ndef train(model, dataloaders, epochs, criterion, optimizer):\n    print(epochs)\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            if (batch_idx) % 100 == 0:\n                train_accuracy = calcultate_accuracy(model, dataloaders['train'], device)\n                test_accuracy = calcultate_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":"2024-03-06T10:58:43.474009Z","iopub.execute_input":"2024-03-06T10:58:43.474585Z","iopub.status.idle":"2024-03-06T10:58:43.484994Z","shell.execute_reply.started":"2024-03-06T10:58:43.47455Z","shell.execute_reply":"2024-03-06T10:58:43.484199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#GPU trainning\ntrain_on_gpu = torch.cuda.is_available()\nif not train_on_gpu:\n    print(\"Trainning on CPU\")\nelse:\n    print(\"Trainning on GPU\")\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","metadata":{"execution":{"iopub.status.busy":"2024-03-06T10:58:43.486012Z","iopub.execute_input":"2024-03-06T10:58:43.486276Z","iopub.status.idle":"2024-03-06T10:58:43.500822Z","shell.execute_reply.started":"2024-03-06T10:58:43.486229Z","shell.execute_reply":"2024-03-06T10:58:43.500003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#resnet18\nbatch_size = 128\nimg_size = 48\nepochs = 30\ndataloaders, class_names, predict_dataset = load_dataset(batch_size,img_size)\nmodel = resNet_18(len(class_names))\nmodel.to(device)\ndisplay_data(dataloaders,class_names)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\ntrain(model,dataloaders,epochs,criterion,optimizer)","metadata":{"execution":{"iopub.status.busy":"2024-03-06T10:58:43.501852Z","iopub.execute_input":"2024-03-06T10:58:43.502082Z","iopub.status.idle":"2024-03-06T12:01:11.465294Z","shell.execute_reply.started":"2024-03-06T10:58:43.50206Z","shell.execute_reply":"2024-03-06T12:01:11.464281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataloaders, 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    \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":"2024-03-06T12:01:11.46659Z","iopub.execute_input":"2024-03-06T12:01:11.466901Z","iopub.status.idle":"2024-03-06T12:01:14.481685Z","shell.execute_reply.started":"2024-03-06T12:01:11.466871Z","shell.execute_reply":"2024-03-06T12:01:14.480715Z"},"trusted":true},"execution_count":null,"outputs":[]}]}