{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":39272,"databundleVersionId":4629629,"sourceType":"competition"},{"sourceId":5089415,"sourceType":"datasetVersion","datasetId":2694061}],"dockerImageVersionId":30746,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"import cv2\nimport pydicom\nfrom pydicom.data import get_testdata_file\nfrom gzip import GzipFile\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom PIL import Image","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:16:55.819458Z","iopub.execute_input":"2024-08-17T09:16:55.820401Z","iopub.status.idle":"2024-08-17T09:16:55.825688Z","shell.execute_reply.started":"2024-08-17T09:16:55.820363Z","shell.execute_reply":"2024-08-17T09:16:55.824604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Đọc dữ liệu","metadata":{}},{"cell_type":"code","source":"file_path = '/kaggle/input/rsna-breast-cancer-detection/train.csv'\ndf = pd.read_csv(file_path)\n\n\n# df_MLO = df[df['view'] != 'MLO']\n# cancer_1 = df_MLO[df_MLO['cancer'] == 1].head(25)\n# cancer_0 = df_MLO[df_MLO['cancer'] == 0].head(25)\n# result = pd.concat([cancer_1, cancer_0])\n# print(result)\ncancer_1 = df[df['cancer'] == 1].head(25)\ncancer_0 = df[df['cancer'] == 0].head(25)\nresult = pd.concat([cancer_1, cancer_0])\n# in ket qua\nprint(result.head(3))\nprint(\"--------------------------------------------------------------------------------\")\nprint(result.tail(3))\n# cancer_1\n# df_MLO","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:16:55.827523Z","iopub.execute_input":"2024-08-17T09:16:55.827805Z","iopub.status.idle":"2024-08-17T09:16:55.936452Z","shell.execute_reply.started":"2024-08-17T09:16:55.82778Z","shell.execute_reply":"2024-08-17T09:16:55.935477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Show để so sánh cancer hoặc không cancer","metadata":{}},{"cell_type":"code","source":"import matplotlib.image as mpimg\nimport os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image\n\ndef load_images_from_paths(image_paths):\n    images = []\n    for path in image_paths:\n        img = Image.open(path)\n        images.append(np.array(img))\n    return images\n\ndef plot_image_grid(images, grid_size=(5, 10), figsize=(25, 25)):\n    fig, axes = plt.subplots(grid_size[0], grid_size[1], figsize=figsize)\n    axes = axes.flatten()\n    \n    for img, ax in zip(images, axes):\n        ax.imshow(img, cmap='gray')\n        ax.axis('off')\n\n    plt.tight_layout()\n    plt.show()\n\nimage_paths = []\n\nfor index, row in result.iterrows():\n    temp ='/kaggle/input/rsna-breast-cancer-detection-poi-images/bc_1280_train_lut/'\n    img_path = temp + str(row['patient_id']) + '_' + str(row['image_id'])+ '.png'\n    image_paths.append(img_path)\nimages = load_images_from_paths(image_paths)\nplot_image_grid(images, grid_size=(2, 25))","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:16:55.937534Z","iopub.execute_input":"2024-08-17T09:16:55.9378Z","iopub.status.idle":"2024-08-17T09:17:00.305853Z","shell.execute_reply.started":"2024-08-17T09:16:55.937776Z","shell.execute_reply":"2024-08-17T09:17:00.304804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## So sánh độ cân bằng","metadata":{}},{"cell_type":"code","source":"cancer = df[df['cancer'] == 1]\nnon_cancer = df[df['cancer'] == 0]\ncancer_count = len(cancer)\nnon_cancer_count = len(non_cancer)\n\nprint(f'Số lượng ảnh ung thư: {cancer_count}')\nprint(f'Số lượng ảnh không ung thư: {non_cancer_count}')\nprint(f'Tổng số bức ảnh: {cancer_count + non_cancer_count}')\n\nlabels = ['Ảnh ung thư', 'Ảnh không ung thư']\ncounts = [cancer_count, non_cancer_count]\n\n# Điều chỉnh kích thước của biểu đồ bằng cách sử dụng figsize\nfig, ax = plt.subplots(figsize=(4, 3))  # Kích thước 4x3 inches\n\nax.bar(labels, counts, color=['red', 'blue'])\n\nax.set_ylabel('Số lượng')\nax.set_title('So sánh số lượng ảnh ung thư và không ung thư')\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:00.307876Z","iopub.execute_input":"2024-08-17T09:17:00.308267Z","iopub.status.idle":"2024-08-17T09:17:00.519367Z","shell.execute_reply.started":"2024-08-17T09:17:00.30824Z","shell.execute_reply":"2024-08-17T09:17:00.518439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\nfrom matplotlib.colors import ListedColormap, LinearSegmentedColormap\nclass clr:\n    S = '\\033[1m' + '\\033[91m'\n    E = '\\033[0m'\n\nmy_colors = [\"#517664\", \"#73AA90\", \"#94DDBC\", \"#DAB06C\", \n             \"#DF928E\", \"#C97973\", \"#B25F57\"]\nCMAP1 = ListedColormap(my_colors)\n\nprint(clr.S+\"Notebook Color Schemes:\"+clr.E)\nsns.palplot(sns.color_palette(my_colors))\n\n\nf, (a0, a1) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [3, 1]}, figsize=(24, 15))\nsns.distplot(a=cancer[\"age\"], rug=True, hist=False, \n             rug_kws={\"color\": my_colors[5]},\n             kde_kws={\"color\": my_colors[5], \"lw\": 5, \"alpha\": 0.7},\n             ax=a0)\n\na0.axvline(x=58, ls=\":\", lw=2, color=\"black\")\na0.text(x=58.5, y=0.018, s=\"mean: 58\", size=17, color=\"black\", weight=\"bold\")\na0.axvline(x=26, ls=\":\", lw=2, color=\"black\")\na0.text(x=26.5, y=0.008, s=\"min: 26\", size=17, color=\"black\", weight=\"bold\")\na0.axvline(x=89, ls=\":\", lw=2, color=\"black\")\na0.text(x=84, y=0.037, s=\"max: 89\", size=17, color=\"black\", weight=\"bold\")\n\nsns.boxenplot(x=cancer[\"age\"], ax=a1, color=my_colors[2])\n\nplt.suptitle(\"Age Distribution\", weight=\"bold\", size=25)\nsns.despine(right=True, top=True, left=True);","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:00.520722Z","iopub.execute_input":"2024-08-17T09:17:00.521023Z","iopub.status.idle":"2024-08-17T09:17:01.413038Z","shell.execute_reply.started":"2024-08-17T09:17:00.520983Z","shell.execute_reply":"2024-08-17T09:17:01.412056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## EDA thử","metadata":{}},{"cell_type":"code","source":"image_paths_cancer = image_paths[0] \nimage_paths_non_cancer = image_paths[-5]\n","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:01.414263Z","iopub.execute_input":"2024-08-17T09:17:01.414559Z","iopub.status.idle":"2024-08-17T09:17:01.418954Z","shell.execute_reply.started":"2024-08-17T09:17:01.414532Z","shell.execute_reply":"2024-08-17T09:17:01.418058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef select_largest_obj(img_bin, lab_val=255, fill_holes=False, \n                       smooth_boundary=False, kernel_size=15):\n    n_labels, img_labeled, lab_stats, _ = cv2.connectedComponentsWithStats(\n        img_bin, connectivity=8, ltype=cv2.CV_32S)\n    largest_obj_lab = np.argmax(lab_stats[1:, 4]) + 1\n    largest_mask = np.zeros(img_bin.shape, dtype=np.uint8)\n    largest_mask[img_labeled == largest_obj_lab] = lab_val\n    if fill_holes:\n        bkg_locs = np.where(img_labeled == 0)\n        bkg_seed = (bkg_locs[0][0], bkg_locs[1][0])\n        img_floodfill = largest_mask.copy()\n        h_, w_ = largest_mask.shape\n        mask_ = np.zeros((h_ + 2, w_ + 2), dtype=np.uint8)\n        cv2.floodFill(img_floodfill, mask_, seedPoint=bkg_seed, newVal=lab_val)\n        holes_mask = cv2.bitwise_not(img_floodfill)  # mask of the holes.\n        largest_mask = largest_mask + holes_mask\n    if smooth_boundary:\n        kernel_ = np.ones((kernel_size, kernel_size), dtype=np.uint8)\n        largest_mask = cv2.morphologyEx(largest_mask, cv2.MORPH_OPEN, kernel_)\n        \n    return largest_mask\n\ndef process_image(image_path, threshold=230):\n    image_array = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n    if image_array.dtype != np.uint8:\n        image_array = cv2.normalize(image_array, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)\n    _, binary_image = cv2.threshold(image_array, threshold, 255, cv2.THRESH_BINARY)\n    largest_object_mask = select_largest_obj(binary_image, lab_val=255, fill_holes=True, smooth_boundary=True, kernel_size=15)\n    result_image = cv2.bitwise_and(image_array, largest_object_mask)\n    return image_array, binary_image, largest_object_mask, result_image\n\n# Đường dẫn tới các ảnh .png\nimage_pathCancer = cancer\nimage_pathNonCancer = non_cancer\n\n# Process both images\nimage_arrayCancer, binary_imageCancer, largest_object_maskCancer, result_imageCancer = process_image(image_paths_cancer)\nimage_arrayNonCancer, binary_imageNonCancer, largest_object_maskNonCancer, result_imageNonCancer = process_image(image_paths_non_cancer)\n\n# Display the images in a single row\nfig, axes = plt.subplots(2, 4, figsize=(20, 12))\n\n# Display Original Image Cancer\naxes[0, 0].imshow(image_arrayCancer, cmap='gray')\naxes[0, 0].set_title('Original Image Cancer')\naxes[0, 0].axis('off')\n\n# Display Binarized Image Cancer\naxes[0, 1].imshow(binary_imageCancer, cmap='gray')\naxes[0, 1].set_title('Binarized Image Cancer')\naxes[0, 1].axis('off')\n\n# Display Largest Object Mask Cancer\naxes[0, 2].imshow(largest_object_maskCancer, cmap='gray')\naxes[0, 2].set_title('Largest Object Mask Cancer')\naxes[0, 2].axis('off')\n\n# Display Artifact Suppressed Image Cancer\naxes[0, 3].imshow(result_imageCancer, cmap='gray')\naxes[0, 3].set_title('Artifact Suppressed Image Cancer')\naxes[0, 3].axis('off')\n\n# Display Original Image NonCancer\naxes[1, 0].imshow(image_arrayNonCancer, cmap='gray')\naxes[1, 0].set_title('Original Image NonCancer')\naxes[1, 0].axis('off')\n\n# Display Binarized Image NonCancer\naxes[1, 1].imshow(binary_imageNonCancer, cmap='gray')\naxes[1, 1].set_title('Binarized Image NonCancer')\naxes[1, 1].axis('off')\n\n# Display Largest Object Mask NonCancer\naxes[1, 2].imshow(largest_object_maskNonCancer, cmap='gray')\naxes[1, 2].set_title('Largest Object Mask NonCancer')\naxes[1, 2].axis('off')\n\n# Display Artifact Suppressed Image NonCancer\naxes[1, 3].imshow(result_imageNonCancer, cmap='gray')\naxes[1, 3].set_title('Artifact Suppressed Image NonCancer')\naxes[1, 3].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:01.42033Z","iopub.execute_input":"2024-08-17T09:17:01.42061Z","iopub.status.idle":"2024-08-17T09:17:02.958607Z","shell.execute_reply.started":"2024-08-17T09:17:01.420586Z","shell.execute_reply":"2024-08-17T09:17:02.957555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Do có su chenh lech giua cac mat cat ne nhom chung em quyet dinh sai nguon cho 195 *","metadata":{}},{"cell_type":"markdown","source":"# PYTORCH DATASET","metadata":{}},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder, normalize","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:02.959729Z","iopub.execute_input":"2024-08-17T09:17:02.960036Z","iopub.status.idle":"2024-08-17T09:17:02.964575Z","shell.execute_reply.started":"2024-08-17T09:17:02.95999Z","shell.execute_reply":"2024-08-17T09:17:02.963635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Keep only columns in test + target variable and reset the index\ntrain = df[[\"patient_id\", \"image_id\", \"laterality\", \"age\", \"implant\", \"cancer\"]].reset_index(drop=True)\n\nbase_path = \"/kaggle/input/rsna-breast-cancer-detection-poi-images/bc_1280_train_lut/\"\n\n# Add the 'path' column\ntrain['path'] = base_path + train['patient_id'].astype(str) + \"_\" + train['image_id'].astype(str) + \".png\"\n\n# Encode categorical variables\nle_laterality = LabelEncoder()\nle_view = LabelEncoder()\n\ntrain['laterality'] = le_laterality.fit_transform(df['laterality'])\ntrain['view'] = le_view.fit_transform(df['view'])\n\ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:02.96776Z","iopub.execute_input":"2024-08-17T09:17:02.968371Z","iopub.status.idle":"2024-08-17T09:17:03.104149Z","shell.execute_reply.started":"2024-08-17T09:17:02.968345Z","shell.execute_reply":"2024-08-17T09:17:03.103179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:03.105939Z","iopub.execute_input":"2024-08-17T09:17:03.106354Z","iopub.status.idle":"2024-08-17T09:17:03.121703Z","shell.execute_reply.started":"2024-08-17T09:17:03.106322Z","shell.execute_reply":"2024-08-17T09:17:03.120836Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(clr.S+\"Number of missing values in Age:\"+clr.E, train[\"age\"].isna().sum())\ntrain['age'] = train['age'].fillna(58)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:03.122999Z","iopub.execute_input":"2024-08-17T09:17:03.123925Z","iopub.status.idle":"2024-08-17T09:17:03.133018Z","shell.execute_reply.started":"2024-08-17T09:17:03.123897Z","shell.execute_reply":"2024-08-17T09:17:03.132074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q efficientnet_pytorch","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:03.134198Z","iopub.execute_input":"2024-08-17T09:17:03.134471Z","iopub.status.idle":"2024-08-17T09:17:15.750174Z","shell.execute_reply.started":"2024-08-17T09:17:03.134446Z","shell.execute_reply":"2024-08-17T09:17:15.748837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# General Libraries\nimport os\nimport re\nimport gc\nimport cv2\nimport wandb\nimport random\nimport math\nfrom glob import glob\nfrom tqdm import tqdm\nfrom pprint import pprint\nfrom time import time\nimport datetime as dtime\nfrom datetime import datetime\nimport itertools\nimport warnings\nimport pandas as pd\nimport numpy as np\nfrom skimage.transform import resize\nfrom sklearn.preprocessing import LabelEncoder, normalize\n\n# For the Visuals\nimport seaborn as sns\nimport matplotlib as mpl\nfrom matplotlib import cm\nimport matplotlib.patches as patches\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nfrom matplotlib.offsetbox import AnnotationBbox, OffsetImage\nfrom matplotlib.colors import ListedColormap, LinearSegmentedColormap\nfrom matplotlib.patches import Rectangle\nfrom IPython.display import display_html\nimport torch\nimport torch.nn as nn\nfrom torchvision.models import resnext50_32x4d\nplt.rcParams.update({'font.size': 16})\n\n# Environment check\nwarnings.filterwarnings(\"ignore\")\nos.environ[\"WANDB_SILENT\"] = \"true\"\nCONFIG = {'competition': 'RSNA_Breast_Cancer', '_wandb_kernel': 'aot'}\n\n# Custom colors\nclass clr:\n    S = '\\033[1m' + '\\033[91m'\n    E = '\\033[0m'\n    \nmy_colors = [\"#517664\", \"#73AA90\", \"#94DDBC\", \"#DAB06C\", \n             \"#DF928E\", \"#C97973\", \"#B25F57\"]\nCMAP1 = ListedColormap(my_colors)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.75185Z","iopub.execute_input":"2024-08-17T09:17:15.752185Z","iopub.status.idle":"2024-08-17T09:17:15.765629Z","shell.execute_reply.started":"2024-08-17T09:17:15.752155Z","shell.execute_reply":"2024-08-17T09:17:15.764591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\n# PyTorch\nimport torch\nimport torchvision\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch import FloatTensor, LongTensor\nfrom torch.utils.data import Dataset, DataLoader, Subset\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\n\n# Data Augmentation for Image Preprocessing\nfrom albumentations import (ToFloat, Normalize, VerticalFlip, HorizontalFlip, Compose, Resize,\n                            RandomBrightnessContrast, HueSaturationValue, Blur, GaussNoise,\n                            Rotate, RandomResizedCrop, ShiftScaleRotate, ToGray)\nfrom albumentations.pytorch import ToTensorV2\n\nfrom efficientnet_pytorch import EfficientNet\nfrom torchvision.models import resnet34, resnet50\n\n# SKlearn\nfrom sklearn.model_selection import StratifiedKFold, GroupKFold\nfrom sklearn.metrics import accuracy_score, roc_auc_score, confusion_matrix\n\ndef set_seed(seed = 1234):\n    '''Sets the seed of the entire notebook so results are the same every time we run.\n    This is for REPRODUCIBILITY.'''\n    np.random.seed(seed)\n    random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    # When running on the CuDNN backend, two further options must be set\n    torch.backends.cudnn.deterministic = True\n    # Set a fixed value for the hash seed\n    os.environ['PYTHONHASHSEED'] = str(seed)\n\ndef show_values_on_bars(axs, h_v=\"v\", space=0.4):\n    '''Plots the value at the end of the a seaborn barplot.\n    axs: the ax of the plot\n    h_v: weather or not the barplot is vertical/ horizontal'''\n    \n    def _show_on_single_plot(ax):\n        if h_v == \"v\":\n            for p in ax.patches:\n                _x = p.get_x() + p.get_width() / 2\n                _y = p.get_y() + p.get_height()\n                value = int(p.get_height())\n                ax.text(_x, _y, format(value, ','), ha=\"center\") \n        elif h_v == \"h\":\n            for p in ax.patches:\n                _x = p.get_x() + p.get_width() + float(space)\n                _y = p.get_y() + p.get_height()\n                value = int(p.get_width())\n                ax.text(_x, _y, format(value, ','), ha=\"left\")\n\n    if isinstance(axs, np.ndarray):\n        for idx, ax in np.ndenumerate(axs):\n            _show_on_single_plot(ax)\n    else:\n        _show_on_single_plot(axs)\n        \n\n\n# Seed\nset_seed()\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint('Device available now:', DEVICE)\n\n# Read in Data\n# train = pd.read_csv(file_path)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.767051Z","iopub.execute_input":"2024-08-17T09:17:15.767964Z","iopub.status.idle":"2024-08-17T09:17:15.786438Z","shell.execute_reply.started":"2024-08-17T09:17:15.767924Z","shell.execute_reply":"2024-08-17T09:17:15.785443Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ----- GLOBAL PARAMS -----\nvertical_flip = 0.5\nhorizontal_flip = 0.5\n\ncsv_columns = ['laterality', 'view', 'age', 'implant']\nno_columns = len(csv_columns)\noutput_size = 1\n# -------------------------","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.787645Z","iopub.execute_input":"2024-08-17T09:17:15.787974Z","iopub.status.idle":"2024-08-17T09:17:15.802733Z","shell.execute_reply.started":"2024-08-17T09:17:15.787949Z","shell.execute_reply":"2024-08-17T09:17:15.801801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\nimport numpy as np\nfrom torch.utils.data import Dataset\nfrom albumentations import Compose, RandomResizedCrop, ShiftScaleRotate, HorizontalFlip, VerticalFlip\nfrom albumentations.pytorch import ToTensorV2\n\nclass RSNADataset(Dataset):\n    \n    def __init__(self, dataframe, vertical_flip, horizontal_flip, is_train=True):\n        self.dataframe = dataframe\n        self.is_train = is_train\n        self.vertical_flip = vertical_flip\n        self.horizontal_flip = horizontal_flip\n        \n        # Data Augmentation (custom for each dataset type)\n        if is_train:\n            self.transform = Compose([\n                RandomResizedCrop(height=224, width=224),\n                ShiftScaleRotate(rotate_limit=90, scale_limit=[0.8, 1.2]),\n                HorizontalFlip(p=self.horizontal_flip),\n                VerticalFlip(p=self.vertical_flip),\n                ToTensorV2()\n            ])\n        else:\n            self.transform = Compose([\n                ToTensorV2()\n            ])\n            \n    def __len__(self):\n        return len(self.dataframe)\n    \n    def __getitem__(self, index):\n        '''Take each row in batch at a time.'''\n        \n        # Select path and read image\n        image_path = self.dataframe['path'][index]\n        image = Image.open(image_path).convert('RGB')\n        image = np.array(image).astype(np.float32)\n        \n        # For this image also import .csv information\n        csv_row = self.dataframe.iloc[index][csv_columns]\n        csv_data = []\n        for value in csv_row:\n            try:\n                csv_data.append(float(value))\n            except ValueError:\n                # Handle the case where conversion fails\n                csv_data.append(np.nan)  # or some other default value\n                print(f\"Warning: Unable to convert value '{value}' to float.\")\n        \n        csv_data = np.array(csv_data, dtype=np.float32)\n        \n        # Apply transforms\n        # albumentations expects a dictionary with an 'image' key\n        transformed = self.transform(image=image)\n        transf_image = transformed['image']\n        \n        # Return info\n        if self.is_train:\n            return {\"image\": transf_image, \n                    \"meta\": csv_data, \n                    \"target\": self.dataframe['cancer'][index]}\n        else:\n            return {\"image\": transf_image, \n                    \"meta\": csv_data}\n","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.803905Z","iopub.execute_input":"2024-08-17T09:17:15.804312Z","iopub.status.idle":"2024-08-17T09:17:15.817687Z","shell.execute_reply.started":"2024-08-17T09:17:15.804287Z","shell.execute_reply":"2024-08-17T09:17:15.81669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def data_to_device(data):\n    image, metadata, targets = data.values()\n    return image.to(DEVICE), metadata.to(DEVICE), targets.to(DEVICE)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.819062Z","iopub.execute_input":"2024-08-17T09:17:15.819373Z","iopub.status.idle":"2024-08-17T09:17:15.831006Z","shell.execute_reply.started":"2024-08-17T09:17:15.819348Z","shell.execute_reply":"2024-08-17T09:17:15.830029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sample data\n# train = \n# Instantiate Dataset object\ndataset = RSNADataset(train.head(6), vertical_flip, horizontal_flip,\n                      is_train=True)\n# # The Dataloader\ndataloader = DataLoader(dataset, batch_size=3, shuffle=False)\n\n# Output of the Dataloader\nfor k, data in enumerate(dataloader):\n    image, meta, targets = data_to_device(data)\n    print(clr.S + f\"Batch: {k}\" + clr.E, \"\\n\" +\n          clr.S + \"Image:\" + clr.E, image.shape, \"\\n\" +\n          clr.S + \"Meta:\" + clr.E, meta, \"\\n\" +\n          clr.S + \"Targets:\" + clr.E, targets, \"\\n\" +\n          \"=\"*50)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.832247Z","iopub.execute_input":"2024-08-17T09:17:15.832526Z","iopub.status.idle":"2024-08-17T09:17:15.939096Z","shell.execute_reply.started":"2024-08-17T09:17:15.832502Z","shell.execute_reply":"2024-08-17T09:17:15.937984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# NET WORK\n","metadata":{}},{"cell_type":"markdown","source":"## Resnet50","metadata":{}},{"cell_type":"code","source":"class ResNet50Network(nn.Module):\n    def __init__(self, output_size, no_columns):\n        super().__init__()\n        self.no_columns, self.output_size = no_columns, output_size\n        \n        # Define Feature part (IMAGE)\n        self.features = resnet50(pretrained=True) # 1000 neurons out\n        # (metadata)\n        self.csv = nn.Sequential(nn.Linear(self.no_columns, 500),\n                                 nn.BatchNorm1d(500),\n                                 nn.ReLU(),\n                                 nn.Dropout(p=0.2))\n        \n        # Define Classification part\n        self.classification = nn.Linear(1000 + 500, output_size)\n        \n        \n    def forward(self, image, meta, prints=False):\n        if prints: print('Input Image shape:', image.shape, '\\n'+\n                         'Input metadata shape:', meta.shape)\n        \n        # Image CNN\n        image = self.features(image)\n        if prints: print('Features Image shape:', image.shape)\n        \n        # CSV FNN\n        meta = self.csv(meta)\n        if prints: print('Meta Data:', meta.shape)\n            \n        # Concatenate layers from image with layers from csv_data\n        image_meta_data = torch.cat((image, meta), dim=1)\n        if prints: print('Concatenated Data:', image_meta_data.shape)\n        \n        # CLASSIF\n        out = self.classification(image_meta_data)\n        if prints: print('Out shape:', out.shape)\n        \n        return out","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.940338Z","iopub.execute_input":"2024-08-17T09:17:15.940692Z","iopub.status.idle":"2024-08-17T09:17:15.950736Z","shell.execute_reply.started":"2024-08-17T09:17:15.940665Z","shell.execute_reply":"2024-08-17T09:17:15.949777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load Model\nmodel_example = ResNet50Network(output_size=output_size, no_columns=no_columns).to(DEVICE)\n\n# Outputs\nout = model_example(image, meta, prints=True)\n\n# Criterion example\ncriterion_example = nn.BCEWithLogitsLoss()\n# Unsqueeze(1) from shape=[3] to shape=[3, 1]\nloss = criterion_example(out, targets.unsqueeze(1).float()) \nprint(\"=\"*50)\nprint(clr.S+'Loss:'+clr.E, loss.item())","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:15.951931Z","iopub.execute_input":"2024-08-17T09:17:15.952238Z","iopub.status.idle":"2024-08-17T09:17:16.939865Z","shell.execute_reply.started":"2024-08-17T09:17:15.952213Z","shell.execute_reply":"2024-08-17T09:17:16.938897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ResNeXt50","metadata":{}},{"cell_type":"code","source":"class ResNeXt50Network(nn.Module):\n    def __init__(self, output_size, no_columns):\n        super().__init__()\n        self.no_columns, self.output_size = no_columns, output_size\n        \n        # Define Feature part (IMAGE) using ResNeXt\n        self.features = resnext50_32x4d(pretrained=True)  # 1000 neurons out\n        \n        # (metadata)\n        self.csv = nn.Sequential(nn.Linear(self.no_columns, 500),\n                                 nn.BatchNorm1d(500),\n                                 nn.ReLU(),\n                                 nn.Dropout(p=0.2))\n        \n        # Define Classification part\n        self.classification = nn.Linear(1000 + 500, output_size)\n        \n    def forward(self, image, meta, prints=False):\n        if prints: print('Input Image shape:', image.shape, '\\n' +\n                         'Input metadata shape:', meta.shape)\n        \n        # Image CNN\n        image = self.features(image)\n        if prints: print('Features Image shape:', image.shape)\n        \n        # CSV FNN\n        meta = self.csv(meta)\n        if prints: print('Meta Data:', meta.shape)\n            \n        # Concatenate layers from image with layers from csv_data\n        image_meta_data = torch.cat((image, meta), dim=1)\n        if prints: print('Concatenated Data:', image_meta_data.shape)\n        \n        # CLASSIF\n        out = self.classification(image_meta_data)\n        if prints: print('Out shape:', out.shape)\n        \n        return out\n","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:16.94145Z","iopub.execute_input":"2024-08-17T09:17:16.941826Z","iopub.status.idle":"2024-08-17T09:17:16.952065Z","shell.execute_reply.started":"2024-08-17T09:17:16.941793Z","shell.execute_reply":"2024-08-17T09:17:16.950998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load Model\nmodel_example = ResNeXt50Network(output_size=output_size, no_columns=no_columns).to(DEVICE)\n\n# Outputs\nout = model_example(image, meta, prints=True)\n\n# Criterion example\ncriterion_example = nn.BCEWithLogitsLoss()\n# Unsqueeze(1) from shape=[3] to shape=[3, 1]\nloss = criterion_example(out, targets.unsqueeze(1).float()) \nprint(\"=\"*50)\nprint(clr.S+'Loss:'+clr.E, loss.item())","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:16.953206Z","iopub.execute_input":"2024-08-17T09:17:16.953493Z","iopub.status.idle":"2024-08-17T09:17:17.509976Z","shell.execute_reply.started":"2024-08-17T09:17:16.953469Z","shell.execute_reply":"2024-08-17T09:17:17.509055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# TRAINING","metadata":{}},{"cell_type":"code","source":"def add_in_file(text, f):\n    \n    with open(f'logs_{VERSION}.txt', 'a+') as f:\n        print(text, file=f)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:17.511162Z","iopub.execute_input":"2024-08-17T09:17:17.511426Z","iopub.status.idle":"2024-08-17T09:17:17.516355Z","shell.execute_reply.started":"2024-08-17T09:17:17.511404Z","shell.execute_reply":"2024-08-17T09:17:17.515463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, classification_report\n\nimport matplotlib.pyplot as plt\n\ndef train_folds(model, train_original):\n    # Creates a .txt file that will contain the logs\n    # logs == what we also print to console\n    f = open(f\"logs_{VERSION}.txt\", \"w+\")\n    \n    # Split in folds\n    group_fold = GroupKFold(n_splits=FOLDS)\n\n    # Generate indices to split data into training and test set.\n    k_folds = group_fold.split(X=np.zeros(len(train_original)), \n                               y=train_original['cancer'], \n                               groups=train_original['patient_id'].tolist())\n    \n    # For each fold\n    for i, (train_index, valid_index) in enumerate(k_folds):\n        \n        print(clr.S+f\"---------- Fold: {i+1} ----------\"+clr.E)\n        add_in_file(f\"---------- Fold: {i+1} ----------\", f)\n        \n        # 🐝 W&B Tracking\n        RUN_CONFIG = CONFIG.copy()\n        params = dict(model=MODEL, \n                      version=VERSION,\n                      fold=i,\n                      epochs=EPOCHS, \n                      batch=BATCH_SIZE1,\n                      lr=LR,\n                      weight_decay=WD)\n        RUN_CONFIG.update(params)\n#         run = wandb.init(project='RSNA_Breast_Cancer', config=RUN_CONFIG)\n\n#         wandb.watch(model, log_freq=100) # 🐝\n\n        # --- Create Instances ---\n        best_roc = None\n        patience_f = PATIENCE\n\n        optimizer = torch.optim.Adam(model.parameters(), lr=LR, \n                                     weight_decay=WD)\n        scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='max', \n                                      patience=LR_PATIENCE, verbose=True, factor=LR_FACTOR)\n        criterion = nn.BCEWithLogitsLoss()\n\n        # --- Read in Data ---\n        train_data = train_original.iloc[train_index].reset_index(drop=True)\n        valid_data = train_original.iloc[valid_index].reset_index(drop=True)\n\n        # Create Data instances\n        train = RSNADataset(train_data, vertical_flip, horizontal_flip, \n                            is_train=True)\n        valid = RSNADataset(valid_data, vertical_flip, horizontal_flip,\n                            is_train=True)\n\n        # Dataloaders\n        train_loader = DataLoader(train, batch_size=BATCH_SIZE1, \n                                  shuffle=True, num_workers=WORKERS)\n        valid_loader = DataLoader(valid, batch_size=BATCH_SIZE2, \n                                  shuffle=False, num_workers=WORKERS)\n\n        # Lists to store losses\n        train_losses_list = []\n        valid_losses_list = []\n\n        # === EPOCHS ===\n        for epoch in range(EPOCHS):\n            start_time = time()\n            correct = 0\n            train_losses = 0\n\n            # === TRAIN ===\n            model.train()\n\n            for k, data in tqdm(enumerate(train_loader)):\n                image, meta, targets = data_to_device(data)\n                optimizer.zero_grad()\n                out = model(image, meta)\n                loss = criterion(out, targets.unsqueeze(1).float())\n                loss.backward()\n                optimizer.step()\n\n                train_losses += loss.item()\n                train_preds = torch.round(torch.sigmoid(out)) \n                correct += (train_preds.cpu() == targets.cpu().unsqueeze(1)).sum().item()\n\n            train_acc = correct / len(train_index)\n            train_losses_list.append(train_losses / len(train_loader))  # Store avg train loss\n\n            # === EVAL ===\n            model.eval()\n            valid_preds = torch.zeros(size=(len(valid_index), 1), \n                                      device=DEVICE, dtype=torch.float32)\n            valid_losses = 0\n\n            with torch.no_grad():\n                for k, data in tqdm(enumerate(valid_loader)):\n                    image, meta, targets = data_to_device(data)\n                    out = model(image, meta)\n                    pred = torch.sigmoid(out)\n                    valid_preds[k*image.shape[0]:k*image.shape[0] + image.shape[0]] = pred\n\n                    # Calculate validation loss\n                    valid_loss = criterion(out, targets.unsqueeze(1).float())\n                    valid_losses += valid_loss.item()\n\n                valid_acc = accuracy_score(valid_data['cancer'].values, \n                                           torch.round(valid_preds.cpu()))\n                valid_roc = roc_auc_score(valid_data['cancer'].values, \n                                          valid_preds.cpu())\n                valid_losses_list.append(valid_losses / len(valid_loader))  # Store avg valid loss\n\n                duration = str(dtime.timedelta(seconds=time() - start_time))[:7]\n\n                final_logs = '{} | Epoch: {}/{} | Loss: {:.4} | Acc_tr: {:.3} | Acc_vd: {:.3} | ROC: {:.3}'.\\\n                                format(duration, epoch+1, EPOCHS, \n                                       train_losses, train_acc, valid_acc, valid_roc)\n                add_in_file(final_logs,f)\n                print(final_logs)\n\n                # === CONFUSION MATRIX ===\n                cm = confusion_matrix(valid_data['cancer'].values, torch.round(valid_preds.cpu()))\n                print(\"Confusion Matrix:\")\n                print(cm)\n                print(\"Classification Report:\")\n                print(classification_report(valid_data['cancer'].values, torch.round(valid_preds.cpu())))\n\n                # Save the confusion matrix and report to log file\n                add_in_file(f\"Confusion Matrix:\\n{cm}\\n\", f)\n                add_in_file(f\"Classification Report:\\n{classification_report(valid_data['cancer'].values, torch.round(valid_preds.cpu()))}\\n\", f)\n\n                # === SAVE MODEL ===\n                scheduler.step(valid_roc)\n                model_name = f\"Fold{i+1}_Epoch{epoch+1}_ValidAcc{valid_acc:.3f}_ROC{valid_roc:.3f}.pth\"\n\n                if not best_roc: \n                    best_roc = valid_roc\n                    torch.save(model.state_dict(), model_name)\n                    continue\n\n                if valid_roc > best_roc:\n                    best_roc = valid_roc\n                    patience_f = PATIENCE\n                    torch.save(model.state_dict(), model_name)\n                else:\n                    patience_f = patience_f - 1\n                    if patience_f == 0:\n                        stop_logs = 'Early stopping (no improvement since 3 models) | Best ROC: {}'.\\\n                                    format(best_roc)\n                        add_in_file(stop_logs, f)\n                        print(stop_logs)\n                        break\n\n        # Plot training and validation loss\n        plt.figure(figsize=(10, 5))\n        plt.plot(range(1, len(train_losses_list) + 1), train_losses_list, label='Training Loss')\n        plt.plot(range(1, len(valid_losses_list) + 1), valid_losses_list, label='Validation Loss')\n        plt.title(f\"Fold {i+1} - Loss over Epochs\")\n        plt.xlabel('Epochs')\n        plt.ylabel('Loss')\n        plt.legend()\n        plt.grid(True)\n        plt.show()\n\n        del train, valid, train_loader, valid_loader, image, targets\n        gc.collect()\n","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:17.521676Z","iopub.execute_input":"2024-08-17T09:17:17.522106Z","iopub.status.idle":"2024-08-17T09:17:17.551998Z","shell.execute_reply.started":"2024-08-17T09:17:17.522079Z","shell.execute_reply":"2024-08-17T09:17:17.551077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train Resnet50","metadata":{}},{"cell_type":"code","source":"train","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:17.553189Z","iopub.execute_input":"2024-08-17T09:17:17.553473Z","iopub.status.idle":"2024-08-17T09:17:17.577232Z","shell.execute_reply.started":"2024-08-17T09:17:17.553449Z","shell.execute_reply":"2024-08-17T09:17:17.576318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Filter images with cancer = 0 and cancer = 1\ncancer_0 = train[train['cancer'] == 0].sample(n=1000, random_state=42)\ncancer_1 = train[train['cancer'] == 1].sample(n=1000, random_state=42)\n\n# Concatenate the two sets to get a balanced dataset\nbalanced_dataset = pd.concat([cancer_0, cancer_1]).reset_index(drop=True)\n\n# Optional: Shuffle the dataset if needed\nbalanced_dataset = balanced_dataset.sample(frac=1, random_state=42).reset_index(drop=True)\n\n# Display the result\nprint(balanced_dataset.head())\nprint(f\"Balanced dataset size: {balanced_dataset.shape}\")","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:17.578486Z","iopub.execute_input":"2024-08-17T09:17:17.578792Z","iopub.status.idle":"2024-08-17T09:17:17.60794Z","shell.execute_reply.started":"2024-08-17T09:17:17.578767Z","shell.execute_reply":"2024-08-17T09:17:17.606939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"FOLDS = 3\nEPOCHS = 50\nPATIENCE = 3\nWORKERS = 8\nLR = 0.0005\nWD = 0.0\nLR_PATIENCE = 1            # 1 model not improving until lr is decreasing\nLR_FACTOR = 0.4            # by how much the lr is decreasing\n\nBATCH_SIZE1 = 64           # for train\nBATCH_SIZE2 = 16           # for valid\n\nVERSION = 'v1'\nMODEL = 'resnet50'\n\nmodel1 = ResNet50Network(output_size=output_size, no_columns=no_columns).to(DEVICE)\\\n\n\n\n\n# ------------------\n\n# Run the cell below to train\n# Ran it locally on all data, see the results below\ntrain_folds(model=model1, train_original=balanced_dataset)\n\n# Print the logs during training\n# f = open('/kaggle/working/logs_v1.txt', \"r\")\n# contents = f.read()\n# print(contents)","metadata":{"execution":{"iopub.status.busy":"2024-08-17T09:17:17.609253Z","iopub.execute_input":"2024-08-17T09:17:17.609549Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train ResNeXt","metadata":{}},{"cell_type":"code","source":"FOLDS = 3\nEPOCHS = 50\nPATIENCE = 3\nWORKERS = 8\nLR = 0.0005\nWD = 0.0\nLR_PATIENCE = 1            # 1 model not improving until lr is decreasing\nLR_FACTOR = 0.4            # by how much the lr is decreasing\n\nBATCH_SIZE1 = 64           # for train\nBATCH_SIZE2 = 16           # for valid\n\nVERSION = 'v1'\nMODEL = 'resnext50'\n\nmodel1 = ResNeXt50Network(output_size=output_size, no_columns=no_columns).to(DEVICE)\n\n# ------------------\n\n# Run the cell below to train\n# Ran it locally on all data, see the results below\ntrain_folds(model=model1, train_original=balanced_dataset)\n\n# Print the logs during training\n# f = open('/kaggle/working/logs_v1.txt', \"r\")\n# contents = f.read()\n# print(contents)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n","metadata":{},"execution_count":null,"outputs":[]}]}