{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Information about the notebook\n\nThis notebook is an example of PyTorch Inference for ongoing Cassava Leaf Disease Classification. \n\nFor the training of the model, I have forked this excellent [notebook](https://www.kaggle.com/sachinprabhu/pytorch-resnet50-snapmix-train-pipeline) with little tweak of label smoothing loss. **Resnet50 + SnapMix + Label Smoothing Loss** combinations are used for training of the models.\n\nLabel Smoothing Loss is implemented like this - [Source](https://medium.com/towards-artificial-intelligence/how-to-use-label-smoothing-for-regularization-aa349f7f1dbb)  \n\n\n    def linear_combination(x, y, epsilon): \n        return epsilon*x + (1-epsilon)*y\n\n    def reduce_loss(loss, reduction='mean'):\n        return loss.mean() if reduction=='mean' else loss.sum() if reduction=='sum' else loss\n\n\n    class LabelSmoothingCrossEntropy(nn.Module):\n        def __init__(self, epsilon:float=0.1, reduction='mean'):\n            super().__init__()\n            self.epsilon = epsilon\n            self.reduction = reduction\n    \n        def forward(self, preds, target):\n            n = preds.size()[-1]\n            log_preds = F.log_softmax(preds, dim=-1)\n            loss = reduce_loss(-log_preds.sum(dim=-1), self.reduction)\n            nll = F.nll_loss(log_preds, target, reduction=self.reduction)\n            return linear_combination(loss/n, nll, self.epsilon)\n"},{"metadata":{},"cell_type":"markdown","source":"# Import required libs"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"!pip install ../input/timmwhl/timm-0.3.3-py3-none-any.whl","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import random\nimport os\nimport sys\n\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torchvision\nimport timm\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, utils\nfrom tqdm import tqdm\nimport torch.nn.functional as F\n\nimport albumentations as A\nfrom albumentations import Compose\nfrom albumentations.pytorch import ToTensorV2\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Adding sys path for offline import"},{"metadata":{"trusted":true},"cell_type":"code","source":"sys.path.append('../input/pytorchimagemodelsmaster/pytorch-image-models-master')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Required Variables"},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH = '../input/cassava-leaf-disease-classification/'\nbs = 16\nsz = 448\nTIMM_MODEL = 'resnet50'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True\n\nSEED = 1234\nseed_everything(SEED)\n\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Cassava Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaDataset(Dataset):\n    \n    def __init__(self, dataframe, root_dir, transforms=None):\n        super().__init__()\n        self.dataframe = dataframe\n        self.root_dir = root_dir\n        self.transforms = transforms\n\n    def __len__(self):\n        return len(self.dataframe)\n    \n    def get_img_bgr_to_rgb(self, path):\n        im_bgr = cv2.imread(path)\n        im_rgb = im_bgr[:, :, ::-1]\n        return im_rgb\n\n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        img_name = os.path.join(self.root_dir,\n                                self.dataframe.iloc[idx, 0])\n        image = self.get_img_bgr_to_rgb(img_name)\n        if self.transforms:\n            image = self.transforms(image=image)['image']\n        csv_row = self.dataframe.iloc[idx, 1:]\n        sample = {\n            'image': image, \n            'label': csv_row.label,\n        }\n        return sample","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Transforms for test data using albumentations"},{"metadata":{"trusted":true},"cell_type":"code","source":"def test_transforms():\n    return Compose([\n            A.Resize(sz, sz),\n            A.Normalize(mean=[0.485, 0.456, 0.406], \n                        std=[0.229, 0.224, 0.225], \n                        max_pixel_value=255.0, p=1.0),\n            ToTensorV2(p=1.0),\n        ], p=1.)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaNet(nn.Module):\n    def __init__(self):\n        super().__init__()\n        backbone = timm.create_model(TIMM_MODEL, pretrained=False)\n        n_features = backbone.fc.in_features\n        self.backbone = nn.Sequential(*backbone.children())[:-2]\n        self.classifier = nn.Linear(n_features, 5)\n        self.pool = nn.AdaptiveAvgPool2d((1, 1))\n\n    def forward_features(self, x):\n        x = self.backbone(x)\n        return x\n\n    def forward(self, x):\n        feats = self.forward_features(x) #self.backbone(x)\n        x = self.pool(feats).view(x.size(0), -1) # avg pool and flattening\n        x = self.classifier(x) # Linear classifier\n        return x, feats","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = CassavaNet().to(device)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Inference"},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict(model, ckpts, dataloader):    \n    predict_list=[]\n    with torch.no_grad():\n            for _, data in enumerate(dataloader):\n                avg_preds = []\n                for ckpt in ckpts:\n                    model.load_state_dict(ckpt['state_dict'])\n                    model.eval()                    \n                    images, label = data.values()\n                    images =  images.to(device)\n                    outputs, _ = model(images)\n                    preds = F.softmax(outputs).to('cpu').numpy()\n                    avg_preds.append(preds)                \n                predict_list.append(np.mean(avg_preds, axis=0))            \n            predict_list = np.concatenate(predict_list)\n                \n    return predict_list.argmax(axis=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data Loading"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.read_csv('../input/cassava-leaf-disease-classification/sample_submission.csv')\n\ntest_dir = '../input/cassava-leaf-disease-classification/test_images/'\n\ntest_ds = CassavaDataset(dataframe=test_df,\n                         root_dir=test_dir,\n                         transforms=test_transforms())\n\ntest_dl = DataLoader(test_ds, batch_size=bs, \n                                      shuffle=False, num_workers=8, \n                                      pin_memory=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Loading"},{"metadata":{"trusted":true},"cell_type":"code","source":"ckpts=[]\ntrained_model_path = \"../input/cassavalblsmoothingresnet50\"\nfor path in os.listdir(trained_model_path):\n    ckpts.append(torch.load(os.path.join(trained_model_path, path)))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_predict_list=predict(model, ckpts, test_dl)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_predict_list","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission "},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df['label'] = test_predict_list\ntest_df[['image_id', 'label']].to_csv('submission.csv', index=False)\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### If you like the notebook, please upvote !!"}],"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":4,"nbformat_minor":4}