{"cells":[{"metadata":{},"cell_type":"markdown","source":"1. Overview\n2. EDA\n3. Model Details\n4. Inference\n\n"},{"metadata":{},"cell_type":"markdown","source":"### Overview\n\nIn this competition, we introduce a dataset of 21,367 labeled images collected during a regular survey in Uganda. Most images were crowdsourced from farmers taking photos of their gardens, and annotated by experts at the National Crops Resources Research Institute (NaCRRI) in collaboration with the AI lab at Makerere University, Kampala. This is in a format that most realistically represents what farmers would need to diagnose in real life."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport os\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torchvision\nfrom PIL import Image\nimport albumentations\nimport json\nfrom tqdm import tqdm\n# import cv2\nfrom sklearn import metrics , model_selection, preprocessing\n\n%matplotlib inline \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BASE_DIR = '../input/cassava-leaf-disease-classification'\ndf = pd.read_csv(os.path.join(BASE_DIR,'train.csv'))\n# df = df[:100] \ndf['path'] = df['image_id'].map(lambda x: os.path.join(BASE_DIR,'train_images',x))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.drop(columns=['image_id'],inplace=True)\ndf = df.reset_index(drop=True)\ndf.head(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### EDA\nWe have the five categories to predict and number of records are highly biased  "},{"metadata":{"trusted":true},"cell_type":"code","source":"df.label.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.plot.hist(df.label,figsize=(10,5))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have 5 different types of category \n* Cassava Bacterial Blight (CBB)\n* Cassava Brown Streak Disease (CBSD)\n* Cassava Green Mottle (CGM)\n* Cassava Mosaic Disease (CMD)\n* Healthy\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"with open('../input/cassava-leaf-disease-classification/label_num_to_disease_map.json') as fn:\n    print(json.loads(fn.read()))\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(df))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = Image.open(df['path'][1])\nw,b = img.size\nprint(w,b)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head()\ndf_train, df_valid = model_selection.train_test_split( df, test_size =0.15, random_state = 42, stratify=df.label.values)\ndf_train = df_train.reset_index(drop=True)\ndf_valid = df_valid.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_valid.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE=64\nEPOCHS=10\nVALID_BATCH_SIZE=128\nMODEL_PATH = '/kaggle/working'\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Show sample images"},{"metadata":{"trusted":true},"cell_type":"code","source":"import random \ndef show_image_using_path(image,label):\n    img =Image.open(image)\n#     plt.figure(figsize=(10,10))\n    plt.imshow(img)\n    lbl =label \n    plt.title(f'Class: {lbl}')\n    plt.axis('off')\n\nplt.figure(figsize=(16, 12))\nfor i in range(5):\n    df_temp = df_train[df_train[\"label\"] == i]\n    plt.subplot(3,3,i+1)\n    ranom_number = random.randint(0,100)\n    show_image_using_path(list(df_temp['path'])[ranom_number], list(df_temp['label'])[ranom_number] )\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Create the dataset for images"},{"metadata":{"trusted":true},"cell_type":"code","source":"class LeafDataset:\n    def __init__(self, img_path, labels, resize, albumentations=None):\n        self.img_path = img_path\n        self.labels = labels\n        self.resize = resize\n        self.albumentations =albumentations\n    \n    def __len__(self):\n        return len(self.img_path)\n    \n    def __getitem__(self, item):\n        labels = self.labels[item]\n        img = Image.open(self.img_path[item])\n        img = img.resize((self.resize[0],self.resize[1]),resample=Image.BILINEAR)\n        img = np.array(img)\n        if self.albumentations is not None:\n            augmented_imgs = self.albumentations(image=img)\n            img = augmented_imgs[\"image\"]\n\n            img= np.transpose(img, (2,0,1)).astype(np.float32)\n        return {\n            'image': torch.tensor(img, dtype=torch.float),\n            'label' : torch.tensor(labels,dtype=torch.long)\n        }","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Test dataset "},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_image_tensor(image_tensor,label):\n    print(image_tensor.shape)\n    plt.figure(figsize=(10,10))\n    plt.title(f'Class: {label}')\n    plt.imshow(img)\n    plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Augmnet images with albumentation library"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_albumentations = albumentations.Compose([\n            albumentations.RandomResizedCrop(400,300),\n#             albumentations.Transpose(p=0.5),\n            albumentations.HorizontalFlip(p=0.5),\n            albumentations.VerticalFlip(p=0.5),\n            albumentations.ShiftScaleRotate(p=0.5),\n            albumentations.Normalize(\n                mean=[0.485, 0.456, 0.406], \n                std=[0.229, 0.224, 0.225], \n                max_pixel_value=255.0, \n                p=1.0\n            )], p=1.)\n\nvalid_albumentations = albumentations.Compose([\n             albumentations.RandomResizedCrop(400,300),\n            albumentations.Resize(400,300),\n            albumentations.Normalize(\n                mean=[0.485, 0.456, 0.406], \n                std=[0.229, 0.224, 0.225], \n                max_pixel_value=255.0, \n                p=1.0\n            )], p=1.)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset= LeafDataset(df_train.path.values,df_train.label.values,(400,300),train_albumentations)\ntemp_dataset= train_dataset[0] \nshow_image_tensor(temp_dataset['image'], temp_dataset['label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nvalid_dataset= LeafDataset(df_valid.path.values,df_valid.label.values,(400,300),valid_albumentations)\ntemp_dataset= valid_dataset[0] \nshow_image_tensor(temp_dataset['image'], temp_dataset['label'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Create dataloader"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=BATCH_SIZE,num_workers=2)\nvalid_data_loader = torch.utils.data.DataLoader(valid_dataset,batch_size=VALID_BATCH_SIZE,num_workers=2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Create model : We used resnet 18"},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaModel(nn.Module):\n    def __init__(self, num_classes):\n        super().__init__()\n        self.resnet= torchvision.models.resnet18(pretrained=True)\n        self.resnet.fc = nn.Linear(512,num_classes)\n        self.step_scheduler_after = 'epoch'\n#         print(self.resnet)\n    \n    \n    def forward(self,image,labels=None):\n        batch_size , _, _,_ = image.shape\n        outputs = self.resnet(image)        \n        return outputs\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Test the model "},{"metadata":{"trusted":true},"cell_type":"code","source":"cm = CassavaModel(5)\nprint(cm.resnet)\nimg = torch.rand((1, 3, 50, 200))\nx = cm(img, torch.rand((1, 5)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"define utilities function"},{"metadata":{"trusted":true},"cell_type":"code","source":"def loss_fn(outputs,labels):\n    return  nn.CrossEntropyLoss()(outputs,labels)\n\ndef train_fn(data_loader, model, optimizer, device, scheduler):\n    model.train()\n    \n    for bi , data in tqdm(enumerate(data_loader),total=len(data_loader)):\n        labels = data['label']\n        images = data['image']\n        \n        labels = labels.to(device,dtype=torch.long)\n        images = images.to(device,dtype=torch.float)\n        \n        optimizer.zero_grad()\n        outputs = model(images,labels)\n        loss = loss_fn(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        scheduler.step()\n        \ndef eval_fn(data_loader, model, device):\n    model.eval()\n    final_targets = []\n    final_outputs = []\n    \n    with torch.no_grad():\n        for bi,data in tqdm(enumerate(data_loader),total=len(data_loader)):\n            labels = data['label']\n            images = data['image']\n            \n            labels= labels.to(device, dtype=torch.long)\n            images = images.to(device,dtype=torch.float)\n            \n            outputs = model(images,labels)\n            final_targets.extend(labels.tolist())\n            outputs = torch.argmax(outputs, dim=1)\n#             print(outputs)\n            final_outputs.extend(outputs.cpu())\n            accuracy = metrics.accuracy_score(labels.cpu(), outputs.cpu())\n    return accuracy,final_outputs\n\n     \ndef pred_fn(data_loader, model, device):\n    model.eval()\n    final_targets = []\n    final_outputs = []\n    \n    with torch.no_grad():\n        for bi,data in tqdm(enumerate(data_loader),total=len(data_loader)):\n            labels = data['label']\n            images = data['image']\n            \n            labels= labels.to(device, dtype=torch.long)\n            images = images.to(device,dtype=torch.float)\n            \n            outputs = model(images,labels)\n            final_targets.extend(labels.tolist())\n            outputs = torch.argmax(outputs, dim=1)\n            final_outputs.extend(outputs.cpu())\n           \n    return final_outputs\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"See the model structure"},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cuda')\nmodel = CassavaModel(num_classes=5)\nmodel.to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# image =train_dataset[0]['image'].unsqueeze(0)\n# label =train_dataset[0]['label'].unsqueeze(0)\n# model(image,label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nnum_train_steps = int(len(train_dataset)/BATCH_SIZE *EPOCHS)\noptimizer = torch.optim.Adam(model.parameters(),lr=3e-4)\n# scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=0, num_training_steps=num_train_steps)\n# scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=0.8, patience=5, verbose=True)\nscheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=0.7)\n\nbest_accuracy =0 \nfor epoch in range(EPOCHS):\n    train_fn(train_data_loader, model,optimizer,device,scheduler)\n    accuracy,final_preds = eval_fn(valid_data_loader,model,device)\n    if accuracy >= best_accuracy:\n#         torch.save(model.state_dict(), MODEL_PATH)\n        best_accuracy = accuracy\n        print(best_accuracy)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.read_csv(\"../input/cassava-leaf-disease-classification/sample_submission.csv\")\ntest_df['path'] = test_df['image_id'].map(lambda x: os.path.join(BASE_DIR,'test_images',x))\n# fake targets\n# test_df.drop(columns=['image_id'],inplace=True)\ntest_targets = test_df.label.values\ntest_df.reset_index(drop=True)\n\ntest_df.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_albumentations = albumentations.Compose([\n             albumentations.RandomResizedCrop(400,300),\n            albumentations.Resize(400,300),\n            albumentations.Normalize(\n                mean=[0.485, 0.456, 0.406], \n                std=[0.229, 0.224, 0.225], \n                max_pixel_value=255.0, \n                p=1.0\n            )], p=1.)\n\n\n\ntest_dataset = LeafDataset(test_df.path.values,test_df.label.values,(256,256),test_albumentations)\ntest_data_loader = torch.utils.data.DataLoader(test_dataset, batch_size=BATCH_SIZE,num_workers=2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"final_preds = pred_fn(test_data_loader,model,device)\ntest_df.drop(columns=['path'],inplace=True)\ntest_df.label = int(final_preds[0])\ntest_df.head()\ntest_df.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Done')","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}