{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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# 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","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os.path as osp\n\n# computation\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\n\n# data pipeline\nimport imageio\nfrom PIL import Image\nfrom imgaug import augmenters as iaa\nfrom torch.utils.data import Dataset, DataLoader\n\nfrom torchvision import transforms, models\nfrom torch.optim import lr_scheduler\nfrom torch.optim.lr_scheduler import StepLR\nfrom torchvision import datasets\n\n# utils\nfrom tqdm.notebook import tqdm\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport time\nimport os\nimport copy\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# dir(transforms)\ndir(lr_scheduler)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Some paths\nROOT = '/kaggle/input/cassava-leaf-disease-classification'\nTRAIN_DIR = f'{ROOT}/train_images/'\nTRAIN_CSV = f'{ROOT}/train.csv'\nTEST_DIR = f'{ROOT}/test_images/'\nTEST_CSV = f'{ROOT}/sample_submission.csv'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pip install torch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # pip install --upgrade pip\n# train = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\n# train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaDataset(Dataset):\n    def __init__(self, split, transform=None):\n        assert split in ('train', 'val', 'test')\n        self.split = split\n        self.transform = transform\n        if split in ('train', 'val'):\n            csv = pd.read_csv(TRAIN_CSV)\n            # TODO: \n            #    Tear off a small portion of the given training data as a validation set. \n            #    Make sure that the training and validation sets are mutually exclusive.\n#             self.df = train_test_split(csv, test_size=0.1,random_state=42)[0 if split =='train' else 1].reset_index()\n            csv_tr, csv_te = train_test_split(csv, test_size=0.1, random_state=42)\n            if split =='train':\n                self.df = csv_tr\n            else:\n                self.df = csv_te\n        else:\n            self.df = pd.read_csv(TEST_CSV)\n        \n    def __len__(self):\n        return self.df.shape[0]\n    \n    def __getitem__(self, i: int):\n        # TODO: \n        #\n        #     1. Return a (image, label) tuple for the train/val splits.\n        #     2. Return a (image, -1) tuple for the test split.\n        #\n        # NOTE: \n        #    \n        #    - image should be a tensor of shape (3, 600, 800).\n        #    - label should be a tensor of integer/long type.\n        #    - CSV files contain two columns, 'image_id' and 'label':\n        #       - 'image_id': Filename of the image in the directory.\n        \n        #       - 'label': Integer that represents the class of the image.\n#         base_dir = TRAIN_DIR if self.split in('train','val') else TEST_DIR\n#         x = imageio.imread(osp.join(base_dir, self.df['image_id'][i]))\n#         y = self.df['label'][i] if self.split in ('train','val') else -1\n#         if self.transform:\n#             x = self.transform(x)\n#         return(x,y)\n        if self.split in ('train', 'val'):\n            img = Image.open(osp.join(TRAIN_DIR, self.df.iloc[i]['image_id']))\n            label = self.df.iloc[i]['label']\n            #img = imageio.imread(osp.join(TRAIN_DIR, self.df.iloc[i]['image_id']))\n        else:\n            img = Image.open(osp.join(TEST_DIR, self.df.iloc[i]['image_id']))\n            label = -1\n            \n        #img = np.asarray(img)  # imageaug, transforms.\n        img = self.transform(img)\n        \n        return (img, torch.Tensor(label))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"a = CassavaDataset('train', TRANSFORMS['train'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# TODO: You'll need some heavy augmentations to get a high score. \n#\n# See \n#     https://github.com/aleju/imgaug \n#     https://imageio.readthedocs.io/en/stable/\n#\n# for detailed `imgaug` references.\n#\n# NOTE: If you choose to normalize the training images, you should normalize the test images as well.\n#\nTRANSFORMS = {\n    'train': transforms.Compose([\n             transforms.RandomHorizontalFlip(p=0.3),\n             transforms.RandomVerticalFlip(p=0.3),\n             transforms.RandomResizedCrop(224),\n            transforms.ToTensor(),\n             transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),\n        ]),\n    'val': transforms.Compose([\n            transforms.RandomHorizontalFlip(p=0.3),\n             transforms.RandomVerticalFlip(p=0.3),\n             transforms.RandomResizedCrop(224),\n        transforms.ToTensor(),\n             transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),\n    ]),\n#     'test': transforms.Compose([CenterCrop(100),\n#             Transpose(p=0.5),\n#             HorizontalFlip(p=0.5),\n#             VerticalFlip(p=0.5),\n#             ShiftScaleRotate(p=0.5),\n#             HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2, p=0.5),\n#             RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n#             CoarseDropout(p=0.5),\n#             Cutout(p=0.5),\n#             transforms.ToTensor(),\n       \n#     ]),\n}\n\n# base_dir = TRAIN_DIR\n# image_datasets = {x: datasets.ImageFolder(os.path.join(base_dir, x),\n#                                           TRANSFORMS[x])\n#                   for x in ['train', 'val']}\n# dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,\n#                                              shuffle=True, num_workers=4)\n#               for x in ['train', 'val']}\n# dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}\n# # class_names = image_datasets['train'].classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaClassifier(nn.Module):\n    \n    def __init__(self, num_classes=5):\n        # TODO: Design your own architecture for classifying Cassava leaf diseases\n        #\n        # Some points to consider:\n        #\n        # - The size of the image is (3, 600, 800) and there are 5 classes in total.\n        # - One of the 5 classes, CMD (class index 3), occupies half of the dataset.\n        super().__init__()\n        self.backbone = torchvision.models.resnet18(pretrained=False)\n        \n        in_features = self.backbone.fc.in_features\n\n        self.logit = nn.Linear(in_features, num_classes)\n        \n    def forward(self, x):\n        batch_size, C, H, W = x.shape\n        \n        x = self.backbone.conv1(x)\n        x = self.backbone.bn1(x)\n        x = self.backbone.relu(x)\n        x = self.backbone.maxpool(x)\n\n        x = self.backbone.layer1(x)\n        x = self.backbone.layer2(x)\n        x = self.backbone.layer3(x)\n        x = self.backbone.layer4(x)\n        \n        x = F.adaptive_avg_pool2d(x,1).reshape(batch_size,-1)\n        x = F.dropout(x, 0.25, self.training)\n\n        x = self.logit(x)\n\n        return x\n        \n#     def forward(self, x):\n        # TODO: implement your forward-pass logic here.\n#         return torch.randn(x.size(0), 5).cuda()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# TODO: Define some hyperparameters here.\nEPOCHS = 10\nbatch_size = 64","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pip install torchvision","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torchvision # TODO: Prepare some components for training your network.\n#\n# See\n#\n#     Optimizer:    https://pytorch.org/docs/stable/optim.html#how-to-use-an-optimizer\n#     LR Scheduler: https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate\n#     DataLoader:   https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader\n#\n# for their actual APIs and detailed usages.\nmodel = CassavaClassifier()\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n\n# lr_scheduler = NotImplemented\n# train_dataset = NotImplemented\n# val_dataset = NotImplemented","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataloaders = {\n    'train': CassavaDataset('train', transform=TRANSFORMS['train']),\n    'val': CassavaDataset('val', transform=TRANSFORMS['val']),\n}\n\ndef train_model(model, criterion, optimizer, scheduler, num_epochs=EPOCHS):\n    since = time.time()\n\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n\n        # Each epoch has a training and validation phase\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Set model to training mode\n            else:\n                model.eval()   # Set model to evaluate mode\n\n            running_loss = 0.0\n            running_corrects = 0\n\n            # Iterate over data.\n            for inputs, labels in dataloaders[phase]:\n                # TODO 1: Move the data samples to GPU\n                inputs = inputs.cuda()\n                labels = labels.cuda()\n\n                with torch.set_grad_enabled(phase == 'train'):\n                    # TODO 2: Compute `preds` tensor of shape (B,) that represents class predictions of the network, and a scalar `loss` tensor \n                    outputs = model(inputs)\n                    _, preds = torch.max(outputs, 1)\n                    loss = criterion(outputs, labels)\n                    \n                    # TODO 3: With the computed `loss` tensor, implement the main training logic. Make sure you only train your network when you are in the 'train' phase.\n                    if phase == 'train':\n                        optimizer.zero_grad()\n                        loss.backward()\n                        optimizer.step()\n\n                # statistics\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n            if phase == 'train':\n                scheduler.step()\n\n            epoch_loss = running_loss / dataset_sizes[phase]\n            epoch_acc = running_corrects.double() / dataset_sizes[phase]\n\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n                phase, epoch_loss, epoch_acc))\n\n            # deep copy the model\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n\n        print()\n\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(\n        time_elapsed // 60, time_elapsed % 60))\n    print('Best val Acc: {:4f}'.format(best_acc))\n\n    # load best model weights\n    model.load_state_dict(best_model_wts)\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\nmodel_ft = models.resnet18(pretrained=True)\nnum_features = model_ft.fc.in_features\n\n# Here the size of each output sample is set to 2.\n# Alternatively, it can be generalized to nn.Linear(num_ftrs, len(class_names)).\nmodel_ft.fc = nn.Linear(num_features, 2)\n\nmodel_ft = model_ft.cuda()\ncriterion = nn.CrossEntropyLoss()\n\n# Observe that all parameters are being optimized!\noptimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)\n\n# Decay LR by a factor of 0.1 every 7 epochs\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# TODO: Implement your validation logic here.\nmodel_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_dataset = CassavaDataset('test', transform=TRANSFORMS['test'])\ntest_loader = DataLoader(test_dataset, batch_size=32)\ntest_csv = pd.read_csv(TEST_CSV)\n\npredictions_on_test_set = []\nfor x, _ in test_loader:\n    y_hat = model(x.cuda())\n    y_hat = torch.argmax(y_hat,dim=1)\n    predictions_on_test_set.extend(y_hat.cpu().detach().numpy().tolist())\n    \n\ntest_csv['label'] = predictions_on_test_set\ntest_csv[['image_id','label']].to_csv(\"submission.csv\", index=False)\ntest_csv.head()","execution_count":null,"outputs":[]}],"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}