{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","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":30787,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"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\nimport matplotlib.image as mpimg\nimport os\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.colors import ListedColormap\nfrom sklearn.preprocessing import LabelEncoder, normalize\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:38.442868Z","iopub.execute_input":"2024-11-07T02:43:38.443286Z","iopub.status.idle":"2024-11-07T02:43:40.148444Z","shell.execute_reply.started":"2024-11-07T02:43:38.443247Z","shell.execute_reply":"2024-11-07T02:43:40.147401Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Đọ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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:40.150067Z","iopub.execute_input":"2024-11-07T02:43:40.150675Z","iopub.status.idle":"2024-11-07T02:43:40.271054Z","shell.execute_reply.started":"2024-11-07T02:43:40.15049Z","shell.execute_reply":"2024-11-07T02:43:40.269988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cancer_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))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:40.272335Z","iopub.execute_input":"2024-11-07T02:43:40.272676Z","iopub.status.idle":"2024-11-07T02:43:40.307075Z","shell.execute_reply.started":"2024-11-07T02:43:40.272642Z","shell.execute_reply":"2024-11-07T02:43:40.306056Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Show để so sánh cancer hoặc không cancer\n","metadata":{}},{"cell_type":"code","source":"def 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_cancer_vs_no_cancer(cancer_images, no_cancer_images, figsize=(20, 10)):\n    fig, axes = plt.subplots(2, 10, figsize=figsize)  # 2 rows, 10 columns\n    for i in range(10):\n        # Plot cancer images in the first row\n        axes[0, i].imshow(cancer_images[i], cmap='gray')\n        axes[0, i].axis('off')\n        axes[0, i].set_title(\"Cancer\")\n\n        # Plot no-cancer images in the second row\n        axes[1, i].imshow(no_cancer_images[i], cmap='gray')\n        axes[1, i].axis('off')\n        axes[1, i].set_title(\"No Cancer\")\n\n    plt.tight_layout()\n    plt.show()\n\n# Separate image paths based on cancer diagnosis\ncancer_image_paths = []\nno_cancer_image_paths = []\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    \n    if row['cancer'] == 1:  # Assuming 'cancer' column indicates presence of cancer\n        cancer_image_paths.append(img_path)\n    else:\n        no_cancer_image_paths.append(img_path)\n\n# Load the first 10 images of each type\ncancer_images = load_images_from_paths(cancer_image_paths[:10])\nno_cancer_images = load_images_from_paths(no_cancer_image_paths[:10])\n\n# Plot the grid with the updated function\nplot_cancer_vs_no_cancer(cancer_images, no_cancer_images)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:40.309672Z","iopub.execute_input":"2024-11-07T02:43:40.310024Z","iopub.status.idle":"2024-11-07T02:43:43.585351Z","shell.execute_reply.started":"2024-11-07T02:43:40.309986Z","shell.execute_reply":"2024-11-07T02:43:43.584072Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","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()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:43.586794Z","iopub.execute_input":"2024-11-07T02:43:43.587161Z","iopub.status.idle":"2024-11-07T02:43:43.803691Z","shell.execute_reply.started":"2024-11-07T02:43:43.587123Z","shell.execute_reply":"2024-11-07T02:43:43.802778Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class 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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:43.805048Z","iopub.execute_input":"2024-11-07T02:43:43.805474Z","iopub.status.idle":"2024-11-07T02:43:43.897563Z","shell.execute_reply.started":"2024-11-07T02:43:43.805414Z","shell.execute_reply":"2024-11-07T02:43:43.896379Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\n# Create the KDE plot\nplt.figure(figsize=(24, 10))\nsns.distplot(\n    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)\n\n# Add vertical lines and text for mean, min, and max\nplt.axvline(x=58, ls=\":\", lw=2, color=\"black\")\nplt.text(x=58.5, y=0.018, s=\"mean: 58\", size=17, color=\"black\", weight=\"bold\")\nplt.axvline(x=26, ls=\":\", lw=2, color=\"black\")\nplt.text(x=26.5, y=0.008, s=\"min: 26\", size=17, color=\"black\", weight=\"bold\")\nplt.axvline(x=89, ls=\":\", lw=2, color=\"black\")\nplt.text(x=84, y=0.037, s=\"max: 89\", size=17, color=\"black\", weight=\"bold\")\n\nplt.title(\"Age Distribution KDE Plot\", weight=\"bold\", size=20)\nsns.despine(right=True, top=True, left=True)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:43.899174Z","iopub.execute_input":"2024-11-07T02:43:43.900413Z","iopub.status.idle":"2024-11-07T02:43:44.486101Z","shell.execute_reply.started":"2024-11-07T02:43:43.900348Z","shell.execute_reply":"2024-11-07T02:43:44.485121Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create the boxen plot\nplt.figure(figsize=(24, 5))\nsns.boxenplot(x=cancer[\"age\"], color=my_colors[2])\n\nplt.title(\"Age Distribution Boxen Plot\", weight=\"bold\", size=20)\nsns.despine(right=True, top=True, left=True)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:44.487279Z","iopub.execute_input":"2024-11-07T02:43:44.4877Z","iopub.status.idle":"2024-11-07T02:43:44.713385Z","shell.execute_reply.started":"2024-11-07T02:43:44.487666Z","shell.execute_reply":"2024-11-07T02:43:44.712537Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### EDA","metadata":{}},{"cell_type":"code","source":"image_paths_cancer = cancer_image_paths[0] \nimage_paths_non_cancer = no_cancer_image_paths[-5]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:44.71464Z","iopub.execute_input":"2024-11-07T02:43:44.714947Z","iopub.status.idle":"2024-11-07T02:43:44.719173Z","shell.execute_reply.started":"2024-11-07T02:43:44.714915Z","shell.execute_reply":"2024-11-07T02:43:44.718252Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_paths_cancer","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:44.723091Z","iopub.execute_input":"2024-11-07T02:43:44.723391Z","iopub.status.idle":"2024-11-07T02:43:44.733799Z","shell.execute_reply.started":"2024-11-07T02:43:44.723359Z","shell.execute_reply":"2024-11-07T02:43:44.732966Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def 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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:44.735177Z","iopub.execute_input":"2024-11-07T02:43:44.735498Z","iopub.status.idle":"2024-11-07T02:43:46.187256Z","shell.execute_reply.started":"2024-11-07T02:43:44.735462Z","shell.execute_reply":"2024-11-07T02:43:46.186273Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### PYTORCH DATASET","metadata":{}},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:46.188836Z","iopub.execute_input":"2024-11-07T02:43:46.189157Z","iopub.status.idle":"2024-11-07T02:43:46.318745Z","shell.execute_reply.started":"2024-11-07T02:43:46.189124Z","shell.execute_reply":"2024-11-07T02:43:46.31783Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:46.32006Z","iopub.execute_input":"2024-11-07T02:43:46.32054Z","iopub.status.idle":"2024-11-07T02:43:46.327725Z","shell.execute_reply.started":"2024-11-07T02:43:46.320496Z","shell.execute_reply":"2024-11-07T02:43:46.326824Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q efficientnet_pytorch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:43:46.329024Z","iopub.execute_input":"2024-11-07T02:43:46.329661Z","iopub.status.idle":"2024-11-07T02:44:01.356734Z","shell.execute_reply.started":"2024-11-07T02:43:46.329617Z","shell.execute_reply":"2024-11-07T02:44:01.35562Z"}},"outputs":[],"execution_count":null},{"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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:01.358252Z","iopub.execute_input":"2024-11-07T02:44:01.358629Z","iopub.status.idle":"2024-11-07T02:44:02.310595Z","shell.execute_reply.started":"2024-11-07T02:44:01.358589Z","shell.execute_reply":"2024-11-07T02:44:02.309821Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:02.311682Z","iopub.execute_input":"2024-11-07T02:44:02.312126Z","iopub.status.idle":"2024-11-07T02:44:05.811156Z","shell.execute_reply.started":"2024-11-07T02:44:02.312091Z","shell.execute_reply":"2024-11-07T02:44:05.810161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:05.812517Z","iopub.execute_input":"2024-11-07T02:44:05.813113Z","iopub.status.idle":"2024-11-07T02:44:05.819618Z","shell.execute_reply.started":"2024-11-07T02:44:05.813067Z","shell.execute_reply":"2024-11-07T02:44:05.818594Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:05.82082Z","iopub.execute_input":"2024-11-07T02:44:05.821109Z","iopub.status.idle":"2024-11-07T02:44:07.0676Z","shell.execute_reply.started":"2024-11-07T02:44:05.821078Z","shell.execute_reply":"2024-11-07T02:44:07.0668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 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\n# SKlearn\nfrom sklearn.model_selection import StratifiedKFold, GroupKFold\nfrom sklearn.metrics import accuracy_score, roc_auc_score, confusion_matrix","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:07.068776Z","iopub.execute_input":"2024-11-07T02:44:07.069257Z","iopub.status.idle":"2024-11-07T02:44:07.944907Z","shell.execute_reply.started":"2024-11-07T02:44:07.069223Z","shell.execute_reply":"2024-11-07T02:44:07.943867Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def 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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:07.946251Z","iopub.execute_input":"2024-11-07T02:44:07.946611Z","iopub.status.idle":"2024-11-07T02:44:07.958132Z","shell.execute_reply.started":"2024-11-07T02:44:07.946574Z","shell.execute_reply":"2024-11-07T02:44:07.957101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Seed\nset_seed()\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint('Device available now:', DEVICE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:07.95939Z","iopub.execute_input":"2024-11-07T02:44:07.959784Z","iopub.status.idle":"2024-11-07T02:44:08.001273Z","shell.execute_reply.started":"2024-11-07T02:44:07.959749Z","shell.execute_reply":"2024-11-07T02:44:08.000314Z"}},"outputs":[],"execution_count":null},{"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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.002354Z","iopub.execute_input":"2024-11-07T02:44:08.00269Z","iopub.status.idle":"2024-11-07T02:44:08.007499Z","shell.execute_reply.started":"2024-11-07T02:44:08.002658Z","shell.execute_reply":"2024-11-07T02:44:08.006496Z"}},"outputs":[],"execution_count":null},{"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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.00887Z","iopub.execute_input":"2024-11-07T02:44:08.009351Z","iopub.status.idle":"2024-11-07T02:44:08.018752Z","shell.execute_reply.started":"2024-11-07T02:44:08.009307Z","shell.execute_reply":"2024-11-07T02:44:08.017715Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class 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}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.020212Z","iopub.execute_input":"2024-11-07T02:44:08.020548Z","iopub.status.idle":"2024-11-07T02:44:08.034462Z","shell.execute_reply.started":"2024-11-07T02:44:08.020512Z","shell.execute_reply":"2024-11-07T02:44:08.033628Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.035753Z","iopub.execute_input":"2024-11-07T02:44:08.036191Z","iopub.status.idle":"2024-11-07T02:44:08.048479Z","shell.execute_reply.started":"2024-11-07T02:44:08.036133Z","shell.execute_reply":"2024-11-07T02:44:08.047645Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = 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)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.049566Z","iopub.execute_input":"2024-11-07T02:44:08.04992Z","iopub.status.idle":"2024-11-07T02:44:08.766974Z","shell.execute_reply.started":"2024-11-07T02:44:08.049874Z","shell.execute_reply":"2024-11-07T02:44:08.765659Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.768947Z","iopub.execute_input":"2024-11-07T02:44:08.769753Z","iopub.status.idle":"2024-11-07T02:44:08.786225Z","shell.execute_reply.started":"2024-11-07T02:44:08.769689Z","shell.execute_reply":"2024-11-07T02:44:08.784646Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision.models import resnet50\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.797088Z","iopub.execute_input":"2024-11-07T02:44:08.797831Z","iopub.status.idle":"2024-11-07T02:44:08.80449Z","shell.execute_reply.started":"2024-11-07T02:44:08.797768Z","shell.execute_reply":"2024-11-07T02:44:08.802799Z"}},"outputs":[],"execution_count":null},{"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())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:08.806513Z","iopub.execute_input":"2024-11-07T02:44:08.807065Z","iopub.status.idle":"2024-11-07T02:44:10.695531Z","shell.execute_reply.started":"2024-11-07T02:44:08.807007Z","shell.execute_reply":"2024-11-07T02:44:10.694333Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:10.696856Z","iopub.execute_input":"2024-11-07T02:44:10.697563Z","iopub.status.idle":"2024-11-07T02:44:10.703079Z","shell.execute_reply.started":"2024-11-07T02:44:10.697524Z","shell.execute_reply":"2024-11-07T02:44:10.702003Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Train Resnet50\n","metadata":{}},{"cell_type":"code","source":"#  data \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:10.704598Z","iopub.execute_input":"2024-11-07T02:44:10.705044Z","iopub.status.idle":"2024-11-07T02:44:10.712923Z","shell.execute_reply.started":"2024-11-07T02:44:10.704999Z","shell.execute_reply":"2024-11-07T02:44:10.711914Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T02:44:10.714254Z","iopub.execute_input":"2024-11-07T02:44:10.714679Z","iopub.status.idle":"2024-11-07T02:44:10.74689Z","shell.execute_reply.started":"2024-11-07T02:44:10.714635Z","shell.execute_reply":"2024-11-07T02:44:10.745842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cài đặt các tham số tối ưu hóa\nFOLDS = 3\nEPOCHS = 1            # Tăng số epoch để mô hình có thêm thời gian học\nPATIENCE = 3           # Tăng patience cho early stopping\nWORKERS = 4\nLR = 0.00001            # Tăng nhẹ learning rate để tăng tốc độ hội tụ\nWD = 0.05              # Giảm nhẹ weight decay để mô hình không quá bảo thủ\nLR_WARMUP = 5          # Giảm số epoch warmup để mô hình thích nghi nhanh hơn\nLR_FACTOR = 0.2        # Giảm LR factor để tránh giảm tốc độ học quá nhanh\nLR_PATIENCE = 1\n\nBATCH_SIZE1 = 128      # Tăng batch size cho tập huấn luyện nếu GPU cho phép\nBATCH_SIZE2 = 64       # Tăng batch size cho tập kiểm định nếu GPU cho phép\nVERSION = 'v2'\nMODEL = 'resnet50'\n\n# Kiểm tra lại cấu hình sau khi điều chỉnh\nprint(f\"FOLDS: {FOLDS}, EPOCHS: {EPOCHS}, PATIENCE: {PATIENCE}, WORKERS: {WORKERS}\")\nprint(f\"Learning Rate (LR): {LR}, Weight Decay (WD): {WD}\")\nprint(f\"Learning Rate Warmup Epochs: {LR_WARMUP}, Learning Rate Factor: {LR_FACTOR}, LR Patience: {LR_PATIENCE}\")\nprint(f\"Batch Size (Train): {BATCH_SIZE1}, Batch Size (Validation): {BATCH_SIZE2}\")\nprint(f\"Model Version: {VERSION}, Model Type: {MODEL}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T03:14:24.410703Z","iopub.execute_input":"2024-11-07T03:14:24.411101Z","iopub.status.idle":"2024-11-07T03:14:24.419312Z","shell.execute_reply.started":"2024-11-07T03:14:24.411062Z","shell.execute_reply":"2024-11-07T03:14:24.418271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom sklearn.metrics import confusion_matrix, classification_report, accuracy_score, roc_auc_score\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport datetime as dtime\nfrom time import time\nimport gc\n\n# Hàm huấn luyện với các fold và lưu mô hình\ndef train_folds(model, train_original):\n    # Tạo file .txt để lưu log\n    f = open(f\"logs_{VERSION}.txt\", \"w+\")\n    \n    # Chia data thành các fold\n    group_fold = GroupKFold(n_splits=FOLDS)\n\n    # Tạo các chỉ số để chia data thành tập huấn luyện và kiểm định\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    # Huấn luyện theo từng fold\n    for i, (train_index, valid_index) in enumerate(k_folds):\n        print(clr.S + f\"---------- Fold: {i+1} ----------\" + clr.E)\n        add_in_file(f\"---------- Fold: {i+1} ----------\", f)\n        \n        # Thiết lập huấn luyện\n        best_roc = 0\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, factor=LR_FACTOR)\n        criterion = nn.BCEWithLogitsLoss()\n\n        # Chia dữ liệu thành tập huấn luyện và kiểm định cho fold hiện tại\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        # Tạo dataset và dataloader\n        train = RSNADataset(train_data, vertical_flip, horizontal_flip, is_train=True)\n        valid = RSNADataset(valid_data, vertical_flip, horizontal_flip, is_train=True)\n\n        train_loader = DataLoader(train, batch_size=BATCH_SIZE1, shuffle=True, num_workers=WORKERS)\n        valid_loader = DataLoader(valid, batch_size=BATCH_SIZE2, shuffle=False, num_workers=WORKERS)\n\n        train_losses_list = []\n        valid_losses_list = []\n\n        # Vòng lặp qua các epoch\n        for epoch in range(EPOCHS):\n            start_time = time()\n            correct = 0\n            train_losses = 0\n\n            # Huấn luyện\n            model.train()\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))\n\n            # Kiểm định\n            model.eval()\n            valid_preds = torch.zeros(size=(len(valid_index), 1), 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                    valid_loss = criterion(out, targets.unsqueeze(1).float())\n                    valid_losses += valid_loss.item()\n\n                valid_acc = accuracy_score(valid_data['cancer'].values, torch.round(valid_preds.cpu()))\n                valid_roc = roc_auc_score(valid_data['cancer'].values, valid_preds.cpu())\n                valid_losses_list.append(valid_losses / len(valid_loader))\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 và Classification Report\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                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                # Lưu lại mô hình nếu ROC tốt hơn\n                scheduler.step(valid_roc)\n                model_name = f\"best_model_fold{i+1}.pth\"\n\n                if valid_roc > best_roc:\n                    best_roc = valid_roc\n                    torch.save(model.state_dict(), model_name)\n                    print(f\"Saved Best Model for Fold {i+1} with ROC: {best_roc:.3f}\")\n\n                    patience_f = PATIENCE\n                else:\n                    patience_f -= 1\n                    if patience_f == 0:\n                        stop_logs = f\"Early stopping (no improvement after {PATIENCE} epochs) | Best ROC: {best_roc}\"\n                        add_in_file(stop_logs, f)\n                        print(stop_logs)\n                        break\n\n        # Vẽ biểu đồ 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        # Giải phóng bộ nhớ\n        del train, valid, train_loader, valid_loader, image, targets\n        gc.collect()\n\n    # Lưu lại mô hình cuối cùng sau khi hoàn thành các folds\n    torch.save(model.state_dict(), \"final_trained_model.pth\")\n    print(\"Model saved as 'final_trained_model.pth'.\")\n\n# Sử dụng hàm train_folds và lưu lại mô hình tốt nhất cho mỗi fold\nmodel1 = ResNet50Network(output_size=output_size, no_columns=no_columns).to(DEVICE)\ntrain_folds(model=model1, train_original=balanced_dataset)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T03:14:27.356958Z","iopub.execute_input":"2024-11-07T03:14:27.357384Z","iopub.status.idle":"2024-11-07T03:23:40.383949Z","shell.execute_reply.started":"2024-11-07T03:14:27.357343Z","shell.execute_reply":"2024-11-07T03:23:40.382847Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport torchvision.transforms as transforms\n\n# Khởi tạo mô hình và tải trọng số đã huấn luyện\nmodel = ResNet50Network(output_size=output_size, no_columns=no_columns).to(DEVICE)\nmodel.load_state_dict(torch.load(\"final_trained_model.pth\"))\nmodel.eval()  # Chuyển mô hình sang chế độ đánh giá\nprint(\"Model loaded successfully.\")\n\n# Hàm xử lý ảnh đầu vào\ndef preprocess_image(image_path):\n    transform = transforms.Compose([\n        transforms.Resize((224, 224)),  # Kích thước yêu cầu của ResNet50\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n    ])\n    image = Image.open(image_path).convert('RGB')\n    image = transform(image)\n    return image.unsqueeze(0)  # Thêm chiều batch\n\n# Hàm dự đoán và trực quan hóa ảnh với kết quả chẩn đoán\ndef predict_and_visualize(image_path, model):\n    image_tensor = preprocess_image(image_path).to(DEVICE)\n    \n    # Tạo một dummy tensor cho meta (kích thước phù hợp với mô hình)\n    meta_dummy = torch.zeros((1, no_columns)).to(DEVICE)  # no_columns là số lượng cột mà `meta` yêu cầu\n    \n    with torch.no_grad():\n        output = model(image_tensor, meta=meta_dummy)  # Dự đoán\n        prediction = torch.sigmoid(output).item()  # Chuyển đổi đầu ra thành xác suất\n        \n    # Xác định kết quả dự đoán và tiêu đề\n    if prediction >= 0.5:\n        title = f\"Ảnh này có ung thư (Xác suất: {prediction:.2f})\"\n    else:\n        title = f\"Ảnh này không có ung thư (Xác suất: {prediction:.2f})\"\n    \n    # Hiển thị ảnh với tiêu đề\n    image = Image.open(image_path)\n    plt.figure(figsize=(6, 6))\n    plt.imshow(image)\n    plt.axis('off')\n    plt.title(title, fontsize=16, fontweight='bold')\n    plt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T03:23:51.783669Z","iopub.execute_input":"2024-11-07T03:23:51.784066Z","iopub.status.idle":"2024-11-07T03:23:52.447408Z","shell.execute_reply.started":"2024-11-07T03:23:51.784029Z","shell.execute_reply":"2024-11-07T03:23:52.446444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_path = \"/kaggle/input/rsna-breast-cancer-detection-poi-images/bc_1280_train_lut/65198_712545807.png\"\npredict_and_visualize(image_path, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T03:23:54.618056Z","iopub.execute_input":"2024-11-07T03:23:54.618452Z","iopub.status.idle":"2024-11-07T03:23:54.911322Z","shell.execute_reply.started":"2024-11-07T03:23:54.618402Z","shell.execute_reply":"2024-11-07T03:23:54.9106Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_path = \"/kaggle/input/rsna-breast-cancer-detection-poi-images/bc_1280_train_lut/62634_1788417811.png\"\npredict_and_visualize(image_path, model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-07T03:23:57.886399Z","iopub.execute_input":"2024-11-07T03:23:57.887085Z","iopub.status.idle":"2024-11-07T03:23:58.208389Z","shell.execute_reply.started":"2024-11-07T03:23:57.887045Z","shell.execute_reply":"2024-11-07T03:23:58.207495Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}