{"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 numpy as np \nimport pandas as pd\nfrom PIL import Image\nfrom IPython.display import display\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.models import resnet50, ResNet50_Weights\nfrom torchvision import transforms\nfrom torchvision import models\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.model_selection import KFold\nfrom tqdm import tqdm\nimport albumentations\nfrom albumentations.pytorch.transforms import ToTensorV2","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:09.322378Z","iopub.execute_input":"2023-05-01T12:52:09.323165Z","iopub.status.idle":"2023-05-01T12:52:09.330068Z","shell.execute_reply.started":"2023-05-01T12:52:09.323123Z","shell.execute_reply":"2023-05-01T12:52:09.328896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_path = '../input/classify-leaves/train.csv'\ntest_path = '../input/classify-leaves/test.csv'\nimage_path = '../input/classify-leaves'\n\n# Load the data\ntrain = pd.read_csv(train_path)\ntest = pd.read_csv(test_path)\n\ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:11.797880Z","iopub.execute_input":"2023-05-01T12:52:11.798366Z","iopub.status.idle":"2023-05-01T12:52:11.855749Z","shell.execute_reply.started":"2023-05-01T12:52:11.798322Z","shell.execute_reply":"2023-05-01T12:52:11.854761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.describe","metadata":{"execution":{"iopub.status.busy":"2023-05-01T03:25:10.760881Z","iopub.execute_input":"2023-05-01T03:25:10.761395Z","iopub.status.idle":"2023-05-01T03:25:10.773579Z","shell.execute_reply.started":"2023-05-01T03:25:10.761334Z","shell.execute_reply":"2023-05-01T03:25:10.772496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.label.value_counts()","metadata":{"execution":{"iopub.status.busy":"2023-05-01T03:25:10.775544Z","iopub.execute_input":"2023-05-01T03:25:10.775998Z","iopub.status.idle":"2023-05-01T03:25:10.787533Z","shell.execute_reply.started":"2023-05-01T03:25:10.775959Z","shell.execute_reply":"2023-05-01T03:25:10.786489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img1_path = os.path.join(image_path, train.loc[0, 'image'])\nimg_1 = Image.open(img1_path)\nimg_size = transforms.ToTensor()\nprint(img_size(img_1).shape)\ndisplay(img_1)","metadata":{"execution":{"iopub.status.busy":"2023-05-01T03:25:10.790483Z","iopub.execute_input":"2023-05-01T03:25:10.790895Z","iopub.status.idle":"2023-05-01T03:25:10.808697Z","shell.execute_reply.started":"2023-05-01T03:25:10.790855Z","shell.execute_reply":"2023-05-01T03:25:10.807550Z"},"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()))))\nnum_to_class = {y: x for x, y in class_to_num.items()}","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:19.579101Z","iopub.execute_input":"2023-05-01T12:52:19.580119Z","iopub.status.idle":"2023-05-01T12:52:19.589337Z","shell.execute_reply.started":"2023-05-01T12:52:19.580078Z","shell.execute_reply":"2023-05-01T12:52:19.588052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_train_transforms():\n    return albumentations.Compose(\n        [\n            albumentations.Resize(320, 320),\n            albumentations.HorizontalFlip(p=0.5),\n            albumentations.VerticalFlip(p=0.5),\n            albumentations.Rotate(limit=180, p=0.7),\n            albumentations.RandomBrightnessContrast(),\n            albumentations.ShiftScaleRotate(\n                shift_limit=0.25, scale_limit=0.1, rotate_limit=0\n            ),\n            albumentations.Normalize(\n                [0.485, 0.456, 0.406], [0.229, 0.224, 0.225],\n                max_pixel_value=255.0, always_apply=True\n            ),\n            ToTensorV2(p=1.0),\n        ]\n    )\n\ndef get_valid_transforms():\n    return albumentations.Compose(\n        [\n            albumentations.Resize(320, 320),\n            albumentations.Normalize(\n                [0.485, 0.456, 0.406], [0.229, 0.224, 0.225],\n                max_pixel_value=255.0, always_apply=True\n            ),\n            ToTensorV2(p=1.0)\n        ]\n    )","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:22.164793Z","iopub.execute_input":"2023-05-01T12:52:22.165815Z","iopub.status.idle":"2023-05-01T12:52:22.174691Z","shell.execute_reply.started":"2023-05-01T12:52:22.165760Z","shell.execute_reply":"2023-05-01T12:52:22.173354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class LeavesDataset(Dataset):\n    def __init__(self, data_info, file_path, index_arr=[], transform=None):\n        self.data_info = data_info\n        self.file_path = file_path\n        self.index_arr = index_arr\n        self.transform = transform\n        \n        if len(index_arr) > 0:\n            self.train_image = self.data_info.loc[index_arr, 'image'].to_numpy()\n            self.train_label = self.data_info.loc[index_arr, 'label'].to_numpy()\n        else:\n            self.train_image = self.data_info.loc[:, 'image'].to_numpy()\n            \n        print('Finished reading %d number samples found.' % (len(self.train_image)))\n        \n    def __getitem__(self, index):\n        image_path = self.train_image[index]\n        image = np.asarray(Image.open(os.path.join(self.file_path, image_path)))  \n        \n        if self.transform:\n            image = self.transform(image=image)['image']\n        \n        if self.train_label:\n            label = self.train_label[index]\n            label_num = class_to_num[label]\n            return image, label_num\n        else:\n            return image\n        \n    def __len__(self):\n        return len(self.train_image)","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:24.822383Z","iopub.execute_input":"2023-05-01T12:52:24.823484Z","iopub.status.idle":"2023-05-01T12:52:24.834369Z","shell.execute_reply.started":"2023-05-01T12:52:24.823429Z","shell.execute_reply":"2023-05-01T12:52:24.833139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Whether to freeze the front layers of the model\ndef set_parameter_requires_grad(model, feature_extracting):\n    if feature_extracting:\n        model = model\n        for param in model.parameters():\n            param.requires_grad = False\n            \n# ResNest model\ndef resnest_model(num_classes, feature_extract = False):\n    model_ft = resnet50(weights=ResNet50_Weights.DEFAULT)\n    set_parameter_requires_grad(model_ft, feature_extract)\n    num_features = model_ft.fc.in_features\n    model_ft.fc = nn.Sequential(nn.Linear(num_features, num_classes))\n    \n    return model_ft","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:28.109820Z","iopub.execute_input":"2023-05-01T12:52:28.110212Z","iopub.status.idle":"2023-05-01T12:52:28.117062Z","shell.execute_reply.started":"2023-05-01T12:52:28.110175Z","shell.execute_reply":"2023-05-01T12:52:28.115821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = \"cuda:0\" if torch.cuda.is_available() else \"cpu\"\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:30.776046Z","iopub.execute_input":"2023-05-01T12:52:30.776770Z","iopub.status.idle":"2023-05-01T12:52:30.782027Z","shell.execute_reply.started":"2023-05-01T12:52:30.776731Z","shell.execute_reply":"2023-05-01T12:52:30.781006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = resnest_model(176)\nmodel.to(device)","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:32.605433Z","iopub.execute_input":"2023-05-01T12:52:32.606547Z","iopub.status.idle":"2023-05-01T12:52:33.351818Z","shell.execute_reply.started":"2023-05-01T12:52:32.606497Z","shell.execute_reply":"2023-05-01T12:52:33.344350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Configuration options\nk_folds = 5\nepochs = 10\noptimizer = optim.Adam(model.parameters(), lr=1e-3)\nloss_func = nn.CrossEntropyLoss()\n\n# For fold results\nresults = {}\n\n# Set fixed random number seed\ntorch.manual_seed(42)\n\n# Define the K-fold Cross Validator\nkfold = KFold(n_splits=k_folds, random_state=42, shuffle=True)\ny = train.label.values\n\n# Checkpoint path\nmodel_path = '/kaggle/working/model.ckpt'","metadata":{"execution":{"iopub.status.busy":"2023-05-01T12:52:37.871039Z","iopub.execute_input":"2023-05-01T12:52:37.872035Z","iopub.status.idle":"2023-05-01T12:52:37.880036Z","shell.execute_reply.started":"2023-05-01T12:52:37.871996Z","shell.execute_reply":"2023-05-01T12:52:37.878696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k, (t_, v_) in enumerate(kfold.split(X=train, y=y)):\n    print(\"---------------The \", k + 1, \" fold start!---------------\")\n    train_dataset = LeavesDataset(train, image_path, t_, get_train_transforms())\n    valid_dataset = LeavesDataset(train, image_path, v_, get_valid_transforms())\n    train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=True)\n    valid_loader = DataLoader(dataset=valid_dataset, batch_size=32)\n    best_acc = 0\n    for epoch in range(epochs):\n        for step, (x, y) in enumerate(train_loader):\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            accuracy = 0\n            if step % 100 == 0 and step != 0:\n                model.eval()\n                val_acc = []\n                with torch.no_grad():\n                    for valid_x, valid_y in valid_loader:\n                        valid_x = valid_x.to(device)\n                        valid_y = valid_y.to(device)\n                        valid_output = model(valid_x)\n                        acc = accuracy_score(valid_y.cpu().data.numpy(), torch.max(valid_output, 1)[1].cpu().data.numpy())\n                        val_acc.append(acc)\n                accuracy = np.mean(val_acc)\n                print('Epoch: {}, step: {}, loss:{:.4f}, valid_accuracy: {:.4f}'.format(epoch + 1, step, loss.cpu().data.numpy(), accuracy))\n\n                if accuracy > best_acc:\n                    best_acc = accuracy\n                    torch.save(model.state_dict(), model_path)\n                    print('Saving model with an accuracy of {}'.format(best_acc))","metadata":{"execution":{"iopub.status.busy":"2023-05-01T03:25:11.396116Z","iopub.execute_input":"2023-05-01T03:25:11.396556Z","iopub.status.idle":"2023-05-01T11:36:11.142747Z","shell.execute_reply.started":"2023-05-01T03:25:11.396517Z","shell.execute_reply":"2023-05-01T11:36:11.141601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dataset = LeavesDataset(test, image_path)\ntest_loader = DataLoader(dataset=test_dataset, batch_size=32)\nsaveFileName = '/kaggle/working/submission.csv'\nmodel.to(device)\nmodel.load_state_dict(torch.load(model_path))\nmodel.eval()\npredictions = []\nfor x in test_loader:\n    with torch.no_grad():\n        y_pred = model(x.to(device))\n        predictions.extend(y_pred.argmax(dim=-1).cpu().numpy().tolist())\n        \ntest_data = pd.read_csv(test_path)\ntest_data['label'] = pd.Series(predictions)\nsubmission = pd.concat([test_data['image'], test_data['label']], axis=1)\nsubmission.to_csv(saveFileName, index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}