{"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":"# 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    if 'images' in dirname:\n        continue\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n#         pass\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":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-17T10:42:31.210358Z","iopub.execute_input":"2022-02-17T10:42:31.210727Z","iopub.status.idle":"2022-02-17T10:42:36.994694Z","shell.execute_reply.started":"2022-02-17T10:42:31.210698Z","shell.execute_reply":"2022-02-17T10:42:36.993745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('../input/classify-leaves/train.csv')\ntest = pd.read_csv('../input/classify-leaves/test.csv')\n\ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:44:59.129783Z","iopub.execute_input":"2022-02-16T11:44:59.130021Z","iopub.status.idle":"2022-02-16T11:44:59.185182Z","shell.execute_reply.started":"2022-02-16T11:44:59.129993Z","shell.execute_reply":"2022-02-16T11:44:59.184541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp = pd.read_csv('../input/classify-leaves/train.csv', header=None)\ntemp.head()","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:44:59.307958Z","iopub.execute_input":"2022-02-16T11:44:59.308313Z","iopub.status.idle":"2022-02-16T11:44:59.336225Z","shell.execute_reply.started":"2022-02-16T11:44:59.308283Z","shell.execute_reply":"2022-02-16T11:44:59.335606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\n\npath = '/kaggle/input/classify-leaves/'\nimage1_path = os.path.join(path, train.loc[0, 'image'])\nprint(image1_path)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:44:59.484244Z","iopub.execute_input":"2022-02-16T11:44:59.484628Z","iopub.status.idle":"2022-02-16T11:44:59.49194Z","shell.execute_reply.started":"2022-02-16T11:44:59.484598Z","shell.execute_reply":"2022-02-16T11:44:59.49121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom PIL import Image\n\nimage1 = Image.open(image1_path)\nplt.imshow(image1)\nplt.title(train.loc[0, 'label'])\nplt.axis('off')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:44:59.628627Z","iopub.execute_input":"2022-02-16T11:44:59.628924Z","iopub.status.idle":"2022-02-16T11:44:59.910689Z","shell.execute_reply.started":"2022-02-16T11:44:59.628894Z","shell.execute_reply":"2022-02-16T11:44:59.909981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision.transforms as transform\nimg2tensor = transform.ToTensor()\nprint(img2tensor(image1).shape)\nprint(img2tensor(image1).permute(1,2,0).shape)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:44:59.91243Z","iopub.execute_input":"2022-02-16T11:44:59.912832Z","iopub.status.idle":"2022-02-16T11:45:01.523948Z","shell.execute_reply.started":"2022-02-16T11:44:59.912794Z","shell.execute_reply":"2022-02-16T11:45:01.522209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_to_num = dict(zip(list(train.loc[:, 'label'].unique()), range(len(train.label.unique())) ))\nprint(class_to_num)\nprint(len(class_to_num))","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:45:01.52596Z","iopub.execute_input":"2022-02-16T11:45:01.526225Z","iopub.status.idle":"2022-02-16T11:45:01.537821Z","shell.execute_reply.started":"2022-02-16T11:45:01.526186Z","shell.execute_reply":"2022-02-16T11:45:01.536746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_to_class = { a : b for b, a in class_to_num.items()}\nprint(num_to_class)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:45:01.539427Z","iopub.execute_input":"2022-02-16T11:45:01.53969Z","iopub.status.idle":"2022-02-16T11:45:01.546341Z","shell.execute_reply.started":"2022-02-16T11:45:01.539655Z","shell.execute_reply":"2022-02-16T11:45:01.545169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torchvision\nimport torch.nn as nn\nimport torch.utils.data as Data\nimport torchvision.transforms as transforms\n\nclass LeavesDataset(Data.Dataset):\n    \"\"\"\n    args:\n    csv_path: indicates the path of csv,\n    file_path: indicates where the images loads,\n    mode: choose between 'train', 'valid' and 'test'. default set 'train'.\n    valid_ratio: indicates the length of valid dataset. default 0.2.\n    resize_height: indicates how to resize the images. default 256.\n    resize_width: indicates how to resize the images. default 256.\n    \"\"\"\n    def __init__(self, csv_path, file_path, mode='train', valid_ratio=0.2, resize_height=256, resize_width=256):\n        self.resize_height = resize_height\n        self.resize_width = resize_width\n        self.file_path = file_path\n        self.mode = mode\n        self.data_info = pd.read_csv(csv_path)\n        self.data_len = len(self.data_info.index)\n        self.train_len = int(self.data_len * (1 - valid_ratio))\n        \n        if mode == 'train':\n            self.train_image = np.asarray(self.data_info.loc[:self.train_len, 'image'])\n            self.train_label = np.asarray(self.data_info.loc[:self.train_len, 'label'])\n            self.image_arr = self.train_image\n            self.label_arr = self.train_label\n        elif mode == 'valid':\n            self.valid_image = np.asarray(self.data_info.loc[self.train_len:, 'image'])\n            self.valid_label = np.asarray(self.data_info.loc[self.train_len:, 'label'])\n            self.image_arr = self.valid_image\n            self.label_arr = self.valid_label\n        elif mode == 'test':\n            self.test_image = np.asarray(self.data_info.loc[:, 'image'])\n            self.image_arr = self.test_image\n            \n        self.real_len = len(self.image_arr)\n        \n        print('Finished reading %s dataset. %d number samples found.' % (mode, self.real_len))\n        \n        \n    def __getitem__(self, index):\n        image_path = self.image_arr[index]\n        image = Image.open(os.path.join(self.file_path, image_path))\n        \n        if self.mode == 'train':\n            transform = transforms.Compose([transforms.RandomResizedCrop(224),\n                                 transforms.RandomHorizontalFlip(),\n                                 transforms.ToTensor(),\n                                 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])\n        else:\n            transform = transforms.Compose([transforms.Resize(256),\n                               transforms.CenterCrop(224),\n                               transforms.ToTensor(),\n                               transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])\n            \n        image = transform(image)\n        \n        if self.mode == 'test':\n            return image\n        \n        label = self.label_arr[index]\n        label_num = class_to_num[label]\n        return image, label_num\n    \n    \n    def __len__(self):\n        return self.real_len","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:48:45.052081Z","iopub.execute_input":"2022-02-16T11:48:45.052412Z","iopub.status.idle":"2022-02-16T11:48:45.071302Z","shell.execute_reply.started":"2022-02-16T11:48:45.052371Z","shell.execute_reply":"2022-02-16T11:48:45.070606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_path = '/kaggle/input/classify-leaves/train.csv'\ntest_path = '/kaggle/input/classify-leaves/test.csv'\nimage_path = '/kaggle/input/classify-leaves/'\n\ndata_transform = {\n    \"train\": transforms.Compose([transforms.RandomResizedCrop(224),\n                                 transforms.RandomHorizontalFlip(),\n                                 transforms.ToTensor(),\n                                 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),\n    \"val\": transforms.Compose([transforms.Resize(256),\n                               transforms.CenterCrop(224),\n                               transforms.ToTensor(),\n                               transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])}\n\ntrain_dataset = LeavesDataset(train_path, image_path, mode='train', valid_ratio=0.2)\nvalid_dataset = LeavesDataset(train_path, image_path, mode='valid', valid_ratio=0.2)\ntest_dataset = LeavesDataset(test_path, image_path, mode='test')","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:48:45.893743Z","iopub.execute_input":"2022-02-16T11:48:45.894266Z","iopub.status.idle":"2022-02-16T11:48:45.950207Z","shell.execute_reply.started":"2022-02-16T11:48:45.89423Z","shell.execute_reply":"2022-02-16T11:48:45.949347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_loader = Data.DataLoader(train_dataset, batch_size=10, shuffle=True, num_workers=4)\nvalid_loader = Data.DataLoader(valid_dataset, batch_size=10, shuffle=True, num_workers=4)\ntest_loader = Data.DataLoader(test_dataset, batch_size=10, shuffle=False, num_workers=4)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:48:46.068467Z","iopub.execute_input":"2022-02-16T11:48:46.068779Z","iopub.status.idle":"2022-02-16T11:48:46.079197Z","shell.execute_reply.started":"2022-02-16T11:48:46.068751Z","shell.execute_reply":"2022-02-16T11:48:46.078537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_loader(loader):\n    for (x, y) in loader:\n        print(x)\n        print(y)\n        break\nshow_loader(valid_loader)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:50:36.083906Z","iopub.execute_input":"2022-02-16T11:50:36.084187Z","iopub.status.idle":"2022-02-16T11:50:36.569975Z","shell.execute_reply.started":"2022-02-16T11:50:36.084158Z","shell.execute_reply":"2022-02-16T11:50:36.569165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = torchvision.models.resnet34(pretrained=True, progress=True)\nprint(model)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:48:46.234432Z","iopub.execute_input":"2022-02-16T11:48:46.23494Z","iopub.status.idle":"2022-02-16T11:48:46.681291Z","shell.execute_reply.started":"2022-02-16T11:48:46.23491Z","shell.execute_reply":"2022-02-16T11:48:46.680468Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = \"cuda:0\" if torch.cuda.is_available() else \"cpu\"\ninput_channel = model.fc.in_features\nmodel.fc = nn.Linear(input_channel, 176)\nmodel.to(device)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:48:46.682896Z","iopub.execute_input":"2022-02-16T11:48:46.683166Z","iopub.status.idle":"2022-02-16T11:48:46.72442Z","shell.execute_reply.started":"2022-02-16T11:48:46.68313Z","shell.execute_reply":"2022-02-16T11:48:46.723619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_path = '/kaggle/input/k/ltfall/classify-leaves/model.ckpt'\n\nmodel.load_state_dict(torch.load(model_path))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score\nEPOCH = 100\nLR = 1e-4\n\n\noptimizer = torch.optim.Adam(model.parameters(), lr=LR)\nloss_func = nn.CrossEntropyLoss()\nmetric_func = lambda y_test, y_pred: accuracy_score(y_test.cpu().data.numpy(), y_pred.cpu().data.numpy())","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:51:34.840214Z","iopub.execute_input":"2022-02-16T11:51:34.840913Z","iopub.status.idle":"2022-02-16T11:51:34.84811Z","shell.execute_reply.started":"2022-02-16T11:51:34.840874Z","shell.execute_reply":"2022-02-16T11:51:34.847339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"best_acc = 0\nfor epoch in range(EPOCH):\n    for step, (x, y) in enumerate(train_loader, 1):\n        model.train()\n        x = x.to(device)\n        y = y.to(device)\n        output = model(x)\n        loss = loss_func(output, y)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        if step % 50 == 0 or step == 1:\n            model.eval()\n            with torch.no_grad():\n                accuracy = []\n                for (valid_x, valid_y) in valid_loader:\n                    valid_x = valid_x.to(device)\n                    valid_y = valid_y.to(device)\n                    output = model(valid_x)\n                    acc = metric_func(valid_y, torch.max(output, 1)[1])\n                    accuracy.append(acc)\n                accuracy = np.mean(accuracy)\n                print('Epoch: {}, step: {}, loss:{:.4f}, valid_accuracy: {:.4f}'.format(epoch, step, loss.cpu().data.numpy(), accuracy))\n                if step == 1 and epoch == 0:\n                    best_acc = accuracy\n    if accuracy >= best_acc:\n        best_acc = accuracy\n        torch.save(model.state_dict(), './model.ckpt')\n        print('Saving model with an accuracy of {}'.format(best_acc))\n    else:\n        print('The accuracy of this epoch is not good as the last epoch : {}. Kernel shut down.'.format(best_acc))\n        break","metadata":{"execution":{"iopub.status.busy":"2022-02-16T11:51:54.109737Z","iopub.execute_input":"2022-02-16T11:51:54.110132Z","iopub.status.idle":"2022-02-16T11:59:35.562999Z","shell.execute_reply.started":"2022-02-16T11:51:54.110093Z","shell.execute_reply":"2022-02-16T11:59:35.562082Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2022-02-16T12:03:43.83031Z","iopub.execute_input":"2022-02-16T12:03:43.830768Z","iopub.status.idle":"2022-02-16T12:03:43.862484Z","shell.execute_reply.started":"2022-02-16T12:03:43.830722Z","shell.execute_reply":"2022-02-16T12:03:43.860659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}