{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction\n\nThis is a simple fork of my previous kernel (https://www.kaggle.com/taindow/pytorch-efficientnet-b0), except here we make use of ResNeXt and \"weakly supervised pre-training\" as opposed to EfficientNet. See https://github.com/facebookresearch/WSL-Images for model information. Note due to the number of parameters a single sweep of the data will take approx. 4-5h."},{"metadata":{},"cell_type":"markdown","source":"# Sources\n\nWindowing functions for pre-processed data taken from the following:\n\n- https://www.kaggle.com/omission/eda-view-dicom-images-with-correct-windowing "},{"metadata":{},"cell_type":"markdown","source":"# Parameters"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Input\n\ndir_csv = '../input/rsna-intracranial-hemorrhage-detection'\ndir_train_img = '../input/rsna-train-stage-1-images-png-224x/stage_1_train_png_224x'\ndir_test_img = '../input/rsna-test-stage-1-images-png-224x/stage_1_test_png_224x'\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# Parameters\n\nn_classes = 6\nn_epochs = 2\nbatch_size = 64\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Setup\n\nNeed to grab a couple of extra libraries\n\n- Nvidia Apex for mixed precision training (https://github.com/NVIDIA/apex)"},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"# Installing useful libraries\n\n!git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option=\"--cpp_ext\" --global-option=\"--cuda_ext\" ./\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Libraries\n\nfrom apex import amp\nimport os\nimport cv2\nimport glob\nimport pydicom\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.optim as optim\nfrom albumentations import Compose, ShiftScaleRotate, Resize\nfrom albumentations.pytorch import ToTensor\nfrom torch.utils.data import Dataset\nfrom tqdm import tqdm_notebook as tqdm\nfrom matplotlib import pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# Functions\n\nclass IntracranialDataset(Dataset):\n\n    def __init__(self, csv_file, path, labels, transform=None):\n        \n        self.path = path\n        self.data = pd.read_csv(csv_file)\n        self.transform = transform\n        self.labels = labels\n\n    def __len__(self):\n        \n        return len(self.data)\n\n    def __getitem__(self, idx):\n        \n        img_name = os.path.join(self.path, self.data.loc[idx, 'Image'] + '.png')\n        img = cv2.imread(img_name)   \n        \n        if self.transform:       \n            \n            augmented = self.transform(image=img)\n            img = augmented['image']   \n            \n        if self.labels:\n            \n            labels = torch.tensor(\n                self.data.loc[idx, ['epidural', 'intraparenchymal', 'intraventricular', 'subarachnoid', 'subdural', 'any']])\n            return {'image': img, 'labels': labels}    \n        \n        else:      \n            \n            return {'image': img}\n    \n    \n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# CSV"},{"metadata":{"trusted":true},"cell_type":"code","source":"# CSVs\n\ntrain = pd.read_csv(os.path.join(dir_csv, 'stage_1_train.csv'))\ntest = pd.read_csv(os.path.join(dir_csv, 'stage_1_sample_submission.csv'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# Split train out into row per image and save a sample\n\ntrain[['ID', 'Image', 'Diagnosis']] = train['ID'].str.split('_', expand=True)\ntrain = train[['Image', 'Diagnosis', 'Label']]\ntrain.drop_duplicates(inplace=True)\ntrain = train.pivot(index='Image', columns='Diagnosis', values='Label').reset_index()\ntrain['Image'] = 'ID_' + train['Image']\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Some files didn't contain legitimate images, so we need to remove them\n\npng = glob.glob(os.path.join(dir_train_img, '*.png'))\npng = [os.path.basename(png)[:-4] for png in png]\npng = np.array(png)\n\ntrain = train[train['Image'].isin(png)]\ntrain.to_csv('train.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Also prepare the test data\n\ntest[['ID','Image','Diagnosis']] = test['ID'].str.split('_', expand=True)\ntest['Image'] = 'ID_' + test['Image']\ntest = test[['Image', 'Label']]\ntest.drop_duplicates(inplace=True)\n\ntest.to_csv('test.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# DataLoaders"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Data loaders\n\ntransform_train = Compose([\n    ShiftScaleRotate(),\n    ToTensor()\n])\n\ntransform_test= Compose([\n    ToTensor()\n])\n\ntrain_dataset = IntracranialDataset(\n    csv_file='train.csv', path=dir_train_img, transform=transform_train, labels=True)\n\ntest_dataset = IntracranialDataset(\n    csv_file='test.csv', path=dir_test_img, transform=transform_test, labels=False)\n\ndata_loader_train = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=False, num_workers=4)\ndata_loader_test = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plot train example\n\nbatch = next(iter(data_loader_train))\nfig, axs = plt.subplots(1, 5, figsize=(15,5))\n\nfor i in np.arange(5):\n    \n    axs[i].imshow(np.transpose(batch['image'][i].numpy(), (1,2,0))[:,:,0], cmap=plt.cm.bone)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plot test example\n\nbatch = next(iter(data_loader_test))\nfig, axs = plt.subplots(1, 5, figsize=(15,5))\n\nfor i in np.arange(5):\n    \n    axs[i].imshow(np.transpose(batch['image'][i].numpy(), (1,2,0))[:,:,0], cmap=plt.cm.bone)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Model\n\ndevice = torch.device(\"cuda:0\")\nmodel = torch.hub.load('facebookresearch/WSL-Images', 'resnext101_32x8d_wsl')\nmodel.fc = torch.nn.Linear(2048, n_classes)\n\nmodel.to(device)\n\ncriterion = torch.nn.BCEWithLogitsLoss()\nplist = [{'params': model.parameters(), 'lr': 2e-5}]\noptimizer = optim.Adam(plist, lr=2e-5)\n\nmodel, optimizer = amp.initialize(model, optimizer, opt_level=\"O1\")\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train\n\n\nfor epoch in range(n_epochs):\n    \n    print('Epoch {}/{}'.format(epoch, n_epochs - 1))\n    print('-' * 10)\n\n    model.train()    \n    tr_loss = 0\n    \n    tk0 = tqdm(data_loader_train, 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        with amp.scale_loss(loss, optimizer) as scaled_loss:\n            scaled_loss.backward()\n\n        tr_loss += loss.item()\n\n        optimizer.step()\n        optimizer.zero_grad()\n\n    epoch_loss = tr_loss / len(data_loader_train)\n    print('Training Loss: {:.4f}'.format(epoch_loss))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Inference"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Inference\n\nfor param in model.parameters():\n    param.requires_grad = False\n\nmodel.eval()\n\ntest_pred = np.zeros((len(test_dataset) * n_classes, 1))\n\nfor i, x_batch in enumerate(tqdm(data_loader_test)):\n    \n    x_batch = x_batch[\"image\"]\n    x_batch = x_batch.to(device, dtype=torch.float)\n    \n    with torch.no_grad():\n        \n        pred = model(x_batch)\n        \n        test_pred[(i * batch_size * n_classes):((i + 1) * batch_size * n_classes)] = torch.sigmoid(\n            pred).detach().cpu().reshape((len(x_batch) * n_classes, 1))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Submission\n\nsubmission =  pd.read_csv(os.path.join(dir_csv, 'stage_1_sample_submission.csv'))\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)\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Clean Up\n\nHave to clean up since Kaggle limits the number of files that can be output from a kernel"},{"metadata":{"trusted":true},"cell_type":"code","source":"!rm -rf /kaggle/working/apex\n!rm test.csv\n!rm train.csv","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}