{"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":"raw","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# 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\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\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"}},{"cell_type":"code","source":"# [1] - Import Modules\n\"\"\"import modules\"\"\"\n\nimport sys\nsys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nimport pandas as pd\n\nimport torch\nimport torch.nn as nn\nfrom torch.nn import functional as F\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\nfrom torch.autograd import Variable\nimport torch.optim as optim\nfrom torch.optim.lr_scheduler import ExponentialLR, CosineAnnealingWarmRestarts\n\nimport PIL\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport cv2\nimport itertools\n\nfrom torchvision.transforms import ToTensor\nimport torchvision.transforms as transforms\nimport torchvision.models as models\n\nfrom sklearn import metrics, model_selection, preprocessing\nfrom imblearn.over_sampling import SMOTE\n\nfrom tqdm.notebook import tqdm\nimport time\nimport datetime\nimport timm\n\n","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:04.255517Z","iopub.execute_input":"2021-06-18T13:58:04.255829Z","iopub.status.idle":"2021-06-18T13:58:08.241478Z","shell.execute_reply.started":"2021-06-18T13:58:04.255801Z","shell.execute_reply":"2021-06-18T13:58:08.240646Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Data","metadata":{}},{"cell_type":"code","source":"# [2] - Dataset Loader\n\"\"\"Dataset loader class\"\"\"\n\nclass CassavaDataset(Dataset):                    # Override torch.utils.data.Dataset\n  def __init__(self, data, targets, dataset, transform=None):\n    \"\"\"\n    Args:\n      csv_file    (string): path of csv file\n      dir         (string): path of images\n      transform  (callable, optional): Optional transform\n    \"\"\"\n    self.files = data\n    self.targets = targets\n    self.classes = list(set(targets))\n    self.transform = transform\n    self.dataset = dataset\n\n  def __len__(self):\n    return len(self.files)\n\n  def __getitem__(self, idx):\n    if torch.is_tensor(idx):\n      idx = idx.tolist()\n    name = self.files[idx]\n    img_name = os.path.join(name)\n    image = Image.open(img_name)\n    \"\"\"\n    ------------------------------------------------------------\"\"\"\n    input_size = 384\n    imagenet_stats = ([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n    \n    if self.dataset == 'train':\n        transform = transforms.Compose([transforms.RandomResizedCrop((input_size, input_size)),\n                                        transforms.RandomHorizontalFlip(p=0.5),\n                                        transforms.RandomVerticalFlip(p=0.5),\n                                        transforms.ToTensor(),\n                                        transforms.Normalize(*imagenet_stats)])\n        image = transform(image)\n    elif self.dataset == 'test':\n        transform = transforms.Compose([transforms.Resize((input_size, input_size)),\n                                        transforms.ToTensor(),\n                                        transforms.Normalize(*imagenet_stats)])   \n        image = transform(image)\n    \"\"\"---------------------------------------------------------\"\"\"\n\n    label = self.targets[idx]\n\n    if self.transform:                    ## IDK\n      sample = self.transform(sample)\n\n    return image, label","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:08.242888Z","iopub.execute_input":"2021-06-18T13:58:08.243199Z","iopub.status.idle":"2021-06-18T13:58:08.254779Z","shell.execute_reply.started":"2021-06-18T13:58:08.243164Z","shell.execute_reply":"2021-06-18T13:58:08.253701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [3] - load csv file\n\"\"\"load from csv\"\"\"\n\ndfx = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\n\ndf_train, df_valid = model_selection.train_test_split(dfx, test_size=0.1, random_state=42, stratify=dfx.label.values)\n\n_train = df_train.reset_index(drop=True)\ndf_valid = df_valid.reset_index(drop=True)\n\nimage_path = \"../input/cassava-leaf-disease-classification/train_images/\"\n\ntrain_image_paths = [os.path.join(image_path, x) for x in df_train.image_id.values]\nvalid_image_paths = [os.path.join(image_path, x) for x in df_valid.image_id.values]\n\ntrain_targets = df_train.label.values\nvalid_targets = df_valid.label.values","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:08.257164Z","iopub.execute_input":"2021-06-18T13:58:08.257841Z","iopub.status.idle":"2021-06-18T13:58:08.345055Z","shell.execute_reply.started":"2021-06-18T13:58:08.257807Z","shell.execute_reply":"2021-06-18T13:58:08.344223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"markdown","source":"Module to summarize loss and accuracy from (reference: https://github.com/rwightman/pytorch-image-models/blob/master/timm/utils/metrics.py )","metadata":{}},{"cell_type":"code","source":"# [4] - Module to print loss and accuracy\n\"\"\"load datasets\"\"\"\n\nclass AverageMeter:\n    \"\"\"Computes and stores the average and current value\"\"\"\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\n\ndef accuracy(output, target, topk=(1,)):\n    \"\"\"Computes the accuracy over the k top predictions for the specified values of k\"\"\"\n    maxk = max(topk)\n    batch_size = target.size(0)\n    _, pred = output.topk(maxk, 1, True, True)\n    pred = pred.t()\n    correct = pred.eq(target.reshape(1, -1).expand_as(pred))\n    return [correct[:k].reshape(-1).float().sum(0) * 100. / batch_size for k in topk]","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:08.346671Z","iopub.execute_input":"2021-06-18T13:58:08.347050Z","iopub.status.idle":"2021-06-18T13:58:08.355996Z","shell.execute_reply.started":"2021-06-18T13:58:08.347014Z","shell.execute_reply":"2021-06-18T13:58:08.354924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Models\n","metadata":{}},{"cell_type":"code","source":"# [5] - Train one epoch\n\"\"\"Function to train one epoch\"\"\"\n\ndef train_epoch(model, loader, device, loss_func, optimizer, scheduler):\n    model.train()\n    summary_loss = AverageMeter() # track running loss\n    summary_acc = AverageMeter() # track running accuracy\n    start = time.time() # track time\n   \n    n = len(loader)\n    \n    for batch in tqdm(loader):\n\n        images, labels = batch\n        images = images.to(device)\n        labels = labels.to(device)\n\n        out = model(images)                  # Generate predictions\n        loss = loss_func(out, labels)  # Calculate loss   \n\n\n\n        loss.backward()\n        optimizer.step()\n        optimizer.zero_grad()\n\n    \n        with torch.no_grad():\n            acc = accuracy(out, labels)[0]\n            \n        summary_loss.update(loss.detach().item(), batch_size)\n        summary_acc.update(acc.detach().item(), batch_size)\n        \n    train_time = str(datetime.timedelta(seconds=time.time() - start))\n    print('Train loss: {:.5f} - Train acc: {:.2f}% - time: {}'.format(summary_loss.avg, \n                                                                      summary_acc.avg,\n                                                                      train_time))\n    return summary_loss, summary_acc","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:08.357475Z","iopub.execute_input":"2021-06-18T13:58:08.357901Z","iopub.status.idle":"2021-06-18T13:58:08.368863Z","shell.execute_reply.started":"2021-06-18T13:58:08.357847Z","shell.execute_reply":"2021-06-18T13:58:08.367726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [6] - Validate one epoch\n\"\"\"Function to test one epoch\"\"\"\n\ndef validate_epoch(model, loader, device, loss_func):\n    model.eval()\n    summary_loss = AverageMeter() # track running loss\n    summary_acc = AverageMeter() # track running accuracy\n    start = time.time() # track time\n    \n    n = len(loader)\n    \n    for batch in tqdm(loader):\n        with torch.no_grad():\n            images, labels = batch\n            images = images.to(device)\n            labels = labels.to(device)\n\n            out = model(images)                  # Generate predictions\n            loss = loss_func(out, labels)  # Calculate loss   \n\n            acc = accuracy(out, labels)[0]\n            \n            summary_loss.update(loss.detach().item(), batch_size)\n            summary_acc.update(acc.detach().item(), batch_size)\n\n        \n    eval_time = str(datetime.timedelta(seconds=time.time() - start))\n    print('Val loss: {:.5f} - Val acc: {:.2f}% - time: {}'.format(summary_loss.avg,\n                                                                  summary_acc.avg,\n                                                                  eval_time))\n    return summary_loss, summary_acc","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:08.370446Z","iopub.execute_input":"2021-06-18T13:58:08.370833Z","iopub.status.idle":"2021-06-18T13:58:08.382768Z","shell.execute_reply.started":"2021-06-18T13:58:08.370795Z","shell.execute_reply":"2021-06-18T13:58:08.381804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"# [7] - Load the ResNext Model\n\"\"\"Load the ResNext model with the input path file\"\"\"\n\nPATH = '../input/timm-resnext/timm_resnext_epoch10_384.pth'\n\nresnet = timm.create_model('resnext50_32x4d', pretrained=False)\n\nnum_ftrs = resnet.fc.in_features\nresnet.fc = nn.Linear(num_ftrs, 5)\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nresnet.to(device)\n\nresnet.load_state_dict(torch.load(PATH))\nresnet.eval()","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:08.384141Z","iopub.execute_input":"2021-06-18T13:58:08.384502Z","iopub.status.idle":"2021-06-18T13:58:15.421673Z","shell.execute_reply.started":"2021-06-18T13:58:08.384467Z","shell.execute_reply":"2021-06-18T13:58:15.420911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [8] - Load the Xception Model\n\"\"\"Load the Xception model with the input path file\"\"\"\n\nPATH = '../input/timm-resnext/timm_xception_epoch10_384 (1).pth'\n\nxception = timm.create_model('xception', pretrained=False)\n\nnum_ftrs = resnet.fc.in_features\nxception.fc = nn.Linear(num_ftrs, 5)\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nxception.to(device)\n\nxception.load_state_dict(torch.load(PATH))\nxception.eval()","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:15.425948Z","iopub.execute_input":"2021-06-18T13:58:15.426190Z","iopub.status.idle":"2021-06-18T13:58:16.894985Z","shell.execute_reply.started":"2021-06-18T13:58:15.426166Z","shell.execute_reply":"2021-06-18T13:58:16.894152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [8] - For submission\n\"\"\"Create submission csv\"\"\"\n\nsubmission_df = pd.read_csv('../input/cassava-leaf-disease-classification/sample_submission.csv')\nsubmission_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:16.896544Z","iopub.execute_input":"2021-06-18T13:58:16.896911Z","iopub.status.idle":"2021-06-18T13:58:16.915380Z","shell.execute_reply.started":"2021-06-18T13:58:16.896853Z","shell.execute_reply":"2021-06-18T13:58:16.914659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [9] - TTA\n\"\"\"TTA\"\"\"\ninput_size = 384\nstats = ([0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261])\n\ntrans1 = transforms.Compose([transforms.Resize((input_size, input_size)),\n                             transforms.Pad(8, padding_mode='reflect'),\n                             transforms.ToTensor(),\n                             transforms.Normalize(*stats)])\n\ntrans2 = transforms.Compose([transforms.Resize((input_size, input_size)),\n                             transforms.RandomHorizontalFlip(p=0.3),\n                             transforms.RandomResizedCrop(input_size),\n                             transforms.ToTensor(),\n                             transforms.Normalize(*stats)])\n\ntrans3 = transforms.Compose([transforms.Resize((input_size, input_size)),\n                             transforms.RandomVerticalFlip(p=0.3),\n                             transforms.RandomResizedCrop(input_size),\n                             transforms.ToTensor(),\n                             transforms.Normalize(*stats)])\n\ntrans4 = transforms.Compose([transforms.Resize((input_size, input_size)),\n                             transforms.RandomHorizontalFlip(p=0.5),\n                             transforms.RandomVerticalFlip(p=0.5),\n                             transforms.RandomResizedCrop(input_size),\n                             transforms.ToTensor(),\n                             transforms.Normalize(*stats)])\ntranss = [trans1, trans2, trans3, trans4]","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:16.918428Z","iopub.execute_input":"2021-06-18T13:58:16.918667Z","iopub.status.idle":"2021-06-18T13:58:16.927217Z","shell.execute_reply.started":"2021-06-18T13:58:16.918643Z","shell.execute_reply":"2021-06-18T13:58:16.926277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [10]\n\"\"\"Inference\"\"\"\n\nfrom PIL import Image\n\ntest_path = '/kaggle/input/cassava-leaf-disease-classification/test_images/'\ntest_images = os.listdir(test_path)\ntrain_image_paths = [os.path.join(test_path, x) for x in test_images]\n\ny_preds = []\ny2_preds = []\n\n\np = 0\nfor i in test_images:\n    res = []\n    image = Image.open(f'/kaggle/input/cassava-leaf-disease-classification/test_images/{i}')\n    input_size = 384\n    \n    outs = torch.Tensor(np.zeros((len(transs), 5)))\n    outs2 = torch.Tensor(np.zeros((len(transs), 5)))\n    k = 0\n    for trans in transs:\n        img = trans(image)\n        img = img.reshape(1, img.shape[0], img.shape[1], img.shape[2])\n        img = Variable(img.to(device))\n        out = resnet(img)\n        out2= xception(img)\n        outs[k,:] = 4*out\n        outs2[k,:] = 5*out2\n        k += 1\n\n    out = outs.mean(axis=0)\n    out2 = outs2.mean(axis=0)\n    res.append(out2)\n\n    mean = torch.mean(torch.stack(res), dim = 0)\n\n    _, predicted = torch.max(out2.data, 0)\n    y_preds.append(predicted.item())","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:16.928702Z","iopub.execute_input":"2021-06-18T13:58:16.929498Z","iopub.status.idle":"2021-06-18T13:58:18.074323Z","shell.execute_reply.started":"2021-06-18T13:58:16.929456Z","shell.execute_reply":"2021-06-18T13:58:18.073442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [11]\n\"\"\"Testing dataframe\"\"\"\n\ndf_sub = pd.DataFrame({'image_id': test_images, 'label': y_preds})\ndisplay(df_sub)","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:18.075666Z","iopub.execute_input":"2021-06-18T13:58:18.076029Z","iopub.status.idle":"2021-06-18T13:58:18.085858Z","shell.execute_reply.started":"2021-06-18T13:58:18.075993Z","shell.execute_reply":"2021-06-18T13:58:18.084948Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# [10]\n\"\"\"Create CSV\"\"\"\n\ndf_sub.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2021-06-18T13:58:18.087282Z","iopub.execute_input":"2021-06-18T13:58:18.087781Z","iopub.status.idle":"2021-06-18T13:58:18.320672Z","shell.execute_reply.started":"2021-06-18T13:58:18.087744Z","shell.execute_reply":"2021-06-18T13:58:18.319885Z"},"trusted":true},"execution_count":null,"outputs":[]}]}