{"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://storage.googleapis.com/kaggle-competitions/kaggle/29653/logos/header.png)","metadata":{}},{"cell_type":"markdown","source":"<a id=\"top\"></a>\n\n<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='color:white; background:darkviolet; border:0' role=\"tab\" aria-controls=\"home\"><center>Quick Navigation</center></h3>\n\n* [Overview](#1)\n* [Data Visualization](#2)\n    \n* [Sample Submission](#20)\n    \n\n* [Modeling](#100)","metadata":{}},{"cell_type":"markdown","source":"<a id=\"1\"></a>\n<h2 style='background:darkviolet; border:0; color:white'><center>Overview<center><h2>","metadata":{}},{"cell_type":"code","source":"#import libraries\nimport os\nimport json\nimport glob\nimport random\nimport collections\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","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:04:39.399852Z","iopub.execute_input":"2021-12-12T18:04:39.400351Z","iopub.status.idle":"2021-12-12T18:04:39.409574Z","shell.execute_reply.started":"2021-12-12T18:04:39.400306Z","shell.execute_reply":"2021-12-12T18:04:39.408514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**train/** - folder containing the training files, with each top-level folder representing a subject  \n**train_labels.csv** - file containing the target MGMT_value for each subject in the training data (e.g. the presence of MGMT promoter methylation)   \n**test/** - the test files, which use the same structure as train/   \n**sample_submission.csv** - a sample submission file in the correct format","metadata":{}},{"cell_type":"markdown","source":"![image.png](attachment:c9f09ace-85db-4a7f-ba37-7df032dd785f.png)","metadata":{},"attachments":{"c9f09ace-85db-4a7f-ba37-7df032dd785f.png":{"image/png":"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"}}},{"cell_type":"markdown","source":"<a id=\"2\"></a>\n<h2 style='background:darkviolet; border:0; color:white'><center>Data Visualization<center><h2>","metadata":{"execution":{"iopub.status.busy":"2021-07-14T06:41:32.077425Z","iopub.execute_input":"2021-07-14T06:41:32.077767Z","iopub.status.idle":"2021-07-14T06:41:32.0845Z","shell.execute_reply.started":"2021-07-14T06:41:32.077737Z","shell.execute_reply":"2021-07-14T06:41:32.082683Z"}}},{"cell_type":"code","source":"train_df = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv\")\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:04:43.518539Z","iopub.execute_input":"2021-12-12T18:04:43.518927Z","iopub.status.idle":"2021-12-12T18:04:43.538434Z","shell.execute_reply.started":"2021-12-12T18:04:43.518894Z","shell.execute_reply":"2021-12-12T18:04:43.537650Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Our dataset has almost equal sets with 585 patients. (305 patients with MGMT and 280 without it)","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(5, 5))\nsns.countplot(data=train_df, x=\"MGMT_value\");","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:04:46.758903Z","iopub.execute_input":"2021-12-12T18:04:46.759292Z","iopub.status.idle":"2021-12-12T18:04:46.878471Z","shell.execute_reply.started":"2021-12-12T18:04:46.759256Z","shell.execute_reply":"2021-12-12T18:04:46.877418Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Our dataset is divised into 4 directories. MRI Sequences\n- Fluid Attenuated Inversion Recovery (FLAIR):\n- T1-weighted pre-contrast (T1w)\n- T1-weighted post-contrast (T1Gd)\n- T2-weighted (T2)\n\nEach independent case has a dedicated folder identified by a five-digit number\n\n\n![image.png](attachment:1852206b-7c50-44c3-89a1-9d021a2a1cc9.png)","metadata":{},"attachments":{"1852206b-7c50-44c3-89a1-9d021a2a1cc9.png":{"image/png":"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"}}},{"cell_type":"markdown","source":"Since we are using a Medical Dataset all our images have a .dcm extension (an image file saved in the Digital Imaging and Communications in Medicine) in this case we need to use the pydicom library to use our data","metadata":{}},{"cell_type":"code","source":"#read each picture and return an array with values[0..255] since dicom images typically \n#contain between 12–16 bits/pixel, which corresponds to approximately 4,096 to 65,536 shades of gray\ndef load_dicom(path):\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\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    return data\n\n\ndef visualize_sample(\n    brats21id,\n    #the slice represents the way we slice the brain the first images represents a small slice \n    #the bigger slice_i the bigger the slice(front of the brain)\n    slice_i,\n    mgmt_value,\n    types=(\"FLAIR\", \"T1w\", \"T1wCE\", \"T2w\")\n):\n    #create a 16x16 figure with 5 inch space\n    plt.figure(figsize=(16, 5))\n    patient_path = os.path.join(\n        \"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/\", \n        str(brats21id).zfill(5), \n        \n    #the id in our csv file is 0 but 00000 in our directory that's why we use zfill\n    )\n    \n    for i, t in enumerate(types, 1):\n        #a sorted list of each subject's images\n        t_paths = sorted(\n            #glob used to return all file paths that match a specific pattern.\n            glob.glob(os.path.join(patient_path, t, \"*\")), \n            key=lambda x: int(x[:-4].split(\"-\")[-1]),\n        )\n        data = load_dicom(t_paths[int(len(t_paths) * slice_i)])\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    plt.suptitle(f\"MGMT_value: {mgmt_value}\", fontsize=16)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:04:50.126983Z","iopub.execute_input":"2021-12-12T18:04:50.127312Z","iopub.status.idle":"2021-12-12T18:04:50.137518Z","shell.execute_reply.started":"2021-12-12T18:04:50.127281Z","shell.execute_reply":"2021-12-12T18:04:50.136372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#takes 10 samples of our training dataset. Each row represents a patient.\n#as previously seen train_df.shape[0] is 585 \nfor i in random.sample(range(train_df.shape[0]), 10):\n    _brats21id = train_df.iloc[i][\"BraTS21ID\"]\n    _mgmt_value = train_df.iloc[i][\"MGMT_value\"]\n    visualize_sample(brats21id=_brats21id, mgmt_value=_mgmt_value, slice_i=0.5)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:04:54.006670Z","iopub.execute_input":"2021-12-12T18:04:54.007042Z","iopub.status.idle":"2021-12-12T18:04:57.182728Z","shell.execute_reply.started":"2021-12-12T18:04:54.007009Z","shell.execute_reply":"2021-12-12T18:04:57.181817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Animation**","metadata":{}},{"cell_type":"code","source":"from matplotlib import animation, rc\nrc('animation', html='jshtml')\n\n#takes a couple of images and returns an animation\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)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:05:02.044281Z","iopub.execute_input":"2021-12-12T18:05:02.044611Z","iopub.status.idle":"2021-12-12T18:05:02.050237Z","shell.execute_reply.started":"2021-12-12T18:05:02.044580Z","shell.execute_reply":"2021-12-12T18:05:02.049427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#returns a list of images\ndef load_dicom_line(path):\n    t_paths = sorted(\n        glob.glob(os.path.join(path, \"*\")), \n        key=lambda x: int(x[:-4].split(\"-\")[-1]),\n    )\n    images = []\n    for filename in t_paths:\n        data = load_dicom(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n        \n    return images","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:05:03.927146Z","iopub.execute_input":"2021-12-12T18:05:03.927491Z","iopub.status.idle":"2021-12-12T18:05:03.934641Z","shell.execute_reply.started":"2021-12-12T18:05:03.927458Z","shell.execute_reply":"2021-12-12T18:05:03.933453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = load_dicom_line(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/00000/FLAIR\")\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:05:06.486664Z","iopub.execute_input":"2021-12-12T18:05:06.487022Z","iopub.status.idle":"2021-12-12T18:05:22.677584Z","shell.execute_reply.started":"2021-12-12T18:05:06.486992Z","shell.execute_reply":"2021-12-12T18:05:22.676780Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = load_dicom_line(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/00000/T1w\")\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:05:22.679183Z","iopub.execute_input":"2021-12-12T18:05:22.679798Z","iopub.status.idle":"2021-12-12T18:05:24.710882Z","shell.execute_reply.started":"2021-12-12T18:05:22.679753Z","shell.execute_reply":"2021-12-12T18:05:24.709903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = load_dicom_line(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/00000/T1wCE\")\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:05:43.758147Z","iopub.execute_input":"2021-12-12T18:05:43.758483Z","iopub.status.idle":"2021-12-12T18:05:49.106575Z","shell.execute_reply.started":"2021-12-12T18:05:43.758452Z","shell.execute_reply":"2021-12-12T18:05:49.105577Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = load_dicom_line(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/00000/T2w\")\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:06:04.297824Z","iopub.execute_input":"2021-12-12T18:06:04.298197Z","iopub.status.idle":"2021-12-12T18:06:19.679846Z","shell.execute_reply.started":"2021-12-12T18:06:04.298156Z","shell.execute_reply":"2021-12-12T18:06:19.678820Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"100\"></a>\n<h2 style='background:darkviolet; border:0; color:white'><center>Modeling<center><h2>","metadata":{}},{"cell_type":"code","source":"#import Libraries\n#use Efficient Net Architecture\npackage_path = \"../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master/\"\nimport sys \nsys.path.append(package_path)\n\nimport time\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 efficientnet_pytorch\n\nfrom sklearn.model_selection import StratifiedKFold","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:06:19.681606Z","iopub.execute_input":"2021-12-12T18:06:19.681994Z","iopub.status.idle":"2021-12-12T18:06:19.689196Z","shell.execute_reply.started":"2021-12-12T18:06:19.681953Z","shell.execute_reply":"2021-12-12T18:06:19.687774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This function is usually used to lock pytorch randomness for reproducibility","metadata":{}},{"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\n\nset_seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T16:56:45.558565Z","iopub.execute_input":"2021-12-12T16:56:45.559035Z","iopub.status.idle":"2021-12-12T16:56:45.666795Z","shell.execute_reply.started":"2021-12-12T16:56:45.558993Z","shell.execute_reply":"2021-12-12T16:56:45.660835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv\")\ndf_train, df_valid = sk_model_selection.train_test_split(\n    df, \n    test_size=0.2, \n    random_state=42,\n    stratify=train_df[\"MGMT_value\"],#split data based on MGMT_value\n)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:06:42.968471Z","iopub.execute_input":"2021-12-12T18:06:42.968835Z","iopub.status.idle":"2021-12-12T18:06:42.980967Z","shell.execute_reply.started":"2021-12-12T18:06:42.968802Z","shell.execute_reply":"2021-12-12T18:06:42.980147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#return tensors of resized photos, label for each patient.\nclass DataRetriever(torch_data.Dataset):\n    def __init__(self, paths, targets):\n        self.paths = paths\n        self.targets = targets\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):\n        _id = self.paths[index]\n        patient_path = f\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/{str(_id).zfill(5)}/\"\n        #resized images\n        channels = []\n        for t in (\"FLAIR\", \"T1w\", \"T1wCE\"): # \"T2w\"\n            t_paths = sorted(\n                glob.glob(os.path.join(patient_path, t, \"*\")), \n                key=lambda x: int(x[:-4].split(\"-\")[-1]),\n            )\n            # start, end = int(len(t_paths) * 0.475), int(len(t_paths) * 0.525)\n            x = len(t_paths)\n            if x < 10:\n                r = range(x)\n            else:\n                d = x // 10\n                r = range(d, x - d, d)\n                \n            channel = []\n            # for i in range(start, end + 1):\n            for i in r:\n                channel.append(cv2.resize(load_dicom(t_paths[i]), (256, 256)) / 255)\n            channel = np.mean(channel, axis=0)\n            channels.append(channel)\n            \n        y = torch.tensor(self.targets[index], dtype=torch.float)\n        \n        return {\"X\": torch.tensor(channels).float(), \"y\": y}","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:06:45.341171Z","iopub.execute_input":"2021-12-12T18:06:45.341514Z","iopub.status.idle":"2021-12-12T18:06:45.351917Z","shell.execute_reply.started":"2021-12-12T18:06:45.341483Z","shell.execute_reply":"2021-12-12T18:06:45.350688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_retriever = DataRetriever(\n    df_train[\"BraTS21ID\"].values, \n    df_train[\"MGMT_value\"].values, \n)\n\nvalid_data_retriever = DataRetriever(\n    df_valid[\"BraTS21ID\"].values, \n    df_valid[\"MGMT_value\"].values,\n)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:06:57.437588Z","iopub.execute_input":"2021-12-12T18:06:57.437968Z","iopub.status.idle":"2021-12-12T18:06:57.443615Z","shell.execute_reply.started":"2021-12-12T18:06:57.437935Z","shell.execute_reply":"2021-12-12T18:06:57.442470Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#plotting 3 images for patient number 100\nplt.figure(figsize=(16, 6))\nfor i in range(3):\n    plt.subplot(1, 3, i + 1)\n    plt.imshow(train_data_retriever[100][\"X\"].numpy()[i], cmap=\"gray\")","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:06:59.037855Z","iopub.execute_input":"2021-12-12T18:06:59.038185Z","iopub.status.idle":"2021-12-12T18:06:59.851475Z","shell.execute_reply.started":"2021-12-12T18:06:59.038156Z","shell.execute_reply":"2021-12-12T18:06:59.850684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#loading the model EfficientNet\nclass Model(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.net = efficientnet_pytorch.EfficientNet.from_name(\"efficientnet-b0\")\n        checkpoint = torch.load(\"../input/efficientnet-pytorch/efficientnet-b0-08094119.pth\")\n        self.net.load_state_dict(checkpoint)\n        n_features = self.net._fc.in_features\n        self.net._fc = nn.Linear(in_features=n_features, out_features=1, bias=True)\n    \n    def forward(self, x):\n        out = self.net(x)\n        return out","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:07:02.328513Z","iopub.execute_input":"2021-12-12T18:07:02.329256Z","iopub.status.idle":"2021-12-12T18:07:02.348864Z","shell.execute_reply.started":"2021-12-12T18:07:02.329210Z","shell.execute_reply":"2021-12-12T18:07:02.346317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Our Model doesn't have a score function like the ones already implemented in Sklearn so It needs its own metrics","metadata":{}},{"cell_type":"code","source":"#loss and Accuracy Meters: same ones used for EfficientNet\nclass LossMeter:\n    def __init__(self):\n        self.avg = 0\n        self.n = 0\n\n    def update(self, val):\n        self.n += 1\n        # incremental update\n        self.avg = val / self.n + (self.n - 1) / self.n * self.avg\n\n        \nclass AccMeter:\n    def __init__(self):\n        self.avg = 0\n        self.n = 0\n        \n    def update(self, y_true, y_pred):\n        y_true = y_true.cpu().numpy().astype(int)\n        y_pred = y_pred.cpu().numpy() >= 0\n        last_n = self.n\n        self.n += len(y_true)\n        true_count = np.sum(y_true == y_pred)\n        # incremental update\n        self.avg = true_count / self.n + last_n / self.n * self.avg","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:07:10.677261Z","iopub.execute_input":"2021-12-12T18:07:10.677599Z","iopub.status.idle":"2021-12-12T18:07:10.685501Z","shell.execute_reply.started":"2021-12-12T18:07:10.677569Z","shell.execute_reply":"2021-12-12T18:07:10.684247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Here we define our trainer, we give it our model, optimizer:minimize the error function, criterion: when to stop the algorithm, and our metrics.\nAlongside the Fit function(trains, returns messages, and saves best model for validation) it has a train and a validation epoch.\nAn epoch is the number of passes for the entire training dataset through the model. (diff from iteration). in these function we will also be splitting our data into batches to increase speed. iteration is the number of times a batch of data has passed through the model.","metadata":{}},{"cell_type":"code","source":"class Trainer:\n    def __init__(\n        self, \n        model, \n        device, \n        optimizer, \n        criterion, \n        loss_meter, \n        score_meter\n    ):\n        self.model = model\n        self.device = device\n        self.optimizer = optimizer\n        self.criterion = criterion\n        self.loss_meter = loss_meter\n        self.score_meter = score_meter\n        \n        self.best_valid_score = -np.inf\n        self.n_patience = 0\n        \n        self.messages = {\n            \"epoch\": \"[Epoch {}: {}] loss: {:.5f}, score: {:.5f}, time: {} s\",\n            \"checkpoint\": \"The score improved from {:.5f} to {:.5f}. Save model to '{}'\",\n            \"patience\": \"\\nValid score didn't improve last {} epochs.\"\n        }\n    \n    def fit(self, epochs, train_loader, valid_loader, save_path, patience):        \n        for n_epoch in range(1, epochs + 1):\n            self.info_message(\"EPOCH: {}\", n_epoch)\n            \n            train_loss, train_score, train_time = self.train_epoch(train_loader)\n            valid_loss, valid_score, valid_time = self.valid_epoch(valid_loader)\n            \n            self.info_message(\n                self.messages[\"epoch\"], \"Train\", n_epoch, train_loss, train_score, train_time\n            )\n            \n            self.info_message(\n                self.messages[\"epoch\"], \"Valid\", n_epoch, valid_loss, valid_score, valid_time\n            )\n\n            if self.best_valid_score < valid_score:\n\n                self.info_message(\n                    self.messages[\"checkpoint\"], self.best_valid_score, valid_score, save_path\n                )\n                self.best_valid_score = valid_score\n                self.save_model(n_epoch, save_path)\n                self.n_patience = 0\n            else:\n                self.n_patience += 1\n            \n            if self.n_patience >= patience:\n                self.info_message(self.messages[\"patience\"], patience)\n                break\n            \n    def train_epoch(self, train_loader):\n        self.model.train()\n        t = time.time()\n        train_loss = self.loss_meter()\n        train_score = self.score_meter()\n        \n        \n        for step, batch in enumerate(train_loader, 1):\n            X = batch[\"X\"].to(self.device)\n            targets = batch[\"y\"].to(self.device)\n            self.optimizer.zero_grad()\n            outputs = self.model(X).squeeze(1)\n            \n            loss = self.criterion(outputs, targets)\n            loss.backward()\n\n            train_loss.update(loss.detach().item())\n            train_score.update(targets, outputs.detach())\n\n            self.optimizer.step()\n            \n            _loss, _score = train_loss.avg, train_score.avg\n            message = 'Train Step {}/{}, train_loss: {:.5f}, train_score: {:.5f}'\n            self.info_message(message, step, len(train_loader), _loss, _score, end=\"\\r\")\n        \n        return train_loss.avg, train_score.avg, int(time.time() - t)\n    \n    def valid_epoch(self, valid_loader):\n        self.model.eval()\n        t = time.time()\n        valid_loss = self.loss_meter()\n        valid_score = self.score_meter()\n\n        for step, batch in enumerate(valid_loader, 1):\n            with torch.no_grad():\n                X = batch[\"X\"].to(self.device)\n                targets = batch[\"y\"].to(self.device)\n\n                outputs = self.model(X).squeeze(1)\n                loss = self.criterion(outputs, targets)\n\n                valid_loss.update(loss.detach().item())\n                valid_score.update(targets, outputs)\n                \n            _loss, _score = valid_loss.avg, valid_score.avg\n            message = 'Valid Step {}/{}, valid_loss: {:.5f}, valid_score: {:.5f}'\n            self.info_message(message, step, len(valid_loader), _loss, _score, end=\"\\r\")\n        \n        return valid_loss.avg, valid_score.avg, int(time.time() - t)\n    \n    def save_model(self, n_epoch, save_path):\n        torch.save(\n            {\n                \"model_state_dict\": self.model.state_dict(),\n                \"optimizer_state_dict\": self.optimizer.state_dict(),\n                \"best_valid_score\": self.best_valid_score,\n                \"n_epoch\": n_epoch,\n            },\n            save_path,\n        )\n    \n    @staticmethod\n    def info_message(message, *args, end=\"\\n\"):\n        print(message.format(*args), end=end)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:07:17.292268Z","iopub.execute_input":"2021-12-12T18:07:17.292595Z","iopub.status.idle":"2021-12-12T18:07:17.313589Z","shell.execute_reply.started":"2021-12-12T18:07:17.292563Z","shell.execute_reply":"2021-12-12T18:07:17.312353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ntrain_data_retriever = DataRetriever(\n    df_train[\"BraTS21ID\"].values, \n    df_train[\"MGMT_value\"].values, \n)\n\nvalid_data_retriever = DataRetriever(\n    df_valid[\"BraTS21ID\"].values, \n    df_valid[\"MGMT_value\"].values,\n)\n\n#use a dataloader to have easier access to our data.Data Loader reads, extracts, and loads data \n#from comma-separated values (CSV) files or from a database connection. \n#When exporting data, it outputs CSV files.\n\ntrain_loader = torch_data.DataLoader(\n    train_data_retriever,\n    batch_size=8,\n    shuffle=True,\n    num_workers=8,\n)\n\nvalid_loader = torch_data.DataLoader(\n    valid_data_retriever, \n    batch_size=8,\n    shuffle=False,\n    num_workers=8,\n)\n\nmodel = Model()\nmodel.to(device)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\ncriterion = torch_functional.binary_cross_entropy_with_logits\n\ntrainer = Trainer(\n    model, \n    device, \n    optimizer, \n    criterion, \n    LossMeter, \n    AccMeter\n)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:07:21.968161Z","iopub.execute_input":"2021-12-12T18:07:21.968495Z","iopub.status.idle":"2021-12-12T18:07:22.102984Z","shell.execute_reply.started":"2021-12-12T18:07:21.968464Z","shell.execute_reply":"2021-12-12T18:07:22.102124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"To avoid overfitting we are taking into consideration the validation score and saving the model with the best validation score.","metadata":{}},{"cell_type":"code","source":"history = trainer.fit(\n    20, \n    train_loader, \n    valid_loader, \n    f\"best-model-0.pth\", \n    100,\n)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:07:37.198645Z","iopub.execute_input":"2021-12-12T18:07:37.198997Z","iopub.status.idle":"2021-12-12T18:28:01.878409Z","shell.execute_reply.started":"2021-12-12T18:07:37.198967Z","shell.execute_reply":"2021-12-12T18:28:01.877346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#load the model\nmodels = []\nfor i in range(1):\n    model = Model()\n    model.to(device)\n    \n    checkpoint = torch.load(f\"best-model-{i}.pth\")\n    model.load_state_dict(checkpoint[\"model_state_dict\"])\n    model.eval()\n    \n    models.append(model)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:28:07.422324Z","iopub.execute_input":"2021-12-12T18:28:07.422787Z","iopub.status.idle":"2021-12-12T18:28:07.843141Z","shell.execute_reply.started":"2021-12-12T18:28:07.422736Z","shell.execute_reply":"2021-12-12T18:28:07.842257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:28:09.432840Z","iopub.execute_input":"2021-12-12T18:28:09.433168Z","iopub.status.idle":"2021-12-12T18:28:09.444089Z","shell.execute_reply.started":"2021-12-12T18:28:09.433137Z","shell.execute_reply":"2021-12-12T18:28:09.442932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Testing**","metadata":{}},{"cell_type":"code","source":"class DataRetriever(torch_data.Dataset):\n    def __init__(self, paths):\n        self.paths = paths\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):\n        _id = self.paths[index]\n        patient_path = f\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/test/{str(_id).zfill(5)}/\"\n        channels = []\n        for t in (\"FLAIR\", \"T1w\", \"T1wCE\"): # \"T2w\"\n            t_paths = sorted(\n                glob.glob(os.path.join(patient_path, t, \"*\")), \n                key=lambda x: int(x[:-4].split(\"-\")[-1]),\n            )\n            # start, end = int(len(t_paths) * 0.475), int(len(t_paths) * 0.525)\n            x = len(t_paths)\n            if x < 10:\n                r = range(x)\n            else:\n                d = x // 10\n                r = range(d, x - d, d)\n                \n            channel = []\n            # for i in range(start, end + 1):\n            for i in r:\n                channel.append(cv2.resize(load_dicom(t_paths[i]), (256, 256)) / 255)\n            channel = np.mean(channel, axis=0)\n            channels.append(channel)\n        \n        return {\"X\": torch.tensor(channels).float(), \"id\": _id}","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:28:17.368992Z","iopub.execute_input":"2021-12-12T18:28:17.369316Z","iopub.status.idle":"2021-12-12T18:28:17.378652Z","shell.execute_reply.started":"2021-12-12T18:28:17.369284Z","shell.execute_reply":"2021-12-12T18:28:17.377737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv\")\n\ntest_data_retriever = DataRetriever(\n    submission[\"BraTS21ID\"].values, \n)\n\ntest_loader = torch_data.DataLoader(\n    test_data_retriever,\n    batch_size=4,\n    shuffle=False,\n    num_workers=8,\n)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:28:21.001076Z","iopub.execute_input":"2021-12-12T18:28:21.001413Z","iopub.status.idle":"2021-12-12T18:28:21.013353Z","shell.execute_reply.started":"2021-12-12T18:28:21.001381Z","shell.execute_reply":"2021-12-12T18:28:21.012143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = []\nids = []\n\nfor e, batch in enumerate(test_loader):\n    print(f\"{e}/{len(test_loader)}\", end=\"\\r\")\n    with torch.no_grad():\n        tmp_pred = np.zeros((batch[\"X\"].shape[0], ))\n        for model in models:\n            tmp_res = torch.sigmoid(model(batch[\"X\"].to(device))).cpu().numpy().squeeze()\n            tmp_pred += tmp_res\n        y_pred.extend(tmp_pred)\n        ids.extend(batch[\"id\"].numpy().tolist())","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:28:26.848782Z","iopub.execute_input":"2021-12-12T18:28:26.849109Z","iopub.status.idle":"2021-12-12T18:28:35.779037Z","shell.execute_reply.started":"2021-12-12T18:28:26.849078Z","shell.execute_reply":"2021-12-12T18:28:35.778162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame({\"BraTS21ID\": ids, \"MGMT_value\": y_pred})\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:31:36.741361Z","iopub.execute_input":"2021-12-12T18:31:36.741743Z","iopub.status.idle":"2021-12-12T18:31:36.750724Z","shell.execute_reply.started":"2021-12-12T18:31:36.741685Z","shell.execute_reply":"2021-12-12T18:31:36.749628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(5, 5))\nplt.hist(submission[\"MGMT_value\"]);","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:31:40.552491Z","iopub.execute_input":"2021-12-12T18:31:40.552875Z","iopub.status.idle":"2021-12-12T18:31:40.717375Z","shell.execute_reply.started":"2021-12-12T18:31:40.552838Z","shell.execute_reply":"2021-12-12T18:31:40.716588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission","metadata":{"execution":{"iopub.status.busy":"2021-12-12T18:32:06.152811Z","iopub.execute_input":"2021-12-12T18:32:06.153168Z","iopub.status.idle":"2021-12-12T18:32:06.169472Z","shell.execute_reply.started":"2021-12-12T18:32:06.153137Z","shell.execute_reply":"2021-12-12T18:32:06.168336Z"},"trusted":true},"execution_count":null,"outputs":[]}]}