{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Simple Starter Code: pytorch + EfficientNet "},{"metadata":{"trusted":true},"cell_type":"code","source":"# !pip install -q efficientnet_pytorch\n# from efficientnet_pytorch import EfficientNet\n\n#install efficientnet without internet\n!mkdir -p /tmp/pip/cache/\n!cp ../input/resources-for-google-landmark-recognition-2020/efficientnet_pytorch-0.6.3-py3-none-any.whl /tmp/pip/cache/\n!pip install --no-index --find-links /tmp/pip/cache/ efficientnet_pytorch","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import torch\nimport torchvision\nimport torch.nn.functional as F\nimport torch.nn as nn\nfrom torch.utils.data import Dataset,DataLoader, Subset\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\nfrom torchvision import models\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nimport pytorch_lightning as pl\nfrom tqdm import tqdm\nimport albumentations as A\nfrom efficientnet_pytorch import EfficientNet\n\nfrom sklearn.metrics import accuracy_score,roc_auc_score,f1_score,accuracy_score\nfrom sklearn.model_selection import train_test_split,StratifiedKFold,GroupKFold,KFold\nimport pandas as pd\nimport numpy as np \nimport gc\nimport os\nimport glob\nfrom collections import defaultdict\nimport random\nimport cv2\nfrom PIL import Image\nfrom PIL import ImageFile\nImageFile.LOAD_TRUNCATED_IMAGES=True\n\nimport warnings\nimport matplotlib.pyplot as plt\nfrom matplotlib import rc\nfrom pylab import rcParams\nimport seaborn as sns\n%matplotlib inline\n%config InlineBackend.figure_format='retina'\n\nsns.set(style='whitegrid', palette='muted', font_scale=1.2)\n\nHAPPY_COLORS_PALETTE = [\"#01BEFE\", \"#FFDD00\", \"#FF7D00\", \"#FF006D\", \"#ADFF02\", \"#8F00FF\"]\n\nsns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))\n\nrcParams['figure.figsize'] = 12, 8","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#lets checkout the train data\nlabel_to_class = {\n0:\"Cassava Bacterial Blight (CBB)\",\n1:\"Cassava Brown Streak Disease (CBSD)\",\n2:\"Cassava Green Mottle (CGM)\",\n3:\"Cassava Mosaic Disease (CMD)\",\n4:\"Healthy\",\n}\ndf = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\nsns.countplot(df.label.map(label_to_class))\nplt.xticks(rotation=30)\nplt.title('Target Distribution')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#utilities to load and display images\ndef load_image(img_path,resize=True):\n    img = cv2.cvtColor(cv2.imread(img_path),cv2.COLOR_BGR2RGB)\n    if resize:\n        img = cv2.resize(img, (224,224),interpolation=cv2.INTER_AREA)\n    return img\n\ndef show_img(img_path):\n    img = load_image(img_path)\n    plt.imshow(img)\n    plt.axis('off')\n    \n\ndef show_img_grid(img_path):\n    images = [load_image(img) for img in img_path]\n    images = torch.as_tensor(images)\n    images = images.permute(0,3,1,2)\n    grid_img = torchvision.utils.make_grid(images,nrow=5)\n    plt.figure(figsize=(25,12))\n    plt.imshow(grid_img.permute(1,2,0))\n    plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_PATH = '../input/cassava-leaf-disease-classification/train_images/' \nTEST_PATH = '../input/cassava-leaf-disease-classification/test_images/'\npath = [os.path.join(IMG_PATH,img) for img in df.loc[:24,'image_id']]\nshow_img_grid(path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class LeafDiseaseDataset(Dataset):\n    def __init__(self, img_path: str,targets,transforms = None, resize=None,test=False):\n        self.img_path = img_path\n        self.targets = targets\n        self.transforms = transforms\n        self.resize = resize\n        self.test = test\n        \n    def __len__(self):\n        return len(self.img_path)\n        \n    def __getitem__(self, item):\n        image = Image.open(self.img_path[item])\n        image = image.convert('RGB')\n        if not self.test:\n            targets = self.targets[item]\n        if self.resize is not None:\n            image = image.resize(\n                (self.resize[1],self.resize[0]),\n                resample=Image.BILINEAR\n            )\n        image = np.array(image)\n        \n        if self.transforms is not None:\n            augmented = self.transforms(image=image)\n            image = augmented['image']\n            \n        image = np.transpose(image,(2,0,1)).astype(np.float32)        \n        if not self.test:\n            return {\n                \"image\": torch.tensor(image, dtype=torch.float),\n                \"targets\": torch.tensor(targets, dtype=torch.long),\n            }\n        else:\n            return {\n                \"image\": torch.tensor(image, dtype=torch.float),\n            }\n            ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class EfficientNetEncoderHead(nn.Module):\n    def __init__(self, depth, num_classes):\n        super(EfficientNetEncoderHead, self).__init__()\n        self.depth = depth\n        self.base = EfficientNet.from_name(f'efficientnet-b4')\n        pretrained_file = '../input/resources-for-google-landmark-recognition-2020/efficientnet-b4-6ed6700e.pth'\n        self.base.load_state_dict(torch.load(pretrained_file))\n        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n        self.output_filter = self.base._fc.in_features\n        self.classifier = nn.Linear(self.output_filter, num_classes)\n    def forward(self, x):\n        x = self.base.extract_features(x)\n        x = self.avg_pool(x).squeeze(-1).squeeze(-1)\n        x = self.classifier(x)\n        return x\n    \n#ResNet-50\nclass LeafResNet(nn.Module):\n    def __init__(self, resnet, n_targets:int):\n        super(LeafResNet,self).__init__()\n        self.resnet = resnet\n        for param in resnet.parameters():\n            param.requires_grad = False\n        resnet.fc = nn.Sequential(\n            nn.Linear(2048,128),\n            nn.ReLU(inplace=True),\n            nn.Linear(128, n_targets)\n        )\n    def forward(self, x):\n        x = self.resnet(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#we have aleady seen that the data is bit imbalanced so we can perfrom sratifiedKfold\nkf = StratifiedKFold(n_splits=5)\ndf['kfolds'] = -1\nfor fold_,(t_,v_) in enumerate(kf.split(X=df,y=df.label.values)):\n    df.loc[v_,'kfolds'] = fold_\nsns.countplot(df.kfolds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#train/eval step\ndef train(data_loader, model, \n          loss_fn, optimizer, \n          scheduler,device,n_examples):\n    model.train()\n    losses = []\n    accs = []\n    for data in data_loader:\n        correct_predictions = 0\n        inputs = data['image'].to(device,dtype=torch.float)\n        targets = data['targets'].to(device,dtype=torch.long)\n        \n        optimizer.zero_grad()\n        outputs = model(inputs)\n        _,preds = torch.max(outputs,dim=1)\n        loss = loss_fn(outputs,targets)\n        accuracy = accuracy_score(targets.cpu().numpy(), preds.cpu().numpy())\n        \n        correct_predictions += torch.sum(preds==targets).cpu().numpy()\n        losses.append(loss.item())\n        accs.append(accuracy)\n        \n        loss.backward()\n        optimizer.step()\n    scheduler.step()\n\n    return np.mean(accs), np.mean(losses)\n        \ndef evaluate(data_loader, model,\n             loss_fn, device, n_examples):\n    \n    model.eval()\n    losses = []\n    accs = []\n    correct_predictions = 0\n    with torch.no_grad():\n        for data in data_loader:\n            inputs = data['image'].to(device,dtype=torch.float)\n            targets = data['targets'].to(device,dtype=torch.long)\n            outputs = model(inputs)\n            _,preds = torch.max(outputs,dim=1)\n            loss = loss_fn(outputs, targets)\n            \n            accuracy = accuracy_score(targets.cpu().numpy(), preds.cpu().numpy())\n            correct_predictions += torch.sum(preds == targets)\n            losses.append(loss.item())\n            accs.append(accuracy)\n\n    return np.mean(accs), np.mean(losses)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#config settings\ndata_path = '../input/cassava-leaf-disease-classification/train_images/'\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\nprint(f\"device: {device}\")\nN_epochs = 10\nbatch_size=64\nnum_workers=4\nmodel_arch = 'tf_efficientnet_b4_ns'\n\nmean = (0.485,0.456,0.406)\nstd = (0.229,0.224,0.225)\ntrain_aug = A.Compose(\n[\n    A.ShiftScaleRotate(shift_limit=0.05,scale_limit=0.05,rotate_limit=15,p=0.5),\n    A.HorizontalFlip(),\n    A.RandomRotate90(),\n    A.RandomBrightnessContrast(p=0.5),\n    A.Normalize(mean,std,max_pixel_value=255.0,always_apply=True)\n])\n\nval_aug = A.Compose([\n    A.Normalize(mean,std,max_pixel_value=255.0,always_apply=True)\n])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_model(model,train_data_loader,\n                val_data_loader,\n                device,n_epochs):\n    optimizer = optim.Adam(model.parameters(),lr=1e-3)\n    scheduler = lr_scheduler.StepLR(optimizer,step_size=7,gamma=0.1)\n    loss_fn = nn.CrossEntropyLoss().to(device)\n    \n    history = defaultdict(list)\n    best_accuracy = 0\n    \n    for epoch in range(n_epochs):\n        print(f\"epoch {epoch + 1}/{n_epochs}\")\n        print('-' * 10)\n        train_acc,train_loss = train(\n            train_data_loader,model,\n            loss_fn,optimizer,\n            scheduler,device,len(train_data_loader)\n        )\n        print(f\"Train loss {train_loss}, train_acc: {train_acc}\")\n        \n        val_acc, val_loss = evaluate(\n            val_data_loader,model,\n            loss_fn,device,len(val_data_loader)\n        )\n        \n        print(f\"Val loss: {val_loss}, val accuracy: {val_acc}\")\n        history['train_acc'].append(train_acc)\n        history['train_loss'].append(train_loss)\n        history['val_acc'].append(val_acc)\n        history['val_loss'].append(val_loss)\n        \n        if val_acc > best_accuracy:\n            torch.save(model.state_dict(), f'best_model_state_{val_acc}.bin')\n            best_accuracy = val_acc\n        \n    print(f\"Best val accuracy: {best_accuracy}\")\n    \n    return history,f'best_model_state_{best_accuracy}.bin'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Kfold cross validation training\n'''for fold_ in range(5):\n    model = LeafNet(eff,len(df.label.unique()))\n    model.to(device)\n    print(f\"___________FOLD: {fold_}____________\")\n    train_df,val_df = df[df.kfolds!=fold_], df[df.kfolds==fold_] \n    train_img_id = train_df.image_id.values.tolist()\n    train_imgs = [os.path.join(data_path, img) for img in train_img_id]\n    train_targets = train_df.label.values\n    \n    val_img_id = val_df.image_id.values.tolist()\n    val_imgs = [os.path.join(data_path, img) for img in val_img_id]\n    val_targets = val_df.label.values\n    \n    train_dataset = LeafDiseaseDataset(img_path=train_imgs,\n                                       targets=train_targets,\n                                       transforms=train_aug,\n                                       resize=(224,224)\n                                      )\n    train_loader = DataLoader(train_dataset,\n                              batch_size=batch_size,\n                              num_workers=num_workers)\n    \n    valid_dataset = LeafDiseaseDataset(img_path=val_imgs,\n                                      targets=val_targets,\n                                      transforms=val_aug,\n                                      resize=(224,224))\n    valid_loader = DataLoader(valid_dataset,\n                              batch_size=batch_size * 2,\n                              num_workers=num_workers)\n    \n    train_model(model,train_loader,valid_loader,device,N_epochs)'''\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = df.sample(frac=1).reset_index(drop=True)\nxtrain,xtest,ytrain,ytest = train_test_split(df,df.label,test_size=0.1)\ntrain_img_id = xtrain.image_id.values.tolist()\ntrain_imgs = [os.path.join(data_path,img) for img in train_img_id]\ntrain_targets = ytrain.values\n\ntest_img_id = xtest.image_id.values.tolist()\ntest_imgs = [os.path.join(data_path,img) for img in test_img_id]\ntest_targets = ytest.values\n\ntrain_dataset = LeafDiseaseDataset(img_path=train_imgs,\n                                    targets=train_targets,\n                                    transforms=train_aug,\n                                    resize=(224,224)\n                                      )\ntrain_loader = DataLoader(train_dataset,\n                        batch_size=batch_size,\n                        num_workers=num_workers)\n    \ntest_dataset = LeafDiseaseDataset(img_path=test_imgs,\n                                targets=test_targets,\n                                transforms=val_aug,\n                                resize=(224,224))\ntest_loader = DataLoader(test_dataset,\n                              batch_size=batch_size * 2,\n                              num_workers=num_workers)\nmodel = EfficientNetEncoderHead(depth=4, num_classes=len(df.label.unique()))\nmodel.to(device)\n\n\nhist,best_model_pth = train_model(model,train_loader,test_loader,device,N_epochs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_model = EfficientNetEncoderHead(depth=4, num_classes=len(df.label.unique()))\ntest_model.to(device)\ntest_model.load_state_dict(torch.load(best_model_pth))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_imgs = os.listdir('../input/cassava-leaf-disease-classification/test_images/')\nTEST_PATH = '../input/cassava-leaf-disease-classification/test_images/'\nimg = Image.open(os.path.join(TEST_PATH, test_imgs[0]))\nimg","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image = img.convert('RGB')\nimage = image.resize(\n        (224,224),\n        resample=Image.BILINEAR\n    )\nimage = np.array(image)\nimg_tfs = val_aug(image=image) \nimage = torch.tensor(img_tfs['image'],dtype=torch.float32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"final_result = []\nimg = image.permute(2,0,1).unsqueeze(0).to(device)\npreds = torch.argmax(test_model(img))\nfinal_result.append([test_imgs[0],preds.item()])\n\n#submission\nsub = pd.DataFrame(final_result, columns=['image_id', 'label'])\nsub.to_csv('submission.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def final_submission(model, dataloader, device, samp_sub):\n    model.eval()\n    img_preds_all = []\n    with torch.no_grad():\n        for data in dataloader:\n            inputs = data['image'].to(device,dtype=torch.float)\n            output = model(img)\n            img_preds_all += [torch.softmax(output, 1).detach().cpu().numpy()]\n\n    img_preds_all = np.concatenate(img_preds_all, axis=0)\n    samp_sub[\"label\"] = np.argmax(img_preds_all, axis=1)\n    samp_sub.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"samp_sub = pd.read_csv(\"../input/cassava-leaf-disease-classification/sample_submission.csv\")\nsamp_sub_img_id = samp_sub.image_id.values.tolist()\nsamp_sub_imgs = [os.path.join(TEST_PATH,img) for img in samp_sub_img_id]\n\n\nsamp_sub_dataset = LeafDiseaseDataset(img_path=samp_sub_imgs,\n                                    targets=None,\n                                    transforms=val_aug,\n                                    resize=(224,224),\n                                    test = True\n                                      )\nsamp_sub_loader = DataLoader(samp_sub_dataset,\n                        batch_size=batch_size,\n                        num_workers=num_workers)\n\nfinal_submission(test_model,samp_sub_loader,device,samp_sub)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}