{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\nimport os\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-10-25T16:45:52.66407Z","iopub.execute_input":"2021-10-25T16:45:52.66437Z","iopub.status.idle":"2021-10-25T16:45:52.688295Z","shell.execute_reply.started":"2021-10-25T16:45:52.664288Z","shell.execute_reply":"2021-10-25T16:45:52.687657Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip3 install --quiet albumentations pytorch-ignite","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:45:52.689748Z","iopub.execute_input":"2021-10-25T16:45:52.690424Z","iopub.status.idle":"2021-10-25T16:46:01.323816Z","shell.execute_reply.started":"2021-10-25T16:45:52.690389Z","shell.execute_reply":"2021-10-25T16:46:01.322978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nfrom tqdm import tqdm, trange\nimport torch\nfrom torch import nn\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import WeightedRandomSampler\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import train_test_split\nfrom ignite.metrics import Accuracy\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:46:01.326352Z","iopub.execute_input":"2021-10-25T16:46:01.326633Z","iopub.status.idle":"2021-10-25T16:46:05.196895Z","shell.execute_reply.started":"2021-10-25T16:46:01.326596Z","shell.execute_reply":"2021-10-25T16:46:05.196141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUM_CLASSES = 5\n\ndf = pd.read_csv(\"/kaggle/input/cassava-leaf-disease-classification/train.csv\")\ndf = list(df.itertuples(index=False, name=None))\ntrain_df, val_df = train_test_split(df, test_size=0.25, random_state=42)\n\ndef getClassDistribution(arr):\n    res = [0] * NUM_CLASSES\n    for fname, label in arr:\n        res[label] += 1\n    return res\n\nlabel_weights = []\ntrain_dist = getClassDistribution(train_df)\nfor fname, label in train_df:\n    label_weights.append(sum(train_dist) / train_dist[label])\n\nprint('Train class distribution', getClassDistribution(train_df))\nprint('Valid class distribution', getClassDistribution(val_df))","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:46:05.199561Z","iopub.execute_input":"2021-10-25T16:46:05.200104Z","iopub.status.idle":"2021-10-25T16:46:05.265344Z","shell.execute_reply.started":"2021-10-25T16:46:05.200065Z","shell.execute_reply":"2021-10-25T16:46:05.264625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CassavaLeafDataset(Dataset):\n    def __init__(\n        self, df, root_dir, transforms=None, output_label=True\n    ):\n        super().__init__()\n        self.df = df\n        self.length = len(df)\n        self.transforms = transforms\n        self.root_dir = root_dir\n        self.output_label = output_label\n    \n    def __len__(self):\n        return self.length\n    \n    def read_img(self, image_id):\n        path_img = os.path.join(self.root_dir, str(image_id))\n        img = cv2.imread(path_img)[:,:,::-1]\n        return img\n    \n    def __getitem__(self, index: int):\n        \n        # get labels\n        if self.output_label:\n            target = self.df[index][1]\n        \n        img  = self.read_img(self.df[index][0])\n        \n        if self.transforms:\n            img = self.transforms(image=img)['image']\n            \n        # do label smoothing\n        if self.output_label == True:\n            return img, target\n        else:\n            return img","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:46:05.26668Z","iopub.execute_input":"2021-10-25T16:46:05.266982Z","iopub.status.idle":"2021-10-25T16:46:05.278467Z","shell.execute_reply.started":"2021-10-25T16:46:05.266926Z","shell.execute_reply":"2021-10-25T16:46:05.277616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_SIZE = 224\n\ntrain_transform = A.Compose([\n    A.Resize(256, 256),\n    A.CenterCrop(IMG_SIZE, IMG_SIZE),\n#     A.RandomCrop(IMG_SIZE, IMG_SIZE),\n#     A.Transpose(p=0.5),\n#     A.HorizontalFlip(p=0.5),\n#     A.VerticalFlip(p=0.5),\n#     A.ShiftScaleRotate(p=0.5),\n#     A.HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2, p=0.5),\n#     A.RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], p=1.0),\n#     A.CoarseDropout(p=0.5),\n#     A.Cutout(p=0.5),\n    ToTensorV2(p=1.0),\n])\n\ntest_transform = A.Compose([\n    A.Resize(256, 256),\n    A.CenterCrop(IMG_SIZE, IMG_SIZE),\n#     A.Transpose(p=0.5),\n#     A.HorizontalFlip(p=0.5),\n#     A.VerticalFlip(p=0.5),\n#     A.HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2, p=0.5),\n#     A.RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], p=1.0),\n    ToTensorV2(p=1.0),\n])","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:46:05.279754Z","iopub.execute_input":"2021-10-25T16:46:05.280465Z","iopub.status.idle":"2021-10-25T16:46:05.291651Z","shell.execute_reply.started":"2021-10-25T16:46:05.280428Z","shell.execute_reply":"2021-10-25T16:46:05.290978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(device)\n\nEPOCHES = 20\nBATCH_SIZE = 64\nNUM_WORKERS = 2\nIMG_PATH = '/kaggle/input/cassava-leaf-disease-classification/train_images'\n\ntrain_dataset = CassavaLeafDataset(train_df, IMG_PATH, train_transform, output_label=True)\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS)\nval_dataset = CassavaLeafDataset(val_df, IMG_PATH, test_transform, output_label=True)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKERS)\n\nmodel = torch.hub.load('PingoLH/Pytorch-HarDNet', 'hardnet68', pretrained=True)\nmodel.base[16][3] = nn.Linear(in_features=1024, out_features=NUM_CLASSES, bias=True)\nmodel = model.to(device)\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9, nesterov=True, weight_decay=1e-4)\nscheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)\n\ndef train_one_epoch():\n    model.train()\n    losses = []\n    for imgs, labels in train_loader:\n        imgs, labels = imgs.to(device), labels.to(device)\n        outputs = model(imgs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        \n        losses.append(loss.item())\n    scheduler.step()\n    return sum(losses) / len(losses)\n\ndef evaluate():\n    model.eval()\n    with torch.no_grad():\n        metrics = Accuracy()\n        for imgs, labels in val_loader:\n            imgs, labels = imgs.to(device), labels.to(device)\n            outputs = model(imgs)\n            metrics.update((outputs, labels))\n        return metrics.compute()\n\nhistory = {'loss': [], 'acc': []}\ntbar = trange(EPOCHES)\nbest_acc = 0\nfor epoch in tbar:\n    loss = train_one_epoch()\n    acc = evaluate()\n    \n    if acc > best_acc:\n        best_acc = acc\n        torch.save(model, '/kaggle/working/model.pth')\n    \n    tbar.set_postfix({\n        'loss' : loss,\n        'acc' : acc\n    })\n    history['loss'].append(loss)\n    history['acc'].append(acc)","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:47:29.05931Z","iopub.execute_input":"2021-10-25T16:47:29.059765Z","iopub.status.idle":"2021-10-25T16:48:10.263631Z","shell.execute_reply.started":"2021-10-25T16:47:29.059729Z","shell.execute_reply":"2021-10-25T16:48:10.262536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in range(EPOCHES):\n    print('loss: {}, acc: {}'.format(history['loss'][i], history['acc'][i]))","metadata":{"execution":{"iopub.status.busy":"2021-10-25T16:46:20.629345Z","iopub.status.idle":"2021-10-25T16:46:20.63029Z","shell.execute_reply.started":"2021-10-25T16:46:20.630035Z","shell.execute_reply":"2021-10-25T16:46:20.630061Z"},"trusted":true},"execution_count":null,"outputs":[]}]}