{"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":"reference\n\n- https://www.kaggle.com/ihelon/brain-tumor-eda-with-animations-and-modeling\n- https://www.kaggle.com/ayuraj/brain-tumor-eda-and-interactive-viz-with-w-b\n- https://www.kaggle.com/mikecho/rsna-miccai-monai-ensemble?scriptVersionId=74508923","metadata":{}},{"cell_type":"code","source":"import os\nimport sys \nimport json\nfrom glob import glob\nimport random\nimport collections\nimport time\nimport re\n\nimport numpy as np\nimport pandas as pd\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport torch\nfrom torch import nn\nfrom torch.utils import data as torch_data\nfrom sklearn import model_selection as sk_model_selection\nfrom torch.nn import functional as torch_functional\nimport torch.nn.functional as F\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import roc_auc_score","metadata":{"papermill":{"duration":1.048295,"end_time":"2021-07-14T20:26:46.309722","exception":false,"start_time":"2021-07-14T20:26:45.261427","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-09-14T06:53:50.411770Z","iopub.execute_input":"2021-09-14T06:53:50.412143Z","iopub.status.idle":"2021-09-14T06:53:53.244352Z","shell.execute_reply.started":"2021-09-14T06:53:50.412062Z","shell.execute_reply":"2021-09-14T06:53:53.243513Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA_PATH = '../input/rsna-miccai-brain-tumor-radiogenomic-classification'\nMRI_TYPES = ['FLAIR','T1w','T1wCE','T2w']\nSIZE = 256\nNUM_IMAGES = 64\nSEED = 42","metadata":{"lines_to_end_of_cell_marker":2,"lines_to_next_cell":2,"papermill":{"duration":0.05565,"end_time":"2021-07-14T20:26:46.486521","exception":false,"start_time":"2021-07-14T20:26:46.430871","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-09-14T06:53:55.192782Z","iopub.execute_input":"2021-09-14T06:53:55.193131Z","iopub.status.idle":"2021-09-14T06:53:55.198139Z","shell.execute_reply.started":"2021-09-14T06:53:55.193099Z","shell.execute_reply":"2021-09-14T06:53:55.197286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:53:58.651643Z","iopub.execute_input":"2021-09-14T06:53:58.651966Z","iopub.status.idle":"2021-09-14T06:53:58.686287Z","shell.execute_reply.started":"2021-09-14T06:53:58.651937Z","shell.execute_reply":"2021-09-14T06:53:58.685592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_patients = glob(os.path.join(DATA_PATH, 'train/*'))\ntest_patients = glob(os.path.join(DATA_PATH, 'test/*'))","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:54:01.192530Z","iopub.execute_input":"2021-09-14T06:54:01.192883Z","iopub.status.idle":"2021-09-14T06:54:01.269452Z","shell.execute_reply.started":"2021-09-14T06:54:01.192852Z","shell.execute_reply":"2021-09-14T06:54:01.268652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_patients[0]","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:54:04.168984Z","iopub.execute_input":"2021-09-14T06:54:04.169326Z","iopub.status.idle":"2021-09-14T06:54:04.175062Z","shell.execute_reply.started":"2021-09-14T06:54:04.169293Z","shell.execute_reply":"2021-09-14T06:54:04.174161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def natural_sort(l): \n    convert = lambda text: int(text) if text.isdigit() else text.lower()\n    alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]\n    return sorted(l, key=alphanum_key)\n\n# key: patient id , values: image paths for 4 types (dictionary, key: MRI type, value: image paths)\ndef get_dicom_data(split='train'):\n    '''\n    dicoms = {\n        '00688' (patient_id) :\n            {\n                'FLAIR' : [image paths ...]\n                'T1w' : [image paths ...]\n                'T1wCE' : [image paths ...]\n                'T2w' : [image paths ...]\n            }\n        ...\n    }\n    '''\n    \n    assert split == 'train' or split == 'test'\n    \n    dicoms = {}\n\n    for patient in glob(os.path.join(DATA_PATH, f'{split}/*')):\n        patient_id = patient.split('/')[-1]\n\n        d = {}\n        for t in MRI_TYPES:\n            t_images = glob(os.path.join(patient, f'{t}/*'))\n            d[f'{t}'] = natural_sort(t_images)\n\n        dicoms[f'{patient_id}'] = d\n    \n    return dicoms\n\ntrain_dicoms = get_dicom_data('train')\ntest_dicoms = get_dicom_data('test')","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:55:14.911636Z","iopub.execute_input":"2021-09-14T06:55:14.912185Z","iopub.status.idle":"2021-09-14T06:55:33.291648Z","shell.execute_reply.started":"2021-09-14T06:55:14.912145Z","shell.execute_reply":"2021-09-14T06:55:33.290785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_patient = list(train_dicoms.keys())[0]\nprint(f'patient id - {sample_patient}')\nfor i, v in train_dicoms[sample_patient].items():\n    print(f'{i} : {len(v)}')","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:55:33.293265Z","iopub.execute_input":"2021-09-14T06:55:33.293612Z","iopub.status.idle":"2021-09-14T06:55:33.301859Z","shell.execute_reply.started":"2021-09-14T06:55:33.293576Z","shell.execute_reply":"2021-09-14T06:55:33.300794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load 2D images","metadata":{}},{"cell_type":"code","source":"# Original from: https://www.kaggle.com/raddar/convert-dicom-to-np-array-the-correct-way\ndef read_mri(path, voi_lut=True, fix_monochrome=True):\n    dicom = pydicom.read_file(path)\n    # VOI LUT (if available by DICOM device) is used to transform raw DICOM data to \n    # \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n               \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        \n    data = data - np.min(data)\n    if np.max(data) != 0:\n        data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n        \n    return data","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:59:45.316987Z","iopub.execute_input":"2021-09-14T06:59:45.317324Z","iopub.status.idle":"2021-09-14T06:59:45.323606Z","shell.execute_reply.started":"2021-09-14T06:59:45.317288Z","shell.execute_reply":"2021-09-14T06:59:45.322667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def visualize_sample(patient_id, slice_ratio=0.5):\n    \n    dicoms = train_dicoms[patient_id]\n    \n    plt.figure(figsize=(16, 5))\n    \n    for i, t in enumerate(MRI_TYPES, 1):\n        slice_idx = int(len(dicoms[t]) * slice_ratio) - 1\n        sample_dicom = dicoms[t][slice_idx]\n        data = read_mri(sample_dicom)\n        plt.subplot(1, 4, i)\n        plt.imshow(data, cmap=\"gray\")\n        plt.title(f\"{t}\", fontsize=16)\n        plt.axis(\"off\")\n\n    mgmt_value = train_df[train_df.BraTS21ID == int(patient_id)].MGMT_value.item()\n    plt.suptitle(f\"MGMT_value: {mgmt_value}\", fontsize=16)\n    plt.show()\n    \nvisualize_sample(sample_patient)","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:59:47.076045Z","iopub.execute_input":"2021-09-14T06:59:47.076381Z","iopub.status.idle":"2021-09-14T06:59:47.501934Z","shell.execute_reply.started":"2021-09-14T06:59:47.076349Z","shell.execute_reply":"2021-09-14T06:59:47.501114Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load 3D images","metadata":{}},{"cell_type":"code","source":"from matplotlib import animation, rc\nrc('animation', html='jshtml')\n\n\ndef create_animation(ims):\n    fig = plt.figure(figsize=(6, 6))\n    plt.axis('off')\n    im = plt.imshow(ims[0], cmap=\"gray\")\n\n    def animate_func(i):\n        im.set_array(ims[i])\n        return [im]\n\n    return animation.FuncAnimation(fig, animate_func, frames = len(ims), interval = 1000//24)\n\ndef load_dicom_line(t_paths):\n    images = []\n    for filename in t_paths:\n        data = read_mri(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n        \n    return images\n\nimages = load_dicom_line(train_dicoms[sample_patient]['FLAIR'])\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-09-14T06:59:48.479368Z","iopub.execute_input":"2021-09-14T06:59:48.479678Z","iopub.status.idle":"2021-09-14T06:59:59.261668Z","shell.execute_reply.started":"2021-09-14T06:59:48.479649Z","shell.execute_reply":"2021-09-14T06:59:59.260697Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dicom_image(path, img_size=SIZE, voi_lut=True, rotate=0):\n    dicom = pydicom.read_file(path)\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom) if voi_lut else dicom.pixel_array\n    else:\n        data = dicom.pixel_array\n        \n    if np.min(data)==np.max(data):\n        data = np.zeros((img_size,img_size))\n        return data\n        \n    if rotate > 0:\n        rot_choices = [0, cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE, cv2.ROTATE_180]\n        data = cv2.rotate(data, rot_choices[rotate])\n        \n    data = cv2.resize(data, (img_size, img_size))\n    return data\n\ndef load_dicom_images_3d(scan_id, num_imgs=NUM_IMAGES, img_size=SIZE, mri_type=\"FLAIR\", split=\"train\"):\n    files = train_dicoms[scan_id][mri_type]\n    \n    images = []\n    for filename in files:\n        data = load_dicom_image(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n    \n    if num_imgs > 0:\n        assert len(images) >= num_imgs, f'len(images)({len(images)}) is less than num_imgs({num_imgs})'\n\n        every_nth = len(images) / num_imgs\n        indexes = [min(int(round(i*every_nth)), len(images)-1) for i in range(0,num_imgs)]\n        selected_images = [images[i] for i in indexes]\n    else:\n        selected_images = images\n    \n    img3d = np.stack(selected_images).T\n    \n    img3d = img3d - np.min(img3d)\n    if np.max(img3d) != 0:\n        img3d = img3d / np.max(img3d)\n    \n    return np.expand_dims(img3d,0)\n\nb = load_dicom_images_3d(sample_patient)\nprint(b.shape)\nprint(np.min(b), np.max(b), np.mean(b), np.median(b))","metadata":{"execution":{"iopub.status.busy":"2021-09-14T07:51:33.445698Z","iopub.execute_input":"2021-09-14T07:51:33.446018Z","iopub.status.idle":"2021-09-14T07:51:35.264903Z","shell.execute_reply.started":"2021-09-14T07:51:33.445988Z","shell.execute_reply":"2021-09-14T07:51:35.263434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mri_anim = [(b[0,:,:,i] * 255).astype(np.uint8) for i in range(NUM_IMAGES)]\ncreate_animation(mri_anim)","metadata":{"execution":{"iopub.status.busy":"2021-09-14T07:00:45.842151Z","iopub.execute_input":"2021-09-14T07:00:45.842507Z","iopub.status.idle":"2021-09-14T07:00:47.955064Z","shell.execute_reply.started":"2021-09-14T07:00:45.842475Z","shell.execute_reply":"2021-09-14T07:00:47.954133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from IPython.display import clear_output\nimport time\n\nfor mri_image in mri_anim:\n    plt.imshow(mri_image, cmap='gray')\n    plt.show()\n    time.sleep(0.01)\n    clear_output(wait=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-14T07:01:26.863817Z","iopub.execute_input":"2021-09-14T07:01:26.864132Z","iopub.status.idle":"2021-09-14T07:01:35.633412Z","shell.execute_reply.started":"2021-09-14T07:01:26.864103Z","shell.execute_reply":"2021-09-14T07:01:35.632558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    if torch.cuda.is_available():\n        torch.cuda.manual_seed_all(seed)\n        torch.backends.cudnn.deterministic = True\n\nset_seed(SEED)","metadata":{"papermill":{"duration":0.668331,"end_time":"2021-07-14T20:27:48.114522","exception":false,"start_time":"2021-07-14T20:27:47.446191","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-09-13T06:28:21.524984Z","iopub.execute_input":"2021-09-13T06:28:21.525329Z","iopub.status.idle":"2021-09-13T06:28:21.589631Z","shell.execute_reply.started":"2021-09-13T06:28:21.525301Z","shell.execute_reply":"2021-09-13T06:28:21.588799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create GIF using Imageio and log WanDB","metadata":{}},{"cell_type":"code","source":"def convert_3d_to_list(arr):\n    return [(arr[0,:,:,i] * 255).astype(np.uint8) for i in range(arr.shape[3])]","metadata":{"execution":{"iopub.status.busy":"2021-09-14T07:52:51.940045Z","iopub.execute_input":"2021-09-14T07:52:51.940378Z","iopub.status.idle":"2021-09-14T07:52:51.945072Z","shell.execute_reply.started":"2021-09-14T07:52:51.940346Z","shell.execute_reply":"2021-09-14T07:52:51.944108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import imageio\nimport wandb\nwandb.login()","metadata":{"execution":{"iopub.status.busy":"2021-09-14T07:09:07.673845Z","iopub.execute_input":"2021-09-14T07:09:07.674167Z","iopub.status.idle":"2021-09-14T07:09:31.924851Z","shell.execute_reply.started":"2021-09-14T07:09:07.674133Z","shell.execute_reply":"2021-09-14T07:09:31.923839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CONFIG = {\n    'IMG_SIZE': 224, \n    'NUM_FRAMES': 14,\n    'competition': 'rsna-miccai-brain', \n}","metadata":{"execution":{"iopub.status.busy":"2021-09-14T07:22:49.968689Z","iopub.execute_input":"2021-09-14T07:22:49.969021Z","iopub.status.idle":"2021-09-14T07:22:49.973791Z","shell.execute_reply.started":"2021-09-14T07:22:49.968984Z","shell.execute_reply":"2021-09-14T07:22:49.972618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"run = wandb.init(\n    entity = 'monet-kaggle',\n    project='brain-tumor-viz',\n    config=CONFIG,\n    job_type='vis-dataset-tables')","metadata":{"execution":{"iopub.status.busy":"2021-09-14T08:03:58.674720Z","iopub.execute_input":"2021-09-14T08:03:58.675048Z","iopub.status.idle":"2021-09-14T08:04:04.878430Z","shell.execute_reply.started":"2021-09-14T08:03:58.675018Z","shell.execute_reply":"2021-09-14T08:04:04.877481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"patient_ids = []\nfor patient_id in train_dicoms.keys():\n    if patient_id in ['00109', '00123', '00709']:\n        continue\n    patient_ids.append(patient_id)\nlen(patient_ids)","metadata":{"execution":{"iopub.status.busy":"2021-09-14T08:01:22.146951Z","iopub.execute_input":"2021-09-14T08:01:22.147300Z","iopub.status.idle":"2021-09-14T08:01:22.156361Z","shell.execute_reply.started":"2021-09-14T08:01:22.147244Z","shell.execute_reply":"2021-09-14T08:01:22.155348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_at = wandb.Table(columns=['patent_id', 'target', 'FLAIR', 'T1w', 't1wCE', 'T2w'])\n\nfor i, patient_id in enumerate(patient_ids):\n    os.makedirs('tables-gif/', exist_ok=True)\n    mgmt_value = train_df[train_df.BraTS21ID == int(patient_id)].MGMT_value.item()\n    \n    for j, mri_type in enumerate(MRI_TYPES):\n        arr_3d = load_dicom_images_3d(patient_id,\n                                      num_imgs=0,\n                                      img_size=CONFIG['IMG_SIZE'],\n                                      mri_type=mri_type,\n                                      split=\"train\")\n        frames = convert_3d_to_list(arr_3d)\n        imageio.mimsave(f'tables-gif/out-{patient_id}-{j}.gif', frames)\n    \n    data_at.add_data(\n        patient_id,\n        mgmt_value,\n        wandb.Image(f'tables-gif/out-{patient_id}-0.gif'),\n        wandb.Image(f'tables-gif/out-{patient_id}-1.gif'),\n        wandb.Image(f'tables-gif/out-{patient_id}-2.gif'),\n        wandb.Image(f'tables-gif/out-{patient_id}-3.gif'),\n    )\n\nwandb.log({'MRI Sequencing Dataset' : data_at})\nwandb.finish()","metadata":{"execution":{"iopub.status.busy":"2021-09-14T08:15:12.868450Z","iopub.execute_input":"2021-09-14T08:15:12.868801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## train / test splits","metadata":{}},{"cell_type":"code","source":"# because of some missing MRIs, 3 samples could be excluded\nsamples_to_exclude = [109, 123, 709]\n\ntrain_df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\nprint(\"original shape\", train_df.shape)\ntrain_df = train_df[~train_df.BraTS21ID.isin(samples_to_exclude)]\nprint(\"new shape\", train_df.shape)\ndisplay(train_df)\n\ndf_train, df_valid = sk_model_selection.train_test_split(\n    train_df, \n    test_size=0.2, \n    random_state=SEED, \n    stratify=train_df[\"MGMT_value\"],\n)","metadata":{"papermill":{"duration":0.633753,"end_time":"2021-07-14T20:27:49.350524","exception":false,"start_time":"2021-07-14T20:27:48.716771","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-09-13T15:00:04.795456Z","iopub.execute_input":"2021-09-13T15:00:04.795831Z","iopub.status.idle":"2021-09-13T15:00:04.821622Z","shell.execute_reply.started":"2021-09-13T15:00:04.795798Z","shell.execute_reply":"2021-09-13T15:00:04.820788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.tail()","metadata":{"execution":{"iopub.status.busy":"2021-09-13T15:00:07.414057Z","iopub.execute_input":"2021-09-13T15:00:07.414369Z","iopub.status.idle":"2021-09-13T15:00:07.423321Z","shell.execute_reply.started":"2021-09-13T15:00:07.414341Z","shell.execute_reply":"2021-09-13T15:00:07.422442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model and training classes","metadata":{}},{"cell_type":"code","source":"class BrainDataset(torch_data.Dataset):\n    def __init__(self, paths, targets=None, mri_type=None, label_smoothing=0.01, split=\"train\", augment=False):\n        self.paths = paths\n        self.targets = targets\n        self.mri_type = mri_type\n        self.label_smoothing = label_smoothing\n        self.split = split\n        self.augment = augment\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):\n        scan_id = self.paths[index]\n        if self.targets is None:\n            data = load_dicom_images_3d(str(scan_id).zfill(5), mri_type=self.mri_type[index], split=self.split)\n        else:\n            if self.augment:\n                rotation = np.random.randint(0,4)\n            else:\n                rotation = 0\n\n            data = load_dicom_images_3d(str(scan_id).zfill(5), mri_type=self.mri_type[index], split=\"train\", rotate=rotation)\n\n        if self.targets is None:\n            return {\"X\": torch.tensor(data).float(), \"id\": scan_id}\n        else:\n            y = torch.tensor(abs(self.targets[index]-self.label_smoothing), dtype=torch.float)\n            return {\"X\": torch.tensor(data).float(), \"y\": y}\n","metadata":{"papermill":{"duration":0.634322,"end_time":"2021-07-14T20:27:50.594701","exception":false,"start_time":"2021-07-14T20:27:49.960379","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-09-13T15:10:43.839742Z","iopub.execute_input":"2021-09-13T15:10:43.840068Z","iopub.status.idle":"2021-09-13T15:10:43.849612Z","shell.execute_reply.started":"2021-09-13T15:10:43.840037Z","shell.execute_reply":"2021-09-13T15:10:43.848584Z"},"trusted":true},"execution_count":null,"outputs":[]}]}