{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# RSNA-MICCAI Brain Tumor Radiogenomic Classificationn - **An approach with PyTorch EfficientNet 3D**\n\n## **Problem Description**:\n\nThere are structural multi-parametric MRI (mpMRI) scans for different subjects, in DICOM format. The exact mpMRI scans included are:\n\n* Fluid Attenuated Inversion Recovery (FLAIR)\n* T1-weighted pre-contrast (T1w)\n* T1-weighted post-contrast (T1Gd)\n* T2-weighted (T2)\n\n`train_labels.csv` - file contains the target **MGMT_value** for each subject in the training data **(e.g. the presence of MGMT promoter methylation)**.\n\nSo, it's a binary classification problem.\n\n## **An EfficientNet3D solution**:\n\n* For each patient, we consider 4 sequences (FLAIR, T1w, T1Gd, T2), and for each of those sequences we take 64 slices from the middle. We resize the slices in shape (256, 256).\n\n* Construct an efficientnet-3d in pytorch with input shape (256, 256, 256) or (4, 256, 256, 64).\n\n* Perform binary classification.\n\n\n### ⚡ **Inference kernel:** https://www.kaggle.com/furcifer/torch-effnet3d-for-mri-no-inference/\n","metadata":{}},{"cell_type":"markdown","source":"### **Importing libraries**","metadata":{}},{"cell_type":"code","source":"import os\nimport glob\nfrom tqdm import tqdm_notebook as tqdm\nimport math\nimport random\nimport numpy as np\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.nn.functional as F\nfrom torchvision import transforms, utils\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nfrom sklearn.metrics import roc_auc_score\n\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2021-07-23T01:14:21.188270Z","iopub.execute_input":"2021-07-23T01:14:21.188667Z","iopub.status.idle":"2021-07-23T01:14:23.463959Z","shell.execute_reply.started":"2021-07-23T01:14:21.188590Z","shell.execute_reply":"2021-07-23T01:14:23.462970Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Importing EfficientNet-3D**","metadata":{}},{"cell_type":"code","source":"import sys\nsys.path.append('../input/efficientnetpyttorch3d/EfficientNet-PyTorch-3D')\nfrom efficientnet_pytorch_3d import EfficientNet3D","metadata":{"execution":{"iopub.status.busy":"2021-07-23T01:17:04.171421Z","iopub.execute_input":"2021-07-23T01:17:04.171782Z","iopub.status.idle":"2021-07-23T01:17:04.236057Z","shell.execute_reply.started":"2021-07-23T01:17:04.171750Z","shell.execute_reply":"2021-07-23T01:17:04.235304Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Inspecting Labels**","metadata":{}},{"cell_type":"code","source":"path = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification'\ntrain_data = pd.read_csv(os.path.join(path, 'train_labels.csv'))\nprint('Num of train samples:', len(train_data))\ntrain_data.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-23T01:17:06.836743Z","iopub.execute_input":"2021-07-23T01:17:06.837064Z","iopub.status.idle":"2021-07-23T01:17:06.868954Z","shell.execute_reply.started":"2021-07-23T01:17:06.837035Z","shell.execute_reply":"2021-07-23T01:17:06.867996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **MRI Slice Loading/Processing**","metadata":{}},{"cell_type":"code","source":"def dicom2array(path, voi_lut=True, fix_monochrome=True, remove_black_boundary=True):\n    dicom = pydicom.read_file(path)\n    # VOI LUT (if available by DICOM device) is used to\n    # transform raw DICOM data to \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    if remove_black_boundary:\n        (x, y) = np.where(data > 0)\n        if len(x) > 0 and len(y) > 0:\n            x_mn = np.min(x)\n            x_mx = np.max(x)\n            y_mn = np.min(y)\n            y_mx = np.max(y)\n            if (x_mx - x_mn) > 10 and (y_mx - y_mn) > 10:\n                data = data[:,np.min(y):np.max(y)]\n    data = cv2.resize(data, (256, 256))\n    return data\n\ndef load_3d_dicom_images(scan_id, split = \"train\", channel_expand = True, remove_black_boundary=True):\n    \"\"\"\n    we will use some heuristics to choose the slices to avoid any numpy zero matrix (if possible)\n    \"\"\"\n    flair = sorted(glob.glob(f\"{path}/{split}/{scan_id}/FLAIR/*.dcm\"))\n    t1w = sorted(glob.glob(f\"{path}/{split}/{scan_id}/T1w/*.dcm\"))\n    t1wce = sorted(glob.glob(f\"{path}/{split}/{scan_id}/T1wCE/*.dcm\"))\n    t2w = sorted(glob.glob(f\"{path}/{split}/{scan_id}/T2w/*.dcm\"))\n    \n    \n    flair_img = np.array([dicom2array(a, remove_black_boundary = remove_black_boundary) for a in flair[len(flair)//2 - 32:len(flair)//2 + 32]]).T\n    \n    if len(flair_img) == 0:\n        flair_img = np.zeros((256, 256, 64))\n    elif flair_img.shape[-1] < 64:\n        n_zero = 64 - flair_img.shape[-1]\n        flair_img = np.concatenate((flair_img, np.zeros((256, 256, n_zero))), axis = -1)\n    #print(flair_img.shape)\n        \n    \n    \n    t1w_img = np.array([dicom2array(a, remove_black_boundary = remove_black_boundary) for a in t1w[len(t1w)//2 - 32:len(t1w)//2 + 32]]).T\n    \n    if len(t1w_img) == 0:\n        t1w_img = np.zeros((256, 256, 64))\n    elif t1w_img.shape[-1] < 64:\n        n_zero = 64 - t1w_img.shape[-1]\n        t1w_img = np.concatenate((t1w_img, np.zeros((256, 256, n_zero))), axis = -1)\n    #print(t1w_img.shape)\n    \n    \n    t1wce_img = np.array([dicom2array(a, remove_black_boundary = remove_black_boundary) for a in t1wce[len(t1wce)//2 - 32:len(t1wce)//2 + 32]]).T\n    \n    if len(t1wce_img) == 0:\n        t1wce_img = np.zeros((256, 256, 64))\n    elif t1wce_img.shape[-1] < 64:\n        n_zero = 64 - t1wce_img.shape[-1]\n        t1wce_img = np.concatenate((t1wce_img, np.zeros((256, 256, n_zero))), axis = -1)\n    #print(t1wce_img.shape)\n    \n    \n    t2w_img = np.array([dicom2array(a, remove_black_boundary = remove_black_boundary) for a in t2w[len(t2w)//2 - 32:len(t2w)//2 + 32]]).T\n    \n    if len(t2w_img) == 0:\n        t2w_img = np.zeros((256, 256, 64))\n    elif t2w_img.shape[-1] < 64:\n        n_zero = 64 - t2w_img.shape[-1]\n        t2w_img = np.concatenate((t2w_img, np.zeros((256, 256, n_zero))), axis = -1)\n    #print(t2w_img.shape)\n    \n    return np.concatenate((flair_img, t1w_img, t1wce_img, t2w_img), axis = -1) if not channel_expand else np.moveaxis(np.array((flair_img, t1w_img, t1wce_img, t2w_img)), 0, -1)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:15:37.837416Z","iopub.execute_input":"2021-07-23T02:15:37.837743Z","iopub.status.idle":"2021-07-23T02:15:37.859912Z","shell.execute_reply.started":"2021-07-23T02:15:37.837714Z","shell.execute_reply":"2021-07-23T02:15:37.858999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"load_3d_dicom_images(\"00000\", channel_expand = False).shape","metadata":{"execution":{"iopub.status.busy":"2021-07-23T01:37:42.039218Z","iopub.execute_input":"2021-07-23T01:37:42.039597Z","iopub.status.idle":"2021-07-23T01:37:43.418727Z","shell.execute_reply.started":"2021-07-23T01:37:42.039565Z","shell.execute_reply":"2021-07-23T01:37:43.417832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"slices = load_3d_dicom_images(\"00000\", remove_black_boundary=False)\nprint(slices.shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:15:42.765121Z","iopub.execute_input":"2021-07-23T02:15:42.765492Z","iopub.status.idle":"2021-07-23T02:15:43.909810Z","shell.execute_reply.started":"2021-07-23T02:15:42.765459Z","shell.execute_reply":"2021-07-23T02:15:43.908102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# doing a little more cleaning up\ns_slice = slices[:,:,0,0]\nplt.imshow(s_slice)\nplt.title(\"Lots of black pixels\")\nplt.show()\n(x, y) = np.where(s_slice > 0)\nns_slice = s_slice[np.min(x):np.max(x),np.min(y):np.max(y)]\nplt.title(\"Less black pixels\")\nplt.imshow(ns_slice)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:15:47.250658Z","iopub.execute_input":"2021-07-23T02:15:47.251019Z","iopub.status.idle":"2021-07-23T02:15:47.540306Z","shell.execute_reply.started":"2021-07-23T02:15:47.250987Z","shell.execute_reply":"2021-07-23T02:15:47.539172Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Visualization**","metadata":{}},{"cell_type":"code","source":"# https://www.kaggle.com/josepc/rsna-effnet/\n\nviews = ['FLAIR', 'T1w', 'T1wCE', 'T2w']\ndef load_imgs(idx):\n    slices = load_3d_dicom_images(idx)\n    imgs = {}\n    for i, view in enumerate(views):\n        imgs[view] = slices[:,:,:,i].swapaxes(0, -1)\n    return imgs\n\nfor i in range(10,32):\n    idx = str(i).zfill(5)\n    imgs = load_imgs(idx)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:15:51.863889Z","iopub.execute_input":"2021-07-23T02:15:51.864258Z","iopub.status.idle":"2021-07-23T02:16:13.665253Z","shell.execute_reply.started":"2021-07-23T02:15:51.864223Z","shell.execute_reply":"2021-07-23T02:16:13.664436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# the video play doesn't work, you can download it to view\n\nfrom IPython.display import HTML\nfrom base64 import b64encode\nimport matplotlib.animation as animation\n\ndef play(filename):\n    html = ''\n    video = open(filename,'rb').read()\n    src = 'data:video/mp4;base64,' + b64encode(video).decode()\n    html += '<video width=500 controls autoplay loop><source src=\"%s\" type=\"video/mp4\"></video>' % src \n    return HTML(html)\n\ndef create_video(imgs, output='/kaggle/working/vis_video.mp4', duration=30, subplot=True, \n                frame_delay=200):\n    fig, ax = plt.subplots(figsize=(15, 10))\n    ims = []\n    if not subplot:\n        shape = imgs.shape[0]\n        for i in range(duration):\n            im = ax.imshow(imgs[i % shape], animated=True)\n            ims.append([im])\n        plt.close(fig)\n    else:\n        shapes = [imgs[views[0]].shape[0], imgs[views[1]].shape[0], \n                  imgs[views[2]].shape[0], imgs[views[3]].shape[0]]\n        fig, ax = plt.subplots(2,2, figsize=(10,10))\n        for k in range(duration):\n            im_ = []\n            for i in range(2):\n                for j in range(2):\n                    im = ax[i,j].imshow(imgs[views[2*i+j]][k % shapes[2*i+j]], animated=True)\n                    im_.append(im)\n                    ax[i,j].set_title(views[2*i+j])\n                    plt.close()\n            ims.append(im_)\n\n    ani = animation.ArtistAnimation(fig, ims, interval=frame_delay, blit=True, repeat_delay=1000)\n\n    ani.save(output)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:17:53.561063Z","iopub.execute_input":"2021-07-23T02:17:53.561429Z","iopub.status.idle":"2021-07-23T02:17:53.575186Z","shell.execute_reply.started":"2021-07-23T02:17:53.561395Z","shell.execute_reply":"2021-07-23T02:17:53.574216Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_video(imgs, duration=60, subplot=True, frame_delay=300)\nplay('/kaggle/working/vis_video.mp4')","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:17:54.355920Z","iopub.execute_input":"2021-07-23T02:17:54.356241Z","iopub.status.idle":"2021-07-23T02:18:07.850504Z","shell.execute_reply.started":"2021-07-23T02:17:54.356209Z","shell.execute_reply":"2021-07-23T02:18:07.849612Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Data Loader**","metadata":{}},{"cell_type":"code","source":"# let's write a simple pytorch dataloader\n\n\nclass BrainTumor(Dataset):\n    def __init__(self, path = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification', split = \"train\", validation_split = 0.2):\n        # labels\n        train_data = pd.read_csv(os.path.join(path, 'train_labels.csv'))\n        self.labels = {}\n        brats = list(train_data[\"BraTS21ID\"])\n        mgmt = list(train_data[\"MGMT_value\"])\n        for b, m in zip(brats, mgmt):\n            self.labels[str(b).zfill(5)] = m\n            \n        if split == \"valid\":\n            self.split = split\n            self.ids = [a.split(\"/\")[-1] for a in sorted(glob.glob(path + f\"/train/\" + \"/*\"))]\n            self.ids = self.ids[:int(len(self.ids)* validation_split)] # first 20% as validation\n        elif split == \"train\":\n            self.split = split\n            self.ids = [a.split(\"/\")[-1] for a in sorted(glob.glob(path + f\"/{split}/\" + \"/*\"))]\n            self.ids = self.ids[int(len(self.ids)* validation_split):] # last 80% as train\n        else:\n            self.split = split\n            self.ids = [a.split(\"/\")[-1] for a in sorted(glob.glob(path + f\"/{split}/\" + \"/*\"))]\n            \n    \n    def __len__(self):\n        return len(self.ids)\n    \n    def __getitem__(self, idx):\n        imgs = load_3d_dicom_images(self.ids[idx], self.split)\n        imgs = imgs - imgs.min()\n        imgs = (imgs + 1e-5) / (imgs.max() - imgs.min() + 1e-5)\n        \n        # imgs = imgs - imgs.mean()\n        # imgs = (imgs + 1e-5)/(imgs.std() + 1e-5)\n        \n        if self.split != \"test\":\n            label = self.labels[self.ids[idx]]\n            return torch.tensor(imgs, dtype = torch.float32).permute(-1, 0, 1, 2), torch.tensor(label, dtype = torch.long)\n        else:\n            return torch.tensor(imgs, dtype = torch.float32).permute(-1, 0, 1, 2)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:21:48.447189Z","iopub.execute_input":"2021-07-23T02:21:48.447574Z","iopub.status.idle":"2021-07-23T02:21:48.462342Z","shell.execute_reply.started":"2021-07-23T02:21:48.447537Z","shell.execute_reply":"2021-07-23T02:21:48.461346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# testing the dataloader\ntrain_dataset = BrainTumor()\ntrain_bs = 4\ntrain_loader = DataLoader(train_dataset, batch_size = train_bs, shuffle=True)\n\nval_dataset = BrainTumor(split = \"valid\")\nval_bs = 2\nval_loader = DataLoader(val_dataset, batch_size = val_bs, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:21:51.459669Z","iopub.execute_input":"2021-07-23T02:21:51.460016Z","iopub.status.idle":"2021-07-23T02:21:51.483116Z","shell.execute_reply.started":"2021-07-23T02:21:51.459988Z","shell.execute_reply":"2021-07-23T02:21:51.482369Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for img, label in train_loader:\n    print(img.shape)\n    print(img.max())\n    print(img.mean())\n    print(img.min())\n    print(label.shape)\n    break\n\nfor img, label in val_loader:\n    print(img.shape)\n    print(label.shape)\n    break","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:22:03.380137Z","iopub.execute_input":"2021-07-23T02:22:03.380491Z","iopub.status.idle":"2021-07-23T02:22:13.684191Z","shell.execute_reply.started":"2021-07-23T02:22:03.380460Z","shell.execute_reply":"2021-07-23T02:22:13.680839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Model: EfficientNet-3D B0**","metadata":{}},{"cell_type":"code","source":"PATH = \"../input/rsna-efficientnet3db0/best_roc_0.29_loss_1826.83.pt\" # using a pretrained weight\n\nmodel = EfficientNet3D.from_name(\"efficientnet-b0\", override_params={'num_classes': 2}, in_channels=4)\nmodel.load_state_dict(torch.load(PATH))\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.AdamW(model.parameters(),lr = 0.0007, weight_decay=0.08)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=3, factor=0.25)\nn_epochs = 10","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:28:16.009760Z","iopub.execute_input":"2021-07-23T02:28:16.010097Z","iopub.status.idle":"2021-07-23T02:28:20.868909Z","shell.execute_reply.started":"2021-07-23T02:28:16.010067Z","shell.execute_reply":"2021-07-23T02:28:20.868079Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(model)\nmodel(torch.randn(1, 4, 256, 256, 64))","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:28:28.670674Z","iopub.execute_input":"2021-07-23T02:28:28.671002Z","iopub.status.idle":"2021-07-23T02:28:30.626157Z","shell.execute_reply.started":"2021-07-23T02:28:28.670973Z","shell.execute_reply":"2021-07-23T02:28:30.625276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Training**","metadata":{}},{"cell_type":"code","source":"# helper\ndef one_hot(arr):\n    return [[1, 0] if a_i == 0 else [0, 1] for a_i in arr]","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:28:25.838434Z","iopub.execute_input":"2021-07-23T02:28:25.838771Z","iopub.status.idle":"2021-07-23T02:28:25.842605Z","shell.execute_reply.started":"2021-07-23T02:28:25.838743Z","shell.execute_reply":"2021-07-23T02:28:25.841784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# let's train\ngpu = torch.device(f\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(gpu)\n\ntrain_loss = []\nval_loss = []\ntrain_roc = []\nval_roc = []\nbest_roc = 0.0\n\nfor epoch in range(n_epochs):  # loop over the dataset multiple times\n    y_all = []\n    outputs_all = []\n    running_loss = 0.0\n    roc = 0.0\n    \n    model.train()\n    for i, data in tqdm(enumerate(train_loader, 0)):\n        x, y = data\n        \n        # x = torch.unsqueeze(x, dim = 1)\n        x = x.to(gpu)\n        y = y.to(gpu)\n\n        # zero the parameter gradients\n        optimizer.zero_grad()\n\n        # forward + backward + optimize\n        outputs = model(x)\n        loss = criterion(outputs, y)\n        loss.backward()\n        optimizer.step()\n\n        # print statistics\n        running_loss += loss.item()\n        y_all.extend(y.tolist())\n        outputs_all.extend(outputs.tolist())\n    \n    roc += roc_auc_score(one_hot(y_all), outputs_all) / train_bs\n    print(f\"epoch {epoch+1} train loss: {running_loss} train roc: {roc}\")\n    \n    train_loss.append(running_loss)\n    train_roc.append(roc)\n\n    y_all = []\n    outputs_all = []\n    running_loss = 0.0\n    roc = 0.0 \n    \n    model.eval()\n    for i, data in tqdm(enumerate(val_loader, 0)):\n\n        x, y = data\n        \n        # x = torch.unsqueeze(x, dim = 1)\n        x = x.to(gpu)\n        y = y.to(gpu)\n\n        # forward\n        outputs = model(x)\n        loss = criterion(outputs, y)\n\n        # print statistics\n        running_loss += loss.item()\n        y_all.extend(y.tolist())\n        outputs_all.extend(outputs.tolist())\n    \n    roc += roc_auc_score(one_hot(y_all), outputs_all) / val_bs\n    scheduler.step(running_loss)\n        \n    print(f\"epoch {epoch+1} val loss: {running_loss} val roc: {roc}\")\n    \n    val_loss.append(running_loss)\n    val_roc.append(roc)\n    \n    if roc > best_roc:\n        best_roc = roc\n        torch.save(model.state_dict(), f'best_roc_{round(roc, 2)}_loss_{round(running_loss, 2)}.pt')","metadata":{"execution":{"iopub.status.busy":"2021-07-23T02:28:41.821987Z","iopub.execute_input":"2021-07-23T02:28:41.822405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(train_loss, label = 'train loss')\nplt.plot(val_loss, label = 'val loss')\nplt.xlabel('epochs')\nplt.ylabel('loss')\nplt.legend(['train loss', 'val loss'])\nplt.show()\n\nplt.plot(train_roc, label = 'train roc')\nplt.plot(val_roc, label = 'val roc')\nplt.xlabel('epochs')\nplt.ylabel('roc auc')\nplt.legend(['train roc', 'val roc'])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-22T03:16:32.946176Z","iopub.execute_input":"2021-07-22T03:16:32.946574Z","iopub.status.idle":"2021-07-22T03:16:33.291648Z","shell.execute_reply.started":"2021-07-22T03:16:32.946537Z","shell.execute_reply":"2021-07-22T03:16:33.290808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv\")\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}