{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom zipfile import ZipFile\nimport matplotlib.pyplot as plt\nimport os\nimport glob\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls ../input/proj2-ds/Covid19action-radiology-CXR_v1.1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels = pd.read_csv('../input/proj2-ds/Covid19action-radiology-CXR_v1.1/Train_Combined.csv')\nprint(labels.shape)\nlabels.drop(labels[(labels['Non-Pneumonia']==-1)|(labels['Other Pneumonia']==-1)].index, inplace=True)\nprint(labels.shape)\nlabels.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"l = labels[['Non-Pneumonia', 'Other Pneumonia', 'COVID-19']].idxmax(axis=1)\nl.hist()\nl.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ignoring the Source-3 rows, since Source-3 dataset have 11GB total memory which is impossible for me to download at home.\nprint(labels.shape)\nlabels = labels[~labels['Data Source'].isin(['Source-3'])]\nprint(labels.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv')\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df['Target'].hist()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torchvision\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torchvision import transforms\nimport pydicom as dicom","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image\n\nclass custom_dataset(torch.utils.data.Dataset):\n    def __init__(self, targets, height, width):\n        self.targets = targets\n        self.height = height\n        self.width = width\n        \n    def transform(self):\n        return (transforms.Compose([\n            transforms.Resize(size=(self.height, self.width)),\n            transforms.ToTensor()\n        ]))\n        \n    def get_im_proj2(self, name):\n        im = cv2.imread(name)\n        if len(im.shape) != 3 or im.shape[2] != 3:\n            im = np.stack((im,) * 3, -1)\n        return im\n    \n    def get_im_s4(self, name):\n        im = dicom.read_file(name).pixel_array\n        if len(im.shape) != 3 or im.shape[2] != 3:\n            im = np.stack((im,) * 3, -1)\n        return im\n        \n    def __getitem__(self, index):\n        label = self.targets.iloc[index]['disease']\n        if self.targets.iloc[index]['name'].split('/')[3] == 'proj2-ds':\n            im = self.get_im_proj2(self.targets.iloc[index]['name'])\n        else:\n            im = self.get_im_s4(self.targets.iloc[index]['name'])\n        return self.transform()(Image.fromarray(im)), label\n    \n    def __len__(self):\n        return len(self.targets.index)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.utils import shuffle\nfrom torch.utils.data.sampler import SubsetRandomSampler\n\ndef get_targets_others(labels, base_path):\n    labels = labels[~labels['Data Source'].isin(['Source-3'])]\n    targets = pd.DataFrame({'name':pd.Series([], dtype=str), 'disease':pd.Series([], dtype=int)})\n    classes = ['Non-Pneumonia', 'Other Pneumonia', 'COVID-19']\n\n    for i, row in labels.iterrows():\n        path1 = base_path+'Source'+row['Data Source'].split('-')[-1]+'/'+row['Image Name']\n        if path1.split('/')[-1].split('.')[-1]==row['Image Name']:\n            path1+='.jpg'\n        if(row['Data Source'] == 'Source-4'):\n            continue\n        if os.path.isfile(path1):\n            for indx, e in enumerate(classes):\n                if row[e]==1:\n                    targets = targets.append({'name':path1, 'disease':indx}, ignore_index=True)\n                    break\n        else:\n            print('File: '+path1+\" -- Doesn't exists\")\n            \n    return targets\n            \ndef get_targets_s4(df, base_path, test_size=0.05):\n    seen = set()\n    targets = pd.DataFrame({'name':pd.Series([], dtype=str), 'disease':pd.Series([], dtype=int)})\n    for i, row in df.iterrows():\n        path1 = base_path+row['patientId']+'.dcm'\n        if path1 not in seen:\n            seen.add(path1)\n            targets = targets.append({'name':path1, 'disease':row['Target']}, ignore_index=True)\n            \n    seen.clear()\n    targets = shuffle(targets)\n    split = int(len(targets)*test_size)\n    test_targets, train_targets = targets.iloc[0:split], targets[split:]\n    \n    return train_targets, test_targets\n\ndef create_dataset(test_size=0.05, valid_size=0.05, batch_size=512, height=35, width=35):\n    labels = pd.read_csv('../input/proj2-ds/Covid19action-radiology-CXR_v1.1/Train_Combined.csv')\n    base_path = '/kaggle/input/proj2-ds/Covid19action-radiology-CXR_v1.1/images/'\n    train_targets = get_targets_others(labels, base_path)\n    \n    labels = pd.read_csv('../input/proj2-ds/Covid19action-radiology-CXR_v1.1/Test_Combined.csv')\n    base_path = '/kaggle/input/proj2-ds/Covid19action-radiology-CXR_v1.1/images/'\n    test_targets = get_targets_others(labels, base_path)\n    \n    df = pd.read_csv('/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv')\n    base_path = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images/'\n    train_tgts, test_tgts = get_targets_s4(df, base_path, test_size)\n    \n    train_targets = pd.concat([train_targets, train_tgts])\n    test_targets = pd.concat([test_targets, test_tgts])\n    \n    train_ds = custom_dataset(train_targets, height, width)\n    test_ds = custom_dataset(test_targets, height, width)\n    \n    num_train = len(train_ds)\n    indices = list(range(num_train))\n    np.random.shuffle(indices)\n    split = int(np.floor(valid_size*num_train))\n    valid_idx, train_idx = indices[:split], indices[split:]\n    \n    train_sampler = SubsetRandomSampler(train_idx)\n    valid_sampler = SubsetRandomSampler(valid_idx)\n    \n    train_loader = torch.utils.data.DataLoader(dataset=train_ds, batch_size=batch_size, sampler=train_sampler)\n    valid_loader = torch.utils.data.DataLoader(dataset=train_ds, batch_size=batch_size, sampler=valid_sampler)\n    test_loader = torch.utils.data.DataLoader(dataset=test_ds, batch_size=batch_size, shuffle=True)\n    \n    return train_loader, valid_loader, test_loader","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if torch.cuda.is_available():\n    print(\"GPU is available :D\")\n    device = torch.device('cuda:0')\nelse:\n    print(\"GPU is not available ;-;\")\n    device = torch.device('cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Early Stopping class to stop when valid loss doesn't decrease further\nclass EarlyStopping:\n    def __init__(self, patience=7, verbose=False, delta=0):\n        self.patience = patience\n        self.verbose = verbose\n        self.counter = 0\n        self.best_score = None\n        self.early_stop = False\n        self.val_loss_min = np.Inf\n        self.delta = delta\n\n    def __call__(self, val_loss, model):\n\n        score = -val_loss\n\n        if self.best_score is None:\n            self.best_score = score\n            self.save_checkpoint(val_loss, model)\n        elif score < self.best_score + self.delta:\n            self.counter += 1\n            print(f'EarlyStopping counter: {self.counter} out of {self.patience}')\n            if self.counter >= self.patience:\n                self.early_stop = True\n        else:\n            self.best_score = score\n            self.save_checkpoint(val_loss, model)\n            self.counter = 0\n\n    def save_checkpoint(self, val_loss, model):\n        '''Saves model when validation loss decrease.'''\n        if self.verbose:\n            print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}).  Saving model ...')\n        torch.save(model.state_dict(), 'LeNet_model.pt')\n        self.val_loss_min = val_loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Training function\ndef training(model, learning_rate=0.001, patience=2, num_epochs=10):\n    model = model.to(device)\n    \n    criterion = nn.CrossEntropyLoss(weight=torch.tensor([20676/20676, 20676/6055, 20676/245]).to(device))\n    optimizer = torch.optim.Adam(model.parameters(), lr = learning_rate)\n    \n    early_stopping = EarlyStopping(patience=patience, verbose=True)\n    \n    train_loss = []\n    valid_loss = []\n    train_acc = []\n    \n    total_step = len(train_loader)\n    for epoch in range(num_epochs):\n        \n        model.train()\n        running_loss = 0.0\n        running_acc = 0.0\n        tot = 0\n        for i, (im, label) in enumerate(train_loader):\n            print(\"Iteration: \"+str(i))\n            im = im.to(device)\n            label = label.to(device)\n            \n            out = model(im)\n            loss = criterion(out, label)\n            \n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n            \n            running_loss += loss.item()\n            _, preds = torch.max(out.data, 1)\n            tot += preds.size(0)\n            running_acc += torch.sum(preds==label).item()\n            \n        epoch_loss = running_loss/(i+1)\n        epoch_acc = running_acc/(tot)\n        \n        train_loss.append(epoch_loss)\n        train_acc.append(epoch_acc)\n        \n        model.eval()\n        total = 0\n        running_valid_loss = 0.0\n        with torch.no_grad():\n            for (im, label) in valid_loader:\n                im = im.to(device)\n                label = label.to(device)\n\n                out = model(im)\n                running_valid_loss += criterion(out, label).item()\n                total += label.size(0)\n        \n        epoch_valid_loss = running_valid_loss/total\n        valid_loss.append(epoch_valid_loss)\n        print('Epoch {:.0f}/{:.0f} : Training Loss: {:.4f} | Validation Loss: {:.4f} | Training Accuracy: {:.4f} %'\n                    .format(epoch+1, num_epochs, epoch_loss, epoch_valid_loss, epoch_acc*100))\n        \n        early_stopping(epoch_valid_loss, model)\n        if early_stopping.early_stop:\n            print(\"Early Stopping!!!\")\n            break\n            \n    model.load_state_dict(torch.load('LeNet_model.pt'))\n    return model, train_loss, valid_loss, train_acc","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def evaluate(model):\n    model.eval()\n    \n    with torch.no_grad():\n        correct = 0\n        total = 0\n        \n        for (im, label) in test_loader:\n            im = im.to(device)\n            label = label.to(device)\n            \n            out = model(im)\n            _, preds = torch.max(out.data, axis=1)\n            total += label.size(0)\n            correct += (preds==label).sum().item()\n            \n        print('Test Accuracy : {} %'.format(100*correct/total))\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_epochs=15\npatience=3\nlearning_rate=0.001\n\nmodel = torchvision.models.resnet18(pretrained=True)\nfor params in model.parameters():\n    params.requires_grad = False\nin_ftrs = model.fc.in_features\nmodel.fc = nn.Linear(in_ftrs, 3)\n    \ntrain_loader, valid_loader, test_loader = create_dataset()\nmodel, train_loss, valid_loss, train_acc = training(\n                                                model,\n                                                learning_rate=learning_rate,\n                                                patience=patience,\n                                                num_epochs=num_epochs\n                                            )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"evaluate(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=[15, 5])\n\nplt.subplot(121)\nplt.plot(range(1, len(train_loss)+1), train_loss, 'b', label='Training Loss')\nplt.plot(range(1, len(valid_loss)+1), valid_loss, 'c', label='Validation Loss')\nminposs = valid_loss.index(min(valid_loss))+1 \nplt.axvline(minposs, linestyle='--', color='r',label='Early Stopping Checkpoint')\nplt.gca().set_title('Training And Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\n\nplt.subplot(122)\nplt.plot(range(1, len(train_acc)+1), train_acc, 'g', label='Accuracy')\nplt.gca().set_title('Training Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='upper right')","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}