{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Baseline ResNext50\nThis is a continuation from my previous kernel https://www.kaggle.com/srinesh/baseline-vggnet/notebook which was based on Vggnet. The idea was to gauge the performance of an earlier DNN structure and compare it against newer algorithms. The idea is also to test the efficacy of different windowing techniques mentioned by others in the discussion page. \n\nThe following changes are made:\n1. Use ResNext50 for training the model (done)\n2. Change the loss function to match the competition criterion. Using weighted loss instead (done)\n3. Eventually try out `windowing` for the images (done)\n\nBut firstly, let us train the model using `Resnext50_32x4d` with windowing. Let's run that over 3 epochs in total. Here, I am using the model output after 2 epochs to start with.\n\nI have tried windowing for this kernel. Thanks to @reppic for the part of the code on `windowing` and @Alimbekov Renat [dsmlkz] for the pytorch implementation code."},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd \nfrom tqdm import tqdm\nimport gc\n\n# Imaging libraries\nimport seaborn as sns; sns.set()\nimport pydicom\nimport matplotlib.pyplot as plt\nimport cv2\n\n# Deep learning libraries\nimport torch.optim as optim\nimport torch \nimport torchvision.models as models\nfrom torch.utils.data import Dataset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BASE_PATH = '/kaggle/input/rsna-intracranial-hemorrhage-detection/'\nTRAIN_DIR = 'stage_1_train_images/'\nTEST_DIR = 'stage_1_test_images/'\n\nTRAIN_CSV = 'stage_1_train.csv'\nTEST_CSV = 'stage_1_sample_submission.csv'\n\nMODEL_PATH = '/kaggle/input/baseline-resnext50/resnext50_10.pth'\n\nTRAIN_CSV_PATH = os.path.join(BASE_PATH, TRAIN_CSV)\nTEST_CSV_PATH = os.path.join(BASE_PATH, TEST_CSV)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prepare the training data"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv(TRAIN_CSV_PATH)\ndf_train[['id', 'img', 'subtype']] = df_train['ID'].str.split('_', n=3, expand=True)\ndf_train['img'] = 'ID_' + df_train['img'] \n\ndf_train.drop_duplicates(inplace=True)\ndf_train = df_train.pivot(index='img', columns='subtype', values='Label').reset_index()\ndf_train['path'] = os.path.join(BASE_PATH, TRAIN_DIR) + df_train['img'] + '.dcm'\n\n# Only include valid images (some images are excluded for training)\nlegit_images = pd.read_csv('/kaggle/input/true-imagescsv/legit-images.csv')\ndf_train = df_train.merge(legit_images, left_on='img', right_on='0').drop(['0'], axis=1)\ndf_train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prepare the test data"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_test = pd.read_csv(TEST_CSV_PATH)\ndf_test[['id','img','subtype']] = df_test['ID'].str.split('_', expand=True)\ndf_test['img'] = 'ID_' + df_test['img']\ndf_test = df_test[['img', 'Label']]\ndf_test['path'] = os.path.join(BASE_PATH, TEST_DIR) + df_test['img'] + '.dcm'\ndf_test.drop_duplicates(inplace=True)\n\ndf_test = df_test.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class RSNADataset(Dataset):\n  def __init__(self, df, labels):\n        self.data = df\n        self.labels = labels\n\n  def __len__(self):\n        return len(self.data)\n\n  def __getitem__(self, index):\n        \n        img_name = self.data.loc[index, 'path']   \n        \n        img_dcm = pydicom.read_file(img_name)\n        img = RSNADataset.brain_window(img_dcm)\n        img = cv2.resize(img, (200,200))\n        \n        img = np.stack((img,)*3, axis=-1)\n        img = np.transpose(img, (2, 1, 0))\n    \n                \n        if self.labels:        \n            labels = torch.tensor(\n                self.data.loc[index, ['epidural', 'intraparenchymal', 'intraventricular', 'subarachnoid', 'subdural', 'any']])\n            return {'image': img, 'labels': labels}   \n        else:\n            return {'image': img}\n  \n  @staticmethod      \n  def brain_window(img):\n        window_min = 0\n        window_max = 80\n        _, _, intercept, slope = RSNADataset.get_windowing(img)\n        img = img.pixel_array.astype('float32')\n        img = img * slope + intercept\n        img[img < window_min] = window_min\n        img[img > window_max] = window_max\n        img = (img - np.min(img)) / 1e-5+ (np.max(img) - np.min(img))\n        return img\n  \n  @staticmethod\n  def get_windowing(data):\n        dicom_fields = [data[('0028','1050')].value, #window center\n                        data[('0028','1051')].value, #window width\n                        data[('0028','1052')].value, #intercept\n                        data[('0028','1053')].value] #slope\n        return [RSNADataset.get_first_of_dicom_field_as_int(x) for x in dicom_fields]\n  \n  @staticmethod\n  def get_first_of_dicom_field_as_int(x):\n    #get x[0] as in int is x is a 'pydicom.multival.MultiValue', otherwise get int(x)\n    if type(x) == pydicom.multival.MultiValue:\n        return int(x[0])\n    else:\n        return int(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"params = {'batch_size': 64,\n          'shuffle': False,\n          'num_workers': 4}\n\ntrain_dataset = RSNADataset(df= df_train, labels=True)\ntest_dataset = RSNADataset(df= df_test, labels=False)\n\ndata_train_generator = torch.utils.data.DataLoader(train_dataset, **params)\ndata_test_generator = torch.utils.data.DataLoader(test_dataset,**params)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plot train images\nbatch = next(iter(data_train_generator))\nfig, axs = plt.subplots(1, 3, figsize=(15,5))\n\nfor i in np.arange(3):\n    \n    axs[i].imshow(batch['image'][i][0].numpy(), cmap=plt.cm.bone)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plot test images\nbatch = next(iter(data_test_generator))\nfig, axs = plt.subplots(1, 3, figsize=(15,5))\n\nfor i in np.arange(3):\n    \n    axs[i].imshow(batch['image'][i][0].numpy(), cmap=plt.cm.bone)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model and training"},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda:0\")\nmodel0 = models.resnext50_32x4d(pretrained=True)\nmodel = torch.nn.Sequential(model0, torch.nn.Linear(1000, 6) ) \n\nmodel = model.to(device)\ncriterion = torch.nn.BCEWithLogitsLoss()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"n_epochs = 2\noptimizer = optim.Adam(model.parameters(), lr=4e-5)\n\ntry:\n    model.load_state_dict(torch.load(MODEL_PATH))\n    torch.save(model.state_dict(), 'resnext50_0.pth') \nexcept Exception as e:\n    print('The pre-trained model is used')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for epoch in range(1, n_epochs+1):\n    \n    print('Epoch {}/{}'.format(epoch, n_epochs))\n    print('-' * 10)\n\n    model.train()    \n    tr_loss = 0\n    \n    tk0 = tqdm(data_train_generator, desc=\"Iteration\")\n    \n    for step, batch in enumerate(tk0):\n        \n        inputs = batch[\"image\"]\n        labels = batch[\"labels\"]\n\n        inputs = inputs.to(device, dtype=torch.float)\n        labels = labels.to(device, dtype=torch.float)\n\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n                \n        loss.backward()\n\n        tr_loss += loss.item()\n\n        optimizer.step()\n        optimizer.zero_grad()\n     \n    torch.save(model.state_dict(), f'resnext50_{epoch}.pth') \n\n    epoch_loss = tr_loss / len(data_train_generator)\n    print('Training Loss: {:.4f}'.format(epoch_loss))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for param in model.parameters():\n    param.requires_grad = False\n\nmodel.eval()\n\ntest_pred = np.zeros((len(test_dataset) * 6, 1))\n\nfor i, batch_ in enumerate(tqdm(data_test_generator)):\n    batch_ = batch_[\"image\"]\n    batch_ = batch_.to(device, dtype=torch.float)\n    \n    with torch.no_grad():\n        \n        pred = model(batch_)\n        \n        test_pred[(i * 64 * 6):((i + 1) * 64 * 6)] = torch.sigmoid(\n            pred).detach().cpu().reshape((len(batch_) * 6, 1))  ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Preparing the submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission =  pd.read_csv(TEST_CSV_PATH)\nsubmission = pd.concat([submission.drop(columns=['Label']), pd.DataFrame(test_pred)], axis=1)\nsubmission.columns = ['ID', 'Label']\n\nsubmission.to_csv('submission.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":1}