{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Simple CNN Classifier Starter (Pytorch)\n* Using EfficientNet-B0 as basebone\n* Not do segmentation\n* Only do classification task on gleason_score(then map to isup score****)","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\n# There are two ways to load the data from the PANDA dataset:\n# Option 1: Load images using openslide\nimport openslide\n# Option 2: Load images using skimage (requires that tifffile is installed)\nimport skimage.io\n\nfrom tqdm import tqdm_notebook as tqdm\nimport warnings\n# General packages\nimport pandas as pd\nimport numpy as np\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport PIL\nfrom IPython.display import Image, display\n\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\nfrom torch.utils import model_zoo\nfrom torch.utils.data import Dataset, DataLoader, RandomSampler\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.model_selection import train_test_split\nfrom torch.optim import Adam,SGD\nimport torchvision.models as models\n\n# Plotly for the interactive viewer (see last section)\nimport plotly.graph_objs as go\nwarnings.simplefilter('ignore')\nwarnings.filterwarnings('ignore')\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nrandom_seed = 644","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Download EfficientNet\n* For training, inference kernel can't turn on internet","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import sys\npackage_path = '../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master'\nsys.path.append(package_path)\nfrom efficientnet_pytorch import EfficientNet","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def seed_everything(seed):\n    \"\"\"\n    Seeds basic parameters for reproductibility of results\n    \n    Arguments:\n        seed {int} -- Number of the seed\n    \"\"\"\n    # random.seed(seed)\n    # os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\nseed_everything(random_seed)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load train data","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Location of the training images\ndata_dir = '/kaggle/input/prostate-cancer-grade-assessment/train_images'\nmask_dir = '/kaggle/input/prostate-cancer-grade-assessment/train_label_masks'\n\n# Location of training labels\ntrain_labels = pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/train.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Set map dictionary ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"label_map = {label : i for i, label in enumerate(train_labels['gleason_score'])}\n\nfor i,label_name in enumerate(label_map):\n    label_map[label_name] =i\n    \nmap_label = {label_map[index] : index for i, index in enumerate(label_map)}\nisup_map = {\"0+0\":0,'negative':0,'3+3':1,'3+4':2,'4+3':3,'4+4':4,'3+5':4,'5+3':4,'4+5':5,'5+4':5,'5+5':5}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_map","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels['label'] = train_labels['gleason_score'].map(label_map)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## PANDA Dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class prostate_data(Dataset):\n    def __init__(self, anotation, img_dir, mode='train', size=(512,512), transform=None):\n        self.anotation = anotation\n        self.img_dir = img_dir\n        self.size = size\n        self.mode = mode\n        self.transforms = transform\n        \n    def __len__(self):\n        return len(self.anotation)\n    \n    def __getitem__(self, idx):\n        \n        if self.mode == 'test':\n            img_id, provide  = self.anotation.loc[idx,['image_id','data_provider']].values\n        else:\n            img_id, label, provide  = self.anotation.loc[idx,['image_id','label','data_provider']].values\n            \n        img_path = os.path.join(self.img_dir, img_id+'.tiff')\n        \n        image = openslide.OpenSlide(img_path)\n        image = np.array(image.get_thumbnail(size=self.size).resize(self.size))\n        #print (image.shape)\n        \n        image = self.transforms(image=image)['image']\n        #print (image.shape)\n        #image =  np.rollaxis(image, 2, 0) / 255\n        \n        if self.mode == 'train' or self.mode == 'valid':\n            return image, torch.tensor(label)\n        else:\n            return image","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data augmentation","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nSIZE = 512\ntransforms_train = A.Compose([\n    A.RandomResizedCrop(height=SIZE, width=SIZE, p=1.0),\n    A.Flip(),\n    A.ShiftScaleRotate(rotate_limit=1.0, p=0.8),\n\n    # Pixels\n    A.OneOf([\n        A.IAAEmboss(p=1.0),\n        A.IAASharpen(p=1.0),\n        A.Blur(p=1.0),\n    ], p=0.5),\n\n    # Affine\n    A.OneOf([\n        A.ElasticTransform(p=1.0),\n        A.IAAPiecewiseAffine(p=1.0)\n    ], p=0.5),\n\n    A.Normalize(p=1.0),\n    ToTensorV2(p=1.0),\n])\n\ntransforms_valid = A.Compose([\n    A.Resize(height=SIZE, width=SIZE, p=1.0),\n    A.Normalize(p=1.0),\n    ToTensorV2(p=1.0),\n])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Split tran and valid set\n* only using 100 data as training set to reduce kernel run-time","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train, valid = train_test_split(train_labels,test_size=0.2,stratify= train_labels['label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = prostate_data(train[:100].reset_index(drop=True),data_dir, transform=transforms_train)\nvalid_dataset = prostate_data(valid[:20].reset_index(drop=True),data_dir, transform=transforms_valid)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size=16\ntrain_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)\nvalid_loader = DataLoader(dataset=valid_dataset, batch_size=batch_size, shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"x_train, y = next(iter(valid_loader))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model_name = 'efficientnet-b0'\nmodel_ft = EfficientNet.from_name(model_name)\n\nmodel_ft.load_state_dict(torch.load('../input/efficientnet-pytorch/efficientnet-b0-08094119.pth'))\n# checkpoint = torch.load('../input/panda-checkpoint-demo/model_checkpoint_epoch2.pth')\n# model_ft.load_state_dict(checkpoint['model_state_dict'])\n\nin_features = model_ft._fc.in_features\nmodel_ft._fc = nn.Linear(in_features,len(label_map))\n\n#model_ft = EfficientNet.from_pretrained('efficientnet-b0', num_classes=len(label_map))\nmodel_ft = model_ft.to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import accuracy_score,f1_score,confusion_matrix,classification_report,auc,roc_curve,cohen_kappa_score","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Start training","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"lr = 0.0005\neta_min = 1e-5\nt_max = 10\ncriterion = nn.CrossEntropyLoss()\noptimizer = Adam(params=model_ft.parameters(), lr=lr)\n\ntry:\n    optimizer.load_state_dict(checkpoint['optimizer_state_dict'])\n    prev_epoch = checkpoint['epoch']\n    tloss = checkpoint['loss']\nexcept:\n    prev_epoch = 0\n\ntlen = len(train_loader)\ntlen_valid = len(valid_loader)\naccumulation_steps = 2\nvalid_pred = np.zeros((len(valid[:20]),11))\ntrain_pred = np.zeros((len(train[:100]),11))\ntrain_target = np.zeros((len(train[:100])))\n\n\nfor epoch in range(2):\n    batch_i = 0\n    tloss = 0\n    tloss_valid = 0\n    acc = np.zeros(1)\n    acc_valid = np.zeros(1)\n    model_ft.train()\n    optimizer.zero_grad()\n    for i,(x_train, y_train) in enumerate(tqdm(train_loader)): \n        outputs = model_ft(x_train.cuda())\n        \n        loss = criterion(outputs,  y_train.long().cuda())\n        loss.backward()\n        if (batch_i+1) % accumulation_steps == 0:            \n            optimizer.step()                           \n            optimizer.zero_grad()\n        \n        tloss += loss.item()\n        batch_i+=1\n        \n        train_pred[i * batch_size:(i+1) * batch_size] = outputs.detach().cpu().numpy()\n        train_target[i * batch_size:(i+1) * batch_size] = y_train.detach().cpu().numpy()\n\n        del loss, outputs, y_train, x_train\n\n    #Valid acc\n    model_ft.eval()\n    for i,(x_train, y_train) in enumerate(valid_loader):\n        outputs = model_ft(x_train.cuda())\n        loss = criterion(outputs,  y_train.long().cuda())\n        tloss_valid += loss.item()\n        valid_pred[i * batch_size:(i+1) * batch_size] = outputs.detach().cpu().numpy()\n        del loss, outputs, y_train, x_train\n        \n    acc = cohen_kappa_score(train_pred.argmax(axis =1),train_target,weights='quadratic')\n    acc_valid = cohen_kappa_score(valid_pred.argmax(axis =1),valid['label'][:20],weights='quadratic')\n#     torch.save(model_ft.state_dict(), 'model_checkpoint_epoch{}.pth'.format(epoch+1))\n    curr_epoch = epoch+prev_epoch+1\n    torch.save({\n            'epoch': curr_epoch,\n            'model_state_dict': model_ft.state_dict(),\n            'optimizer_state_dict': optimizer.state_dict(),\n            'loss': tloss\n            }, 'model_checkpoint_epoch{}.pth'.format(curr_epoch))\n    print('Epoch {} -> Train Loss: {:.4f}, Valid Loss: {:.4f}, ACC_train: {:.2f}%, ACC_valid: {:.2f}%'.format(curr_epoch, tloss/tlen, tloss_valid/tlen_valid, acc, acc_valid))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"try:\n    logbook = pd.read_csv('../input/panda-checkpoint-demo/experiment_logs.csv')\nexcept:\n    logbook = pd.DataFrame(columns = ['Model', 'epochs', 'Train Loss', 'Valid Loss', 'ACC_train','ACC_valid'])\n    \nrun_details = {'Model':model_name,'epochs':curr_epoch,'Train Loss':tloss/tlen,'Valid Loss':tloss_valid/tlen_valid,'ACC_train':acc,'ACC_valid':acc_valid}\nlogbook = logbook.append(run_details, ignore_index=True)\nlogbook.to_csv('experiment_logs.csv',index=False)\nlogbook","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test_labels = pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/test.csv')\n# test_dir = '/kaggle/input/prostate-cancer-grade-assessment/test_images'\n\n# if os.path.exists(test_dir):\n#     test_dataset = prostate_data(test_labels,test_dir,mode='test',transform=transforms_valid)\n#     test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size, shuffle=False)\n#     test_pred = np.zeros((len(test_labels),11))\n#     model_ft.eval()\n#     for i,(x_train) in enumerate(tqdm(test_loader)):\n#         outputs = model_ft(x_train.cuda())\n#         test_pred[i * batch_size:(i+1) * batch_size] = outputs.detach().cpu().numpy()\n#         del outputs,x_train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# sub = pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/sample_submission.csv')\n# test_dir = '/kaggle/input/prostate-cancer-grade-assessment/test_images'\n# if os.path.exists(test_dir):\n#     sub['isup_grade'] = test_pred.argmax(axis=1)\n#     sub['isup_grade'] = sub['isup_grade'].map(map_label)\n#     sub['isup_grade'] = sub['isup_grade'].map(isup_map)\n# sub.to_csv('submission.csv',index=False)","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}