{"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":"code","source":"!pip install torchio\nimport torchio as tio","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install wandb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport sys \nimport json\nimport glob\nimport random\nimport collections\nimport time\n\nimport numpy as np\nimport pandas as pd\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport torch\nfrom torch import nn\nfrom torch.utils import data as torch_data\nfrom sklearn import model_selection as sk_model_selection\nfrom torch.nn import functional as torch_functional\nimport torch.nn.functional as F\nfrom torchvision import transforms, utils\n\nfrom sklearn import model_selection\nfrom sklearn import metrics\nfrom skimage import exposure\n\nfrom albumentations import Resize, Normalize, Compose\nfrom albumentations.pytorch import ToTensorV2\nimport albumentations as album\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import roc_auc_score\n\nfrom tqdm import tqdm \n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\nplt.style.use(\"dark_background\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.style.available","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Setting up Configurations**","metadata":{}},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using {device} device\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# CONFIG\n\n# -- Common -- \nSEED = 42\ndata_directory = '../input/rsna-miccai-brain-tumor-radiogenomic-classification'\n    \n# -- Data --\n# mri_types = ['FLAIR','T1w','T1wCE','T2w']\n# mri_types = ['FLAIR', 'T1wCE']\n# mri_types = ['T1wCE']\nmri_types = ['T1w']\nSIZE = 256\nPAD_SIZE = 512\nNUM_IMAGES = 64\n\n# -- Train --\noptimizer = torch.optim.Adam\nLR = 3e-5\nBATCH_SIZE = 3","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    if torch.cuda.is_available():\n        torch.cuda.manual_seed_all(seed)\n        torch.backends.cudnn.deterministic = True\n\nset_seed(SEED)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Useful Functions**","metadata":{}},{"cell_type":"code","source":"def pad_images(images, pad_size=PAD_SIZE):\n    h, w = images.shape[:2]\n    diff_vert = pad_size - h\n    pad_top = diff_vert // 2\n    pad_bottom = diff_vert - pad_top\n    diff_hori = pad_size - w\n    pad_left = diff_hori // 2\n    pad_right = diff_hori - pad_left\n    \n    images = cv2.copyMakeBorder(images, pad_top, pad_bottom, pad_left, pad_right, cv2.BORDER_CONSTANT, value=0)\n    assert images.shape[:2] == (pad_size, pad_size)\n    \n    return images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dicom_image(path, img_size=SIZE):\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\n    \n    if np.min(data) == np.max(data):\n        data = np.zeros((img_size,img_size))\n        return data\n    \n    data = exposure.equalize_adapthist(data, clip_limit=0.04)\n    data = apply_voi_lut(dicom.pixel_array, dicom)\n    \n    if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n        \n    data = cv2.resize(data, (img_size, img_size))\n    \n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n\n    return data.astype(np.uint8)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dicom_images_3d(scan_id, num_imgs=NUM_IMAGES, img_size=SIZE, mri_type=\"FLAIR\", split=\"train\"):\n    files = sorted(glob.glob(f\"{data_directory}/{split}/{scan_id}/{mri_type}/*.dcm\"), \n                   key=lambda x: int(x.split('/')[-1].split('-')[-1].split('.')[0]))\n    \n    middle = len(files) // 2\n    num_imgs2 = num_imgs // 2\n    p1 = max(0, middle - num_imgs2)\n    p2 = min(len(files), middle + num_imgs2)\n    img3d = np.stack([load_dicom_image(f) for f in files[p1:p2]]).T \n    \n    if img3d.shape[-1] < num_imgs:\n        n_zero = np.zeros((img_size, img_size, num_imgs - img3d.shape[-1]))\n        img3d = np.concatenate((img3d,  n_zero), axis=-1)\n        \n        \n    if np.min(img3d) < np.max(img3d):\n        img3d = img3d - np.min(img3d)\n        img3d = img3d / np.max(img3d)\n            \n    return img3d","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def cropped_images(images, img_size=SIZE):\n    try:\n        min=np.array(np.nonzero(images)).min(axis=1)\n        max=np.array(np.nonzero(images)).max(axis=1)\n        images = images[min[0]:max[0], min[1]:max[1], :]\n    except ValueError:\n        pass\n    \n    images = cv2.resize(images, (img_size, img_size))\n    \n    return images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def visualize(**images):\n    n = len(images)\n    plt.figure(figsize=(16, 12))\n    for i, (name, image) in enumerate(images.items()):\n        plt.subplot(1, n, i + 1)\n        plt.xticks([])\n        plt.yticks([])\n        plt.title(' '.join(name.split('_')).title())\n        plt.imshow(image)\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image2Voxel stacking example\n\n# Here the data of one patient with id 00000 is getting loaded\n# The 4 MRI types are stacked and the resulting instance shape in [4, n, w, h]\n# where 4 is the number of MRI types\n# n - middle images chosen (here we take 64 images from the voxel)\n# w, h - image width, height\n\nimages = []\nindex = 0\nimage_id = '00000'\n\nfor i in mri_types:\n    image_pack = load_dicom_images_3d(scan_id=image_id, mri_type=i)\n    images.append(cropped_images(image_pack))\n    \nfour_channel_pack = np.stack(images)\nfour_channel_pack = np.transpose(four_channel_pack, (0, 3, 1, 2))\n\nprint(f'Image shape: {four_channel_pack.shape}')\nprint(f'Image min: {four_channel_pack.min()}')\nprint(f'Image max: {four_channel_pack.max()}')\nplt.imshow(four_channel_pack[0, 30, :, :])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **3D Augmenatation and Transformation**","metadata":{}},{"cell_type":"code","source":"# 2D Augmentation\n\ndef training_augmentation_2d():\n    train_transform = [\n        album.Sharpen(p=1),\n        album.CLAHE(p=1),\n        album.MedianBlur(p=0.3),\n        album.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ]\n    return album.Compose(train_transform,)\n\ndef validation_augmentation_2d():\n    train_transform = [\n#         album.CLAHE(p=1),\n#         album.Sharpen(p=1),\n        album.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ]\n    return album.Compose(train_transform,)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 3D Augmentation\n\nflip = tio.RandomFlip(axes=['inferior-superior'])\n\nswap = tio.RandomSwap(patch_size=[5, 5, 5], p=.4)\nadd_noise = tio.RandomNoise(std=0.5, p=.1)\nbias_field = tio.RandomBiasField(coefficients=0.4, p=.6)\nadd_motion = tio.RandomMotion(num_transforms=1, image_interpolation='nearest', p=.2)\n\ncanonical = tio.ToCanonical()\nstandardize = tio.ZNormalization(masking_method=tio.ZNormalization.mean)\nintensity = tio.RescaleIntensity((-1, 1))\n\ndef training_augmentation_3d():\n    transform = tio.Compose([\n        canonical,\n        flip,\n        swap,\n        bias_field,\n#         standardize,  \n#         intensity\n    ])\n    \n    return transform\n\ndef validation_augmentation_3d():\n    transform = tio.Compose([\n        canonical,\n#         standardize, \n#         intensity\n    ])\n    \n    return transform","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Loading the Dataset**","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(f\"{data_directory}/train_labels.csv\")\ndisplay(train_df)\n\ndf_train, df_valid = sk_model_selection.train_test_split(\n    train_df, \n    test_size=0.3, \n    random_state=SEED, \n    stratify=train_df[\"MGMT_value\"],\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Dataset and Dataloader**","metadata":{}},{"cell_type":"code","source":"class Dataset(torch_data.Dataset):\n    def __init__(self, paths, labels=None, mri_type=None, label_smoothing=0.01, augmentation=None, transformation=None, split=\"train\"):\n        self.paths = paths\n        self.labels = labels\n        self.mri_type = mri_type\n        self.label_smoothing = label_smoothing\n        self.augmentation = augmentation\n        self.transformation = transformation\n        self.split = split\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):\n        scan_id = self.paths[index]\n        label = self.labels[index]\n        \n        images = []\n        \n        for i in mri_types:\n            image_3d = load_dicom_images_3d(scan_id=str(scan_id).zfill(5), mri_type=i)\n            image_3d = cropped_images(image_3d)\n\n            if self.augmentation:\n                for i in range(image_3d.shape[-1]):\n                    temp_img = image_3d[:, :, i].astype(np.uint8)\n                    temp_img = cv2.cvtColor(temp_img, cv2.COLOR_BGR2RGB)\n                    temp_img = self.augmentation(image=temp_img)['image'][:, :, 0]\n                    image_3d[:, :, i] = temp_img\n            \n            if np.all(image_3d is not None):\n                images.append(image_3d)\n        four_channel_pack = np.stack(images)\n        four_channel_pack = np.transpose(four_channel_pack, (0, 3, 2, 1))\n            \n        # transformation\n        if self.transformation:\n            four_channel_pack = self.transformation(four_channel_pack)\n        \n        y = self.labels[index]\n        \n        return {\"X\": torch.tensor(four_channel_pack).float(), \"y\": y}","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:13:23.866716Z","iopub.execute_input":"2022-05-29T15:13:23.867066Z","iopub.status.idle":"2022-05-29T15:13:23.879220Z","shell.execute_reply.started":"2022-05-29T15:13:23.867037Z","shell.execute_reply":"2022-05-29T15:13:23.876956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Test 3D Voxel Augmentation**","metadata":{}},{"cell_type":"code","source":"train_dataset = Dataset(\n    paths=df_train[\"BraTS21ID\"].values, \n    labels=df_train[\"MGMT_value\"].values,\n    transformation=training_augmentation_3d(),\n)\n\n\ntrain_loader = torch_data.DataLoader(train_dataset, batch_size=4, shuffle=False, num_workers=8,)\nimg = train_dataset[4][\"X\"]\nprint(img.shape)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:13:23.880916Z","iopub.execute_input":"2022-05-29T15:13:23.881578Z","iopub.status.idle":"2022-05-29T15:13:25.362611Z","shell.execute_reply.started":"2022-05-29T15:13:23.881427Z","shell.execute_reply":"2022-05-29T15:13:25.361686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = plt.figure(figsize=(20, 20))\ncolumns = 8\nrows = 6\n\nfor i in range(1, columns*rows+1):\n    _img = img[0, i, :, :]\n    ax = fig.add_subplot(rows, columns, i)\n    ax.set_title(f'slice {i}')\n    plt.imshow(_img)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:13:25.363914Z","iopub.execute_input":"2022-05-29T15:13:25.364251Z","iopub.status.idle":"2022-05-29T15:13:29.467636Z","shell.execute_reply.started":"2022-05-29T15:13:25.364214Z","shell.execute_reply":"2022-05-29T15:13:29.466686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **3D ResNet Model**","metadata":{}},{"cell_type":"code","source":"class BasicBlock(nn.Module):\n    expansion = 1\n\n    def __init__(self, in_planes, out_planes, stride=1, downsample=None):\n        super(BasicBlock, self).__init__()\n        \n        \n        self.conv1 = nn.Conv3d(in_planes, \n                               out_planes,\n                               kernel_size=3,\n                               stride=1,\n                               padding=1,\n                               bias=False\n                              )\n        \n        self.conv2 = nn.Conv3d(out_planes, \n                               out_planes,\n                               kernel_size=3,\n                               stride=stride,\n                               padding=1,\n                               bias=False\n                              )\n\n        self.bn1 = nn.BatchNorm3d(out_planes)\n        self.relu = nn.ReLU(inplace=True)\n        self.bn2 = nn.BatchNorm3d(out_planes)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        # Residual Connection Block\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n        \n        out = self.conv2(out)\n        out = self.bn2(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out += residual\n        out = self.relu(out)\n\n        return out\n\n    \nclass BasicStem(nn.Sequential):\n    \"\"\"\n    conv-batchnorm-relu stem\n    \"\"\"\n    def __init__(self, in_planes=64, in_channels=1):\n        super(BasicStem, self).__init__(\n            nn.Conv3d(in_channels, in_planes, \n                      kernel_size=(7, 7, 7), \n                      stride=(1, 2, 2),\n                      padding=(1, 3, 3), \n                      bias=False\n                     ),\n            nn.BatchNorm3d(in_planes),\n            nn.ReLU(inplace=True)\n        )\n\n\nclass ResNet3D(nn.Module):\n\n    def __init__(self, block, stem,\n                 model_name='resnet-18',\n                 in_channels=1,\n                 n_classes=2\n                ):\n        super(ResNet3D, self).__init__()\n        \n        __depths__ = {\n            'resnet-10': [1, 1, 1, 1],\n            'resnet-18': [2, 2, 2, 2],\n        }\n        \n        assert model_name in __depths__, f'Specified model name {model_name} cant be loaded\\nAvailable models: {[model for model in __depths__]}'\n        layers = __depths__[model_name]\n        self.inplanes = 64\n        \n        # Stem\n        self.stem = stem(self.inplanes, in_channels)\n        \n        # Layers\n        self.layer1 = self._layer(block, 64, layers[0],)\n        self.layer2 = self._layer(block, 128, layers[1], stride=2)\n        self.layer3 = self._layer(block, 256, layers[2], stride=2)\n        self.layer4 = self._layer(block, 512, layers[3], stride=2)\n        \n        # Fetching\n        self.avgpool = nn.AdaptiveAvgPool3d((1, 1, 1))\n        self.fc = nn.Linear(512 * block.expansion, n_classes)\n\n        for m in self.modules():\n            if isinstance(m, nn.Conv3d):\n                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n            elif isinstance(m, nn.BatchNorm3d):\n                nn.init.constant_(m.weight, 1)\n                nn.init.constant_(m.bias, 0)\n                \n    def forward(self, x):\n        x = self.stem(x)\n\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n\n        x = self.avgpool(x)\n\n        # Flatten the layer to fc\n        x = x.flatten(1)\n        x = self.fc(x)\n\n        return x\n\n    def _layer(self, block, planes, blocks, stride=1):\n        downsample = None\n        \n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                nn.Conv3d(self.inplanes, planes * block.expansion,\n                          kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm3d(planes * block.expansion)\n            )\n        layers = []\n        layers.append(block(self.inplanes, planes, stride, downsample))\n\n        self.inplanes = planes * block.expansion\n\n        for i in range(blocks - 1):\n            layers.append(block(self.inplanes, planes))\n\n        return nn.Sequential(*layers)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Training**","metadata":{}},{"cell_type":"code","source":"class Trainer:\n    def __init__(\n        self, \n        model, \n        device, \n        optimizer, \n        criterion\n    ):\n        self.model = model\n        self.device = device\n        self.optimizer = optimizer\n        self.criterion = criterion\n\n        self.best_valid_score = np.inf\n        self.n_patience = 0\n        self.lastmodel = None\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_auc, train_time = self.train_epoch(train_loader)\n            valid_loss, valid_auc, valid_time = self.valid_epoch(valid_loader)\n            \n            wandb.log({\"train_auc\": train_auc})\n            wandb.log({\"train_loss\": train_loss})\n            \n            wandb.log({\"valid_auc\": valid_auc})\n            wandb.log({\"valid_loss\": valid_loss})\n            \n            self.info_message(\n                \"[Epoch Train: {}] loss: {:.4f}, time: {:.2f} s            \",\n                n_epoch, train_loss, train_time\n            )\n            \n            self.info_message(\n                \"[Epoch Valid: {}] loss: {:.4f}, auc: {:.4f}, time: {:.2f} s\",\n                n_epoch, valid_loss, valid_auc, valid_time\n            )\n\n            self.save_model(n_epoch, save_path, valid_loss, valid_auc)\n\n            if self.best_valid_score > valid_loss: \n                self.info_message(\n                     \"auc improved from {:.4f} to {:.4f}. Saved model to '{}'\", \n                    self.best_valid_score, valid_loss, self.lastmodel\n                )\n                self.best_valid_score = valid_loss\n                self.n_patience = 0\n            else:\n                self.n_patience += 1\n            \n            if self.n_patience >= patience:\n                self.info_message(\"\\nValid auc didn't improve last {} epochs.\", patience)\n                break\n            \n    def train_epoch(self, train_loader):\n        self.model.train()\n        t = time.time()\n        sum_loss = 0\n        y_all = []\n        outputs_all = []\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.float())\n            loss.backward()\n\n            sum_loss += loss.detach().item()\n\n            y_all.extend(batch[\"y\"].tolist())\n            outputs_all.extend(torch.sigmoid(outputs).tolist())\n                \n            self.optimizer.step()\n            \n            message = 'Train Step {}/{}, train_loss: {:.4f}'\n            self.info_message(message, step, len(train_loader), sum_loss/step, end=\"\\r\")\n        \n        y_all = [1 if x > 0.5 else 0 for x in y_all]\n        auc = roc_auc_score(y_all, outputs_all)\n        \n        return sum_loss/len(train_loader), auc, int(time.time() - t)\n    \n    def valid_epoch(self, valid_loader):\n        self.model.eval()\n        t = time.time()\n        sum_loss = 0\n        y_all = []\n        outputs_all = []\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.float())\n\n                sum_loss += loss.detach().item()\n                y_all.extend(batch[\"y\"].tolist())\n                outputs_all.extend(torch.sigmoid(outputs).tolist())\n\n            message = 'Valid Step {}/{}, valid_loss: {:.4f}'\n            self.info_message(message, step, len(valid_loader), sum_loss/step, end=\"\\r\")\n            \n        y_all = [1 if x > 0.5 else 0 for x in y_all]\n        auc = roc_auc_score(y_all, outputs_all)\n        \n        return sum_loss/len(valid_loader), auc, int(time.time() - t)\n    \n    def save_model(self, n_epoch, save_path, loss, auc):\n        self.lastmodel = f\"{save_path}-best-e{n_epoch}.pth\"\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            self.lastmodel,\n        )\n    \n    @staticmethod\n    def info_message(message, *args, end=\"\\n\"):\n        print(message.format(*args), end=end)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# wandb login\n# import wandb\n\n# wandb.init(project=\"RSNA-MICCAI-Brain-Tumor\", entity=\"slavko_prytula\")\n# wandb.init(project=\"...\", entity=\"...\")","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:13:29.529081Z","iopub.execute_input":"2022-05-29T15:13:29.529805Z","iopub.status.idle":"2022-05-29T15:13:29.537552Z","shell.execute_reply.started":"2022-05-29T15:13:29.529767Z","shell.execute_reply":"2022-05-29T15:13:29.536696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_mri_type(df_train, df_valid):\n    \n    train_data_retriever = Dataset(\n        paths=df_train[\"BraTS21ID\"].values, \n        labels=df_train[\"MGMT_value\"].values,\n        transformation=training_augmentation_3d(),\n    )\n    valid_data_retriever = Dataset(\n        paths=df_valid[\"BraTS21ID\"].values, \n        labels=df_valid[\"MGMT_value\"].values,\n        transformation=validation_augmentation_3d(),\n    )\n\n    train_loader = torch_data.DataLoader(train_data_retriever, batch_size=BATCH_SIZE, shuffle=True, num_workers=8,)\n    valid_loader = torch_data.DataLoader(valid_data_retriever, batch_size=BATCH_SIZE, shuffle=True, num_workers=8,)\n\n    model = ResNet3D(\n        block=BasicBlock, \n        stem=BasicStem, \n        model_name='resnet-10',\n        in_channels=1,\n        n_classes=1\n    )\n    model.to(device)\n\n\n    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n    criterion = torch_functional.binary_cross_entropy_with_logits\n    lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)\n\n    trainer = Trainer(\n        model, \n        device, \n        optimizer, \n        criterion,\n    )\n\n    history = trainer.fit(\n        10, \n        train_loader, \n        valid_loader, \n        \"model\",\n        10,\n    )\n    \n    return trainer.lastmodel\n\ntrain_mri_type(df_train, df_valid)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:13:29.541765Z","iopub.execute_input":"2022-05-29T15:13:29.542074Z","iopub.status.idle":"2022-05-29T15:30:32.336039Z","shell.execute_reply.started":"2022-05-29T15:13:29.542024Z","shell.execute_reply":"2022-05-29T15:30:32.334570Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### ","metadata":{}},{"cell_type":"markdown","source":"# **Testing the model**","metadata":{}},{"cell_type":"code","source":"df_train = df_train.set_index(\"BraTS21ID\")\ndf_train[\"MGMT_pred\"] = 0","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_valid = df_valid.set_index(\"BraTS21ID\")\ndf_valid[\"MGMT_pred\"] = 0","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"modelfile = \"../input/rsnabraintumorclassificationmodels/EYD-resnet-hw256-d64-adam1e-4-bs3-t1wce-e10-l0.681-a0.624.pth\"\n\nmodel = ResNet3D(\n    block=BasicBlock, \n    stem=BasicStem, \n    model_name='resnet-10',\n    in_channels=1,\n    n_classes=1\n)\nmodel.to(device)\n\nif torch.cuda.is_available():\n    checkpoint = torch.load(modelfile)\nelse:\n    checkpoint = torch.load(modelfile, map_location=torch.device('cpu'))    \nmodel.load_state_dict(checkpoint[\"model_state_dict\"])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TestDataset(torch_data.Dataset):\n    def __init__(self, paths, labels=None, mri_type=None, label_smoothing=0.01, augmentation=None, transformation=None, split=\"train\"):\n        self.paths = paths\n        self.labels = labels\n        self.mri_type = mri_type\n        self.label_smoothing = label_smoothing\n        self.augmentation = augmentation\n        self.transformation = transformation\n        self.split = split\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, index):\n        scan_id = self.paths[index]\n        label = self.labels[index]\n        images = []\n        \n        for i in mri_types:\n            image_3d = load_dicom_images_3d(scan_id=str(scan_id).zfill(5), mri_type=i)\n            image_3d = cropped_images(image_3d)\n\n            if self.augmentation:\n                for i in range(image_3d.shape[-1]):\n                    temp_img = image_3d[:, :, i].astype(np.uint8)\n                    temp_img = cv2.cvtColor(temp_img, cv2.COLOR_BGR2RGB)\n                    temp_img = self.augmentation(image=temp_img)['image'][:, :, 0]\n                    image_3d[:, :, i] = temp_img\n            images.append(image_3d)\n        four_channel_pack = np.stack(images)\n        four_channel_pack = np.transpose(four_channel_pack, (0, 3, 2, 1))\n        \n        # transformation\n        if self.transformation:\n            four_channel_pack = self.transformation(four_channel_pack)\n            \n        y = self.labels[index]\n        \n        return torch.tensor(four_channel_pack).float(), y","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.343461Z","iopub.status.idle":"2022-05-29T15:30:32.344081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **AUC Score**","metadata":{}},{"cell_type":"code","source":"data_retriever = Dataset(\n    df_valid.index.values, \n    df_valid[\"MGMT_value\"].values,\n    transformation=validation_augmentation_3d(),\n    split=\"test\",\n)\n\ndata_loader = torch_data.DataLoader(\n    data_retriever,\n    batch_size=1,\n    shuffle=False,\n    num_workers=8,\n)\n\ny_preds = []\ny = []\n\nfor e, batch in enumerate(data_loader):\n    print(f\"{e + 1}/{len(data_loader)}\", end=\"\\r\")\n    with torch.no_grad():\n        model.eval()\n        image, label = batch[\"X\"].to(device), batch[\"y\"]\n    \n        output_ = model(image)\n        _, pred = torch.max(output_, dim=1)\n\n        percentage = output_.sigmoid().detach().cpu().numpy().squeeze()\n        prediction = percentage\n        \n        label = label.detach().cpu().numpy()[0]\n        \n        y.append(label)\n        y_preds.append(prediction)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.345332Z","iopub.status.idle":"2022-05-29T15:30:32.345943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# score\ny = np.array(y)\ny_preds = np.array(y_preds)\n\nfpr, tpr, thresholds = metrics.roc_curve(y, y_preds, pos_label=1)\nroc_auc = metrics.auc(fpr, tpr)\n\nprint(f\"AUC score is: {roc_auc}\")","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.347191Z","iopub.status.idle":"2022-05-29T15:30:32.347928Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.style.use(\"seaborn-white\")\n\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.metrics import roc_curve\n\nplt.figure(figsize=[8, 8])\nplt.plot(fpr, tpr, label='3D ResNet10 (area = %0.2f)' % roc_auc, color='blue')\nplt.plot([0, 1], [0, 1],'r--')\nplt.xlim([0.0, 1.0])\nplt.ylim([0.0, 1.05])\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('Receiver operating characteristic [ROC AUC]')\nplt.legend(loc=\"lower right\")\nplt.savefig('resnet10-rocauc.jpg')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.349199Z","iopub.status.idle":"2022-05-29T15:30:32.349781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SUBMISSIONDataset(torch_data.Dataset):\n    def __init__(self, \n                 augmentation=None, \n                 transformation=None,\n                 preprocessing=None,\n                ):\n        self.indexes = sorted(os.listdir(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/test\"))\n        self.augmentation = augmentation\n        self.transformation = transformation\n        self.preprocessing = preprocessing\n          \n    def __len__(self):\n        return len(self.indexes)\n    \n    def __getitem__(self, index):\n        scan_id = self.indexes[index]\n        four_channel_pack = None\n        images = []\n        \n        try:\n            for i in mri_types:\n                try:\n                    image_3d = load_dicom_images_3d(scan_id=str(scan_id).zfill(5), split=\"test\", mri_type=i)\n                    image_3d = cropped_images(image_3d)\n\n                    if self.augmentation:\n                        for i in range(image_3d.shape[-1]):\n                            temp_img = image_3d[:, :, i].astype(np.uint8)\n                            temp_img = cv2.cvtColor(temp_img, cv2.COLOR_BGR2RGB)\n                            temp_img = self.augmentation(image=temp_img)['image'][:, :, 0]\n                            image_3d[:, :, i] = temp_img\n                    images.append(image_3d)\n                except:\n                    pass\n            four_channel_pack = np.stack(images)\n            four_channel_pack = np.transpose(four_channel_pack, (0, 3, 2, 1))\n        except:\n            pass\n        \n        # transformation\n        if self.transformation:\n            four_channel_pack = self.transformation(four_channel_pack)\n        \n        return {\"X\": torch.tensor(four_channel_pack).float(), \"id\": scan_id}","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.350911Z","iopub.status.idle":"2022-05-29T15:30:32.351521Z"},"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_dataset = SUBMISSIONDataset(\n    augmentation=get_training_augmentation(),\n)\n\ndata_loader = torch_data.DataLoader(\n    test_dataset,\n    batch_size=1,\n    shuffle=False,\n    num_workers=8,\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.353776Z","iopub.status.idle":"2022-05-29T15:30:32.354689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ids = []\npreds = []\n\nfor e, batch in enumerate(data_loader):\n    print(f\"{e}/{len(data_loader)}\", end=\"\\r\")\n    with torch.no_grad():\n        model.eval()\n        image, id = batch[\"X\"].to(device), str(batch[\"id\"][0])\n        \n        try:\n            output_ = model(image)\n            percentage = output_.sigmoid().detach().cpu().numpy()[0][1]\n            prediction = percentage\n        except:\n            prediction = 0.5\n            \n        preds.append(prediction)\n        ids.append(id)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.355886Z","iopub.status.idle":"2022-05-29T15:30:32.356651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame({\"BraTS21ID\": ids, \"MGMT_value\": preds})\ndf[['BraTS21ID', 'MGMT_value']].to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.357805Z","iopub.status.idle":"2022-05-29T15:30:32.358589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.359731Z","iopub.status.idle":"2022-05-29T15:30:32.360512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.displot(df[\"MGMT_value\"])","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:30:32.361643Z","iopub.status.idle":"2022-05-29T15:30:32.362431Z"},"trusted":true},"execution_count":null,"outputs":[]}]}