{"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":"## EDA","metadata":{}},{"cell_type":"code","source":"#load python lobraries\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pydicom # handle dcm format\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport glob","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-26T09:33:25.328343Z","iopub.execute_input":"2022-05-26T09:33:25.328621Z","iopub.status.idle":"2022-05-26T09:33:25.333542Z","shell.execute_reply.started":"2022-05-26T09:33:25.328592Z","shell.execute_reply":"2022-05-26T09:33:25.332372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pydicom # handle dcm format\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport glob\nimport os","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:33:27.953128Z","iopub.execute_input":"2022-05-26T09:33:27.953794Z","iopub.status.idle":"2022-05-26T09:33:27.960679Z","shell.execute_reply.started":"2022-05-26T09:33:27.953737Z","shell.execute_reply":"2022-05-26T09:33:27.959951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !mkdir output\n# df = pd.read_csv('../input/submission-file/sample_submission (2).csv')\n# df.to_csv('output/submission.csv',index=False)\n# df.to_csv('submission.csv',index=False)\n# pd.read_csv('output/submission.csv')","metadata":{"execution":{"iopub.status.busy":"2022-05-25T10:10:10.719595Z","iopub.execute_input":"2022-05-25T10:10:10.720349Z","iopub.status.idle":"2022-05-25T10:10:11.494796Z","shell.execute_reply.started":"2022-05-25T10:10:10.720309Z","shell.execute_reply":"2022-05-25T10:10:11.494103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#material (dicom mri images deep learning , dicom image processing python)\n#https://medium.com/analytics-vidhya/dicom-and-deep-learning-63373e99d79a\n#https://towardsdatascience.com/understanding-dicoms-835cd2e57d0b\n#important features we can extract from dicom fileset\n#dicom mri images deep learning , dicom image processing python ,important header elements in diacom files for deep learning\n#important features we can extract from dicom files\n#important header elements in diacom files for deep learning\n#https://www.researchgate.net/post/Convolutional_Neural_network_for_stack_of_CT_or_MRI_images/61812b52b8ca5f507e065c3b/citation/download\n#https://towardsdatascience.com/understanding-dicom-bce665e62b72\n#https://towardsdatascience.com/medical-image-pre-processing-with-python-d07694852606","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Load the data into dataframe","metadata":{}},{"cell_type":"code","source":"#load the training lables\ntrain_label_df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\ntrain_label_df","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:33:32.245165Z","iopub.execute_input":"2022-05-26T09:33:32.245684Z","iopub.status.idle":"2022-05-26T09:33:32.274984Z","shell.execute_reply.started":"2022-05-26T09:33:32.245649Z","shell.execute_reply":"2022-05-26T09:33:32.274291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## check class imbalance","metadata":{}},{"cell_type":"code","source":"#check class imbalance\nplt.figure(figsize=(5, 5))\nsns.countplot(data=train_label_df, x=\"MGMT_value\");","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:33:36.669874Z","iopub.execute_input":"2022-05-26T09:33:36.670957Z","iopub.status.idle":"2022-05-26T09:33:36.864534Z","shell.execute_reply.started":"2022-05-26T09:33:36.670904Z","shell.execute_reply":"2022-05-26T09:33:36.863781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- data set is balance dataset","metadata":{}},{"cell_type":"markdown","source":"### Headers in dicom images","metadata":{}},{"cell_type":"code","source":"def load_dicom(path):\n    dicom = pydicom.read_file(path)\n    return dicom\nload_dicom('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/00000/FLAIR/Image-1.dcm')","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:33:52.968568Z","iopub.execute_input":"2022-05-26T09:33:52.969099Z","iopub.status.idle":"2022-05-26T09:33:52.995082Z","shell.execute_reply.started":"2022-05-26T09:33:52.969061Z","shell.execute_reply":"2022-05-26T09:33:52.994436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pydicom # handle dcm format\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport glob\nimport os","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:33:59.735716Z","iopub.execute_input":"2022-05-26T09:33:59.736058Z","iopub.status.idle":"2022-05-26T09:33:59.742444Z","shell.execute_reply.started":"2022-05-26T09:33:59.736016Z","shell.execute_reply":"2022-05-26T09:33:59.741744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### create dataframe with headers for eda","metadata":{}},{"cell_type":"code","source":"train_label_df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\n\nimp_headers = ['ImageType','Modality','SliceThickness','PatientPosition','StudyInstanceUID','SeriesInstanceUID','PhotometricInterpretation' ,'Rows','Columns','PixelSpacing','RescaleSlope','RescaleIntercept']\n\ntypes = (\"FLAIR\", \"T1w\", \"T1wCE\", \"T2w\")\ncolumn_list = ['BraTS21ID']\nfor file_type in types:\n    for header in imp_headers:\n        column_list.append(file_type+'_'+header)\ncolumn_list.append('MGMT_value')\nheader_df = pd.DataFrame(columns=column_list)\ncolumn_list\ndef fill_header_df(datapoints):\n    for point_ind , datapoint in enumerate(datapoints):\n        count = point_ind\n        df_row = []\n        folder_id = str(datapoint).zfill(5)\n        df_row.append(folder_id)\n        for type_index, type_val in enumerate(types, 1):\n            \n            patient_path = f'../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/{folder_id}/'\n            all_paths = sorted(\n                #glob used to return all file paths that match a specific pattern.\n                glob.glob(os.path.join(patient_path, type_val, \"*\")), \n                key=lambda x: int(x[:-4].split(\"-\")[-1]),\n            )\n            img_path = all_paths[int(len(all_paths) * 0.5)]\n            dicom_img = pydicom.read_file(img_path)\n            for header in imp_headers:\n                df_row.append(dicom_img[header].value)\n        df_row.append(train_label_df.loc[point_ind,'MGMT_value'])\n        header_df.loc[count] = df_row\nfill_header_df(train_label_df['BraTS21ID'])\nos.mkdir('output')\nheader_df.to_csv('output/header_df.csv',index=False)\nheader_df.head()\n","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:34:02.481192Z","iopub.execute_input":"2022-05-26T09:34:02.481448Z","iopub.status.idle":"2022-05-26T09:36:34.773293Z","shell.execute_reply.started":"2022-05-26T09:34:02.481419Z","shell.execute_reply":"2022-05-26T09:36:34.772613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"header_df = pd.read_csv('output/header_df.csv', index_col= False)","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:36:58.074249Z","iopub.execute_input":"2022-05-26T09:36:58.074508Z","iopub.status.idle":"2022-05-26T09:36:58.094264Z","shell.execute_reply.started":"2022-05-26T09:36:58.074480Z","shell.execute_reply":"2022-05-26T09:36:58.093637Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"header_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:37:01.448751Z","iopub.execute_input":"2022-05-26T09:37:01.449265Z","iopub.status.idle":"2022-05-26T09:37:01.474281Z","shell.execute_reply.started":"2022-05-26T09:37:01.449233Z","shell.execute_reply":"2022-05-26T09:37:01.473450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## check null values","metadata":{}},{"cell_type":"code","source":"header_df.isnull().sum()","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:37:05.670958Z","iopub.execute_input":"2022-05-26T09:37:05.671433Z","iopub.status.idle":"2022-05-26T09:37:05.683815Z","shell.execute_reply.started":"2022-05-26T09:37:05.671399Z","shell.execute_reply":"2022-05-26T09:37:05.683166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"there are no null values in any column","metadata":{}},{"cell_type":"markdown","source":"## plot the hisogram to count the values for  SliceThickness","metadata":{}},{"cell_type":"code","source":"#pixel spacing and slice thickness\n#plot hsitogram and eda\n\n#each feature with no of unique values\n# two features histograms and distribution \ntypes = ('FLAIR','T1w' , 'T1wCE' , 'T2w')\nfor image_type in types:\n    FLAIR_SliceThickness = header_df.FLAIR_SliceThickness.value_counts()\n    #plt.hist(header_df['FLAIR_SliceThickness'])\n    \n    sns.histplot(data=header_df, x=f\"{image_type}_SliceThickness\", hue=\"MGMT_value\", multiple=\"stack\")\n    plt.xlabel(f\"{image_type}_SliceThickness\")\n    plt.ylabel('counts')\n    plt.show()\n    header_df.FLAIR_SliceThickness.describe()","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:37:12.728247Z","iopub.execute_input":"2022-05-26T09:37:12.728511Z","iopub.status.idle":"2022-05-26T09:37:13.751531Z","shell.execute_reply.started":"2022-05-26T09:37:12.728481Z","shell.execute_reply":"2022-05-26T09:37:13.750824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Plot distribution graph for slice thick ness","metadata":{}},{"cell_type":"code","source":"#loop through\nfor image_type in types:\n    sns.distplot(header_df[header_df['MGMT_value'] == 0][f'{image_type}_SliceThickness'], hist=False, color=\"blue\" )\n    sns.distplot(header_df[header_df['MGMT_value'] == 1][f'{image_type}_SliceThickness'], hist=False, color=\"orange\")\n    plt.legend([0,1]) \n    plt.title(f'distribution of {image_type}_SliceThickness') \n    plt.show()\n    header_df[f'{image_type}_SliceThickness'].describe()","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:37:29.698921Z","iopub.execute_input":"2022-05-26T09:37:29.699174Z","iopub.status.idle":"2022-05-26T09:37:30.548545Z","shell.execute_reply.started":"2022-05-26T09:37:29.699147Z","shell.execute_reply":"2022-05-26T09:37:30.547825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## check stats for pixel spacing ","metadata":{}},{"cell_type":"code","source":"# check stats for pixel spacing \nfor image_type in types:\n    print(header_df[f'{image_type}_PixelSpacing'].describe(),'\\n'*2)\n","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:59:20.708424Z","iopub.execute_input":"2022-05-26T09:59:20.709116Z","iopub.status.idle":"2022-05-26T09:59:20.724121Z","shell.execute_reply.started":"2022-05-26T09:59:20.709079Z","shell.execute_reply":"2022-05-26T09:59:20.723431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Median and mode for pixel spacing  and slice thickness","metadata":{}},{"cell_type":"code","source":"for image_type in types:\n    \n    stats = header_df[f'{image_type}_PixelSpacing'].apply(lambda x:eval(x)[0] ).describe()\n    stats['median'] = header_df[f'{image_type}_PixelSpacing'].apply(lambda x:eval(x)[0] ).median()\n    print(stats)","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:59:41.281397Z","iopub.execute_input":"2022-05-26T09:59:41.281645Z","iopub.status.idle":"2022-05-26T09:59:41.338260Z","shell.execute_reply.started":"2022-05-26T09:59:41.281620Z","shell.execute_reply":"2022-05-26T09:59:41.337578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for image_type in types:\n    \n    stats = header_df[f'{image_type}_SliceThickness'].describe()\n    stats['median'] = header_df[f'{image_type}_SliceThickness'].median()\n    print(stats)","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:59:49.801542Z","iopub.execute_input":"2022-05-26T09:59:49.802175Z","iopub.status.idle":"2022-05-26T09:59:49.823906Z","shell.execute_reply.started":"2022-05-26T09:59:49.802140Z","shell.execute_reply":"2022-05-26T09:59:49.823112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#pairrwise histogram\nfor image_type in types:\n    value_counts = header_df[f'{image_type}_PixelSpacing'].value_counts()\n    # value_counts\n    top_header_df = header_df[header_df[f'{image_type}_PixelSpacing'].isin(value_counts.keys())]\n    PixelSpacing = top_header_df[f'{image_type}_PixelSpacing'].apply(lambda x:round(eval(x)[0],3) )\n    plt.figure(figsize=(16,8))\n    sns.histplot(data=top_header_df, x=PixelSpacing, hue=\"MGMT_value\", multiple=\"dodge\" )","metadata":{"execution":{"iopub.status.busy":"2022-05-26T09:59:55.561611Z","iopub.execute_input":"2022-05-26T09:59:55.562221Z","iopub.status.idle":"2022-05-26T09:59:56.774362Z","shell.execute_reply.started":"2022-05-26T09:59:55.562184Z","shell.execute_reply":"2022-05-26T09:59:56.773720Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### we need this plots and stats of pixel spacing and slice thickness to choose pixel spacing and sclice thickness to resample images it will give better model performance","metadata":{}},{"cell_type":"markdown","source":"## keep Columns with more than 1 unique values only","metadata":{}},{"cell_type":"code","source":"value_counts = header_df['FLAIR_PixelSpacing'].value_counts()\nprint(value_counts)","metadata":{"execution":{"iopub.status.busy":"2022-05-26T10:00:07.458398Z","iopub.execute_input":"2022-05-26T10:00:07.458658Z","iopub.status.idle":"2022-05-26T10:00:07.465464Z","shell.execute_reply.started":"2022-05-26T10:00:07.458630Z","shell.execute_reply":"2022-05-26T10:00:07.464793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# loop through and exclude unique values , discrd those features who have only one unique values\ncloumns_exclude = [(column , len(header_df[column].value_counts()) ) for column in header_df.columns if len(header_df[column].value_counts()) > 1]\ncloumns_exclude","metadata":{"execution":{"iopub.status.busy":"2022-05-26T10:00:11.853179Z","iopub.execute_input":"2022-05-26T10:00:11.853720Z","iopub.status.idle":"2022-05-26T10:00:11.895356Z","shell.execute_reply.started":"2022-05-26T10:00:11.853683Z","shell.execute_reply":"2022-05-26T10:00:11.894674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"columns_to_keep = [column for column in header_df.columns if len(header_df[column].value_counts()) > 1]\nfinal_header_df = header_df.loc[:,header_df.columns.isin(columns_to_keep)]\nfinal_header_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-26T10:09:56.029417Z","iopub.execute_input":"2022-05-26T10:09:56.029676Z","iopub.status.idle":"2022-05-26T10:09:56.076432Z","shell.execute_reply.started":"2022-05-26T10:09:56.029649Z","shell.execute_reply":"2022-05-26T10:09:56.075740Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model building\n","metadata":{}},{"cell_type":"code","source":"import torch\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pydicom # handle dcm format\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport glob\nimport os","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:33:31.244332Z","iopub.execute_input":"2022-05-24T10:33:31.244684Z","iopub.status.idle":"2022-05-24T10:33:31.253157Z","shell.execute_reply.started":"2022-05-24T10:33:31.244641Z","shell.execute_reply":"2022-05-24T10:33:31.252297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import DataLoader, Dataset\n#from models import resnet\n\n## sklearn\nfrom sklearn import model_selection\nfrom sklearn.metrics import roc_auc_score","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:33:31.255558Z","iopub.execute_input":"2022-05-24T10:33:31.25638Z","iopub.status.idle":"2022-05-24T10:33:31.267616Z","shell.execute_reply.started":"2022-05-24T10:33:31.256326Z","shell.execute_reply":"2022-05-24T10:33:31.26662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TrainDataset(Dataset):\n    def __init__(self, X_train_data , y_train_data , data_dir,  cohort='FLAIR'):\n        self.X_train_data = X_train_data\n        self.y_train_data = y_train_data\n        self.data_dir = data_dir\n        self.cohort = cohort\n    def __getitem__(self, idx):\n        # get sample info\n        #print(self.X_train_data[idx],'idx')\n        sample_id = self.X_train_data[idx] \n        target = self.y_train_data[idx]\n        # get sample path. combination of dir, padded id and cohort\n        sample_dir = os.path.join(self.data_dir, f'{sample_id:05d}', self.cohort)\n        sample_files = os.listdir(sample_dir)\n        #print(sample_dir,'sample_files')\n        # take subset of available images if n_images > 64\n        if len(sample_files) > 64:\n            sample_files = np.random.choice(sample_files, size=64, replace=False)\n            \n        # sort samples\n        sample_files = sorted(sample_files, key=lambda x: int(x[6:-4]))\n        \n        # load images\n        imgs = [self.read_img(os.path.join(sample_dir, path)) for path in sample_files]\n        imgs = np.stack(imgs)\n        \n        # resample images if not enough samples are available\n        if len(sample_files) < 64:\n            indices = sorted(np.random.choice(len(sample_files), size=64, replace=True))\n            imgs = np.stack(imgs[indices])\n        \n        imgs = np.stack(imgs)\n            \n        return torch.tensor(imgs, dtype=torch.float32).unsqueeze(0), torch.tensor(target, dtype=torch.float32)\n        \n    def __len__(self):\n        return len(self.X_train_data)\n    \n    def read_img(self, path):\n        img = self.read_dicom(path)\n        img = cv2.resize(img, (258, 258))\n        return img\n    \n    @staticmethod\n    def read_dicom(path):\n        dicom = pydicom.read_file(path)\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n        if 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        return data","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:33:37.641816Z","iopub.execute_input":"2022-05-24T10:33:37.642084Z","iopub.status.idle":"2022-05-24T10:33:37.658665Z","shell.execute_reply.started":"2022-05-24T10:33:37.642053Z","shell.execute_reply":"2022-05-24T10:33:37.655952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#nifti dataloader\nimport numpy as np\nimport nibabel as nib\nclass NiftiDataset(Dataset):\n    def __init__(self, X_train_data , y_train_data, data_dir,  cohort='FLAIR'):\n        self.X_train_data = X_train_data\n        self.y_train_data = y_train_data\n        self.data_dir = data_dir\n        self.cohort = cohort\n    def __getitem__(self, idx):\n        # get sample info\n        sample_id = self.X_train_data[idx] \n        \n        if type(self.y_train_data) == type(None):\n            target = []\n        else:\n            target = self.y_train_data[idx]\n        # get sample path. combination of dir, padded id and cohort\n        sample_dir = os.path.join(self.data_dir, f'{sample_id:05d}', self.cohort)\n        #final_tensor = get_padded_data(sample_dir , f'{sample_id:05d}')\n        img = nib.load(f'{sample_dir}/{sample_id:05d}_FLAIR.nii.gz')\n        final_tensor = img.get_fdata()\n        final_tensor = final_tensor - np.min(final_tensor)\n        final_tensor = final_tensor / np.max(final_tensor)\n        return torch.tensor(final_tensor, dtype=torch.float32).unsqueeze(0), torch.tensor(target, dtype=torch.float32)\n        \n    def __len__(self):\n        return len(self.X_train_data)\n    ","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:33:40.617533Z","iopub.execute_input":"2022-05-24T10:33:40.618156Z","iopub.status.idle":"2022-05-24T10:33:40.630866Z","shell.execute_reply.started":"2022-05-24T10:33:40.618116Z","shell.execute_reply":"2022-05-24T10:33:40.629768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#load the training lables\nfrom sklearn.model_selection import train_test_split\ntrain_label_df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\ntrain_label_df = train_label_df[train_label_df.BraTS21ID.isin(list(map(int, os.listdir('../input/dicom-to-normalized-nifti-with-torchio/processed/train/') )))]\n\nX = train_label_df['BraTS21ID']\ny = train_label_df['MGMT_value']\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.33, random_state=42, stratify=y)\nX_test = X_test.reset_index(drop= True)\ny_test = y_test.reset_index(drop= True)\nX_train = X_train.reset_index(drop= True)\ny_train = y_train.reset_index(drop= True)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:33:43.161956Z","iopub.execute_input":"2022-05-24T10:33:43.162232Z","iopub.status.idle":"2022-05-24T10:33:43.188247Z","shell.execute_reply.started":"2022-05-24T10:33:43.1622Z","shell.execute_reply":"2022-05-24T10:33:43.187306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#!rm -rf MedicalNet\n#!git clone https://github.com/Tencent/MedicalNet","metadata":{"execution":{"iopub.status.busy":"2022-05-24T09:27:59.162818Z","iopub.execute_input":"2022-05-24T09:27:59.163223Z","iopub.status.idle":"2022-05-24T09:28:02.226413Z","shell.execute_reply.started":"2022-05-24T09:27:59.163188Z","shell.execute_reply":"2022-05-24T09:28:02.225353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"#pip install -r ./MedicalNet/requirements.txt","metadata":{"execution":{"iopub.status.busy":"2022-05-24T09:28:06.172326Z","iopub.execute_input":"2022-05-24T09:28:06.173197Z","iopub.status.idle":"2022-05-24T09:28:09.038094Z","shell.execute_reply.started":"2022-05-24T09:28:06.173151Z","shell.execute_reply":"2022-05-24T09:28:09.037122Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nimport os\nimport random\nimport time\n\n#run following steps\nos.system('cp -r ../input/medical-net-files/data/ ../input/medical-net/MedicalNet-master')\nos.system('cp -r ../input/medical-net-files/pretrain/ ../input/medical-net/MedicalNet-master')\nos.system('cp -r ../input/medical-net-files/trails/ ../input/medical-net/MedicalNet-master')\nos.system('touch ../input/medical-net/MedicalNet-master/__init__.py')\nsys.path.append('../input/medical-net/MedicalNet-master')\nimport MedicalNet.model","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:33:46.658128Z","iopub.execute_input":"2022-05-24T10:33:46.658865Z","iopub.status.idle":"2022-05-24T10:34:23.736959Z","shell.execute_reply.started":"2022-05-24T10:33:46.658819Z","shell.execute_reply":"2022-05-24T10:34:23.735677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    # system\n    seed=42\n    no_cuda=False\n    \n    # model\n    model_name = 'resnet_34_23dataset'\n    use_pretrained = True\n    \nclass TrainerConfig:\n    num_epochs = 20\n    batch_size = 4\n    gradient_accumulation_steps = 1\n\n    # optimizer\n    lr = 3e-2\n    warm_up_ratio = 0.1\n    weight_decay = 0.0\n\n    # log every log_steps to wandb\n    log_steps = 20\n\n    # environment\n    device = 'cuda'\ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n    \n# MedicalNet expect a class to hold hyperparameters\nclass Struct:\n    def __init__(self, entries):\n        self.__dict__.update(entries)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:37:08.842918Z","iopub.execute_input":"2022-05-24T10:37:08.843221Z","iopub.status.idle":"2022-05-24T10:37:08.852344Z","shell.execute_reply.started":"2022-05-24T10:37:08.843189Z","shell.execute_reply":"2022-05-24T10:37:08.851335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# system setup\nseed_everything(CFG.seed)\nDEVICE = torch.device(\"cuda\") if torch.cuda.is_available() and not CFG.no_cuda else torch.device(\"cuda\")\nDEVICE = torch.device(\"cuda\")","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:37:12.471147Z","iopub.execute_input":"2022-05-24T10:37:12.471958Z","iopub.status.idle":"2022-05-24T10:37:12.477844Z","shell.execute_reply.started":"2022-05-24T10:37:12.471916Z","shell.execute_reply":"2022-05-24T10:37:12.47682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model specific args\nmodel_pretrained_params = {\n    'resnet_10': {'model_depth': 10, 'resnet_shortcut': 'B'},\n    'resnet_10_23dataset': {'model_depth': 10, 'resnet_shortcut': 'B'},\n    'resnet_18': {'model_depth': 18, 'resnet_shortcut': 'A'},\n    'resnet_18_23dataset': {'model_depth': 18, 'resnet_shortcut': 'A'},\n    'resnet_34': {'model_depth': 34, 'resnet_shortcut': 'A'},\n    'resnet_34_23dataset': {'model_depth': 34, 'resnet_shortcut': 'A'},\n    'resnet_50': {'model_depth': 50, 'resnet_shortcut': 'B'},\n    'resnet_50_23dataset': {'model_depth': 50, 'resnet_shortcut': 'B'},\n    'resnet_101': {'model_depth': 101, 'resnet_shortcut': 'B'},\n    'resnet_152': {'model_depth': 152, 'resnet_shortcut': 'B'},\n    'resnet_200': {'model_depth': 200, 'resnet_shortcut': 'B'},\n}\n# consistent args\nopts = {\n    'model': 'resnet',\n    'input_W': 256,\n    'input_H': 256,\n    'input_D': 64,\n    'no_cuda': CFG.no_cuda,\n    'n_seg_classes': 1,\n    'phase': 'train',\n    'pretrain_path': None,\n    'gpu_id': [1],\n}\n\n# merge modelspecific args and global args\nfor model_name, model_dict in model_pretrained_params.items():\n    model_pretrained_params[model_name] = Struct({**model_dict, **opts})\n    \n    \n# MedicalNet with a global pooling head\nclass MedicalNetWithHead(nn.Module):\n    def __init__(self, model_name, pretrain_path=None):\n        super().__init__()\n        self.model_name = model_name\n        \n        model, parameters = MedicalNet.model.generate_model(model_pretrained_params[model_name])\n        self.medical_net = model\n        self.drop_in = nn.Dropout(p=0.1)\n        \n        # init model with pretrained weights\n        if not pretrain_path and CFG.use_pretrained:\n            self.init_model()\n            \n        # use simple pooling for now\n        self.pool = nn.AdaptiveAvgPool3d(1)\n        \n    def forward(self, x):\n        x = self.medical_net(self.drop_in(x))\n        out = self.pool(x)\n        return out\n            \n    def init_model(self):\n        net_dict = self.medical_net.state_dict()\n        # load pretrain\n        pretrain = torch.load(f'../input/medical-net/MedicalNet-master/pretrain/{self.model_name}.pth', map_location=DEVICE)\n        net_dict.update(pretrain_dict)\n        self.medical_net.load_state_dict(net_dict)\n        print(\"loaded pretrained weights\")","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:37:14.427109Z","iopub.execute_input":"2022-05-24T10:37:14.427494Z","iopub.status.idle":"2022-05-24T10:37:14.445161Z","shell.execute_reply.started":"2022-05-24T10:37:14.427455Z","shell.execute_reply":"2022-05-24T10:37:14.444042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def collate_fn(data):\n    \"\"\"\n       data: is a list of tuples with (example, label, length)\n             where 'example' is a tensor of arbitrary shape\n             and label/length are scalars\n    \"\"\"\n    height_max , width_max , depth_max  = 0,0,0\n    data_return = []\n    lebels_return = []\n    for ind , data_point in enumerate(data):\n        ind , height , width , depth  = data[ind][0].shape\n        height_max = max(height_max ,height )\n        width_max = max(width_max ,width )\n        depth_max = max(depth_max ,depth )\n    for ind,data_tensor in enumerate(data):\n        padded_data = torch.zeros((1,height_max,width_max ,depth_max))\n        padded_data[0,:data[ind][0].shape[1],:data[ind][0].shape[2],:data[ind][0].shape[3]] = data_tensor[0][0]\n        \n        data_return.append(padded_data)\n        if data[ind][1].nelement():\n            lebels_return.append(data[ind][1])\n    return torch.cat(data_return ,0).unsqueeze(1), torch.tensor(lebels_return)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:37:18.285929Z","iopub.execute_input":"2022-05-24T10:37:18.288479Z","iopub.status.idle":"2022-05-24T10:37:18.301966Z","shell.execute_reply.started":"2022-05-24T10:37:18.288419Z","shell.execute_reply":"2022-05-24T10:37:18.300946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install tensorboard\n#!tensorboard --logdir=runs","metadata":{"execution":{"iopub.status.busy":"2022-05-24T09:29:22.497154Z","iopub.execute_input":"2022-05-24T09:29:22.498105Z","iopub.status.idle":"2022-05-24T09:29:34.696685Z","shell.execute_reply.started":"2022-05-24T09:29:22.498043Z","shell.execute_reply":"2022-05-24T09:29:34.69556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.tensorboard import SummaryWriter\nwriter = SummaryWriter()\nclass AverageMeter(object):\n    \"\"\"\n    Computes and stores the average and current value\n    Copied from: https://github.com/pytorch/examples/blob/master/imagenet/main.py\n    \"\"\"\n\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\n\nclass Trainer:\n    def __init__(self, cfg: type(TrainerConfig),\n                 model: torch.nn.Module,\n                 model_path: str,\n                 dataset_train: Dataset = None,\n                 dataset_val: Dataset = None,\n                 #wandb_run: wandb.sdk.wandb_run.Run = None\n                 ):\n        self.cfg = cfg\n        self.model = model\n        self.best_model = None\n        self.model_path = model_path\n        #self.wandb_run = wandb_run\n\n        # datasets\n        self.dataset_train = dataset_train\n        self.dataset_eval = dataset_val\n\n        # dataloaders, train/eval is optional\n        kwargs_dataloader = {'batch_size': self.cfg.batch_size, 'num_workers': 2 , 'collate_fn' : collate_fn}\n        if self.dataset_eval is not None:\n            self.dataloader_train = DataLoader(self.dataset_train, shuffle=True, **kwargs_dataloader  )\n        if self.dataset_eval is not None:\n            self.dataloader_eval = DataLoader(self.dataset_eval, shuffle=False, **kwargs_dataloader)\n\n        # setup loss\n        self.loss_fnc = torch.nn.BCEWithLogitsLoss()\n\n        # if train set is provided, setup training\n        if dataset_train is not None:\n            self.optimizer = torch.optim.SGD(self.model.parameters(), self.cfg.lr, weight_decay=self.cfg.weight_decay, momentum=0.9)\n            #self.optimizer = torch.optim.Adam(self.model.parameters(), lr=0.0001)\n            self.scheduler = torch.optim.lr_scheduler.ExponentialLR(self.optimizer, gamma=0.9)\n            # call optimizer once so we can properly init the lr in step_train()\n            self.optimizer.zero_grad()\n            self.optimizer.step()\n            \n        else:\n            self.optimizer = None\n            self.scheduler = None\n            \n        self.epoch = 0\n\n    def train(self):\n        print(f'Training model for {self.cfg.num_epochs} epochs.')\n        print('Epoch | train_loss | eval_loss | train_auc | val_auc')\n        train_log = pd.DataFrame(columns=['epoch', 'train_loss', 'eval_loss', 'train_auc', 'eval_auc', 'lr'])\n        \n        best_loss = 1e3\n\n        for epoch in range(self.cfg.num_epochs):\n            train_loss, train_auc = self.step_train()\n            eval_loss, eval_auc = self.step_eval(return_predictions=False)\n            writer.add_scalar('Loss_epoch/train', train_loss, self.epoch)\n            writer.add_scalar('auc_epoch/train', train_auc,self.epoch)\n            writer.add_scalar('Loss/test', eval_loss, self.epoch)\n            writer.add_scalar('auc/test', eval_auc, self.epoch)\n            \n            log_item = {\n                'epoch': epoch,\n                'step': epoch*len(self.dataloader_train),\n                'train_loss': train_loss,\n                'eval_loss': eval_loss,\n                'train_auc': train_auc,\n                'eval_auc': eval_auc,\n                'lr': self.optimizer.param_groups[0]['lr']\n            }\n            #self.wandb_run.log(log_item)\n            train_log = train_log.append(log_item, ignore_index=True)\n            print(f\"{epoch: <6}|{train_loss: >12.3f}|{eval_loss: >11.3f}|{train_auc: >11.3f}|{eval_auc: >8.3f}\")\n      \n            # checkpointing\n            if eval_loss < best_loss:\n                torch.save(self.model, self.model_path)\n                best_loss = eval_loss\n            self.epoch += 1\n        best_epoch = train_log.eval_loss.idxmin()\n        print(\"Training done. Best model at epoch {} with eval_loss {:3.2f} and auc {:3.2f}\".format(\n            train_log.loc[best_epoch, 'epoch'],\n            train_log.loc[best_epoch, 'eval_loss'],\n            train_log.loc[best_epoch, 'eval_auc']\n        ))\n        return train_log\n\n    def step_train(self):\n        self.model.train()\n        \n        # setup logging\n        loss_agg = AverageMeter()\n        targets = []\n        predictions = []\n        steps_per_ep = len(self.dataset_train)//self.cfg.batch_size +1\n        # train one epoch\n        for batch_idx, (x, y) in enumerate(self.dataloader_train):\n            \n            x = x.to(self.cfg.device)\n            y = y.to(self.cfg.device)\n            \n            # forward pass  \n            logits = self.model(x)\n            loss = self.loss_fnc(logits.view(-1), y)\n            writer.add_scalar('Loss_step/train', loss, self.epoch*steps_per_ep + batch_idx)\n            batch_pred = torch.sigmoid(logits.view(-1)).detach().cpu().squeeze().numpy()\n            batch_tar  = y.detach().cpu().squeeze().numpy()\n            #batch_auc = roc_auc_score(batch_tar, batch_pred)\n            #writer.add_scalar('auc_step/train', batch_auc, self.epoch*steps_per_ep + batch_idx)\n            # backward pass\n            loss.backward()\n            if (batch_idx+1) % self.cfg.gradient_accumulation_steps == 0 or (batch_idx+1) == len(self.dataloader_train):\n                self.optimizer.step()\n                self.optimizer.zero_grad()\n                self.scheduler.step()\n\n            # update loss meter\n            loss_agg.update(loss.item(), self.cfg.batch_size)\n\n            # save preds/targets for roc computation\n            predictions.append(batch_pred)\n            targets.append(batch_tar)\n\n            # log every cfg.log_steps steps\n            if batch_idx > 0 and batch_idx % self.cfg.log_steps == 0:\n                log_item = {\n                    'step': self.epoch*len(self.dataloader_train) + batch_idx,\n                    'train_loss': loss_agg.avg,\n                    'train_auc': roc_auc_score(np.hstack(targets), np.hstack(predictions)),\n                    'lr': self.optimizer.param_groups[0]['lr']\n                }\n                #self.wandb_run.log(log_item)\n            \n        # compute auc for whole epoch\n        auc = roc_auc_score(np.hstack(targets), np.hstack(predictions))\n        \n        # tesorboard \n        \n        torch.cuda.empty_cache()\n        return loss_agg.avg, auc\n\n    @torch.no_grad()\n    def step_eval(self, return_predictions=False):\n        self.model.eval()\n        loss_agg = AverageMeter()\n        predictions = []\n        targets = []\n        for batch_idx, (x, y) in enumerate(self.dataloader_eval):\n            x = x.to(self.cfg.device)\n            y = y.to(self.cfg.device)\n            logits = self.model(x)\n            loss = self.loss_fnc(logits.view(-1), y)\n\n            # update loss meter\n            loss_agg.update(loss.item(), self.cfg.batch_size)\n\n            # optionally return predictions\n            # save preds/targets for roc computation\n            predictions.append(torch.sigmoid(logits.view(-1)).detach().cpu().squeeze().numpy())\n            targets.append(y.detach().cpu().squeeze().numpy())\n            \n        # compute auc\n        targets = np.hstack(targets)\n        predictions = np.hstack(predictions)\n        auc = roc_auc_score(targets, predictions)\n        # setup output\n        if return_predictions:\n            out = (loss_agg.avg, auc, predictions)\n        else:\n            out = (loss_agg.avg, auc)\n        return out\n    \n    def predict_results(self):\n        self.model.eval()\n        loss_agg = AverageMeter()\n        predictions = []\n        targets = []\n        for batch_idx, (x, y) in enumerate(self.dataloader_eval):\n            x = x.to(self.cfg.device)\n            logits = self.model(x)\n            # optionally return predictions\n            # save preds/targets for roc computation\n            predictions.append(torch.sigmoid(logits.view(-1)).detach().cpu().squeeze().numpy())\n\n        # get predictions\n        predictions = np.hstack(predictions)\n\n        return predictions\n    ","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:37:21.580854Z","iopub.execute_input":"2022-05-24T10:37:21.581475Z","iopub.status.idle":"2022-05-24T10:37:21.639374Z","shell.execute_reply.started":"2022-05-24T10:37:21.581434Z","shell.execute_reply":"2022-05-24T10:37:21.637966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2022-05-07T09:26:01.377866Z","iopub.execute_input":"2022-05-07T09:26:01.37818Z","iopub.status.idle":"2022-05-07T09:26:14.942804Z","shell.execute_reply.started":"2022-05-07T09:26:01.378145Z","shell.execute_reply":"2022-05-07T09:26:14.94144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#model training\ntraining_data = NiftiDataset(X_train,y_train, data_dir='../input/dicom-to-normalized-nifti-with-torchio/processed/train', cohort='FLAIR')\ntest_data = NiftiDataset(X_test,y_test, data_dir='../input/dicom-to-normalized-nifti-with-torchio/processed/train', cohort='FLAIR')\n\n#DEVICE = torch.device(\"cuda\")\nmodel = MedicalNetWithHead(model_name=CFG.model_name).to(DEVICE)\n\n# setup trainer\ntrainer = Trainer(cfg=TrainerConfig,\n                  model=model,\n                  model_path=f'model_save.torch',\n                  dataset_train=training_data,\n                  dataset_val=test_data,\n                  #wandb_run=wandb_run\n                 )\ntrain_log = trainer.train()\n#save the model\ntrain_log.to_csv(f\"model_log.csv\")\ntorch.save(model.state_dict(), './MedicalNet/final_model' )\n# added inference funtion\n","metadata":{"execution":{"iopub.status.busy":"2022-05-24T10:37:28.708633Z","iopub.execute_input":"2022-05-24T10:37:28.709012Z","iopub.status.idle":"2022-05-24T13:12:49.430482Z","shell.execute_reply.started":"2022-05-24T10:37:28.708971Z","shell.execute_reply":"2022-05-24T13:12:49.429485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## inference funtion","metadata":{}},{"cell_type":"code","source":"path_to_test_data = '../input/rsna-miccai-brain-tumor-radiogenomic-classification/test'\ndef create_submission_csv(path_to_test_data):\n    test_eval_data =  list(map(int,list(os.listdir(path_to_test_data))))\n    test_eval_dataset = NiftiDataset(test_eval_data, None, data_dir='../input/dicom-to-normalized-nifti-with-torchio/processed/test', cohort='FLAIR')\n    #test_eval_dataloader = DataLoader(test_eval_dataset, batch_size=3, shuffle=True)\n    model_test_pred= MedicalNetWithHead(model_name=CFG.model_name).to(DEVICE)\n    model_test_pred.load_state_dict(torch.load('../input/final-modal/model_submit.torch'))\n    #model_test_pred.eval()\n    trainer_pred = Trainer(cfg=TrainerConfig,\n                      model=model_test_pred,\n                      model_path=f'model_save.torch',\n                      dataset_train=training_data,\n                      dataset_val=test_eval_dataset,\n                      #wandb_run=wandb_run\n                     )\n    test_data_pred = trainer_pred.predict_results()\n    df = pd.DataFrame({'BraTS21ID': list(map(lambda sample_id: (5 - len(str(sample_id))) * '0'+str(sample_id) ,test_eval_data)),\n                       'MGMT_value': test_data_pred , \n                      })\n    df=df.set_index('BraTS21ID')\n    df.to_csv('submission.csv')\nprint(test_data_pred)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_submission_csv(path_to_test_data)","metadata":{"execution":{"iopub.status.busy":"2022-05-09T13:26:05.662938Z","iopub.execute_input":"2022-05-09T13:26:05.663497Z","iopub.status.idle":"2022-05-09T13:26:34.540424Z","shell.execute_reply.started":"2022-05-09T13:26:05.663458Z","shell.execute_reply":"2022-05-09T13:26:34.539308Z"},"trusted":true},"execution_count":null,"outputs":[]}]}