{"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":"https://www.kaggle.com/c/rsna-miccai-brain-tumor-radiogenomic-classification/overview\n\n# Definition\n\nMRI is an imaging modality that uses non-ionizing radiation to create useful diagnostic images.\nMRI is used to distinguish pathologic tissue such as a brain tumor or MS lesions from normal tissue.\nIn simple terms, an MRI scanner consists of a large, powerful magnet in which the patient lies. A radio wave antenna is used to send signals to the body and then a radiofrequency receiver detects the emitted signals. These returning signals are converted into images by a computer attached to the scanner. Imaging of any part of the body can be obtained in any plane.\nSource: MRI | Radiology Reference Article | Radiopaedia.org\n\n# Parameter Weighting\n\nFollowing are some of the main parameter weighting techniques being used in MRI:\n\nhttps://geekymedics.com/wp-content/uploads/2020/04/t1-and-t2-770x287.png\n\n## T1-weighted\n\nONE tissue is bright: fat\nprovides the most anatomically-relevant images\nshape of the brain can be clearly seen, and morphological abnormalities are easy to detect.\nfat is depicted in white and water in black.\ngrey matter is darker than white matter.\n\n## T2-weighted\n\nTWO tissues are bright: fat and water (WW2 – Water is White in T2)\nRegular T2 MRI's are important for tracking long-term disease progression.\nWhite matter is darker than grey\nLesions appear white.\nSuitable for lesion evaluation.\n\n## T1Gd\n\nA Gadolinium (gd)-Enhanced T1-Weighted scan reveals only new lesions. These are areas where the disease is currently active.\nBefore the MRI, an injection of gadolinium (gd) is administered. This will distinguish the active lesions from the normal parts of the brain.\nThis type of MRI will not show older, inactive lesions.\n\n## Fluid Attenuated Inversion Recovery (FLAIR)\n\nFLAIR is similar to T2, but the fluid is darker or \"suppressed\".\nIn T2, the spinal fluid (water) is white and the lesion is also white, so you have to look for the white in the white, which is difficult to understand. FLAIR can be roughly thought of as T2, in which the water is also black, making it easier to find the lesion.\n\n\n# Imaging Planes\n\nMagnetic resonance imaging (MRI) is partially defined by the plane or direction of the image that is taken. The most important model coordinate system for medical imaging is the anatomical coordinate system (also called patient coordinate system).\n\nThe Three Basic Anatomical Planes:\n\nThis coordinate system consists of three planes to describe the standard anatomical position of a human. The basic orientation terms for an MRI of the body taken: From the side would be a sagittal plane; from the front would be a coronal plane, and from the top down would be a transverse or axial plane.\n![Image](https://users.fmrib.ox.ac.uk/~stuart/thesis/chapter_3/image3_5.gif)\nSource: https://users.fmrib.ox.ac.uk/~stuart/thesis/chapter_3/section3_2.html\n\n## Sagittal plane\n\nAlso known as median plane.\nIt is a y-z plane, perpendicular to the ground, which separates left from right.\nThe mid-sagittal plane is the specific sagittal plane that is exactly in the middle of the body.\nA sagittal MRI looks at the brain from the side in a series of images starting at one ear and moving to the other.\n\n## Coronal plane\n\nAlso known as frontal plane.\nIt is an x-z plane, perpendicular to the ground, which (in humans) separates the anterior from the posterior, the front from the back, the ventral from the dorsal.\nA coronal MRI looks at the brain from behind in a series of images starting at the back of the head and moving to the face.\n\n## Axial plane\n\nAlso known as transverse plane.\nIt is an x-y-z plane, parallel to the ground, which (in humans) separates the superior from the inferior, or put another way, the head from the feet.\nAn axial MRI looks at the brain from below in a series of images starting at the chin and moving to the top of the head.\n\nThe idea is to select out the section with the tomor on it with a preprocessing network and after just use 2D restnet to train the data","metadata":{}},{"cell_type":"code","source":"# matplotlib and it settings\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\nmpl.rcParams['figure.dpi'] = 300\nimport torch\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nimport torchvision.models as models\nprint(f\"device: {device}\")\nimport torch\nimport os\nimport numpy as np\nimport matplotlib.animation as animation\nfrom IPython.display import HTML\nimport pydicom\nimport re\nimport time\nimport torchvision\nfrom torchvision import datasets, models, transforms\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nimport copy\nimport random\nimport zipfile\nimport pandas as pd\nimport io\nimport h5py\nimport torch.nn as nn\nfrom tqdm import tqdm\nimport shutil\nfrom PIL import Image\n# for batch loading\nfrom distributed import Client\nimport dask\nimport glob\nimport toolz\n# weight classes\nfrom sklearn.utils import class_weight\n# image preprocessing\nimport cv2\nfrom PIL import Image\nimport shutil","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:41:52.324191Z","iopub.execute_input":"2021-08-25T15:41:52.324527Z","iopub.status.idle":"2021-08-25T15:41:52.334062Z","shell.execute_reply.started":"2021-08-25T15:41:52.324495Z","shell.execute_reply":"2021-08-25T15:41:52.333098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"version = \"1.4.4\"\nhastumor_version = \"1.4.2\"\nscan_types = {'t2': 'T2w', 'flair': 'FLAIR'}\nmodel_scan_type = \"t2\"\ndata_raw = \"../input/rsna-miccai-brain-tumor-radiogenomic-classification/\"\ndata_sourcedir = \"./data_1.4\"\ndata_dir = \"./data_1.4_filtered\"\ndata_dir_predict = \"./data_1.4_predict\"\ntargetsize = 224","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:41:52.335671Z","iopub.execute_input":"2021-08-25T15:41:52.336026Z","iopub.status.idle":"2021-08-25T15:41:52.345742Z","shell.execute_reply.started":"2021-08-25T15:41:52.33599Z","shell.execute_reply":"2021-08-25T15:41:52.34481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing the data","metadata":{}},{"cell_type":"code","source":"# copy the files to the traning dir\ntry:\n    shutil.rmtree(data_sourcedir)\nexcept Exception as e:\n    print(e)\n# create directories\nif not os.path.exists(data_sourcedir):\n    os.makedirs(data_sourcedir)\ntrain = os.path.join(data_sourcedir, \"train\")\nif not os.path.exists(train):\n    os.makedirs(train)\ntrain_1 = os.path.join(train, \"1\")\nif not os.path.exists(train_1):\n    os.makedirs(train_1)\ntrain_0 = os.path.join(train, \"0\")\nif not os.path.exists(train_0):\n    os.makedirs(train_0)\n# varidation directories\nval = os.path.join(data_sourcedir, \"val\")\nif not os.path.exists(val):\n    os.makedirs(val)\nval_1 = os.path.join(val, \"1\")\nif not os.path.exists(val_1):\n    os.makedirs(val_1)\nval_0 = os.path.join(val, \"0\")\nif not os.path.exists(val_0):\n    os.makedirs(val_0)","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:41:52.347496Z","iopub.execute_input":"2021-08-25T15:41:52.347847Z","iopub.status.idle":"2021-08-25T15:41:52.358083Z","shell.execute_reply.started":"2021-08-25T15:41:52.347813Z","shell.execute_reply":"2021-08-25T15:41:52.357132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# read the csv data from the archive\ndf = pd.read_csv(os.path.join(data_raw, 'train_labels.csv'))\n# fill the patient ids with 0 to match with the dataset directories\ndf['BraTS21ID'] = df['BraTS21ID'].apply( lambda x : str(x).zfill(5))\ndf.set_index(\"BraTS21ID\", inplace=True)\n# drop some value\ndeleteid = [ \"00109\", \"00123\", \"00709\" ]\ndf.drop(deleteid, inplace=True)\n\ndf.head(8)","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:41:52.3597Z","iopub.execute_input":"2021-08-25T15:41:52.36023Z","iopub.status.idle":"2021-08-25T15:41:52.37668Z","shell.execute_reply.started":"2021-08-25T15:41:52.360194Z","shell.execute_reply":"2021-08-25T15:41:52.375766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# the files in the archive\nfiles = []\nfor root, dirnames, filenames in os.walk(data_raw):\n    for filename in filenames:\n        files.append(os.path.join(root, filename))","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:41:52.456378Z","iopub.execute_input":"2021-08-25T15:41:52.456678Z","iopub.status.idle":"2021-08-25T15:42:23.622157Z","shell.execute_reply.started":"2021-08-25T15:41:52.456651Z","shell.execute_reply":"2021-08-25T15:42:23.621237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(files[3])","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:42:23.624499Z","iopub.execute_input":"2021-08-25T15:42:23.624756Z","iopub.status.idle":"2021-08-25T15:42:23.633273Z","shell.execute_reply.started":"2021-08-25T15:42:23.624731Z","shell.execute_reply":"2021-08-25T15:42:23.632553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def imshow(inp, title=None):\n    plt.imshow(inp)\n    if title is not None:\n        plt.title(title)\n    plt.pause(0.001)  # pause a bit so that plots are updated\n\ndef image_orientation(dicom):\n        rt = 'unkown'\n        # https://www.kaggle.com/davidbroberts/determining-mr-image-planes\n        (x1,y1,_,x2,y2,_) = [round(v) for v in dicom.ImageOrientationPatient]\n        if (x1,y1,x2,y2) == (1,0,0,0):\n            rt = 'coronal'\n        if (x1,y1,x2,y2) == (1,0,0,1):\n            rt = 'axial'\n        if (x1,y1,x2,y2) == (0,1,0,0):\n            rt = 'sagittal'        \n        return rt\n\ndef colornormalisation(img):\n    if img is not None and np.max(img) != 0:\n        # values to greyscale\n        img = img - np.min(img)\n        img = img / np.max(img)    # 0~1\n        img = (img * 255).astype(np.uint8)    # 0~255 \n        return img\n    elif img is None:\n        return img\n    else:\n        return img.astype(np.uint8)\n    \ndef imagenormalisation(image, mincutsize=0.1):\n    image = image.astype(np.uint8)\n    # the minimal pixel value \n    cutoff = 5\n    sizecut = 1 # default sizecut is maximum image\n    if np.max(image) > cutoff:\n        \n        # apply binary thresholding to the gray image\n        ret, thresh = cv2.threshold(image, cutoff, 255, cv2.THRESH_BINARY)\n        # detect the contours on the binary image using cv2.CHAIN_APPROX_NONE\n        cnts = cv2.findContours(image=thresh, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)\n        \n        # if not found any contour return the original image\n        if len(cnts[0]) == 0: \n            cv2.imwrite('test.png', image)\n            cv2.imwrite('test_gray.png', image)\n            image_copy1 = image.copy()\n            return colorAndShape(image)\n        cnts = cnts[0] if len(cnts) == 2 else cnts[1]\n        cnts = sorted(cnts, key=cv2.contourArea, reverse=True)\n\n        # Find bounding box and extract ROI\n        x = 10000\n        y = 10000\n        w = 0\n        h = 0\n        for c in cnts:\n            xc,yc,wc,hc = cv2.boundingRect(c)\n            if xc < x:\n                x = xc\n            if yc < y:\n                y = yc\n            if xc+wc > w:\n                w = xc+wc\n            if yc+hc > h:\n                h = yc+hc\n        # crop the image\n        sizecut = (h-y)*(w-x)/(image.shape[0]*image.shape[1])\n        # check the image has got enough pixel to worth to consider\n        if sizecut < mincutsize:\n            image = None\n        else:\n            # cut the image\n            image = image[y:h,x:w]\n    else:\n        # the image haw not meaningfull result\n        image = None\n    if image is not None:\n        # resize the image\n        image = cv2.resize(image, (targetsize, targetsize))\n    return image, sizecut\n    \n    \ndef fileprocess(path_sorted, direction = 'axial'):\n    images = []\n    # how small the new image compaing to the original\n    sizes = []\n    orientation = None\n    for idx in range(len(path_sorted)):\n        ds = pydicom.filereader.dcmread( path_sorted[idx] )\n        orientation = image_orientation(ds)\n        # normalization of the color\n        images.append(ds.pixel_array)\n        \n    # we need to rotate\n    newimages = []\n    if orientation != direction:\n        data = np.stack(images)\n        data = colornormalisation(data)\n        # rotate to axial\n        if direction == 'axial':\n            # coronal -> axial\n            if orientation == 'coronal':                \n                for d in range(data.shape[1]): \n                    i, size = imagenormalisation(data[:, d, :])\n                    newimages.append(i)\n                    sizes.append(size)\n            if orientation == 'sagittal':\n                for d in range(data.shape[2]):\n                    i, size = imagenormalisation(data[:, :, d].T)\n                    newimages.append(i)\n                    sizes.append(size)\n    else:\n        data = np.stack(images)\n        data = colornormalisation(data)\n        for d in range(data.shape[0]):\n            i, size = imagenormalisation(data[d, :, :])            \n            newimages.append(i)\n            sizes.append(size)            \n    \n    return newimages, sizes","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:42:23.636861Z","iopub.execute_input":"2021-08-25T15:42:23.637105Z","iopub.status.idle":"2021-08-25T15:42:23.679357Z","shell.execute_reply.started":"2021-08-25T15:42:23.637082Z","shell.execute_reply":"2021-08-25T15:42:23.678473Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training data","metadata":{}},{"cell_type":"code","source":"datalength = df.shape[0]\nprogress = 0\nfor d in range(datalength):\n    progress += 1\n    idname = df.index[d]\n    print(f\"Process: {np.round(100*progress/datalength, 2)}%\", end=\"\\r\")\n    for scan_type in scan_types.keys():\n        # get the files\n        path = os.path.join( data_raw, \"train\", idname, scan_types[scan_type] )\n        # sort the files to make right timeorder\n        path_sorted = [f for f in files if re.search(path+\"/\", f) ]\n        imagenum = [s.split(\"/\")[6].split(\"-\")[1] for s in path_sorted]\n        imagenum = [s.split(\".\")[0] for s in imagenum]\n        tempdf = pd.DataFrame()\n        tempdf[\"image_num\"] = imagenum\n        tempdf[\"image_num\"] = tempdf[\"image_num\"].astype(\"int\")\n        tempdf[\"temp_path\"] = path_sorted\n        tempdf = tempdf.sort_values(\"image_num\").reset_index(drop=True)\n        # collect the files and process them\n        images, sizes = fileprocess(tempdf[\"temp_path\"].values)\n        # if image is meaningfull\n        images = [ i for i in images if i is not None ]\n        # save as jpg\n        label = str(df.iloc[d]['MGMT_value'])        \n        for idx in range(len(images)):\n            # asign randomly them to train and val group\n            val = np.random.binomial(1, 0.2, 1)[0]\n            if val == 1:\n                val = \"val\"\n            else:\n                val = \"train\"\n            filename = os.path.join(data_sourcedir, val, label, f\"{idname}_{scan_type}_{idx}.jpg\")\n            cv2.imwrite(filename, images[idx])","metadata":{"execution":{"iopub.status.busy":"2021-08-25T15:42:23.680989Z","iopub.execute_input":"2021-08-25T15:42:23.681471Z","iopub.status.idle":"2021-08-25T16:33:40.410671Z","shell.execute_reply.started":"2021-08-25T15:42:23.681431Z","shell.execute_reply":"2021-08-25T16:33:40.409832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Test data","metadata":{}},{"cell_type":"code","source":"# copy the files to the traning dir\ntry:\n    shutil.rmtree(data_dir_predict)\nexcept Exception as e:\n    print(e)\n# create directories\nif not os.path.exists(data_dir_predict):\n    os.makedirs(data_dir_predict)\npre = os.path.join(data_dir_predict, \"pre\")\nif not os.path.exists(pre):\n    os.makedirs(pre)","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:33:40.412041Z","iopub.execute_input":"2021-08-25T16:33:40.412396Z","iopub.status.idle":"2021-08-25T16:33:40.423695Z","shell.execute_reply.started":"2021-08-25T16:33:40.41235Z","shell.execute_reply":"2021-08-25T16:33:40.422758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# files to predict\nfiles_pre = [ f for f in files if re.search('test/', f)]\ndf = pd.DataFrame({'BraTS21ID': list(set([ f.split(\"/\")[4] for f in files_pre ]))})\nprint(df.head())","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:33:40.424931Z","iopub.execute_input":"2021-08-25T16:33:40.425407Z","iopub.status.idle":"2021-08-25T16:33:40.805539Z","shell.execute_reply.started":"2021-08-25T16:33:40.425369Z","shell.execute_reply":"2021-08-25T16:33:40.804687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datalength = df.shape[0]\nprogress = 0\nfor d in range(datalength):\n    progress += 1\n    idname = df.iloc[d]['BraTS21ID']\n    print(f\"Process: {np.round(100*progress/datalength, 2)}%\", end=\"\\r\")\n    for scan_type in scan_types.keys():\n        # get the files\n        path = os.path.join( data_raw, \"test\", idname, scan_types[scan_type] )\n        # sort the files to make right timeorder\n        path_sorted = [f for f in files_pre if re.search(path+\"/\", f) ]\n        imagenum = [s.split(\"/\")[6].split(\"-\")[1] for s in path_sorted]\n        imagenum = [s.split(\".\")[0] for s in imagenum]\n        tempdf = pd.DataFrame()\n        tempdf[\"image_num\"] = imagenum\n        tempdf[\"image_num\"] = tempdf[\"image_num\"].astype(\"int\")\n        tempdf[\"temp_path\"] = path_sorted\n        tempdf = tempdf.sort_values(\"image_num\").reset_index(drop=True)\n        # collect the files and process them\n        images, sizes = fileprocess(tempdf[\"temp_path\"].values)\n        # if image is meaningfull\n        images = [ i for i in images if i is not None ]\n        # save as jpg\n        for idx in range(len(images)):\n            filename = os.path.join(data_dir_predict, f\"{idname}_{scan_type}_{idx}.jpg\")\n            cv2.imwrite(filename, images[idx])","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:33:40.806812Z","iopub.execute_input":"2021-08-25T16:33:40.807285Z","iopub.status.idle":"2021-08-25T16:39:16.035068Z","shell.execute_reply.started":"2021-08-25T16:33:40.807244Z","shell.execute_reply":"2021-08-25T16:39:16.034081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build the model","metadata":{}},{"cell_type":"code","source":"# load has_tumor model model_has_tumor_*.pth\nmodel_has_tumor = {}\nfor scan_type in scan_types:\n    try:\n        model_has_tumor[scan_type] = torch.load(f\"../input/mri-brain-tumor-detection/model_has_tumor_{hastumor_version}_{scan_type}.pth\")\n    except Exception as e:\n        print(f\"Missing {scan_type} model! {e}\")","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:39:16.036285Z","iopub.execute_input":"2021-08-25T16:39:16.036636Z","iopub.status.idle":"2021-08-25T16:39:17.947383Z","shell.execute_reply.started":"2021-08-25T16:39:16.036601Z","shell.execute_reply":"2021-08-25T16:39:17.946504Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test_single_slices(scan_type, num_images=6):\n    \n    fileslist = []\n    # copy the files \n    for root, dirs, files in os.walk(data_sourcedir):\n        for filename in files:\n            if re.search(\"_\"+scan_type+\"_\", filename, re.IGNORECASE):\n                fileslist.append((root, filename))                    \n                \n    # the data\n    # Data augmentation and normalization for training\n    # Just normalization for validation\n    data_transforms =  transforms.Compose([\n            transforms.ToTensor()\n        ])\n\n    # get the model\n    model = model_has_tumor[scan_type]\n    model.to(device)\n    model.eval()\n    \n    \n    with torch.no_grad():\n    \n        # itterate over the images and get prediction\n        predictions = []\n        datalength = len(fileslist)\n        progress = 0\n        for i in range(len(fileslist)):\n            progress += 1\n            print(f\"Process: {np.round(100*progress/datalength, 2)}%\", end=\"\\r\")\n            # read the file\n            filepath = os.path.join(fileslist[i][0], fileslist[i][1])\n            image = Image.open(filepath).convert('RGB') # be sure it is 3 channel\n            image = data_transforms(image) # transform\n            image = image.unsqueeze_(0) #so img is not treated as a batch \n            if torch.cuda.is_available(): \n                image = image.cuda()\n            predict = model(image)\n            if torch.cuda.is_available(): \n                predictions.append( predict.cpu().detach().numpy()[0])\n            else:\n                predictions.append( predict.detach().numpy()[0])\n        \n    df = pd.DataFrame({\n        'path': [ f[0] for f in fileslist], \n        'filename': [ f[1] for f in fileslist],\n        'notumor': [ p[0] for p in predictions ],\n        'tumor': [ p[1] for p in predictions ]        \n    })\n    print(df.head())\n    \n    return df\n\n","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:39:17.951683Z","iopub.execute_input":"2021-08-25T16:39:17.951963Z","iopub.status.idle":"2021-08-25T16:39:17.963795Z","shell.execute_reply.started":"2021-08-25T16:39:17.951937Z","shell.execute_reply":"2021-08-25T16:39:17.962819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndf = test_single_slices(model_scan_type)\n# save data\ndf.to_csv(f\"datalabel_hastomur_{version}_{model_scan_type}.csv\", index=False)\n","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:39:17.965788Z","iopub.execute_input":"2021-08-25T16:39:17.966443Z","iopub.status.idle":"2021-08-25T16:51:28.885568Z","shell.execute_reply.started":"2021-08-25T16:39:17.966382Z","shell.execute_reply":"2021-08-25T16:51:28.88469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(f\"datalabel_hastomur_{version}_{model_scan_type}.csv\")\nprint(df.head())","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:51:28.888942Z","iopub.execute_input":"2021-08-25T16:51:28.889206Z","iopub.status.idle":"2021-08-25T16:51:28.98252Z","shell.execute_reply.started":"2021-08-25T16:51:28.889179Z","shell.execute_reply":"2021-08-25T16:51:28.981694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def imshow(inp, title=None):\n    inp = inp.numpy().transpose((1, 2, 0))\n    \"\"\"Imshow for Tensor.\"\"\"\n    plt.imshow(inp)\n    if title is not None:\n        plt.title(title)\n    plt.pause(0.001)  # pause a bit so that plots are updated\n\ndef visualize_model(model, dataloaders, class_names, num_images=6):\n    was_training = model.training\n    model.eval()\n    images_so_far = 0\n    fig = plt.figure()\n\n    with torch.no_grad():\n        for i, (inputs, labels) in enumerate(dataloaders['val']):\n            inputs = inputs.to(device)\n            labels = labels.to(device)\n\n            outputs = model(inputs)\n            _, preds = torch.max(outputs, 1)\n\n            for j in range(inputs.size()[0]):\n                images_so_far += 1\n                ax = plt.subplot(num_images//2, 2, images_so_far)\n                ax.axis('off')\n                ax.set_title(\n                    f\"predicted: {class_names[preds[j]]} real: {class_names[int(labels[j])]}\"\n                )\n                imshow(inputs.cpu().data[j])\n\n                if images_so_far == num_images:\n                    model.train(mode=was_training)\n                    return\n        model.train(mode=was_training)    \n    \ndef train_model(model, criterions, optimizer, scheduler, dataloaders, dataset_sizes, num_epochs=25):\n    since = time.time()\n\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n\n        # Each epoch has a training and validation phase\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Set model to training mode\n            else:\n                model.eval()   # Set model to evaluate mode\n\n            running_loss = 0.0\n            running_corrects = 0\n\n            # Iterate over data.\n            for inputs, labels in tqdm(dataloaders[phase]):\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n\n                # zero the parameter gradients\n                optimizer.zero_grad()\n\n                # forward\n                # track history if only in train\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    _, preds = torch.max(outputs, 1)\n                    loss = criterions[phase](outputs, labels)\n\n\n                    # backward + optimize only if in training phase\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n\n                # statistics\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n            if phase == 'train':\n                scheduler.step()\n\n            epoch_loss = running_loss / dataset_sizes[phase]\n            epoch_acc = running_corrects.double() / dataset_sizes[phase]\n\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n                phase, epoch_loss, epoch_acc))\n\n            # deep copy the model\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n\n        print()\n\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(\n        time_elapsed // 60, time_elapsed % 60))\n    print('Best val Acc: {:4f}'.format(best_acc))\n\n    # load best model weights\n    model.load_state_dict(best_model_wts)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:51:28.98539Z","iopub.execute_input":"2021-08-25T16:51:28.985657Z","iopub.status.idle":"2021-08-25T16:51:29.00314Z","shell.execute_reply.started":"2021-08-25T16:51:28.985631Z","shell.execute_reply":"2021-08-25T16:51:29.002131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:51:29.004969Z","iopub.execute_input":"2021-08-25T16:51:29.005312Z","iopub.status.idle":"2021-08-25T16:51:29.015104Z","shell.execute_reply.started":"2021-08-25T16:51:29.005277Z","shell.execute_reply":"2021-08-25T16:51:29.013859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\ndef buildmodel(scan_type):\n    \n    df = pd.read_csv(f\"datalabel_hastomur_{version}_{scan_type}.csv\")\n    \n    # copy the files to the traning dir\n    try:\n        shutil.rmtree(data_dir)\n    except Exception as e:\n        print(e)\n    # create directories\n    os.makedirs(data_dir)\n    train = os.path.join(data_dir, \"train\")\n    os.makedirs(train)\n    train_1 = os.path.join(train, \"1\")\n    os.makedirs(train_1)\n    train_0 = os.path.join(train, \"0\")\n    os.makedirs(train_0)\n    val = os.path.join(data_dir, \"val\")\n    os.makedirs(val)\n    val_1 = os.path.join(val, \"1\")\n    os.makedirs(val_1)\n    val_0 = os.path.join(val, \"0\")\n    os.makedirs(val_0)\n    # copy the files \n    for destination in [train_1, train_0, val_0, val_1]:\n        source = destination.replace(data_dir, data_sourcedir)\n        filelist = df[df['path'] == source]\n        filelist = filelist[filelist['tumor'] > filelist['notumor']]\n        for filename in filelist['filename']:\n            shutil.copy( os.path.join(source, filename), destination)\n\n    # Data augmentation and normalization for training\n    # Just normalization for validation\n    data_transforms = {\n        'train': transforms.Compose([\n            transforms.RandomHorizontalFlip(),\n            transforms.RandomVerticalFlip(),\n            transforms.RandomRotation(degrees=(-10, 10)),\n            transforms.ToTensor()\n        ]),\n        'val': transforms.Compose([\n            transforms.ToTensor()\n        ]),\n    }\n\n\n    image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),\n                                              data_transforms[x])\n                      for x in ['train', 'val']}\n    print(image_datasets['train'].classes)\n    dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=64,\n                                                 shuffle=True, num_workers=4)\n                  for x in ['train', 'val']}\n    dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}\n    class_names = image_datasets['train'].classes\n    \n    class_weights = {}\n    for phase in data_transforms.keys():\n        y = [ p for p in df['path'].values if re.search(phase, p) ]\n        classes = np.unique(y)\n        weight=class_weight.compute_class_weight('balanced',classes,y)\n        class_weights[phase] = torch.tensor(weight,dtype=torch.float).to(device)\n    print(class_weights)\n    \n    # Get a batch of training data\n    inputs, classes = next(iter(dataloaders['train']))\n\n    # Make a grid from batch\n    out = torchvision.utils.make_grid(inputs)\n\n    imshow(out, title=[class_names[x] for x in classes])\n    \n    \n    # pretrained pytorch model with internet connection\n    # model_ft = models.resnet18(pretrained=True)\n    # pretrained pytorch model without internet connection\n    model_ft = models.resnet18(pretrained=False)\n    model_ft.load_state_dict(torch.load(f\"../input/pytorch-resnet18/resnet18-f37072fd.pth\"))\n    # number of input feature from the pretrained model\n    num_ftrs = model_ft.fc.in_features\n    # Here the size of each output sample is set to 2.\n    # Alternatively, it can be generalized to nn.Linear(num_ftrs, len(class_names)).    \n    model_ft.fc = nn.Linear(num_ftrs, 2)\n        \n    model_ft = model_ft.to(device)\n    \n\n    criterions = {}\n    for phase in data_transforms.keys():\n        criterions[phase] = nn.CrossEntropyLoss(weight=class_weights[phase])\n    # criterion = torch.nn.BCEWithLogitsLoss() # this use sigmoid automatilcy\n\n    # Observe that all parameters are being optimized    \n    LEARNING_RATE = 1e-3\n    optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)\n    # optimizer_ft = optim.Adam(model_ft.parameters(), lr=LEARNING_RATE)\n\n    # Decay LR by a factor of 0.1 every 7 epochs\n    exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)\n    \n    for i in range(6):\n        model_ft = train_model(model_ft, criterions, optimizer_ft, exp_lr_scheduler, \n                               dataloaders, dataset_sizes,\n                               num_epochs=1)\n        # save the model\n        torch.save(model_ft, f\"model_{version}_{scan_type}.pth\")\n    \n    visualize_model(model_ft, dataloaders, class_names)\n\nbuildmodel(model_scan_type)","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:51:29.017137Z","iopub.execute_input":"2021-08-25T16:51:29.017926Z","iopub.status.idle":"2021-08-25T16:57:05.751727Z","shell.execute_reply.started":"2021-08-25T16:51:29.017822Z","shell.execute_reply":"2021-08-25T16:57:05.750805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Predicting","metadata":{}},{"cell_type":"code","source":"data_sourcedir = data_dir_predict","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:57:05.753337Z","iopub.execute_input":"2021-08-25T16:57:05.753702Z","iopub.status.idle":"2021-08-25T16:57:05.758512Z","shell.execute_reply.started":"2021-08-25T16:57:05.753663Z","shell.execute_reply":"2021-08-25T16:57:05.757575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test_single_slices(scan_type, num_images=6):\n    \n    fileslist = []\n    # copy the files \n    for root, dirs, files in os.walk(data_sourcedir):\n        for filename in files:\n            if re.search(\"_\"+scan_type+\"_\", filename, re.IGNORECASE):\n                fileslist.append((root, filename))                    \n                \n    # the data\n    # Data augmentation and normalization for training\n    # Just normalization for validation\n    data_transforms =  transforms.Compose([\n            transforms.ToTensor()\n        ])\n\n    # get the model\n    model =  torch.load( f\"model_{version}_{scan_type}.pth\" )\n    model.eval()\n    \n    \n    with torch.no_grad():\n    \n        # itterate over the images and get prediction\n        predictions = []\n        datalength = len(fileslist)\n        progress = 0\n        for i in range(len(fileslist)):\n            progress += 1\n            print(f\"Process: {np.round(100*progress/datalength, 2)}%\", end=\"\\r\")\n            # read the file\n            filepath = os.path.join(fileslist[i][0], fileslist[i][1])\n            image = Image.open(filepath).convert('RGB') # be sure it is 3 channel\n            image = data_transforms(image) # transform\n            image = image.unsqueeze_(0) #so img is not treated as a batch \n            if torch.cuda.is_available(): \n                image = image.cuda()\n            predict = model(image)\n            if torch.cuda.is_available(): \n                predictions.append( predict.cpu().detach().numpy()[0])\n            else:\n                predictions.append( predict.detach().numpy()[0])\n        \n    df = pd.DataFrame({\n        'path': [ f[0] for f in fileslist], \n        'filename': [ f[1] for f in fileslist],\n        '0': [ p[0] for p in predictions ],\n        '1': [ p[1] for p in predictions ]        \n    })\n    print(df.head())\n    \n    return df","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:57:05.759867Z","iopub.execute_input":"2021-08-25T16:57:05.760203Z","iopub.status.idle":"2021-08-25T16:57:05.775042Z","shell.execute_reply.started":"2021-08-25T16:57:05.760165Z","shell.execute_reply":"2021-08-25T16:57:05.774272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = test_single_slices(model_scan_type)\n# save data\ndf.to_csv(f\"datalabel_prediction_{version}_{model_scan_type}.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:57:05.778079Z","iopub.execute_input":"2021-08-25T16:57:05.778316Z","iopub.status.idle":"2021-08-25T16:58:42.093786Z","shell.execute_reply.started":"2021-08-25T16:57:05.778293Z","shell.execute_reply":"2021-08-25T16:58:42.092951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_result = df.copy()\ndf_result['BraTS21ID'] = [ int(f.split(\"_\")[0]) for f in df_result['filename']]\ndf_result.drop(['filename', 'path'], axis=1, inplace=True)\ndf_result = df_result.groupby(['BraTS21ID']).sum()\ndf_result['MGMT_value'] = [ 0.0 if df_result.iloc[idx]['0'] > df_result.iloc[idx]['1'] \n                           else 1.0\n                           for idx in range(df_result.shape[0])] \ndf_result.drop(['0', '1'], axis=1, inplace=True)\nprint(df_result.head())\nprint(df_result.shape)\ndf_result.to_csv('submission2.csv')","metadata":{"execution":{"iopub.status.busy":"2021-08-25T16:58:42.095062Z","iopub.execute_input":"2021-08-25T16:58:42.095423Z","iopub.status.idle":"2021-08-25T16:58:42.136905Z","shell.execute_reply.started":"2021-08-25T16:58:42.09536Z","shell.execute_reply":"2021-08-25T16:58:42.1361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df_result.to_string())","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_result = df.copy()\ndf_result['BraTS21ID'] = [ int(f.split(\"_\")[0]) for f in df_result['filename']]\ndf_result.drop(['filename', 'path'], axis=1, inplace=True)\ndf_result['MGMT_value_0'] = [ 1.0 if df_result.iloc[idx]['0'] > df_result.iloc[idx]['1'] \n                           else 0.0\n                           for idx in range(df_result.shape[0])] \ndf_result['MGMT_value_1'] = [ 0.0 if df_result.iloc[idx]['0'] > df_result.iloc[idx]['1'] \n                           else 1.0\n                           for idx in range(df_result.shape[0])] \ndf_result.drop(['0', '1'], axis=1, inplace=True)\ndf_result = df_result.groupby(['BraTS21ID']).sum()\ndf_result['MGMT_value'] = df_result['MGMT_value_1']/(df_result['MGMT_value_0']+df_result['MGMT_value_1'])\ndf_result.drop(['MGMT_value_1', 'MGMT_value_0'], axis=1, inplace=True)\nprint(df_result.head())\nprint(df_result.shape)\ndf_result.to_csv('submission.csv')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df_result.to_string())","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from os import listdir\nprint(listdir(\"./\"))\nwith open('submission.csv','r') as resultfile:\n    # read the file with a for loop\n    for line in resultfile:\n        # strip the newline character from the line\n        print(line.strip())","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\n\nfor d in ['data_1.4_predict',  'data_1.4_filtered',\n          'datalabel_prediction_1.4.4_t2.csv', 'data_1.4', \n          'model_1.4.4_t2.pth', 'submission2.csv' ]:\n    try:\n        shutil.rmtree(d)\n    except Exception as e:\n        print(e)\n\nprint(listdir(\"./\"))","metadata":{},"execution_count":null,"outputs":[]}]}