{"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 numpy as np\nimport pandas as pd\nfrom sklearn.metrics import f1_score","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-05-24T13:35:52.338640Z","iopub.execute_input":"2021-05-24T13:35:52.339085Z","iopub.status.idle":"2021-05-24T13:35:53.174198Z","shell.execute_reply.started":"2021-05-24T13:35:52.338981Z","shell.execute_reply":"2021-05-24T13:35:53.173442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv('../input/plant-pathology-2021-fgvc8/train.csv').sample(frac=1, random_state=666)\ntrain_df['path'] =  train_df['image'].apply(lambda x: '../input/plant2021-downscaled-images-dataset/' + x)\ntrain_df.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:53.175945Z","iopub.execute_input":"2021-05-24T13:35:53.176303Z","iopub.status.idle":"2021-05-24T13:35:53.233205Z","shell.execute_reply.started":"2021-05-24T13:35:53.176268Z","shell.execute_reply":"2021-05-24T13:35:53.232340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['label_id'] = train_df['labels'].str.replace('scab', '1').str.replace('rust', '2') \\\n    .str.replace('healthy', '0').str.replace('frog_eye_leaf_spot', '3') \\\n    .str.replace('complex', '4').str.replace('powdery_mildew', '5').str.split(\" \")","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:53.234439Z","iopub.execute_input":"2021-05-24T13:35:53.234873Z","iopub.status.idle":"2021-05-24T13:35:53.400693Z","shell.execute_reply.started":"2021-05-24T13:35:53.234835Z","shell.execute_reply":"2021-05-24T13:35:53.399857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['label_id'] = [[int(j) for j in i] for i in train_df['label_id'].values]","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:53.647253Z","iopub.execute_input":"2021-05-24T13:35:53.647562Z","iopub.status.idle":"2021-05-24T13:35:53.674364Z","shell.execute_reply.started":"2021-05-24T13:35:53.647533Z","shell.execute_reply":"2021-05-24T13:35:53.673661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from random import sample","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:54.249550Z","iopub.execute_input":"2021-05-24T13:35:54.249879Z","iopub.status.idle":"2021-05-24T13:35:54.253696Z","shell.execute_reply.started":"2021-05-24T13:35:54.249846Z","shell.execute_reply":"2021-05-24T13:35:54.252792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_df = train_df.iloc[17000:, :]\ntrain_df = train_df.iloc[:17000, :]","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:54.799869Z","iopub.execute_input":"2021-05-24T13:35:54.800189Z","iopub.status.idle":"2021-05-24T13:35:54.804896Z","shell.execute_reply.started":"2021-05-24T13:35:54.800158Z","shell.execute_reply":"2021-05-24T13:35:54.803822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label_dic = {\n    0: 'healthy', \n    1: 'scab',\n    2: 'rust',\n    3: 'frog_eye_leaf_spot',\n    4: 'complex', \n    5: 'powdery_mildew'\n}\nprint(label_dic)\nclasses = 6#len(train_df['labels'].value_counts()) #12\n\ndel train_df['labels'] \n\nimage_labels = np.array(train_df['label_id'].values)\nimage_list = np.array(train_df['path'].values)\n\nimage_labels_v = np.array(valid_df['label_id'].values)\nimage_list_v = np.array(valid_df['path'].values)\n\nprint(image_list.shape)","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:55.309990Z","iopub.execute_input":"2021-05-24T13:35:55.310337Z","iopub.status.idle":"2021-05-24T13:35:55.319484Z","shell.execute_reply.started":"2021-05-24T13:35:55.310307Z","shell.execute_reply":"2021-05-24T13:35:55.318331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"[5193 / sum([j in i for i in list(image_labels)]) for j in range(6)]","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:55.865396Z","iopub.execute_input":"2021-05-24T13:35:55.865681Z","iopub.status.idle":"2021-05-24T13:35:55.881286Z","shell.execute_reply.started":"2021-05-24T13:35:55.865653Z","shell.execute_reply":"2021-05-24T13:35:55.880265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cls_weight = [1.24, 1.0001, 2.72, 1.31, 2.61, 4.4]","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:56.399813Z","iopub.execute_input":"2021-05-24T13:35:56.400136Z","iopub.status.idle":"2021-05-24T13:35:56.406949Z","shell.execute_reply.started":"2021-05-24T13:35:56.400103Z","shell.execute_reply":"2021-05-24T13:35:56.406026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!apt install ../input/pyturbojpeg/libturbojpeg_1.4.2-0ubuntu3.4_amd64.deb\n!pip install ../input/pyturbojpeg/PyTurboJPEG-1.4.1","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:35:56.899767Z","iopub.execute_input":"2021-05-24T13:35:56.900058Z","iopub.status.idle":"2021-05-24T13:36:29.087524Z","shell.execute_reply.started":"2021-05-24T13:35:56.900019Z","shell.execute_reply":"2021-05-24T13:36:29.086530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport albumentations as A\nimport cv2, torch\nimport torchvision.transforms as transforms\nfrom tqdm.notebook import tqdm\nfrom torch.utils.data import Dataset, DataLoader\nfrom turbojpeg import TurboJPEG\n\ndevice = torch.device('cuda' if torch.cuda.is_available else 'cpu')\n\n#######################################\n\nfrom albumentations.pytorch import ToTensor\n\ndef get_training_augmentation():\n    \n    augmentation_pipeline = A.Compose(\n         [\n            A.OneOf([\n                A.Compose([\n                    A.SmallestMaxSize(224),\n                    A.RandomCrop(224, 224),\n                ], p=1),\n                A.Compose([\n                    A.SmallestMaxSize(400),\n                    A.RandomCrop(224, 224),\n                ], p=1)\n            ], p=1),\n            \n            A.OneOf(\n                [\n                    A.HueSaturationValue(),\n                    A.RandomBrightness(limit=1.58),\n                    A.RandomGamma(gamma_limit=(500, 1500)), \n                    A.RandomContrast(), \n                    A.Blur(blur_limit=30),\n                    A.GaussNoise()\n                ],\n                p = 0.4\n            ),\n            A.OneOf(\n                [\n                    A.Transpose(p = 0.5),\n                    A.Rotate(limit = 360), \n                    A.Flip(p = 0.5),\n                ],\n                p = 0.3\n            ),\n            A.Normalize(\n                mean=[0.485, 0.456, 0.406],\n                std=[0.229, 0.224, 0.225]\n                ),\n            ToTensor() \n        ],\n        p = 1\n    )\n    return lambda img:augmentation_pipeline(image=np.array(img))['image']\n\n\n\ndef transform_valid():\n    \n    augmentation_pipeline = A.Compose(\n        [\n            A.SmallestMaxSize(224),\n            A.RandomCrop(224, 224),\n            A.Normalize(\n                mean=[0.485, 0.456, 0.406],\n                std=[0.229, 0.224, 0.225]\n                ),\n            ToTensor() \n        ],\n        p = 1\n    )\n    return lambda img:augmentation_pipeline(image=np.array(img))['image']\n\n######################################\n\njpeg_reader = TurboJPEG()\n\ndef read_img(img):\n    with open(img, \"rb\") as f:\n        return jpeg_reader.decode(f.read(), 0) \n    \n\nclass dataset(Dataset) :\n    def __init__(self, image_list, image_labels, transform, device) :\n        self.image_list = image_list\n        self.image_labels = image_labels\n        self.transform = transform\n    \n    def __len__(self) :\n        return len(self.image_list)\n    \n    def __getitem__(self, index) :\n        x = read_img(self.image_list[index])\n        x = self.transform(x).to(device)\n        \n        y = self.image_labels[index]\n        y = torch.nn.functional.one_hot(torch.tensor(y), 6).sum(0).to(device)\n        \n        return x, y\n\n\ntrain_data = dataset(image_list, image_labels, get_training_augmentation(), device)\n\nprint(len(train_data))\n\ntrain_data = DataLoader(train_data, batch_size = 32, shuffle = True)\n\n##########\n# validation loader\nvalid_data = dataset(image_list_v, image_labels_v, transform_valid(), device)\nprint(len(valid_data))\nvalid_data = DataLoader(valid_data, batch_size = 32, shuffle = True)\n########","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:36:29.091629Z","iopub.execute_input":"2021-05-24T13:36:29.091899Z","iopub.status.idle":"2021-05-24T13:36:31.647641Z","shell.execute_reply.started":"2021-05-24T13:36:29.091872Z","shell.execute_reply":"2021-05-24T13:36:31.646131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataloaders = {\n    'train': train_data , \n    'val': valid_data\n}\n\ndataset_sizes = {\n    'train': 17000, \n    'val': 1632\n}","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:36:31.650898Z","iopub.execute_input":"2021-05-24T13:36:31.651171Z","iopub.status.idle":"2021-05-24T13:36:31.654899Z","shell.execute_reply.started":"2021-05-24T13:36:31.651144Z","shell.execute_reply":"2021-05-24T13:36:31.654123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\n\nsys.path.append(\"../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master\")\n\nfrom efficientnet_pytorch import model as enet","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:36:31.656219Z","iopub.execute_input":"2021-05-24T13:36:31.656742Z","iopub.status.idle":"2021-05-24T13:36:31.711409Z","shell.execute_reply.started":"2021-05-24T13:36:31.656706Z","shell.execute_reply":"2021-05-24T13:36:31.710790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = enet.EfficientNet.from_name('efficientnet-b4')\n\nmodel.load_state_dict(torch.load('../input/efficientnet-pytorch/efficientnet-b4-e116e8b3.pth'))","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:36:31.714522Z","iopub.execute_input":"2021-05-24T13:36:31.714860Z","iopub.status.idle":"2021-05-24T13:36:33.208903Z","shell.execute_reply.started":"2021-05-24T13:36:31.714832Z","shell.execute_reply":"2021-05-24T13:36:33.208068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model._fc","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:36:33.212106Z","iopub.execute_input":"2021-05-24T13:36:33.212357Z","iopub.status.idle":"2021-05-24T13:36:33.217178Z","shell.execute_reply.started":"2021-05-24T13:36:33.212331Z","shell.execute_reply":"2021-05-24T13:36:33.216361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn as nn\n\nclass FocalLoss(nn.Module):\n    \"\"\"\n    The focal loss for fighting against class-imbalance\n    \"\"\"\n    def __init__(self, alpha=1, gamma=2):\n        super(FocalLoss, self).__init__()\n        self.alpha = alpha\n        self.gamma = gamma\n        self.epsilon = 1e-12  # prevent training from Nan-loss error\n        self.cls_weights = torch.tensor([cls_weight],dtype=torch.float, requires_grad=False, device=device)\n\n    def forward(self, logits, target):\n        \"\"\"\n        logits & target should be tensors with shape [batch_size, num_classes]\n        \"\"\"\n        probs = torch.sigmoid(logits)\n        one_subtract_probs = 1.0 - probs\n        # add epsilon\n        probs_new = probs + self.epsilon\n        one_subtract_probs_new = one_subtract_probs + self.epsilon\n        # calculate focal loss\n        log_pt = target * torch.log(probs_new) + (1.0 - target) * torch.log(one_subtract_probs_new)\n        pt = torch.exp(log_pt)\n        focal_loss = -1.0 * (self.alpha * (1 - pt) ** self.gamma) * log_pt\n        focal_loss = focal_loss * self.cls_weights\n        return torch.mean(focal_loss)","metadata":{"execution":{"iopub.status.busy":"2021-05-24T13:36:33.218561Z","iopub.execute_input":"2021-05-24T13:36:33.219362Z","iopub.status.idle":"2021-05-24T13:36:33.230623Z","shell.execute_reply.started":"2021-05-24T13:36:33.219326Z","shell.execute_reply":"2021-05-24T13:36:33.229609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn as nn\nfrom torch.optim import Adam, SGD\nfrom torch.optim import lr_scheduler\n\nmodel._fc = torch.nn.Linear(in_features=1792, out_features=classes) #change the last FC layer\n\nmodel = model.to(device)\ncriterion = FocalLoss().to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr = 0.001) # lr, SGD\n\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=9, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:33.809232Z","iopub.execute_input":"2021-05-24T14:01:33.809543Z","iopub.status.idle":"2021-05-24T14:01:33.841926Z","shell.execute_reply.started":"2021-05-24T14:01:33.809511Z","shell.execute_reply":"2021-05-24T14:01:33.841239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset_sizes","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:34.661626Z","iopub.execute_input":"2021-05-24T14:01:34.661954Z","iopub.status.idle":"2021-05-24T14:01:34.667438Z","shell.execute_reply.started":"2021-05-24T14:01:34.661925Z","shell.execute_reply":"2021-05-24T14:01:34.666458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def to_lab(preds):\n    return ((preds > 0) + torch.nn.functional.one_hot(preds.argmax(1), 6) != 0).long()","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:35.221300Z","iopub.execute_input":"2021-05-24T14:01:35.221608Z","iopub.status.idle":"2021-05-24T14:01:35.228444Z","shell.execute_reply.started":"2021-05-24T14:01:35.221580Z","shell.execute_reply":"2021-05-24T14:01:35.227451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import time\nimport copy\n\ndef train_model(model, criterion, optimizer, scheduler, num_epochs=25):\n    since = time.time()\n\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n\n        # Each epoch has a training and validation phase\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                optimizer.step()\n                scheduler.step()\n                model.train()  # Set model to training mode\n            else:\n                model.eval()   # Set model to evaluate mode\n\n            running_loss = 0.0\n            running_corrects = 0\n            f1l = 0\n\n            # Iterate over data.\n            for inputs, labels in tqdm(dataloaders[phase]):\n                inputs = inputs.to(device)\n                labels = labels.to(device) #\n                #print(labels)\n                # zero the parameter gradients\n                optimizer.zero_grad()\n\n                # forward\n                # track history if only in train\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    #outputs = torch.nn.Sigmoid()(outputs)\n                    #_, preds = torch.max(outputs, 1)\n                    preds = to_lab(outputs)\n                    loss = criterion(outputs, labels.float())\n\n                    # backward + optimize only if in training phase\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n                        \n                #torch.cuda.empty_cache()\n\n                # statistics\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += ((preds == labels.data).sum(1)==6).sum()\n                f1l += f1_score(preds.cpu().numpy(), labels.cpu().numpy(), average='macro', zero_division=True) * inputs.size(0)\n\n            epoch_loss = running_loss / dataset_sizes[phase]\n            epoch_acc = running_corrects.double() / dataset_sizes[phase]\n            epoch_f1 = f1l / dataset_sizes[phase]\n\n            print('{} Loss: {:.4f} Acc: {:.4f} F1: {:.4f}'.format(phase, epoch_loss, epoch_acc, epoch_f1))\n\n            # deep copy the model\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n                torch.save(model.state_dict(), 'best_model.pth')\n\n        print()\n\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))\n    print('Best val Acc: {:4f}'.format(best_acc))\n\n    # load best model weights\n    model.load_state_dict(best_model_wts)\n    return model\n","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:35.793305Z","iopub.execute_input":"2021-05-24T14:01:35.793614Z","iopub.status.idle":"2021-05-24T14:01:35.806416Z","shell.execute_reply.started":"2021-05-24T14:01:35.793586Z","shell.execute_reply":"2021-05-24T14:01:35.805463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model(model, criterion, optimizer, exp_lr_scheduler, num_epochs=27)","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:36.379373Z","iopub.execute_input":"2021-05-24T14:01:36.379683Z","iopub.status.idle":"2021-05-24T14:18:22.652408Z","shell.execute_reply.started":"2021-05-24T14:01:36.379654Z","shell.execute_reply":"2021-05-24T14:18:22.650523Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform_valid()","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:27.642003Z","iopub.status.idle":"2021-05-24T14:01:27.642777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from glob import glob\n\nvalid_image_list = glob('../input/plant-pathology-2021-fgvc8/test_images/*.jpg')\n\nmodel.eval()\npredict_list = []\nimage_name_list = []\nfor i, image in tqdm(enumerate(valid_image_list)) :\n    image_name = image[48:]\n    \n    img = read_img(image)\n    img = transform_valid()(img)\n    \n    result_list = torch.FloatTensor(np.zeros((classes))).to(device)\n    img = img.to(device)\n    img = img.reshape(-1, 3, 224, 224)\n    predict = model(img)\n    predict = predict.reshape(-1)\n    result_list += predict\n    \n    predict_list.append(torch.argmax(result_list).item())\n    image_name_list.append(image_name)\n    \npredict_list = np.array(predict_list)\nimage_name_list = np.array(image_name_list)\nprint(image_name_list)\n\nsubmission_df = pd.DataFrame()\nsubmission_df['image'] = image_name_list\nsubmission_df['label_id'] = predict_list\nsubmission_df['labels'] = submission_df['label_id'].map(label_dic)\ndel submission_df['label_id']\nsubmission_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:27.644284Z","iopub.status.idle":"2021-05-24T14:01:27.644999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img.shape","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:27.646303Z","iopub.status.idle":"2021-05-24T14:01:27.647014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index = False)","metadata":{"execution":{"iopub.status.busy":"2021-05-24T14:01:27.648335Z","iopub.status.idle":"2021-05-24T14:01:27.649019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}