{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":52254,"databundleVersionId":9674523,"sourceType":"competition"},{"sourceId":6331238,"sourceType":"datasetVersion","datasetId":3644255}],"dockerImageVersionId":30528,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# import packages\nimport os\nimport pickle\nfrom tqdm.notebook import tqdm\nimport random\nfrom tabulate import tabulate\n\nimport cv2\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport numpy as np\nimport pandas as pd\nimport pydicom\nimport matplotlib.pyplot as plt\nimport torchvision.transforms.v2 as t\n\nfrom sklearn.model_selection import KFold, StratifiedKFold\nfrom sklearn.metrics import accuracy_score, roc_auc_score\nfrom torch.utils.data import Dataset, DataLoader, Subset\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\nfrom torch.optim import Adam\nfrom torchvision import models\nfrom torchvision.transforms.v2 import Resize, Compose, RandomHorizontalFlip, ColorJitter, RandomAffine, RandomErasing, ToTensor","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-11T18:33:33.986354Z","iopub.execute_input":"2024-10-11T18:33:33.987045Z","iopub.status.idle":"2024-10-11T18:33:39.42586Z","shell.execute_reply.started":"2024-10-11T18:33:33.987014Z","shell.execute_reply":"2024-10-11T18:33:39.424972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN_IMG_PATH = '/kaggle/input/rsna-2023-atd-reduced-256-5mm/reduced_256_tickness_5'\nTEST_IMG_PATH = '/kaggle/input/rsna-2023-abdominal-trauma-detection/test_images'\nTRAIN_DF_PATH = '/kaggle/input/rsna-2023-abdominal-trauma-detection/train.csv'","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.427419Z","iopub.execute_input":"2024-10-11T18:33:39.427951Z","iopub.status.idle":"2024-10-11T18:33:39.432666Z","shell.execute_reply.started":"2024-10-11T18:33:39.427922Z","shell.execute_reply":"2024-10-11T18:33:39.431584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def fetch_img_paths(train_img_path):\n    img_paths = []\n    \n    print('Scanning directories...')\n    for patient in tqdm(os.listdir(train_img_path)):\n        for scan in os.listdir(os.path.join(TRAIN_IMG_PATH, patient)):\n            scans = []\n            for img in os.listdir(os.path.join(TRAIN_IMG_PATH, patient, scan)):\n                scans.append(os.path.join(TRAIN_IMG_PATH, patient, scan, img))\n            \n            img_paths.append(scans)\n            \n    return img_paths","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.434008Z","iopub.execute_input":"2024-10-11T18:33:39.434368Z","iopub.status.idle":"2024-10-11T18:33:39.451856Z","shell.execute_reply.started":"2024-10-11T18:33:39.434336Z","shell.execute_reply":"2024-10-11T18:33:39.450987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def select_elements_with_spacing(input_list, spacing):\n    \n    \"\"\"\n    Selects elements with a specified spacing from a given list.\n\n    Args:\n        input_list (list): The input list from which elements will be selected.\n        spacing (int): The spacing between selected elements.\n\n    Returns:\n        list: A list of selected elements from the input list.\n\n    Raises:\n        ValueError: If the input list does not contain at least 4 * spacing elements.\n    \"\"\"\n \n    if len(input_list) < spacing * 4:\n        raise ValueError(\"List should contain at least 4 * spacing elements.\")\n        \n        \n    # We want to select elements in the middle part of the abdomen\n    lower_bound = int(len(input_list) * 0.4)\n    upper_bound = int(len(input_list) * 0.6)\n\n    spacing = (upper_bound - lower_bound) // 3\n    \n    # start_index = random.randint(lower_bound, upper_bound)\n    \n    selected_indices = [lower_bound, lower_bound + spacing, lower_bound + (2*spacing), upper_bound]\n    \n    selected_elements = [input_list[index] for index in selected_indices]\n    \n    return selected_elements","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.453997Z","iopub.execute_input":"2024-10-11T18:33:39.454316Z","iopub.status.idle":"2024-10-11T18:33:39.463052Z","shell.execute_reply.started":"2024-10-11T18:33:39.454291Z","shell.execute_reply":"2024-10-11T18:33:39.462195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def standardize_pixel_array(dicom_image):\n    \"\"\"\n    Standardizes a DICOM pixel array by applying various transformations.\n    \n    Args:\n        dicom_path (str): Path to the DICOM image file.\n        \n    Returns:\n        np.ndarray: The standardized pixel array of the DICOM image.\n    \"\"\"\n    pixel_array = dicom_image.pixel_array\n    \n    if dicom_image.PixelRepresentation == 1:\n        bit_shift = dicom_image.BitsAllocated - dicom_image.BitsStored\n        dtype = pixel_array.dtype \n        new_array = (pixel_array << bit_shift).astype(dtype) >>  bit_shift\n        pixel_array = pydicom.pixel_data_handlers.util.apply_modality_lut(new_array, dicom_image)\n\n    if dicom_image.PhotometricInterpretation == \"MONOCHROME1\":\n        pixel_array = 1 - pixel_array\n\n    # transform to hounsfield units\n    intercept = dicom_image.RescaleIntercept\n    slope = dicom_image.RescaleSlope\n    pixel_array = pixel_array * slope + intercept\n\n    # windowing\n    window_center = int(dicom_image.WindowCenter)\n    window_width = int(dicom_image.WindowWidth)\n    img_min = window_center - window_width // 2\n    img_max = window_center + window_width // 2\n    pixel_array = pixel_array.copy()\n    pixel_array[pixel_array < img_min] = img_min\n    pixel_array[pixel_array > img_max] = img_max\n\n    # normalization\n    if pixel_array.max() == pixel_array.min():\n        pixel_array = np.zeros_like(pixel_array)  # Handle case of constant array\n    else:\n        pixel_array = (pixel_array - pixel_array.min()) / (pixel_array.max() - pixel_array.min())\n\n    return pixel_array","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.464031Z","iopub.execute_input":"2024-10-11T18:33:39.464307Z","iopub.status.idle":"2024-10-11T18:33:39.479043Z","shell.execute_reply.started":"2024-10-11T18:33:39.464283Z","shell.execute_reply":"2024-10-11T18:33:39.478074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocess_jpeg(jpeg_path):\n    \n    img = cv2.imread(jpeg_path)\n    greyscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)/255\n    \n    return greyscale","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.480408Z","iopub.execute_input":"2024-10-11T18:33:39.481009Z","iopub.status.idle":"2024-10-11T18:33:39.492934Z","shell.execute_reply.started":"2024-10-11T18:33:39.480983Z","shell.execute_reply":"2024-10-11T18:33:39.491975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# dataset\nclass AbdominalData(Dataset):\n    \"\"\"\n    Custom dataset class for handling abdominal trauma data classification.\n    \n    Args:\n        df_path (str): Path to the CSV file containing patient labels.\n        current_fold (int): The current fold for cross-validation.\n        num_fold (int, optional): Total number of folds for cross-validation. Default is 5.\n    \"\"\"\n    \n    def __init__(self, df_path, current_fold, num_fold = 5):\n        \n        super().__init__()\n        \n        # collect all the image instance paths\n        self.img_paths = fetch_img_paths(TRAIN_IMG_PATH)\n                \n        self.df = pd.read_csv(df_path)\n        \n        self.num_fold = num_fold\n        self.current_fold = current_fold\n        self.kf = KFold(n_splits=num_fold)\n        \n        self.transform = Compose([\n#                             Resize((256, 256), antialias=True),\n                            RandomHorizontalFlip(),  # Randomly flip images left-right\n                            ColorJitter(brightness=0.2),  # Randomly adjust brightness\n                            ColorJitter(contrast=0.2),  # Randomly adjust contrast\n                            RandomAffine(degrees=0, shear=10),  # Apply shear transformation\n                            RandomAffine(degrees=0, scale=(0.8, 1.2)),  # Apply zoom transformation\n                            RandomErasing(p=0.2, scale=(0.02, 0.2)), # Coarse dropout\n                            ToTensor(),\n                        ])\n    \n    def __len__(self):\n        \"\"\"\n        Returns the total number of samples in the dataset.\n        \"\"\"\n        \n        return len(self.img_paths)\n    \n    def __getitem__(self, idx):\n        \"\"\"\n        Retrieves a sample from the dataset by index.\n        \n        Args:\n            idx (int): Index of the dataset to retrieve.\n        \n        Returns:\n            dict: A dictionary containing the image data and labels for different abdominal structures.\n        \"\"\"\n        \n        # sample 4 image instances\n        dicom_images = select_elements_with_spacing(self.img_paths[idx],\n                                                    spacing = 2)\n        patient_id = dicom_images[0].split('/')[-3]\n        images = []\n        \n        for d in dicom_images:\n            image = preprocess_jpeg(d)\n            images.append(image)\n            \n        images = np.stack(images)\n        image = torch.tensor(images, dtype = torch.float).unsqueeze(dim = 1)\n        \n        image = self.transform(image).squeeze(dim = 1)\n        \n        label = self.df[self.df.patient_id == int(patient_id)].values[0][1:-1]\n        \n        # labels\n        bowel = np.argmax(label[0:2], keepdims = True)\n        extravasation = np.argmax(label[2:4], keepdims = True)\n        kidney = np.argmax(label[4:7], keepdims = False)\n        liver = np.argmax(label[7:10], keepdims = False)\n        spleen = np.argmax(label[10:], keepdims = False)\n        \n        \n        return {\n            'image': image,\n            'bowel': bowel,\n            'extravasation': extravasation,\n            'kidney': kidney,\n            'liver': liver,\n            'spleen': spleen,\n        }\n    \n    def get_splits(self):\n        \"\"\"\n        Splits the dataset into training and validation subsets based on the current fold.\n        \n        Returns:\n            tuple: A tuple containing the training and validation subsets.\n        \"\"\"\n        \n        fold_data = list(self.kf.split(self.img_paths))\n        train_indices, val_indices = fold_data[self.current_fold]\n\n        train_data = self._get_subset(train_indices)\n        val_data = self._get_subset(val_indices)\n        \n        return train_data, val_data\n\n    def _get_subset(self, indices):\n        \"\"\"\n        Returns a subset of the dataset based on the provided indices.\n        \n        Args:\n            indices (list): List of indices to include in the subset.\n        \n        Returns:\n            Subset: A subset of the dataset.\n        \"\"\"\n        return Subset(self, indices)","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.494158Z","iopub.execute_input":"2024-10-11T18:33:39.49444Z","iopub.status.idle":"2024-10-11T18:33:39.511019Z","shell.execute_reply.started":"2024-10-11T18:33:39.494416Z","shell.execute_reply":"2024-10-11T18:33:39.510136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MetricsCalculator:\n    \n    def __init__(self, mode = 'binary'):\n        \n        self.probabilities = []\n        self.predictions = []\n        self.targets = []\n        \n        self.mode = mode\n    \n    def update(self, logits, target):\n        \"\"\"\n        Update the metrics calculator with predicted values and corresponding targets.\n        \n        Args:\n            predicted (torch.Tensor): Predicted values.\n            target (torch.Tensor): Ground truth targets.\n        \"\"\"\n        if self.mode == 'binary':\n            probabilities = torch.sigmoid(logits)\n            predicted = (probabilities > 0.5)\n        else:\n            probabilities = F.softmax(logits, dim = 1)\n            predicted = torch.argmax(probabilities, dim=1)\n            \n        self.probabilities.extend(probabilities.detach().cpu().numpy())\n        self.predictions.extend(predicted.detach().cpu().numpy())\n        self.targets.extend(target.detach().cpu().numpy())\n    \n    def reset(self):\n        \"\"\"Reset the stored predictions and targets.\"\"\"\n        \n        self.probabilities = []\n        self.predictions = []\n        self.targets = []\n    \n    def compute_accuracy(self):\n        \"\"\"\n        Compute the accuracy metric.\n        \n        Returns:\n            float: Accuracy.\n        \"\"\"\n        return accuracy_score(self.targets, self.predictions)\n    \n    def compute_auc(self):\n        \"\"\"\n        Compute the AUC (Area Under the Curve) metric.\n        \n        Returns:\n            float: AUC.\n        \"\"\"\n        if self.mode == 'multi':\n            return roc_auc_score(self.targets, self.probabilities, multi_class = 'ovo', labels=[0, 1, 2])\n    \n        else:\n            return roc_auc_score(self.targets, self.probabilities)","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.51215Z","iopub.execute_input":"2024-10-11T18:33:39.512441Z","iopub.status.idle":"2024-10-11T18:33:39.524777Z","shell.execute_reply.started":"2024-10-11T18:33:39.512416Z","shell.execute_reply":"2024-10-11T18:33:39.523831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Model Architecure\n#class CNNModel(nn.Module):\n  #  def __init__(self):\n  #     super().__init__()\n        \n  #      self.input = nn.Conv2d(4, 3, kernel_size = 3)\n  #      model = models.efficientnet_b0(weights = 'IMAGENET1K_V1')\n        \n  #      self.features = model.features\n  #      self.avgpool = model.avgpool\n        \n  #      self.bowel = nn.Linear(1280, 1)\n  #      self.extravasation = nn.Linear(1280, 1)\n  #      self.kidney = nn.Linear(1280, 3)\n  #      self.liver = nn.Linear(1280,3) \n  #      self.spleen = nn.Linear(1280, 3)\n    \n  #  def forward(self, x):\n        \n        # extract features\n  #      x = self.input(x)\n  #      x = self.features(x)\n  #      x = self.avgpool(x)\n  #      x = torch.flatten(x, 1)\n        \n        # output logits\n  #      bowel = self.bowel(x)\n  #      extravsation = self.extravasation(x)\n  #      kidney = self.kidney(x)\n  #      liver = self.liver(x)\n  #       spleen = self.spleen(x)\n        \n  #      return bowel, extravsation, kidney, liver, spleen","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.525956Z","iopub.execute_input":"2024-10-11T18:33:39.526552Z","iopub.status.idle":"2024-10-11T18:33:39.537784Z","shell.execute_reply.started":"2024-10-11T18:33:39.526506Z","shell.execute_reply":"2024-10-11T18:33:39.536906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torchvision import models\n\nclass ResidualBlock(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        self.shortcut = nn.Conv2d(in_channels, out_channels, kernel_size=1) if in_channels != out_channels else nn.Identity()\n\n    def forward(self, x):\n        out = F.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out += self.shortcut(x)\n        return F.relu(out)\n\nclass CNNModel(nn.Module):\n    def __init__(self):\n        super(CNNModel, self).__init__()\n\n        # Lớp input với 4 kênh đầu vào (ví dụ: ảnh với thông tin y tế)\n        self.input = nn.Conv2d(4, 3, kernel_size=3, padding=1)\n\n        # Sử dụng mô hình EfficientNet pretrained\n        model = models.efficientnet_b0(weights='IMAGENET1K_V1')\n        self.features = model.features\n        self.avgpool = model.avgpool\n\n        # Fully connected layers for each task\n        self.bowel = nn.Linear(1280, 1)\n        self.extravasation = nn.Linear(1280, 1)\n        self.kidney = nn.Linear(1280, 3)\n        self.liver = nn.Linear(1280, 3)\n        self.spleen = nn.Linear(1280, 3)\n\n    def forward(self, x):\n        # Sử dụng layer input để chuyển đổi 4 kênh thành 3 kênh\n        x = self.input(x)\n\n        # Extract features using EfficientNet\n        x = self.features(x)\n        x = self.avgpool(x)\n        x = torch.flatten(x, 1)\n\n        # Output logits cho mỗi cơ quan\n        bowel = self.bowel(x)\n        extravasation = self.extravasation(x)\n        kidney = self.kidney(x)\n        liver = self.liver(x)\n        spleen = self.spleen(x)\n\n        return bowel, extravasation, kidney, liver, spleen\n\n","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.541692Z","iopub.execute_input":"2024-10-11T18:33:39.54207Z","iopub.status.idle":"2024-10-11T18:33:39.556041Z","shell.execute_reply.started":"2024-10-11T18:33:39.542043Z","shell.execute_reply":"2024-10-11T18:33:39.555212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Khởi tạo mô hình với CUDA\nmodel = CNNModel().to('cuda')","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:39.557291Z","iopub.execute_input":"2024-10-11T18:33:39.55789Z","iopub.status.idle":"2024-10-11T18:33:40.421493Z","shell.execute_reply.started":"2024-10-11T18:33:39.557856Z","shell.execute_reply":"2024-10-11T18:33:40.420689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE = 16\nNUM_EPOCHS = 200\nLR = 1e-4","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:40.42253Z","iopub.execute_input":"2024-10-11T18:33:40.422809Z","iopub.status.idle":"2024-10-11T18:33:40.427198Z","shell.execute_reply.started":"2024-10-11T18:33:40.422785Z","shell.execute_reply":"2024-10-11T18:33:40.426274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_0, val_data_0 = AbdominalData('/kaggle/input/rsna-2023-abdominal-trauma-detection/train_2024.csv', current_fold=0).get_splits()\ntrain_data_1, val_data_1 = AbdominalData('/kaggle/input/rsna-2023-abdominal-trauma-detection/train_2024.csv', current_fold=1).get_splits()\ntrain_data_2, val_data_2 = AbdominalData('/kaggle/input/rsna-2023-abdominal-trauma-detection/train_2024.csv', current_fold=2).get_splits()\ntrain_data_3, val_data_3 = AbdominalData('/kaggle/input/rsna-2023-abdominal-trauma-detection/train_2024.csv', current_fold=3).get_splits()\ntrain_data_4, val_data_4 = AbdominalData('/kaggle/input/rsna-2023-abdominal-trauma-detection/train_2024.csv', current_fold=4).get_splits()\n\ntrain_dataloader_0 = DataLoader(train_data_0,batch_size = BATCH_SIZE, shuffle = True)\nval_dataloader_0 = DataLoader(val_data_0,batch_size = BATCH_SIZE, shuffle = False)\ntrain_dataloader_1 = DataLoader(train_data_1,batch_size = BATCH_SIZE, shuffle = True)\nval_dataloader_1 = DataLoader(val_data_1,batch_size = BATCH_SIZE, shuffle = False)\ntrain_dataloader_2 = DataLoader(train_data_2,batch_size = BATCH_SIZE, shuffle = True)\nval_dataloader_2 = DataLoader(val_data_2,batch_size = BATCH_SIZE, shuffle = False)\ntrain_dataloader_3 = DataLoader(train_data_3,batch_size = BATCH_SIZE, shuffle = True)\nval_dataloader_3 = DataLoader(val_data_3,batch_size = BATCH_SIZE, shuffle = False)\ntrain_dataloader_4 = DataLoader(train_data_4,batch_size = BATCH_SIZE, shuffle = True)\nval_dataloader_4 = DataLoader(val_data_4,batch_size = BATCH_SIZE, shuffle = False)","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:33:40.428221Z","iopub.execute_input":"2024-10-11T18:33:40.428474Z","iopub.status.idle":"2024-10-11T18:36:13.392679Z","shell.execute_reply.started":"2024-10-11T18:33:40.428451Z","shell.execute_reply":"2024-10-11T18:36:13.391583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer = torch.optim.Adam(model.parameters(), lr = LR)\nbce_b = nn.BCEWithLogitsLoss(pos_weight = torch.tensor([2.0]).to('cuda'))\nbce_e = nn.BCEWithLogitsLoss(pos_weight = torch.tensor([4.0]).to('cuda'))\ncce = nn.CrossEntropyLoss(label_smoothing = 0.05, weight = torch.tensor([1.0, 2.0, 4.0]).to('cuda'))\nscheduler = ReduceLROnPlateau(optimizer, mode='min', patience=5, factor=0.5, verbose=True)","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:36:13.394098Z","iopub.execute_input":"2024-10-11T18:36:13.394795Z","iopub.status.idle":"2024-10-11T18:36:13.403719Z","shell.execute_reply.started":"2024-10-11T18:36:13.394767Z","shell.execute_reply":"2024-10-11T18:36:13.402683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# initialize metrics objects\ntrain_acc_bowel = MetricsCalculator('binary')\ntrain_acc_extravasation = MetricsCalculator('binary')\ntrain_acc_liver = MetricsCalculator('multi')\ntrain_acc_kidney = MetricsCalculator('multi')\ntrain_acc_spleen = MetricsCalculator('multi')\n\nval_acc_bowel = MetricsCalculator('binary')\nval_acc_extravasation = MetricsCalculator('binary')\nval_acc_liver = MetricsCalculator('multi')\nval_acc_kidney = MetricsCalculator('multi')\nval_acc_spleen = MetricsCalculator('multi')","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:36:13.405076Z","iopub.execute_input":"2024-10-11T18:36:13.405432Z","iopub.status.idle":"2024-10-11T18:36:13.417245Z","shell.execute_reply.started":"2024-10-11T18:36:13.405405Z","shell.execute_reply":"2024-10-11T18:36:13.416553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prev_val_best_loss = float('inf')\n\ndataloaders = [(train_dataloader_0, val_dataloader_0),\n               (train_dataloader_1, val_dataloader_1),\n               (train_dataloader_2, val_dataloader_2), \n               (train_dataloader_3, val_dataloader_3),\n               (train_dataloader_4, val_dataloader_4)]\n\nfor epoch in range(NUM_EPOCHS):\n    \n    # training\n    model.train()\n    \n    train_loss = 0.0\n    val_loss = 0.0\n    \n    print(f'Epoch: [{epoch+1}/{NUM_EPOCHS}]')\n    \n    train_dataloader, val_dataloader = dataloaders[epoch%5]\n    \n    print(f'Fold: {epoch%5}')\n    \n    for batch_idx, batch_data in enumerate(tqdm(train_dataloader)):\n        \n        inputs = batch_data['image'].to('cuda')\n        bowel = batch_data['bowel'].to('cuda')\n        extravasation = batch_data['extravasation'].to('cuda')\n        liver = batch_data['liver'].to('cuda')\n        kidney = batch_data['kidney'].to('cuda')\n        spleen = batch_data['spleen'].to('cuda')\n        \n        optimizer.zero_grad()\n        b, e, k, l, s = model(inputs)\n        b_loss = bce_b(b, bowel.float())\n        e_loss = bce_e(e, extravasation.float())\n        l_loss = cce(l, liver)\n        k_loss = cce(k, kidney)\n        s_loss = cce(s, spleen)\n        \n        total_loss = b_loss + e_loss + l_loss + k_loss + s_loss\n        total_loss.backward()\n        \n        optimizer.step()\n        \n        # calculate training metrics\n        train_loss += total_loss.item()\n        train_acc_bowel.update(b, bowel)\n        train_acc_extravasation.update(e, extravasation)\n        train_acc_liver.update(l, liver)\n        train_acc_kidney.update(k, kidney)\n        train_acc_spleen.update(s, spleen)\n    \n    train_loss = train_loss/(batch_idx+1)\n    \n    # validation\n    model.eval()\n    running_loss = 0.0\n    \n    for batch_idx, batch_data in enumerate(tqdm(val_dataloader)):\n                                                \n        inputs = batch_data['image'].to('cuda')\n        bowel = batch_data['bowel'].to('cuda')\n        extravasation = batch_data['extravasation'].to('cuda')\n        liver = batch_data['liver'].to('cuda')\n        kidney = batch_data['kidney'].to('cuda')\n        spleen = batch_data['spleen'].to('cuda')\n\n        \n        b, e, k, l, s = model(inputs)\n        b_loss = bce_b(b, bowel.float())\n        e_loss = bce_e(e, extravasation.float())\n        l_loss = cce(l, liver)\n        k_loss = cce(k, kidney)\n        s_loss = cce(s, spleen)\n        \n        total_loss = b_loss + e_loss + l_loss + k_loss + s_loss\n        \n        # calculate validation metrics\n        val_loss += total_loss.item()\n        val_acc_bowel.update(b, bowel)\n        val_acc_extravasation.update(e, extravasation)\n        val_acc_liver.update(l, liver)\n        val_acc_kidney.update(k, kidney)\n        val_acc_spleen.update(s, spleen)\n    \n    \n    val_loss = val_loss/(batch_idx+1)\n    scheduler.step(val_loss)\n    \n    if val_loss < prev_val_best_loss:\n        prev_val_best_loss = val_loss\n        print(\"Validation Loss improved, Saving Model...\")\n        torch.save(model, f'efficientnet_b0_{val_loss:.3f}.pth')\n    \n    \n    \n    # accuracy and auc data\n    metrics_data = [\n                    [\"Bowel\", \n                        train_acc_bowel.compute_accuracy(),\n                        val_acc_bowel.compute_accuracy(),\n                        train_acc_bowel.compute_auc(),\n                        val_acc_bowel.compute_auc()],\n                    [\"Extravasation\", \n                        train_acc_extravasation.compute_accuracy(),\n                        val_acc_extravasation.compute_accuracy(),\n                        train_acc_extravasation.compute_auc(),\n                        val_acc_extravasation.compute_auc()],\n                    [\"Liver\", \n                        train_acc_liver.compute_accuracy(),\n                        val_acc_liver.compute_accuracy(),\n                        train_acc_liver.compute_auc(),\n                        val_acc_liver.compute_auc()],\n                    [\"Kidney\", \n                        train_acc_kidney.compute_accuracy(),\n                        val_acc_kidney.compute_accuracy(),\n                        train_acc_kidney.compute_auc(),\n                        val_acc_kidney.compute_auc()],\n                    [\"Spleen\", \n                        train_acc_spleen.compute_accuracy(),\n                        val_acc_spleen.compute_accuracy(),\n                        train_acc_spleen.compute_auc(),\n                        val_acc_spleen.compute_auc()]\n                ]\n    \n    # verbose\n    print('')\n    print(tabulate(metrics_data, headers=[\"\", \"Train Acc\", \"Val Acc\", \"Train AUC\", \"Val AUC\"]))\n    \n    print(f'\\nMean Train Loss: {train_loss:.3f}')\n    print(f'Mean Val Loss: {val_loss:.3f}\\n')\n    \n    #reset metrics\n    train_acc_bowel.reset()\n    train_acc_extravasation.reset()\n    train_acc_liver.reset()\n    train_acc_kidney.reset()\n    train_acc_spleen.reset()\n    val_acc_bowel.reset()\n    val_acc_extravasation.reset()\n    val_acc_liver.reset()\n    val_acc_kidney.reset()\n    val_acc_spleen.reset()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-11T18:36:13.418823Z","iopub.execute_input":"2024-10-11T18:36:13.419103Z","iopub.status.idle":"2024-10-12T00:05:43.181055Z","shell.execute_reply.started":"2024-10-11T18:36:13.419079Z","shell.execute_reply":"2024-10-12T00:05:43.180092Z"},"trusted":true},"execution_count":null,"outputs":[]}]}