{"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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-05-24T06:55:07.096141Z","iopub.execute_input":"2021-05-24T06:55:07.096685Z","iopub.status.idle":"2021-05-24T06:55:07.101425Z","shell.execute_reply.started":"2021-05-24T06:55:07.096601Z","shell.execute_reply":"2021-05-24T06:55:07.100262Z"},"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-24T07:01:56.480536Z","iopub.execute_input":"2021-05-24T07:01:56.480914Z","iopub.status.idle":"2021-05-24T07:01:56.560037Z","shell.execute_reply.started":"2021-05-24T07:01:56.480884Z","shell.execute_reply":"2021-05-24T07:01:56.559174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\nlabel = LabelEncoder()\nlabel.fit(train_df['labels'])\ntrain_df['label_id'] = label.transform(train_df['labels'])\nlabel_dic = dict(sorted(train_df[['label_id', 'labels']].values.tolist())) #save for submission# сохранили в словарь что бы потом при сабмите понимать где какая метка(всего 12 меток)\nprint(label_dic)\nclasses = len(train_df['labels'].value_counts()) #12\n\ndel train_df['labels'] \n\nimage_labels = np.array(train_df['label_id'].values)#[ 9  6  9  9  3  9  3 10  6  6]\nimage_list = np.array(train_df['path'].values)#path to img\n\nprint(image_list.shape) #18632\nprint(image_labels[:10])","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:16:02.482746Z","iopub.execute_input":"2021-05-22T15:16:02.483135Z","iopub.status.idle":"2021-05-22T15:16:03.525535Z","shell.execute_reply.started":"2021-05-22T15:16:02.483103Z","shell.execute_reply":"2021-05-22T15:16:03.524434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n#train_df.groupby('label_id').size()\ncls_weight = list((1.0001/(train_df.groupby('label_id').size() / 4826)).values)\n\n\ncls_weight\n\ndisplay(train_df)\ncls_weight\ntrain_df.groupby('label_id').size()\n(train_df.groupby('label_id').size() / 4826)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:16:04.353815Z","iopub.execute_input":"2021-05-22T15:16:04.354149Z","iopub.status.idle":"2021-05-22T15:16:04.396648Z","shell.execute_reply.started":"2021-05-22T15:16:04.354119Z","shell.execute_reply":"2021-05-22T15:16:04.39544Z"},"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-22T15:16:05.376214Z","iopub.execute_input":"2021-05-22T15:16:05.376708Z","iopub.status.idle":"2021-05-22T15:16:42.015664Z","shell.execute_reply.started":"2021-05-22T15:16:05.376674Z","shell.execute_reply":"2021-05-22T15:16:42.014618Z"},"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.SmallestMaxSize(224),\n            A.RandomCrop(224, 224),\n            A.RandomContrast(), \n            A.OneOf(\n                [\n                    A.RandomGamma(), \n                    A.RandomBrightness(), \n                ],\n                p = 0.2\n            ),\n            A.OneOf(\n                [\n                    A.GaussNoise(),\n                    A.RandomContrast(),\n                    A.RandomGamma(),\n                    A.Rotate(limit=60), \n                    A.MotionBlur(blur_limit=20)\n                ],\n                p = 0.2\n            ),\n            A.OneOf(\n                [\n                    A.Rotate(limit=360),\n                    A.Flip(p=0.2),                \n                ],\n                p = 0.2\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.LongTensor([y,]).to(device)\n        \n        return x, y\n\n\ntrain_data = dataset(image_list[:15000], image_labels[:15000], get_training_augmentation(), device)\n\nprint(len(train_data))\n\ntrain_data = DataLoader(train_data, batch_size = 15, shuffle = True)\n\n##########\n# validation loader\nvalid_data = dataset(image_list[15000:], image_labels[15000:], transform_valid(), device)\nprint(len(valid_data))\nvalid_data = DataLoader(valid_data, batch_size = 15, shuffle = True)\n########","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:17.980192Z","iopub.execute_input":"2021-05-22T15:23:17.980683Z","iopub.status.idle":"2021-05-22T15:23:18.056167Z","shell.execute_reply.started":"2021-05-22T15:23:17.980611Z","shell.execute_reply":"2021-05-22T15:23:18.053668Z"},"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': 15000, \n    'val': 3632\n}","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:19.049267Z","iopub.execute_input":"2021-05-22T15:23:19.04967Z","iopub.status.idle":"2021-05-22T15:23:19.05786Z","shell.execute_reply.started":"2021-05-22T15:23:19.049634Z","shell.execute_reply":"2021-05-22T15:23:19.056431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def gallery(array, ncols=3):\n    nindex, height, width, intensity = array.shape\n    nrows = nindex//ncols\n    assert nindex == nrows * ncols\n    result = (array.reshape(nrows, ncols, height, width, intensity)\n              .swapaxes(1, 2)\n              .reshape(height*nrows, width*ncols, intensity))\n    return result","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:19.843924Z","iopub.execute_input":"2021-05-22T15:23:19.84435Z","iopub.status.idle":"2021-05-22T15:23:19.851664Z","shell.execute_reply.started":"2021-05-22T15:23:19.844309Z","shell.execute_reply":"2021-05-22T15:23:19.850067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image = read_img('../input/plant2021-downscaled-images-dataset/800113bb65efe69e.jpg')\nimages_aug = np.array([(get_training_augmentation()(image)).permute((1,2,0)).numpy() for _ in range(25)])\n\nplt.figure(figsize=(10,10))\nplt.axis('off')\nplt.imshow(gallery(images_aug, ncols=5))\nplt.title('Augmentation pipeline examples')","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:20.374825Z","iopub.execute_input":"2021-05-22T15:23:20.375208Z","iopub.status.idle":"2021-05-22T15:23:20.958022Z","shell.execute_reply.started":"2021-05-22T15:23:20.375175Z","shell.execute_reply":"2021-05-22T15:23:20.956701Z"},"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-22T15:23:20.960296Z","iopub.execute_input":"2021-05-22T15:23:20.960871Z","iopub.status.idle":"2021-05-22T15:23:20.967637Z","shell.execute_reply.started":"2021-05-22T15:23:20.960818Z","shell.execute_reply":"2021-05-22T15:23:20.966074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_training_augmentation()(image).numpy().reshape(1,3,224,224).shape","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:21.869412Z","iopub.execute_input":"2021-05-22T15:23:21.86984Z","iopub.status.idle":"2021-05-22T15:23:21.884448Z","shell.execute_reply.started":"2021-05-22T15:23:21.869807Z","shell.execute_reply":"2021-05-22T15:23:21.882967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = enet.EfficientNet.from_name('efficientnet-b7')\n\nmodel.load_state_dict(torch.load('../input/efficientnet-pytorch/efficientnet-b7-dcc49843.pth'))","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:22.506035Z","iopub.execute_input":"2021-05-22T15:23:22.506453Z","iopub.status.idle":"2021-05-22T15:23:23.819103Z","shell.execute_reply.started":"2021-05-22T15:23:22.50641Z","shell.execute_reply":"2021-05-22T15:23:23.81786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model._fc","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:24.766272Z","iopub.execute_input":"2021-05-22T15:23:24.7668Z","iopub.status.idle":"2021-05-22T15:23:24.774725Z","shell.execute_reply.started":"2021-05-22T15:23:24.766741Z","shell.execute_reply":"2021-05-22T15:23:24.773238Z"},"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-22T15:23:25.951751Z","iopub.execute_input":"2021-05-22T15:23:25.952495Z","iopub.status.idle":"2021-05-22T15:23:25.970124Z","shell.execute_reply.started":"2021-05-22T15:23:25.952442Z","shell.execute_reply":"2021-05-22T15:23:25.969009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class F1_Loss(nn.Module):\n\n    def __init__(self, epsilon=1e-7):\n        super().__init__()\n        self.epsilon = epsilon\n        \n    def forward(self, y_pred, y_true):\n        assert y_pred.ndim == 2\n        assert y_true.ndim == 1\n        y_true = torch.nn.functional.one_hot(y_true, 12).to(torch.float32)\n        y_pred = torch.nn.functional.softmax(y_pred, dim=1)\n        \n        tp = (y_true * y_pred).sum(dim=0).to(torch.float32)\n        tn = ((1 - y_true) * (1 - y_pred)).sum(dim=0).to(torch.float32)\n        fp = ((1 - y_true) * y_pred).sum(dim=0).to(torch.float32)\n        fn = (y_true * (1 - y_pred)).sum(dim=0).to(torch.float32)\n        \n        precision = tp / (tp + fp + self.epsilon)\n        recall = tp / (tp + fn + self.epsilon)\n        \n        f1 = 2 * (precision * recall) / (precision + recall + self.epsilon)\n        f1 = f1.clamp(min=self.epsilon, max=1 - self.epsilon)\n        return 1 - f1.mean()\n\nf1_loss = F1_Loss().cuda()\n","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:28.168154Z","iopub.execute_input":"2021-05-22T15:23:28.16861Z","iopub.status.idle":"2021-05-22T15:23:28.18Z","shell.execute_reply.started":"2021-05-22T15:23:28.168546Z","shell.execute_reply":"2021-05-22T15:23:28.178795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model._fc = nn.Linear(in_features=2560, out_features=12).cuda()","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:29.954792Z","iopub.execute_input":"2021-05-22T15:23:29.955154Z","iopub.status.idle":"2021-05-22T15:23:29.962926Z","shell.execute_reply.started":"2021-05-22T15:23:29.955122Z","shell.execute_reply":"2021-05-22T15:23:29.961454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn as nn\nfrom torch.optim import Adam\nfrom torch.optim import lr_scheduler\n\n# model._fc = torch.nn.Linear(in_features=1280, out_features=classes) #change the last FC layer\n\nmodel = model.to(device)\ncriterion = FocalLoss().to(device) #nn.CrossEntropyLoss().to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr = 0.001) # lr, SGD\n\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:31.588168Z","iopub.execute_input":"2021-05-22T15:23:31.588596Z","iopub.status.idle":"2021-05-22T15:23:31.742609Z","shell.execute_reply.started":"2021-05-22T15:23:31.588544Z","shell.execute_reply":"2021-05-22T15:23:31.74153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset_sizes","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:32.66949Z","iopub.execute_input":"2021-05-22T15:23:32.669929Z","iopub.status.idle":"2021-05-22T15:23:32.677798Z","shell.execute_reply.started":"2021-05-22T15:23:32.669881Z","shell.execute_reply":"2021-05-22T15:23:32.676214Z"},"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\n            # Iterate over data.\n            for inputs, labels in tqdm(dataloaders[phase]):\n                inputs = inputs.to(device)\n                labels = labels.reshape(-1).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                    _, preds = torch.max(outputs, 1)\n                    loss = criterion(outputs, torch.nn.functional.one_hot(labels, num_classes=12).long())\n\n                    # backward + optimize only if in training phase\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n\n                # statistics\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n\n            epoch_loss = running_loss / dataset_sizes[phase]\n            epoch_acc = running_corrects.double() / dataset_sizes[phase]\n\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))\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\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","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:33.433071Z","iopub.execute_input":"2021-05-22T15:23:33.433444Z","iopub.status.idle":"2021-05-22T15:23:33.449806Z","shell.execute_reply.started":"2021-05-22T15:23:33.433411Z","shell.execute_reply":"2021-05-22T15:23:33.447953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model(model, criterion, optimizer, exp_lr_scheduler, num_epochs=15)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T15:23:34.336253Z","iopub.execute_input":"2021-05-22T15:23:34.336678Z","iopub.status.idle":"2021-05-22T18:35:10.388187Z","shell.execute_reply.started":"2021-05-22T15:23:34.336644Z","shell.execute_reply":"2021-05-22T18:35:10.38692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform_valid()","metadata":{"execution":{"iopub.status.busy":"2021-05-22T18:35:18.882328Z","iopub.execute_input":"2021-05-22T18:35:18.882819Z","iopub.status.idle":"2021-05-22T18:35:18.892974Z","shell.execute_reply.started":"2021-05-22T18:35:18.882777Z","shell.execute_reply":"2021-05-22T18:35:18.891708Z"},"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-22T18:35:20.293534Z","iopub.execute_input":"2021-05-22T18:35:20.293913Z","iopub.status.idle":"2021-05-22T18:35:21.006064Z","shell.execute_reply.started":"2021-05-22T18:35:20.293881Z","shell.execute_reply":"2021-05-22T18:35:21.004624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img.shape","metadata":{"execution":{"iopub.status.busy":"2021-05-22T18:35:26.1364Z","iopub.execute_input":"2021-05-22T18:35:26.136985Z","iopub.status.idle":"2021-05-22T18:35:26.151384Z","shell.execute_reply.started":"2021-05-22T18:35:26.136925Z","shell.execute_reply":"2021-05-22T18:35:26.149583Z"},"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-22T18:35:32.870661Z","iopub.execute_input":"2021-05-22T18:35:32.871064Z","iopub.status.idle":"2021-05-22T18:35:33.211365Z","shell.execute_reply.started":"2021-05-22T18:35:32.87103Z","shell.execute_reply":"2021-05-22T18:35:33.210437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}