{"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":"markdown","source":"# Plant Pathology 2021: Inference of EfficientNet model","metadata":{}},{"cell_type":"markdown","source":"Here is an inference notebook based on [PyTorch EfficientNet](https://github.com/lukemelas/EfficientNet-PyTorch). The code for training models is [in this notebook](https://www.kaggle.com/vgarshin/plant-efficientnet-train-pytorch) or you may find code for local training [on GitHub](https://github.com/vgarshin/kaggle_plant).","metadata":{}},{"cell_type":"code","source":"%%time\n!pip install ../input/efficientnet-pytorch/EfficientNet-PyTorch-1.0 -f ./ --no-index","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport gc\nimport sys\nimport json\nimport time\nimport cv2\nimport pandas as pd\nimport numpy as np\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\nfrom torch.utils.data.sampler import SequentialSampler\nfrom efficientnet_pytorch import model as enet\n\nKAGGLE = True\nif not KAGGLE: os.environ['CUDA_VISIBLE_DEVICES'] = '0' \nelse: pass\nDEVICE = torch.device('cuda')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST = True\nVER = 'v0'\nif KAGGLE:\n    DATA_PATH = '../input/plant-pathology-2021-fgvc8'\n    MDLS_PATH = f'../input/plant-efficientnet-train-pytorch/models_{VER}'\nelse:\n    DATA_PATH = './data'\n    MDLS_PATH = f'./models_{VER}'\nTTAS = [0, 1, 2]\nFOLDS = [0]\nIMGS_PATH = f'{DATA_PATH}/test_images' if TEST else f'{DATA_PATH}/train_images'\n\nstart_time = time.time()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(f'{MDLS_PATH}/params.json') as file:\n    params = json.load(file)\nLABELS_ = params['labels_']\nLABELS = params['labels']\nWORKERS = 2 if KAGGLE else params['workers']\nprint('loaded params:', params)\n\nwith open(f'{MDLS_PATH}/ths.json') as file:\n    ths = json.load(file)\nprint('thresholds:', ths)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub = pd.DataFrame(os.listdir(IMGS_PATH)) if TEST else pd.DataFrame(os.listdir(IMGS_PATH)[:100])\ndf_sub.columns = ['image']\ndf_sub['labels'] = 'healthy'\ndisplay(df_sub.head())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def flip(img, axis=0):\n    if axis == 1:\n        return img[::-1, :, ]\n    elif axis == 2:\n        return img[:, ::-1, ]\n    elif axis == 3:\n        return img[::-1, ::-1, ]\n    else:\n        return img\n\nclass PlantDataset(data.Dataset):\n    \n    def __init__(self, df, size, labels, transform=None, tta=0):\n        self.df = df.reset_index(drop=True)\n        self.size = size\n        self.labels = labels\n        self.transform = transform\n        self.tta = tta\n    \n    def __len__(self):\n        return self.df.shape[0]\n    \n    def __getitem__(self, index):\n        row = self.df.iloc[index]\n        img_name = row.image\n        img_path = f'{IMGS_PATH}/{img_name}'\n        img = cv2.imread(img_path)\n        if not np.any(img):\n            print('no img file read:', img_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = cv2.resize(img, (self.size, self.size))\n        img = img.astype(np.float32) / 255\n        if self.transform is not None:\n            img = self.transform(image=img)['image']\n        if self.labels:\n            img = img.transpose(2, 0, 1)\n            label = np.zeros(len(self.labels)).astype(np.float32)\n            for lbl in row.labels.split():\n                label[self.labels[lbl]] = 1\n            return torch.tensor(img), torch.tensor(label)\n        else:\n            img = flip(img, axis=self.tta)\n            img = img.transpose(2, 0, 1)\n            return torch.tensor(img.copy())\n\nclass EffNet(nn.Module):\n    \n    def __init__(self, params, out_dim):\n        super(EffNet, self).__init__()\n        self.enet = enet.EfficientNet.from_name(params['backbone'])\n        nc = self.enet._fc.in_features\n        self.enet._fc = nn.Identity()\n        self.myfc = nn.Sequential(\n            nn.Dropout(params['dropout']),\n            nn.Linear(nc, int(nc / 4)),\n            nn.Dropout(params['dropout']),\n            nn.Linear(int(nc / 4), out_dim)\n        )\n        \n    def extract(self, x):\n        return self.enet(x)\n    \n    def forward(self, x):\n        x = self.extract(x)\n        x = self.myfc(x)\n        return x\n\nclass ResNext(nn.Module):\n    \n    def __init__(self, params, out_dim):\n        super(ResNext, self).__init__()\n        self.rsnxt = torchvision.models.resnext50_32x4d(pretrained=False)\n        nc = self.rsnxt.fc.in_features\n        self.rsnxt.fc = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(nc, int(nc / 4)),\n            nn.ReLU(),\n            nn.Dropout(params['dropout']),\n            nn.Linear(int(nc / 4), out_dim)\n        )\n        self.rsnxt = nn.DataParallel(self.rsnxt)\n        \n    def forward(self, x):\n        x = self.rsnxt(x)\n        return x","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nfor n_fold in FOLDS:\n    if params['backbone'] == 'resnext':\n        model = ResNext(params=params, out_dim=len(LABELS_)) \n    else:\n        model = EffNet(params=params, out_dim=len(LABELS_)) \n    path = '{}/model_best_{}.pth'.format(MDLS_PATH, n_fold)\n    state_dict = torch.load(path, map_location=torch.device('cpu'))\n    model.load_state_dict(state_dict)\n    model.float()\n    model.eval()\n    model.cuda()\n    models.append(model)\n    print('loaded:', path)\ndel state_dict, model\ngc.collect();","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datasets, loaders = [], []\nfor tta in TTAS:\n    dataset = PlantDataset(\n        df=df_sub,\n        size=params['img_size'],\n        labels=None,\n        transform=None,\n        tta=tta)\n    datasets.append(dataset)\n    loader = torch.utils.data.DataLoader(\n        dataset, \n        batch_size=params['batch_size'], \n        sampler=SequentialSampler(dataset), \n        num_workers=WORKERS)\n    loaders.append(loader)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_labels(row, labels, ths):\n    try:\n        row = [i for i, x in enumerate(row) if x > ths[str(i)]]\n        row = [labels[str(i)] for i in row]\n        row = 'healthy' if ('healthy' in row or len(row) == 0) else ' '.join(row)\n    except:\n        print(row)\n    return row\n\nlogits = []\nwith torch.no_grad():\n    for i, model in enumerate(models):\n        for j, loader in enumerate(loaders):\n            logits_tta = []\n            for img_data in loader:\n                img_data = img_data.to(DEVICE)\n                preds = np.squeeze(model(img_data).sigmoid().cpu().numpy())\n                logits_tta.append(preds)\n            print('model {} | loader {} -> done'.format(i, j))\n            logits.append(logits_tta)\nlogits = np.mean(logits, axis=0)\nlogits = np.squeeze(np.vstack(logits))\ndf_sub['labels'] = [get_labels(x, LABELS, ths) for x in list(logits)]\n\nelapsed_time = time.time() - start_time\nprint(f'time elapsed: {elapsed_time // 60:.0f} min {elapsed_time % 60:.0f} sec')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('value counts:')\nprint(df_sub.labels.value_counts())\ndf_sub.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}