{"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 glob\nimport os.path as osp\n\nimport pandas as pdN\nimport numpy as np\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelEncoder\n\nfrom tqdm.notebook import tqdm\nfrom PIL import Image\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.utils.data as data\nimport torchvision\nfrom torchvision import models, transforms\nimport cv2\nimport albumentations as A","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Import Data","metadata":{}},{"cell_type":"code","source":"import pandas as pd\ndf_train = pd.read_csv(\"/kaggle/input/plant-pathology-2021-fgvc8/train.csv\")\ndf_sub = pd.read_csv(\"/kaggle/input/plant-pathology-2021-fgvc8/sample_submission.csv\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"d_set = set()\nfor k in df_train.labels.unique():\n    d_set = d_set | set(k.split(\" \"))\nprint(f\"num of labels: {len(d_set)}  {d_set}\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def to_label(df):\n    \"\"\"\n    Function for Label encoding.\n    \"\"\"\n    le = LabelEncoder()\n    df[\"labels_n\"] = le.fit_transform(df.labels.values)\n    return df\n\ndf_train = to_label(df_train)\ndf_labels_idx = df_train.loc[df_train.duplicated([\"labels\", \"labels_n\"])==False]\\\n                [[\"labels_n\", \"labels\"]].set_index(\"labels_n\").sort_index()\ndisplay(df_labels_idx)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"! ls /kaggle/input/finetuningmodelzoo","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_IMAGE_PATH = '../input/plant-pathology-2021-fgvc8/test_images'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def make_datapath_list(phase=\"train\", val_size=0.25):\n    \"\"\"\n    Function to create a PATH to the data.\n    \n    Parameters\n    ----------\n    phase : 'train' or 'val' or 'test'\n        Specify whether to use Train data or test data.\n    val_size : float\n        Ratio of validation data to train data\n        \n    Returns\n    -------\n    path_lsit : list\n        A list containing the PATH to the data.\n    \"\"\"\n    \n    if phase in [\"train\", \"val\"]:\n        phase_path = \"train_images\"\n    elif phase in [\"test\"]:\n        phase_path = \"test_images\"\n    else:\n        print(f\"{phase} not in path\")\n    rootpath = \"/kaggle/input/plant-pathology-2021-fgvc8/\"\n#     rootpath = \"/kaggle/input/resized-plant2021/img_sz_256/\"\n    target_path = osp.join(TRAIN_IMAGE_PATH , '*.jpg') if  phase in ['train', 'val'] else osp.join(TEST_IMAGE_PATH, \"*.jpg\")\n\n    path_list = []\n    \n    for path in glob.glob(target_path):\n        path_list.append(path)\n        \n    if phase in [\"train\", \"val\"]:\n        train, val = train_test_split(path_list, test_size=val_size, random_state=0, shuffle=True)\n        if phase == \"train\":\n            path_list = train\n        else:\n            path_list = val\n    \n    return path_list","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ImageTransform():\n    \"\"\"\n    Class for image preprocessing.\n    \n    Attributes\n    ----------\n    resize : int\n        224\n    mean : (R, G, B)\n        Average value for each color channel\n    std : (R, G, B)\n        Standard deviation for each color channel\n    \"\"\"\n    \n    def __init__(self, resize, mean, std):\n        self.data_transform = {\n#             'train': A.Compose(albumentation_list),\n            'train': transforms.Compose([\n                transforms.Resize(resize),\n                transforms.RandomResizedCrop(resize, scale=(0.5, 1.0)),\n                transforms.RandomHorizontalFlip(),\n                transforms.RandomPerspective(),\n                transforms.ToTensor(),\n#                 transforms.RandomRotation(),\n                transforms.Normalize(mean, std)\n            ]),\n            'val': transforms.Compose([\n                transforms.Resize(resize),\n                transforms.CenterCrop(resize),\n                transforms.ToTensor(),\n                transforms.Normalize(mean, std)\n            ]),\n            'test': transforms.Compose([\n                transforms.Resize(resize),\n                transforms.CenterCrop(resize),\n                transforms.ToTensor(),\n                transforms.Normalize(mean, std)\n            ])\n        }\n    \n    def __call__(self, img, phase=\"train\"):\n        \"\"\"\n        Parameters\n        ----------\n        phase: 'train' or 'val' or 'test'\n            Specify the mode of preprocessing\n        \"\"\"\n        \n        return self.data_transform[phase](img)\n#         return self.data_transform[phase](image=img).get('image')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class PlantDataset(data.Dataset):\n    \"\"\"\n    Class to create a Dataset\n    \n    Attributes\n    ----------\n    df_train : DataFrame\n        DataFrame containing the image labels.\n    file_list : list\n        A list containing the paths to the images\n    transform : object\n        Instance of the preprocessing class (ImageTransform)\n    phase : 'train' or 'val' or 'test'\n        Specify whether to use train, validation, or test\n    \"\"\"\n    def __init__(self, df_train, file_list, transform=None, phase='train'):\n        self.df_train = df_train\n        self.df_labels_idx = df_labels_idx\n        self.file_list = file_list\n        self.transform = transform\n        self.phase = phase\n   \n    def __len__(self):\n        \"\"\"\n        Returns the number of images.\n        \"\"\"\n        return len(self.file_list)\n    \n    def __getitem__(self, index):\n        \"\"\"\n        Get data in Tensor format and labels of preprocessed images.\n        \"\"\"\n        #print(index)\n        \n        # Load the index number image.\n        img_path = self.file_list[index]\n        img = Image.open(img_path)\n#         img = cv2.imread(img_path)\n#         img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        \n        # Preprocessing images\n        img_transformed = self.transform(img, self.phase)\n        \n        # image name\n        image_name = img_path[-20:]\n        \n        # Extract the labels\n        if self.phase in [\"train\", \"val\"]:\n            label = df_train.loc[df_train[\"image\"]==image_name][\"labels_n\"].values[0]\n        elif self.phase in [\"test\"]:\n            label = -1\n        \n        return img_transformed, label, image_name","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"size=224\nmean = (0.485, 0.456, 0.406)\nstd = (0.229, 0.224, 0.225)\ntest_list = make_datapath_list(phase=\"test\")\ntest_dataset = PlantDataset(df_train, test_list, transform=ImageTransform(size, mean, std), phase='test')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 128\n\n# Create DataLoader\ntest_dataloader = data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n\n# to Dictionary\ndataloaders_dict = {\"test\": test_dataloader}\n\n# Operation check\n#batch_iterator = iter(dataloaders_dict[\"train\"])\n#inputs, labels = next(batch_iterator)\n#print(inputs.size())  # torch.Size([3, 3, 224, 224]) : [batch_size, Channel, H, W]\n#print(labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Model","metadata":{}},{"cell_type":"code","source":"SELECTION_MODEL = 'VGG16' # AlexNet, VGG16, DenseNet","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if SELECTION_MODEL == 'AlexNet':\n    net = models.alexnet(pretrained=False)\n    net.classifier[6] = nn.Linear(in_features=4096, out_features=12)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if SELECTION_MODEL == 'VGG16':\n    net = models.vgg16(pretrained=False)\n    net.classifier[6] = nn.Linear(in_features=4096, out_features=12)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if SELECTION_MODEL == 'DenseNet':\n    net = models.densenet161(pretrained=False)\n    prev_out_feature = net.classifier.in_features\n    \n    new_last_layer = [\n        nn.Linear(prev_out_feature, 2208),\n        nn.ReLU(inplace = True),\n        nn.Dropout(p=0.5, inplace=False),\n        \n        nn.Linear(2208, 1104),\n        nn.ReLU(inplace = True),\n        nn.Dropout(p=0.5, inplace=False),\n        \n        nn.Linear(1104, 552),\n        nn.ReLU(inplace = True),\n        nn.Dropout(p=0.2, inplace=False),\n        \n        nn.Linear(552, 138),\n        nn.ReLU(inplace = True),\n        nn.Dropout(p=0.2, inplace=False),\n        \n        nn.Linear(138, 12),\n    ]\n    \n    net.classifier = nn.Sequential(*new_last_layer)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"load_path = ''\nif SELECTION_MODEL == 'DenseNet':\n    load_path = \"../input/finetuningmodelzoo/densenet_second10epoch_fine_tuning_v1.h\"\nelif SELECTION_MODEL == 'AlexNet':\n    load_path = '/kaggle/input/finetuningmodelzoo/alexnet_final200epoch_fine_tuning_v1.h'\nelif SELECTION_MODEL == 'VGG16':\n    load_path = '../input/finetuningmodelzoo/vgg16_final-50epoch_fine_tuning_v1.h'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if torch.cuda.is_available():\n    load_weights = torch.load(load_path)\n    net.load_state_dict(load_weights)\nelse:\n    load_weights = torch.load(load_path, map_location={\"cuda:0\": \"cpu\"})\n    net.load_state_dict(load_weights)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class PlantPredictor():\n    \"\"\"\n    Class for predicting labels from output results\n    \n    Attributes\n    ----------\n    df_labels_idx: DataFrame\n        DataFrame that associates INDEX with a label name\n    \"\"\"\n    \n    def __init__(self, net, df_labels_idx, dataloaders_dict):\n        self.net = net\n        self.df_labels_idx = df_labels_idx\n        self.dataloaders_dict = dataloaders_dict\n        self.df_submit = pd.DataFrame()\n        \n    \n    def __predict_max(self, out):\n        \"\"\"\n        Get the label name with the highest probability.\n        \n        Parameters\n        ----------\n        predicted_label_name: str\n            Name of the label with the highest prediction probability\n        \"\"\"\n        maxid = np.argmax(out.detach().numpy(), axis=1)\n        df_predicted_label_name = self.df_labels_idx.iloc[maxid]\n        \n        return df_predicted_label_name\n    \n    def inference(self):\n        device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n        print(f\"Devices to be used : {device}\")\n        df_pred_list = []\n        for inputs, _, image_name in tqdm(self.dataloaders_dict['test']):\n            device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n            self.net.to(device)\n            inputs = inputs.to(device)\n            out = self.net(inputs)\n            device = torch.device(\"cpu\")\n            out = out.to(device)\n            df_pred = self.__predict_max(out).reset_index(drop=True)\n            df_pred[\"image\"] = image_name\n            df_pred_list.append(df_pred)\n            \n        self.df_submit = pd.concat(df_pred_list, axis=0)\n        self.df_submit = self.df_submit[[\"image\", \"labels\"]].reset_index(drop=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictor = PlantPredictor(net, df_labels_idx, dataloaders_dict)\npredictor.inference()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submit = predictor.df_submit.copy()\ndf_submit.to_csv(\"/kaggle/working/submission.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}