{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nfrom torch.utils.data import DataLoader\nfrom torchvision.models import resnext50_32x4d\nfrom torch import nn\nfrom torch.optim import Adam\nfrom torch.nn import CrossEntropyLoss\nfrom sklearn.model_selection import train_test_split\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\nimport albumentations\nfrom tqdm.notebook import tqdm\nfrom sklearn.metrics import f1_score\nimport matplotlib.pyplot as plt\n\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\ndevice","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/vinbigdata-chest-xray-abnormalities-detection/train.csv')\ndf_submission = pd.read_csv('../input/vinbigdata-chest-xray-abnormalities-detection/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train[\"Finding\"] = np.where(df_train.class_name == \"No finding\",0,1)\ndf_train = df_train[['image_id','Finding']].drop_duplicates()\ndf_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_submission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.Finding.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.Finding.nunique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train, val = train_test_split(df_train, test_size = 0.20, shuffle = True, stratify = df_train['Finding'])\ntrain = train.reset_index(drop = True)\nval = val.reset_index(drop = True)\ntrain.shape, val.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nos.path.exists('../input/vinbigdata-chest-xray-resized-png-1024x1024/train/9a5094b2563a1ef3ff50dc5c7ff71345.png')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"TRAIN_PATH = '../input/vinbigdata-chest-xray-resized-png-1024x1024/train/'\ntrain_image_paths = [TRAIN_PATH + image+'.png' for image in train.image_id.values]\nval_image_paths = [TRAIN_PATH + image + '.png' for image in val.image_id.values]\nprint(train_image_paths[:5])\nlen(train_image_paths), len(val_image_paths)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_targets = train.Finding.values\nval_targets = val.Finding.values\nprint(len(train_targets), len(val_targets))\ntrain_targets[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class VinBigDataDataset:\n    def __init__(self, image_paths, targets, augmentations = None):\n        self.image_paths = image_paths\n        self.targets = targets\n        self.augmentations = augmentations\n    def __len__(self):\n        return len(self.image_paths)\n    def __getitem__(self, item):\n        targets = self.targets[item]\n        image = cv2.imread(self.image_paths[item])\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        if self.augmentations is not None:\n            augmented = self.augmentations(image = image)\n            image = augmented['image']\n        image = np.transpose(image, (2,0,1)).astype(np.float32)\n        return {\n            \"image\" : torch.tensor(image),\n            \"targets\" : torch.tensor(targets)\n        }","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_aug = albumentations.Compose(\n    [\n        albumentations.Resize(64,64)\n    ]\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = VinBigDataDataset(train_image_paths, train_targets, train_aug)\nval_dataset = VinBigDataDataset(val_image_paths, val_targets, train_aug)\nBATCH_SIZE = 32\ntrain_dataloader = DataLoader(train_dataset, batch_size = BATCH_SIZE, shuffle = True)\nval_dataloader = DataLoader(val_dataset, batch_size = BATCH_SIZE, shuffle = True)\n\ntrain_dataset[0]['image'].shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_images(image_dict):\n    print(image_dict['targets'])\n    image = image_dict['image'].permute(1,2,0) / 255\n    plt.imshow(image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_images(train_dataset[10])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class VinBigDataModel(nn.Module):\n    def __init__(self, num_classes, pretrained = True):\n        super().__init__()\n        self.convnet = resnext50_32x4d(pretrained = True)\n        self.convnet.fc = nn.Linear(2048, num_classes)\n    \n    def loss(self, outputs, classes):\n        if classes is not None:\n            outputs = outputs\n            return CrossEntropyLoss()(outputs, classes)\n    \n    def forward(self, images, classes = None):\n        outputs = self.convnet(images)\n        if classes is not None:\n            loss = self.loss(outputs, classes)\n            return outputs, loss\n        return outputs, None","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = VinBigDataModel(num_classes = df_train.Finding.nunique(), pretrained = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"opt = Adam(model.parameters(), lr = 1e-3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 50\ntrain_preds = []\nval_preds = []\ntrain_actuals = []\nval_actuals = []\nloss_list_train = []\nf1_list_train = []\nloss_list_val = []\nf1_list_val = []\nmin_val_loss = np.inf\nmodel.to(device)\nfor epoch in range(EPOCHS):\n    model.train()\n    tr_loss = 0\n    tr_examples = 0\n    val_loss = 0\n    val_examples = 0\n    for batch in train_dataloader:\n        images, classes = batch['image'].to(device), batch['targets'].to(device)\n        opt.zero_grad()\n        outputs, loss = model(images, classes)\n        loss.backward()\n        opt.step()\n        tr_loss += loss.item()\n        tr_examples += len(batch['targets'])\n        _, predicted = torch.max(outputs.cpu(), 1)\n        train_preds.extend(list(predicted.numpy()))\n        train_actuals.extend(list(classes.cpu().numpy()))\n    f1_score_train = f1_score(train_actuals, train_preds)\n    train_avg_loss = tr_loss/tr_examples\n    model.eval()\n    for batch in val_dataloader:\n        with torch.no_grad():\n            images, classes = batch['image'].to(device), batch['targets'].to(device)\n            outputs, loss = model(images, classes)\n            val_loss += loss.item()\n            val_examples += len(batch['targets'])\n            _, predicted = torch.max(outputs.cpu(),1)\n            val_preds.extend(list(predicted.numpy()))\n            val_actuals.extend(list(classes.cpu().numpy()))\n    f1_score_val = f1_score(val_actuals, val_preds)\n    val_avg_loss = val_loss/val_examples\n    \n    loss_list_train.append(train_avg_loss)\n    loss_list_val.append(val_avg_loss)\n    f1_list_train.append(f1_score_train)\n    f1_list_val.append(f1_score_val)\n    \n    print(\"Epoch: {} TrainLoss: {:.3f} Val Loss: {:.3f} TrainF1: {:.3f} ValF1: {:.3f}\".format(epoch, train_avg_loss, val_avg_loss, f1_score_train, f1_score_val))\n    \n    if val_loss < min_val_loss:\n        torch.save(model.state_dict(),'checkpoint.pt')\n        epochs_no_improve = 0\n        min_val_loss = val_loss\n    else:\n        epochs_no_improve += 1\n        # Check early stopping condition\n        if epochs_no_improve == 5:\n            print('Early stopping!' )\n            model.load_state_dict(torch.load('checkpoint.pt'))\n            break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax1 = plt.subplots()\n\nax2 = ax1.twinx()\n\np1 = ax1.plot(loss_list_train, '-r', label = \"loss_train\")\np2 = ax1.plot(loss_list_val, '-g',label = \"loss_val\")\np3 = ax2.plot(f1_list_train, label = 'f1_train')\np4 = ax2.plot(f1_list_val, label = 'f1_val')\n\nax1.set_xlabel('Epoch')\nax1.set_ylabel('Loss')\nax2.set_ylabel('F1-Score')\n\n# added these three lines\nlns = p1 +p2 +p3+p4\nlabs = [l.get_label() for l in lns]\nax1.legend(lns, labs, loc=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"TEST_PATH = '../input/vinbigdata-chest-xray-resized-png-1024x1024/test/'\ntest_image_paths = [TEST_PATH + image +'.png' for image in df_submission.image_id.values]\ntest_targets = [0 for i in df_submission.image_id.values]\ntest_dataset = VinBigDataDataset(test_image_paths, test_targets, train_aug)\ntest_dataloader = DataLoader(test_dataset, batch_size = BATCH_SIZE, shuffle = False)\ntest_dataset[0]['image'].shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = []\n#Iterate over the validation data\nfor batch in tqdm(test_dataloader):\n    #We dont want to update the gradients\n    with torch.no_grad():\n        images, classes = batch['image'].to(device), batch['targets'].to(device)\n        #Forward pass the input data\n        outputs = model(images)\n        _, predicted = torch.max(outputs[0].cpu(),1)\n        predictions.extend(list(predicted.numpy()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_submission['Finding'] = predictions\ndf_submission.to_csv('submission_temp.csv', index = False)","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}