{"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":"from typing import List, Dict\n\nimport random\nimport os\n\nimport numpy as np\nimport pandas as pd\nimport PIL\n\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport torchvision\nimport torch.onnx\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torchvision import transforms as T\n\nimport skimage.io as io\nfrom tqdm.notebook import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def to_numpy(tensor):\n    return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_image_labels():\n    df = pd.read_csv('../input/plant-pathology-2021-fgvc8/train.csv').set_index('image')\n    return df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_labels = read_image_labels().sample(\n    frac=1.0, \n    random_state=42\n)\n\nimg_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_image_infos(img_labels):\n  \n    df = img_labels.reset_index().groupby(by='labels').count().reset_index()\n    df.columns = ['disease', 'count']\n    \n    df['%'] = np.round((df['count'] / img_labels.shape[0]), 2) * 100\n    df = df.set_index('disease').sort_values(by='count', ascending=False)\n\n    return df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_image_infos(img_labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folders = dict({\n        'data': '../input/plant-pathology-2021-fgvc8',\n        'train': '../input/resized-plant2021/img_sz_256',\n        'val': '../input/resized-plant2021/img_sz_256',\n        'test':  '../input/plant-pathology-2021-fgvc8/test_images',\n        'submiss': '../input/plant-pathology-2021-fgvc8/sample_submission.csv'\n    })\n\ndef get_image(image_id, kind='train'):\n    \"\"\"Loads an image from file\n    \"\"\"\n    fname = os.path.join(folders[kind], image_id)\n    return PIL.Image.open(fname)\n\ndef plot_image_counts(img_labels):\n    fig, ax = plt.subplots(figsize=(18, 7))\n    sns.set_style(\"whitegrid\")\n    palette = sns.color_palette(\"Blues_r\", 12)\n\n    sns.countplot(\n        x='labels', \n        palette=palette,\n        data=img_labels,\n        order=img_labels['labels'].value_counts().index,\n    );\n\n    plt.ylabel(\"# of observations\", size=20);\n    plt.xlabel(\"Class names\", size=20)\n\n    plt.xticks(rotation=45)\n    \n    fig.tight_layout()\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_image_counts(img_labels)  ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_single_labels(unique_labels) -> List[str]:\n    single_labels = []\n    \n    for label in unique_labels:\n        single_labels += label.split()\n        \n    single_labels = set(single_labels)\n    return list(single_labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_one_hot_encoded_labels(dataset_df) -> pd.DataFrame:\n    df = dataset_df.copy()\n    \n    unique_labels = ['rust', \n        'complex', \n        'healthy', \n        'powdery_mildew', \n        'scab', \n        'frog_eye_leaf_spot']\n    column_names = get_single_labels(unique_labels)\n    \n    df[column_names] = 0\n    print(column_names)\n    # one-hot-encoding\n    for label in unique_labels:                \n        label_indices = df[df['labels'] == label].index\n        splited_labels = label.split()\n        df.loc[label_indices, splited_labels] = 1\n    \n    return df\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"one_hot_encoded_labels = get_one_hot_encoded_labels(img_labels)\none_hot_encoded_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_transform = A.Compose([\n    A.Rotate(\n        always_apply=False, \n        p=0.1, \n        limit=(-68, 178), \n        interpolation=1, \n        border_mode=0, \n        value=(0, 0, 0), \n        mask_value=None\n    ),\n    A.RandomShadow(\n        num_shadows_lower=1, \n        num_shadows_upper=1, \n        shadow_dimension=3, \n        shadow_roi=(0, 0.6, 1, 1), \n        p=0.4\n    ),\n    A.ShiftScaleRotate(\n        shift_limit=0.05, \n        scale_limit=0.05, \n        rotate_limit=15, \n        p=0.6\n    ),\n    A.RandomFog(\n        fog_coef_lower=0.2, \n        fog_coef_upper=0.2, \n        alpha_coef=0.2, \n        p=0.3\n    ),\n    A.RGBShift(\n        r_shift_limit=15, \n        g_shift_limit=15, \n        b_shift_limit=15, \n        p=0.3\n    ),\n    A.RandomBrightnessContrast(\n        p=0.3\n    ),\n    A.GaussNoise(\n        var_limit=(50, 70),  \n        always_apply=False, \n        p=0.3\n    ),\n    A.Resize(\n        height=224,\n        width=224,\n    ),\n    A.CoarseDropout(\n        max_holes=5, \n        max_height=5, \n        max_width=5, \n        min_holes=3, \n        min_height=5, \n        min_width=5,\n        always_apply=False, \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    ToTensorV2(),\n])\n\nval_transform = A.Compose([\n    A.Resize(\n        height=224,\n        width=224,\n    ),\n    A.Normalize(\n        mean=(0.485, 0.456, 0.406), \n        std=(0.229, 0.224, 0.225)\n    ),\n    ToTensorV2(),\n])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from scipy.stats import bernoulli\nfrom torch.utils.data import Dataset\n\nclass PlantDataset(Dataset):\n    \"\"\"\n    \"\"\"\n    def __init__(self, \n                 image_ids, \n                 targets,\n                 transform=None, \n                 target_transform=None, \n                 kind='train'):\n        self.image_ids = image_ids\n        self.targets = targets\n        self.transform = transform\n        self.target_transform = target_transform\n        self.kind = kind\n    \n    def __len__(self):\n        return len(self.image_ids)\n    \n    def __getitem__(self, idx):\n        # load and transform image\n        img = np.array(get_image(self.image_ids.iloc[idx], kind=self.kind))\n        \n        if self.transform:\n            img = self.transform(image=img)['image']\n        \n        # get image target \n        target = self.targets[idx]\n        if self.target_transform:\n            target = self.target_transform(target)\n        \n        return img, target","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_vaild, y_train, y_vaild = train_test_split(\n    pd.Series(img_labels.index), \n    np.array(one_hot_encoded_labels[[\n        'rust', \n        'complex', \n        'healthy', \n        'powdery_mildew', \n        'scab', \n        'frog_eye_leaf_spot'\n    ]]),  \n    test_size=0.3, \n    random_state=42\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_set = PlantDataset(X_train, y_train, transform=train_transform, kind='train')\nval_set = PlantDataset(X_vaild, y_vaild, transform=val_transform, kind='val')\nX_train.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Train size: {len(train_set)}')\nprint(f'Validation size: {len(val_set)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader\nfrom torch.nn import BatchNorm2d\n\nbatch_size = 32\n\ntrain_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True)\nvalid_loader = DataLoader(val_set, batch_size=batch_size, shuffle=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_model(pretrained=True):\n    model = torchvision.models.resnet101(pretrained=pretrained).to(device)\n    \n    ct = 0\n    for child in model.children():\n        ct += 1\n        if ct < 5:\n            for param in child.parameters():\n                param.requires_grad = False\n    \n    model.fc = torch.nn.Sequential(\n        torch.nn.Linear(\n            in_features=model.fc.in_features,\n            out_features=6\n        ),\n        torch.nn.Sigmoid()\n    ).to(device)\n    \n    return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model(pretrained=True).to(device)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MetricMonitor:\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.losses = []\n        self.accuracies = []\n        self.scores = []\n        self.metrics = dict({\n            'loss': self.losses,\n            'acc': self.accuracies,\n            'f1': self.scores\n        })\n\n    def update(self, metric_name, value):\n        self.metrics[metric_name] += [value]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import f1_score, accuracy_score\n\ndef get_metrics(\n    y_pred_proba, \n    y_test, \n    threshold=0.25,\n    labels=[\n        'rust', \n        'complex', \n        'healthy', \n        'powdery_mildew', \n        'scab', \n        'frog_eye_leaf_spot'\n    ]) -> None:\n    \"\"\"\n    \"\"\"\n    y_pred = np.where(y_pred_proba > threshold, 1, 0)\n\n    y1 = y_pred.round().astype(np.float)\n    y2 = y_test.round().astype(np.float)\n    \n    f1 = f1_score(y1, y2, average='micro')\n    acc = accuracy_score(y1, y2, normalize=True)\n\n    return acc, f1","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def training_loop(\n    dataloader, \n    model, \n    loss_fn, \n    optimizer, \n    epoch, \n    monitor = MetricMonitor(), \n    is_train=True\n) -> None:\n    \"\"\"\n    \"\"\"\n    size = len(dataloader.dataset)\n    \n    loss_val = 0\n    accuracy = 0\n    f1score = 0\n    \n    if is_train:\n        model.train()\n    else:\n        model.eval()\n    \n    stream = tqdm(dataloader)\n    for batch, (X, y) in enumerate(stream, start=1):\n        X = X.to(device)\n        y = y.to(device)\n        \n        # compute prediction and loss\n        pred_prob = model(X)\n        loss = loss_fn(pred_prob, y)\n        \n        \n        \n        if is_train:\n            # backpropagation\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n\n        \n        loss_val += loss.item()\n        acc, f1 = get_metrics(to_numpy(pred_prob), to_numpy(y))\n        \n        accuracy += acc \n        f1score += f1\n\n        phase = 'Train' if is_train else 'Val'\n        stream.set_description(\n            f'Epoch {epoch:3d}/{7} - {phase} - Loss: {loss_val/batch:.4f}, ' + \n            f'Acc: {accuracy/batch:.4f}, F1: {f1score/batch:.4f}'\n        )\n\n    monitor.update('loss', loss_val/batch)\n    monitor.update('acc', accuracy/batch)\n    monitor.update('f1', f1score/batch) ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_monitor = MetricMonitor()\ntest_monitor = MetricMonitor()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# initialize the loss function\nloss_fn = nn.MultiLabelSoftMarginLoss()\n\noptimizer = torch.optim.Adam(\n    model.parameters(),\n    lr=0.0001\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nepoch = 7\n\nfor epoch in range(1, epoch + 1):\n        \n    if(epoch == 5):\n        ct = 0\n        for child in model.children():\n            ct += 1\n            if ct < 5:\n                for param in child.parameters():\n                    param.requires_grad = True\n        \n    \n    # training loop\n    training_loop(\n        train_loader, \n        model, \n        loss_fn, \n        optimizer, \n        epoch, \n        train_monitor,\n        is_train=True\n    )\n    \n    # validation loop\n    training_loop(\n        valid_loader, \n        model, \n        loss_fn, \n        optimizer, \n        epoch, \n        test_monitor,\n        is_train=False\n    )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from matplotlib.ticker import MaxNLocator \n\ndef plot_result(\n    train_losses, \n    test_losses, \n    train_accuracies, \n    test_accuracies, \n    train_scores,\n    test_scores\n) -> None:\n    \n    epochs = range(1, len(train_losses) + 1)\n    fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(22, 5))\n    \n    # plot loss values\n    ax[0].plot(epochs, train_losses, label='Training loss', marker ='o')\n    ax[0].plot(epochs, test_losses, label='Validation loss', marker ='o')\n    ax[0].legend(frameon=False, fontsize=14)\n    \n    ax[0].get_xaxis().set_major_locator(MaxNLocator(integer=True))\n    ax[0].set_title('Loss', fontsize=18)\n    ax[0].set_xlabel('Epoch', fontsize=14) \n    ax[0].set_ylabel('Loss', fontsize=14)  \n    \n    # plot accuracies \n    ax[1].plot(epochs, train_accuracies, label='Training Accuracy', marker ='o')\n    ax[1].plot(epochs, test_accuracies, label='Validation accuracy', marker ='o')\n    ax[1].legend(frameon=False, fontsize=14)\n    \n    ax[1].get_xaxis().set_major_locator(MaxNLocator(integer=True))\n    ax[1].set_title('Accuracy', fontsize=18)\n    ax[1].set_xlabel('Epoch', fontsize=14) \n    ax[1].set_ylabel('Accuracy', fontsize=14)\n    \n    ax[2].plot(epochs, train_scores, label='Training F1-Score', marker ='o')\n    ax[2].plot(epochs, test_scores, label='Validation F1-Score', marker ='o')\n    ax[2].legend(frameon=False, fontsize=14)\n    \n    ax[2].get_xaxis().set_major_locator(MaxNLocator(integer=True))\n    ax[2].set_title('F1-Score', fontsize=18)\n    ax[2].set_xlabel('Epoch', fontsize=14) \n    ax[2].set_ylabel('F1-Score', fontsize=14) \n        \n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_result(\n    train_monitor.losses, \n    test_monitor.losses,\n    train_monitor.accuracies, \n    test_monitor.accuracies, \n    train_monitor.scores,\n    test_monitor.scores\n)    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model.state_dict(), 'v5.pkl')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch = 32\n\ny_true = np.empty(shape=(0, 6), dtype=np.int)\ny_pred_proba = np.empty(shape=(0, 6), dtype=np.int)\n\nstream = tqdm(valid_loader)\nfor batch, (X, y) in enumerate(stream, start=1):\n    X = X.to(device)\n    y = to_numpy(y.to(device))\n    pred = to_numpy(model(X))\n    \n    y_true = np.vstack((y_true, y))\n    y_pred_proba = np.vstack((y_pred_proba, pred))\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import multilabel_confusion_matrix\n\ndef plot_confusion_matrix(\n    y_test, \n    y_pred_proba, \n    threshold=0.25, \n    label_names=[\n        'rust', \n        'complex', \n        'healthy', \n        'powdery_mildew', \n        'scab', \n        'frog_eye_leaf_spot'\n    ]\n)-> None:\n    \"\"\"\n    \"\"\"\n    y_pred = np.where(y_pred_proba > threshold, 1, 0)\n    c_matrices = multilabel_confusion_matrix(y_test, y_pred)\n    \n    cmap = plt.get_cmap('Blues')\n    fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(15, 8))\n\n    for cm, label, ax in zip(c_matrices, label_names, axes.flatten()):\n        sns.heatmap(cm, annot=True, fmt='g', ax=ax, cmap=cmap);\n\n        ax.set_xlabel('Predicted labels');\n        ax.set_ylabel('True labels'); \n        ax.set_title(f'{label}');\n\n    plt.tight_layout()    \n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(y_true, y_pred_proba)    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = np.where(y_pred_proba > 0.25, 1, 0)\naccuracy, f1 = get_metrics(y_pred, y_true)\n\npd.DataFrame({\n    'name': ['F1', 'Accuracy'],\n    'sorce': [f1, accuracy]\n}).set_index('name')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = pd.read_csv('/kaggle/input/plant-pathology-2021-fgvc8/sample_submission.csv').set_index('image')\n# submission_df.labels = None\nsubmission_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"one_hot_encoded_labels = get_one_hot_encoded_labels(submission_df)\none_hot_encoded_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nX_test = pd.Series(submission_df.index)\ny_test = np.array(one_hot_encoded_labels[[\n        'rust', \n        'complex', \n        'healthy', \n        'powdery_mildew', \n        'scab', \n        'frog_eye_leaf_spot'\n    ]])\nprint(len(y_test))\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_transform = A.Compose([\n    A.Resize(\n        height=224,\n        width=224,\n    \n    ),\nA.Normalize(\n        mean=(0.485, 0.456, 0.406), \n        std=(0.229, 0.224, 0.225)\n    ),    \n    ToTensorV2(),\n])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_set = PlantDataset(X_test, y_test, transform=test_transform, kind='test')\n\nbatch_size = 32\ntest_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False)\nX_test","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch = 32\n\ny_true = np.empty(shape=(0, 6), dtype=np.int)\ny_pred_proba = np.empty(shape=(0, 6), dtype=np.int)\n\nstream = tqdm(test_loader)\nfor batch, (X, y) in enumerate(stream):\n    X = X.float().to(device)\n    y = to_numpy(y.to(device))\n    pred = to_numpy(model(X))\n    \n    y_true = np.vstack((y_true, y))\n    y_pred_proba = np.vstack((y_pred_proba, pred))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# y_pred_proba_df= pd.DataFrame(y_pred_proba, columns = ['healthy','scab','rust','frog_eye_leaf_spot','complex','powdery_mildew'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_proba","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_proba = y_pred_proba.tolist()\nindices =  []\nfor pred in y_pred_proba:\n    temp = []\n    for category in pred:\n        if category >= 0.25:\n            temp.append(pred.index(category))\n    if temp!=[]:\n        indices.append(temp)\n    else:\n        temp.append(np.argmax(pred))\n        indices.append(temp)\n    \nprint(indices)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels =  ['rust', \n        'complex', \n        'healthy', \n        'powdery_mildew', \n        'scab', \n        'frog_eye_leaf_spot']\ntestlabels = []\n\n\nfor image in indices:\n    temp = []\n    for i in image:\n        temp.append(str(labels[i]))\n    testlabels.append(' '.join(temp))\n\nprint(testlabels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.read_csv('../input/plant-pathology-2021-fgvc8/sample_submission.csv')\nsub['labels'] = testlabels\nsub.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}