{"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":24800,"databundleVersionId":1831594,"sourceType":"competition"},{"sourceId":1810938,"sourceType":"datasetVersion","datasetId":1075803},{"sourceId":9355809,"sourceType":"datasetVersion","datasetId":5671733},{"sourceId":9358252,"sourceType":"datasetVersion","datasetId":5673625},{"sourceId":9363154,"sourceType":"datasetVersion","datasetId":5677381},{"sourceId":9365277,"sourceType":"datasetVersion","datasetId":5679044},{"sourceId":9388364,"sourceType":"datasetVersion","datasetId":5696638},{"sourceId":9395486,"sourceType":"datasetVersion","datasetId":5702280},{"sourceId":9445869,"sourceType":"datasetVersion","datasetId":5740774},{"sourceId":9447841,"sourceType":"datasetVersion","datasetId":5742248},{"sourceId":9490408,"sourceType":"datasetVersion","datasetId":5774002},{"sourceId":9507339,"sourceType":"datasetVersion","datasetId":5786706}],"dockerImageVersionId":30684,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"raw","source":"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndDDdEdde# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-19T07:24:27.470566Z","iopub.execute_input":"2024-09-19T07:24:27.471005Z","iopub.status.idle":"2024-09-19T07:24:28.599836Z","shell.execute_reply.started":"2024-09-19T07:24:27.470971Z","shell.execute_reply":"2024-09-19T07:24:28.598947Z"}}},{"cell_type":"code","source":"# Display generic output messages\n!pip install colorama\n\n# Library for visualizing bounding boxes\n!pip install bbox-visualizer\n\n# Install ONNX library, will be used to convert from pytorch model to a tf model\n!pip install onnx onnxruntime onnxsim onnx-tf","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import bbox_visualizer as bbv\nimport cv2\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport shutil, os\nimport tensorflow as tf\nimport yaml\n\nfrom colorama import Fore, Back, Style\nfrom IPython.display import Image, display, clear_output\nfrom sklearn.model_selection import GroupShuffleSplit \nfrom tqdm.notebook import tqdm\nfrom typing import List","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !rm -rf /kaggle/working/data\n!mkdir -p /kaggle/working/data","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp -r /kaggle/input/vinbigdata-chest-xray-resized-png-1024x1024/* /kaggle/working/data/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp /kaggle/input/vinbigdata-chest-xray-abnormalities-detection/train.csv /kaggle/working/data/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp /kaggle/input/lables/output.csv /kaggle/working/data/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp /kaggle/input/yolov8-lan1/yolov8_lan1.pt /kaggle/working/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !git clone https://github.com/WongKinYiu/yolov7.git","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # Clone the YoloV9 repository, install the libray, and obtain the model\n# !git clone https://github.com/WongKinYiu/yolov9.git\n# !wget https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !wget https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !wget https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !pip install -r /kaggle/working/yolov9/requirements.txt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !pip install -r yolov7/requirements.txt\n# !wget https://github.com/WongKinYiu/yolov7/releases/download/v0.1/yolov7.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_SIZE = 1024\nTRAIN_IMAGES_DIRECTORY = '/kaggle/working/data/train/'\nTEST_IMAGES_DIRECTORY = '/kaggle/working/data/test/'\n\nTRAIN_IMAGES_PATH_REFACTORED = '/kaggle/working/refactored_data/images/train/'\nTRAIN_LABELS_PATH_REFACTORED = '/kaggle/working/refactored_data/labels/train/'\nVALID_IMAGES_PATH_REFACTORED = '/kaggle/working/refactored_data/images/val/'\nVALID_LABELS_PATH_REFACTORED = '/kaggle/working/refactored_data/labels/val/'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv('data/output.csv')\ntrain_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_base_df = pd.read_csv('data/train.csv')\ntrain_base_df #image_id,class_name,class_id,rad_id,x_min,y_min,x_max,y_max,width,height","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Tạo từ điển ánh xạ từ class_id đến class_name\nclass_id_to_name = dict(zip(train_base_df['class_id'], train_base_df['class_name']))\n\n# Thêm cột class_name vào new_df dựa trên class_id\ntrain_df['class_name'] = train_df['class_id'].map(class_id_to_name)\n\n# Kiểm tra new_df sau khi thêm cột\ntrain_df\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = 'data/train/'\nimg_path = []\nfor i in train_df['image_id']:\n  img_path.append(path+i+'.png')\n\ntrain_df['img_path'] = img_path\ntrain_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#x_min, y_min, x_max, y_max normalization값으로 update\ntrain_df['x_min'] = train_df.apply(lambda row: (row.x_min) /1024, axis =1)\ntrain_df['y_min'] = train_df.apply(lambda row: (row.y_min) /1024, axis =1)\n\ntrain_df['x_max'] = train_df.apply(lambda row: (row.x_max) /1024, axis =1)\ntrain_df['y_max'] = train_df.apply(lambda row: (row.y_max) /1024, axis =1)\n#x_mid, y_mid가 추가\ntrain_df['x_mid'] = train_df.apply(lambda row: (row.x_min + row.x_max)/2,axis =1)\ntrain_df['y_mid'] = train_df.apply(lambda row: (row.y_min + row.y_max)/2, axis =1)\n#normalization된 width & height 추가\ntrain_df['w'] = train_df.apply(lambda row: (row.x_max - row.x_min), axis = 1)\ntrain_df['h'] = train_df.apply(lambda row: (row.y_max - row.y_min), axis = 1)\n#area 추가\ntrain_df['area'] = train_df['w']*train_df['h']\ntrain_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['ori_x_min'] = (train_df['x_min']*1024).astype('int')\ntrain_df['ori_y_min'] = (train_df['y_min']*1024).astype('int')\ntrain_df['ori_x_max'] = (train_df['x_max']*1024).astype('int')\ntrain_df['ori_y_max'] = (train_df['y_max']*1024).astype('int')\n\ntrain_df['ori_x_mid'] = (train_df['x_mid']*1024).astype('int')\ntrain_df['ori_y_mid'] = (train_df['y_mid']*1024).astype('int')\ntrain_df['ori_w'] = (train_df['w']*1024).astype('int')\ntrain_df['ori_h'] = (train_df['h']*1024).astype('int')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final_df = train_df.copy()\nfinal_df = final_df[['image_id', 'class_name', 'class_id', 'ori_x_min', 'ori_y_min', 'ori_x_max', 'ori_y_max', 'ori_x_mid', 'ori_y_mid', 'ori_w', 'ori_h','img_path']]\nfinal_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport cv2\nimport numpy as np\nfrom tqdm import tqdm\nimport os\n\n# Đọc dữ liệu từ final_df (giả sử final_df đã được định nghĩa trước đó)\nfiltered_df = final_df[final_df['class_id'].isin([1, 12])].copy()\n\n# Hàm để cập nhật bounding box sau khi tăng cường\ndef update_bounding_box(bbox, transform_matrix):\n    \"\"\"\n    Cập nhật bounding box sau khi áp dụng ma trận biến đổi.\n    \n    Args:\n        bbox (list): Danh sách chứa các tọa độ bounding box [x_min, y_min, x_max, y_max].\n        transform_matrix (np.array): Ma trận biến đổi affine 2x3.\n    \n    Returns:\n        tuple: Tọa độ bounding box mới [x_min, y_min, x_max, y_max].\n    \"\"\"\n    ori_x_min, ori_y_min, ori_x_max, ori_y_max = bbox\n    \n    # Tạo mảng các điểm của bounding box\n    points = np.array([\n        [ori_x_min, ori_y_min],  # Góc trên bên trái\n        [ori_x_max, ori_y_min],  # Góc trên bên phải\n        [ori_x_max, ori_y_max],  # Góc dưới bên phải\n        [ori_x_min, ori_y_max]   # Góc dưới bên trái\n    ])\n    \n    # Chuyển đổi điểm bằng ma trận biến đổi\n    # Thay đổi transform_matrix thành dạng 3x3 để dễ tính toán\n    # Thêm hàng thứ ba [0, 0, 1] vào ma trận biến đổi để phù hợp với tọa độ đồng nhất\n    transform_matrix_3x3 = np.vstack([transform_matrix, [0, 0, 1]])\n    \n    # Thêm hàng thứ ba [1] vào các điểm để phù hợp với tọa độ đồng nhất\n    points_homogeneous = np.hstack([points, np.ones((points.shape[0], 1))])\n    \n    # Áp dụng ma trận biến đổi\n    transformed_points = np.dot(points_homogeneous, transform_matrix_3x3.T)\n    \n    # Chuyển đổi trở lại tọa độ không đồng nhất\n    transformed_points[:, 0] /= transformed_points[:, 2]\n    transformed_points[:, 1] /= transformed_points[:, 2]\n    \n    # Tìm giá trị min và max cho các trục x và y\n    ori_x_min = transformed_points[:, 0].min()\n    ori_y_min = transformed_points[:, 1].min()\n    ori_x_max = transformed_points[:, 0].max()\n    ori_y_max = transformed_points[:, 1].max()\n    \n    return ori_x_min, ori_y_min, ori_x_max, ori_y_max\n\n# Thực hiện tăng cường dữ liệu và lưu thông số mới vào CSV\nnew_rows = []\n\nfor index, row in tqdm(filtered_df.iterrows(), total=filtered_df.shape[0]):\n    image_path = row['img_path']\n    bbox = [row['ori_x_min'], row['ori_y_min'], row['ori_x_max'], row['ori_y_max']]\n    image_id = row['image_id']\n    class_name = row['class_name']\n    class_id = row['class_id']\n    ori_x_mid = row['ori_x_mid']\n    ori_y_mid = row['ori_y_mid']\n    ori_w = row['ori_w']\n    ori_h = row['ori_h']\n    \n    # Đọc ảnh\n    image = cv2.imread(image_path)\n    if image is None:\n        continue\n    \n    # Ví dụ về một biến đổi: xoay ảnh 90 độ\n    height, width = image.shape[:2]\n    M = cv2.getRotationMatrix2D((width / 2, height / 2), 90, 1)\n    rotated_image = cv2.warpAffine(image, M, (width, height))\n    \n    # Cập nhật bounding box\n    new_bbox = update_bounding_box(bbox, M)\n    \n    # Lưu ảnh mới\n    new_image_path = os.path.splitext(image_path)[0] + '_rotated.png'\n    cv2.imwrite(new_image_path, rotated_image)\n    \n    # Tạo một dòng mới với thông số cập nhật\n    new_row = row.copy()\n    new_row['img_path'] = new_image_path\n    new_row['ori_x_min'], new_row['ori_y_min'], new_row['ori_x_max'], new_row['ori_y_max'] = new_bbox\n    new_row['image_id'] = image_id + '_rotated'\n    new_row['class_name'] = class_name\n    new_row['class_id'] = class_id\n    new_row['ori_x_mid'] = ori_x_mid\n    new_row['ori_y_mid'] = ori_y_mid\n    new_row['ori_w'] = ori_w\n    new_row['ori_h'] = ori_h\n    new_rows.append(new_row)\n\n# Tạo DataFrame từ các dòng mới\nnew5_df = pd.DataFrame(new_rows)\n\n# # Gộp dữ liệu mới vào DataFrame gốc\n# augmented_df = pd.concat([final_df, new_df], ignore_index=True)\n\n# # Lưu DataFrame đã cập nhật vào file CSV mới\n# augmented_df.to_csv('/kaggle/working/data/train_augmented.csv', index=False)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def flip_image(image_path, bbox):\n    \"\"\"\n    Lật ảnh theo chiều ngang và cập nhật bounding box.\n\n    Args:\n        image_path (str): Đường dẫn đến ảnh gốc.\n        bbox (list): Danh sách chứa các tọa độ bounding box [x_min, y_min, x_max, y_max].\n\n    Returns:\n        tuple: Đường dẫn ảnh mới và bounding box đã được cập nhật.\n    \"\"\"\n    # Đọc ảnh gốc\n    image = cv2.imread(image_path)\n    if image is None:\n        return None, None\n\n    # Lật ảnh theo chiều ngang\n    flipped_image = cv2.flip(image, 1)\n\n    # Cập nhật bounding box\n    width = image.shape[1]\n    flipped_bbox = [\n        width - bbox[2], bbox[1],  # x_max -> new_x_min, y_min\n        width - bbox[0], bbox[3]   # x_min -> new_x_max, y_max\n    ]\n\n    # Lưu ảnh mới\n    new_image_path = os.path.splitext(image_path)[0] + '_flip.png'\n    cv2.imwrite(new_image_path, flipped_image)\n    \n    return new_image_path, flipped_bbox\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def flip_images_in_df(df):\n    \"\"\"\n    Lật ảnh cho các lớp cụ thể và cập nhật thông tin bounding box trong DataFrame.\n\n    Args:\n        df (pd.DataFrame): DataFrame chứa thông tin về ảnh và bounding box.\n\n    Returns:\n        pd.DataFrame: DataFrame đã được cập nhật với ảnh lật và bounding box mới.\n    \"\"\"\n    filtered_df = final_df[final_df['class_id'].isin([1, 12,2,4])].copy()\n    new_rows = []\n\n    for index, row in tqdm(df.iterrows(), total=df.shape[0]):\n        image_path = row['img_path']\n        bbox = [row['ori_x_min'], row['ori_y_min'], row['ori_x_max'], row['ori_y_max']]\n        image_id = row['image_id']\n        class_name = row['class_name']\n        class_id = row['class_id']\n        ori_x_mid = row['ori_x_mid']\n        ori_y_mid = row['ori_y_mid']\n        ori_w = row['ori_w']\n        ori_h = row['ori_h']\n        \n        # Lật ảnh và cập nhật bounding box\n        new_image_path, new_bbox = flip_image(image_path, bbox)\n        \n        if new_image_path is None:\n            continue\n        \n        # Tạo một dòng mới với thông số cập nhật\n        new_row = row.copy()\n        new_row['img_path'] = new_image_path\n        new_row['ori_x_min'], new_row['ori_y_min'], new_row['ori_x_max'], new_row['ori_y_max'] = new_bbox\n        new_row['image_id'] = image_id + '_flip'\n        new_row['class_name'] = class_name\n        new_row['class_id'] = class_id\n        new_row['ori_x_mid'] = ori_x_mid\n        new_row['ori_y_mid'] = ori_y_mid\n        new_row['ori_w'] = ori_w\n        new_row['ori_h'] = ori_h\n        new_rows.append(new_row)\n\n    # Tạo DataFrame từ các dòng mới\n    new_df = pd.DataFrame(new_rows)\n\n    return new_df\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new5_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filtered_df = final_df[final_df['class_id'].isin([1, 12])].copy()\nnew1_df = flip_images_in_df(filtered_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport cv2\nimport numpy as np\nimport imgaug.augmenters as iaa\nfrom tqdm import tqdm\nimport os\n\ndef zoom_image(image_path, bbox, zoom_factor):\n    \"\"\"\n    Zoom ảnh và cập nhật bounding box.\n\n    Args:\n        image_path (str): Đường dẫn đến ảnh gốc.\n        bbox (list): Danh sách chứa các tọa độ bounding box [x_min, y_min, x_max, y_max].\n        zoom_factor (float): Hệ số zoom.\n\n    Returns:\n        tuple: Đường dẫn ảnh mới và bounding box đã được cập nhật.\n    \"\"\"\n    # Đọc ảnh gốc\n    image = cv2.imread(image_path)\n    if image is None:\n        return None, None\n\n    # Tăng cường zoom\n    augment_img_zoom = iaa.Affine(scale=(zoom_factor))\n    zoomed_image = augment_img_zoom.augment_image(image)\n\n    # Cập nhật bounding box\n    height, width = image.shape[:2]\n    new_width, new_height = int(width * zoom_factor), int(height * zoom_factor)\n\n    # Tính toán offset để điều chỉnh bounding box\n    offset_x = (new_width - width) / 2\n    offset_y = (new_height - height) / 2\n\n    new_bbox = [\n        bbox[0] * zoom_factor - offset_x,  # x_min\n        bbox[1] * zoom_factor - offset_y,  # y_min\n        bbox[2] * zoom_factor - offset_x,  # x_max\n        bbox[3] * zoom_factor - offset_y   # y_max\n    ]\n\n    # Lưu ảnh mới\n    new_image_path = os.path.splitext(image_path)[0] + '_zoom.png'\n    cv2.imwrite(new_image_path, zoomed_image)\n    \n    return new_image_path, new_bbox\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def zoom_images_in_df(df, zoom_factor):\n    \"\"\"\n    Thực hiện zoom cho các ảnh thuộc lớp cụ thể và cập nhật thông tin bounding box trong DataFrame.\n\n    Args:\n        df (pd.DataFrame): DataFrame chứa thông tin về ảnh và bounding box.\n        zoom_factor (float): Hệ số zoom.\n\n    Returns:\n        pd.DataFrame: DataFrame đã được cập nhật với ảnh zoom và bounding box mới.\n    \"\"\"\n    new_rows = []\n\n    for index, row in tqdm(df.iterrows(), total=df.shape[0]):\n        image_path = row['img_path']\n        bbox = [row['ori_x_min'], row['ori_y_min'], row['ori_x_max'], row['ori_y_max']]\n        image_id = row['image_id']\n        class_name = row['class_name']\n        class_id = row['class_id']\n        ori_x_mid = row['ori_x_mid']\n        ori_y_mid = row['ori_y_mid']\n        ori_w = row['ori_w']\n        ori_h = row['ori_h']\n        \n        # Zoom ảnh và cập nhật bounding box\n        new_image_path, new_bbox = zoom_image(image_path, bbox, zoom_factor)\n        \n        if new_image_path is None:\n            continue\n        \n        # Tạo một dòng mới với thông số cập nhật\n        new_row = row.copy()\n        new_row['img_path'] = new_image_path\n        new_row['ori_x_min'], new_row['ori_y_min'], new_row['ori_x_max'], new_row['ori_y_max'] = new_bbox\n        new_row['image_id'] = image_id + '_zoom'\n        new_row['class_name'] = class_name\n        new_row['class_id'] = class_id\n        new_row['ori_x_mid'] = ori_x_mid\n        new_row['ori_y_mid'] = ori_y_mid\n        new_row['ori_w'] = ori_w\n        new_row['ori_h'] = ori_h\n        new_rows.append(new_row)\n\n    # Tạo DataFrame từ các dòng mới\n    new_df = pd.DataFrame(new_rows)\n\n    return new_df\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filtered_df = final_df[final_df['class_id'].isin([1, 12])].copy()\n\n# Áp dụng hàm zoom ảnh cho DataFrame đã lọc với hệ số zoom là 10% (1.1)\nnew3_df = zoom_images_in_df(filtered_df, zoom_factor=1.1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport os\n\ndef clahe_image(image_list):\n    \"\"\"\n    Áp dụng CLAHE cho ảnh và lưu ảnh đã được tăng cường.\n\n    Args:\n        image_list (list): Danh sách các đường dẫn đến các ảnh cần áp dụng CLAHE.\n    \"\"\"\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))\n    \n    for path in image_list:\n        img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)\n        if img is None:\n            continue\n        clahe_img = clahe.apply(img)\n        img_name = os.path.basename(path).split('.')[0]\n        new_image_path = f'{os.path.splitext(path)[0]}_clahe.png'\n        cv2.imwrite(new_image_path, clahe_img)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nfrom tqdm import tqdm\n\n# Lọc DataFrame chỉ chứa các lớp có class_id là 1 và 12\nfiltered_df = final_df[final_df['class_id'].isin([1, 12,4])].copy()\n\n# Tạo danh sách các đường dẫn ảnh\nimage_list = filtered_df['img_path'].tolist()\n\n# Thực hiện CLAHE cho các ảnh\nclahe_image(image_list)\n\n# Cập nhật DataFrame với ảnh mới đã áp dụng CLAHE\ndef update_df_with_clahe(df):\n    new_rows = []\n\n    for index, row in tqdm(df.iterrows(), total=df.shape[0]):\n        image_path = row['img_path']\n        img_name = os.path.basename(image_path).split('.')[0]\n        new_image_path = f'{os.path.splitext(image_path)[0]}_clahe.png'\n\n        # Tạo một dòng mới với đường dẫn ảnh CLAHE\n        new_row = row.copy()\n        new_row['img_path'] = new_image_path\n        new_row['image_id'] = row['image_id'] + '_clahe'\n        new_rows.append(new_row)\n\n    # Tạo DataFrame từ các dòng mới\n    new_df = pd.DataFrame(new_rows)\n    \n    return new_df\n\n# Áp dụng hàm cập nhật DataFrame\nnew4_df = update_df_with_clahe(filtered_df)\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport os\n\ndef equ_image(image_list):\n    \"\"\"\n    Áp dụng EqualizeHist cho ảnh và lưu ảnh đã được tăng cường.\n\n    Args:\n        image_list (list): Danh sách các đường dẫn đến các ảnh cần áp dụng EqualizeHist.\n    \"\"\"\n    for path in image_list:\n        img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)\n        if img is None:\n            continue\n        equ_img = cv2.equalizeHist(img)\n        img_name = os.path.basename(path).split('.')[0]\n        new_image_path = f'{os.path.splitext(path)[0]}_equ.png'\n        cv2.imwrite(new_image_path, equ_img)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nfrom tqdm import tqdm\n\n# Lọc DataFrame chỉ chứa các lớp có class_id là 1 và 12\nfiltered_df = final_df[final_df['class_id'].isin([1, 12,4,5,2,6])].copy()\n\n# Tạo danh sách các đường dẫn ảnh\nimage_list = filtered_df['img_path'].tolist()\n\n# Thực hiện EqualizeHist cho các ảnh\nequ_image(image_list)\n\n# Cập nhật DataFrame với ảnh mới đã áp dụng EqualizeHist\ndef update_df_with_equ(df):\n    new_rows = []\n\n    for index, row in tqdm(df.iterrows(), total=df.shape[0]):\n        image_path = row['img_path']\n        img_name = os.path.basename(image_path).split('.')[0]\n        new_image_path = f'{os.path.splitext(image_path)[0]}_equ.png'\n\n        # Tạo một dòng mới với đường dẫn ảnh EqualizeHist\n        new_row = row.copy()\n        new_row['img_path'] = new_image_path\n        new_row['image_id'] = row['image_id'] + '_equ'\n        new_rows.append(new_row)\n\n    # Tạo DataFrame từ các dòng mới\n    new_df = pd.DataFrame(new_rows)\n    \n    return new_df\n\n# Áp dụng hàm cập nhật DataFrame\n\n\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new2_df=update_df_with_equ(filtered_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_train_df = pd.concat([new5_df, new1_df, new2_df, new4_df,new3_df, final_df], ignore_index=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_train_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import pandas as pd\n\n# # Giả sử new_train_df đã tồn tại\n# # Ví dụ:\n# new_train_df = pd.DataFrame(...)\n\n# Tạo một bản sao của new_train_df để xử lý\nnew_df = new_train_df.copy()\n\n# # Đổi tên các cột liên quan\n# new_df.rename(columns={\n#     'ori_x_min': 'x_min',\n#     'ori_y_min': 'y_min',\n#     'ori_x_max': 'x_max',\n#     'ori_y_max': 'y_max'\n# }, inplace=True)\n\n# # Chuyển đổi giá trị các cột x_min, x_max, y_min, y_max\n# new_df['x_min'] = new_df['x_min'] / 1024\n# new_df['y_min'] = new_df['y_min'] / 1024\n# new_df['x_max'] = new_df['x_max'] / 1024\n# new_df['y_max'] = new_df['y_max'] / 1024\n\n# # Chỉ giữ lại các cột x_min, x_max, y_min, y_max\n# new_df = new_df[['image_id','class_id','class_name','x_min', 'x_max', 'y_min', 'y_max']]\n# new_df['x_center'] = (new_df['x_max'] + new_df['x_min']) / 2\n# new_df['y_center'] = (new_df['y_max'] + new_df['y_min']) / 2\n\n# new_df['weight'] = (new_df['x_max'] - new_df['x_min'])\n# new_df['height'] = (new_df['y_max'] - new_df['y_min'])\n# Hiển thị kết quả\nnew_df\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_df['class_id'].value_counts()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\ngkf  = GroupKFold(n_splits = 5)\nnew_df['fold'] = -1\nfor fold, (train_idx, val_idx) in enumerate(gkf.split(new_df, groups = new_df.image_id.tolist())): # cf) tolist한다고 unqiue해지는건 아님\n    new_df.loc[val_idx, 'fold'] = fold\nnew_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_dict = dict(set(zip(final_df.class_id, final_df.class_name)))\nclasses = []\nfor key in sorted(class_dict.keys()):\n    classes.append(class_dict[key])\n\nclasses = ['_'] + classes   # adding background\nclasses","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def label_to_name(id):\n    id = int(id)\n    id = id-1\n    if id == 0:\n        return \"Aortic enlargement\"\n    if id == 1:\n        return \"Atelectasis\"\n    if id == 2:\n        return \"Calcification\"\n    if id == 3:\n        return \"Cardiomegaly\"\n    if id == 4:\n        return \"Consolidation\"\n    if id == 5:\n        return \"ILD\"\n    if id == 6:\n        return \"Infiltration\"\n    if id == 7:\n        return \"Lung Opacity\"\n    if id == 8:\n        return \"Nodule/Mass\"  \n    if id == 9:\n        return \"Other lesion\"\n    if id == 10:\n        return \"Pleural effusion\"\n    if id == 11:\n        return \"Pleural thickening\"\n    if id == 12:\n        return \"Pneumothorax\"\n    if id == 13:\n        return \"Pulmonary fibrosis\"\n    else:\n        return str(id)  ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader, Dataset","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class VBDDataset(Dataset): # class to load training data\n    def __init__(self, dataframe, image_dir, transforms=None):\n        super().__init__()\n\n        self.image_ids = dataframe['image_id'].unique() # image 고유 ID\n        self.df = dataframe\n        self.image_dir = image_dir\n        self.transforms = transforms # data의 경로와 불러올 데이터들에 augmentation을 적용하기위해 transform 인자를 만듬\n\n    def __getitem__(self, idx): # image index로 item 불러오기\n\n        image_id = self.image_ids[idx]\n        # image ID가 같은 dataframe 가져오기\n        records = self.df[self.df['image_id'] == image_id]\n        # cv2로 image 불러오기\n        image = cv2.imread(f'{self.image_dir}/{image_id}.png', cv2.IMREAD_COLOR)\n        # openCV로 각  color를 저장하는 방식인 BGR을 RGB로 변환\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        # 0~1 사이로 scaling\n        image /= 1024.0\n        boxes = records[['ori_x_min', 'ori_y_min', 'ori_x_max', 'ori_y_max']].values\n        \n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        # list를 torch tensor로 view 변환 (data definition)\n        area = torch.as_tensor(area, dtype=torch.float32)\n        # all the labels are shifted by 1 to accomodate background\n        labels = torch.squeeze(torch.as_tensor((records.class_id.values+1,), dtype=torch.int64))\n        \n        # 모든 인스턴스는 crowd 상태가 아님을 가정\n        iscrowd = torch.zeros((records.shape[0],), dtype=torch.int64)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['labels'] = labels\n        # target['masks'] = None\n        target['image_id'] = torch.tensor([idx])\n        target['area'] = area\n        target['iscrowd'] = iscrowd\n        # transform 적용\n        if self.transforms:\n            sample = {\n                'image': image,\n                'bboxes': target['boxes'],\n                'labels': labels\n            }\n            sample = self.transforms(**sample)\n            image = sample['image']\n            \n            target['boxes'] = torch.as_tensor(sample['bboxes'])\n\n        return image, target, image_id\n\n    def __len__(self):\n        return self.image_ids.shape[0]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dir = '/kaggle/working/data/train'  # Đường dẫn đến thư mục chứa hình ảnh\ndt = VBDDataset(new_df, train_dir)  # Khởi tạo đối tượng VBDDataset\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install albumentations==0.4.6\nimport albumentations as A","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from albumentations.pytorch import ToTensorV2\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom albumentations.core.transforms_interface import ImageOnlyTransform","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 이미지 tensor로 바꾸기\ndef get_train_transform():\n    return A.Compose([\n        ToTensorV2(p=1.0) # albumentations의 경우는 normalize 후 ToTensorV2 사용\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})\n\ndef get_valid_transform():\n    return A.Compose([\n        ToTensorV2(p=1.0)\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torchvision\n\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\nfrom torchvision.models.detection.rpn import AnchorGenerator","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#load a model; pre-trained on COCO\nmodel = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 15  # 14 classes + background\n\n# 분류기에서 사용할 입력 특징의 차원 정보 얻음\nin_features = model.roi_heads.box_predictor.cls_score.in_features\n\n# 미리 학습된 모델의 머리 부분을 새로운 것으로 교체\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# A Class for keeping track of average\nclass Averager:\n    def __init__(self):\n        self.current_total = 0.0\n        self.iterations = 0.0\n\n    def send(self, value):\n        self.current_total += value\n        self.iterations += 1\n\n    @property\n    def value(self):\n        if self.iterations == 0:\n            return 0\n        else:\n            return 1.0 * self.current_total / self.iterations\n\n    def reset(self):\n        self.current_total = 0.0\n        self.iterations = 0.0","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch))\n\ntrain_dataset = VBDDataset(new_df, train_dir, get_train_transform())\nvalid_dataset = VBDDataset(new_df, train_dir, get_valid_transform())\n\n\ntrain_data_loader = DataLoader(\n    train_dataset,\n    batch_size=8,\n    shuffle=False,\n    num_workers=4,\n    collate_fn=collate_fn\n)\n\nvalid_data_loader = DataLoader(\n    valid_dataset,\n    batch_size=4,\n    shuffle=False,\n    num_workers=4,\n    collate_fn=collate_fn\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\n\nimages, targets, image_ids = next(iter(train_data_loader))\nimages = list(image.to(device) for image in images)\ntargets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\nboxes = targets[2]['boxes'].cpu().numpy().astype(np.int32)\nsample = images[2].permute(1,2,0).cpu().numpy()\nlabels= targets[2]['labels'].cpu().numpy().astype(np.int32)\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor i in range(len(boxes)):\n    sample = cv2.rectangle(sample,\n                  (boxes[i][0], boxes[i][1]),\n                  (boxes[i][2], boxes[i][3]),\n                  (220, 0, 0), 1)\n    sample = cv2.putText(sample, label_to_name(labels[i]), (int(boxes[i][0]), int(boxes[i][1])),cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255, 0, 0), 1, cv2.LINE_AA)\n\nax.set_axis_off()\nax.imshow(sample)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_dataloaders(df, trn_idx, val_idx):\n    \n    train_ = df.loc[trn_idx,:].reset_index(drop=True)\n    valid_ = df.loc[val_idx,:].reset_index(drop=True)\n        \n    def collate_fn(batch):\n        return tuple(zip(*batch))\n\n    train_dataset = VBDDataset(train_, train_dir, get_train_transform())\n    valid_dataset = VBDDataset(valid_, train_dir, get_valid_transform())\n\n    train_data_loader = DataLoader(\n        train_dataset,\n        batch_size=8,\n        shuffle=False,\n        num_workers=4,\n        collate_fn=collate_fn\n    )\n\n    valid_data_loader = DataLoader(\n        valid_dataset,\n        batch_size=4,\n        shuffle=False,\n        num_workers=4,\n        collate_fn=collate_fn\n    )\n    \n    return train_data_loader, valid_data_loader","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model, dataloader, device, epochs, optimizer, lr_scheduler, fold):\n    \n    best_loss = 1e10\n    loss_hist = Averager()\n    itr = 1\n    all_losses = []\n\n    for epoch in range(epochs):\n        loss_hist.reset() \n    \n        for images, targets, image_ids in dataloader:\n\n            images = list(image.to(device) for image in images)\n            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\n            loss_dict = model(images, targets)\n\n            losses = sum(loss for loss in loss_dict.values())\n            loss_value = losses.item()\n\n            loss_hist.send(loss_value)\n            all_losses.append(loss_value)\n            \n            optimizer.zero_grad()\n            losses.backward()\n            optimizer.step()\n\n            if itr % 50 == 0:\n                print(f\"Iteration #{itr} loss: {loss_value}\")\n\n            itr += 1        \n        # saving the model based on training loss for now. - later can be moved to validation\n        if loss_hist.value < best_loss:\n            best_loss = loss_hist.value\n            torch.save(model.state_dict(), f'fasterrcnn_model_{fold}.pt')\n\n        # update the learning rate\n        if lr_scheduler is not None:\n            lr_scheduler.step()\n\n        print(f\"Epoch #{epoch} loss: {loss_hist.value}\\n\")\n        \n    return all_losses","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def validate_model(model, dataloader, device):\n    print(\"\\n Starting Validation ... \")\n    loss_hist = Averager()\n    itr = 1\n\n    loss_hist.reset() \n\n    for images, targets, image_ids in dataloader:\n\n        images = list(image.to(device) for image in images)\n        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\n        loss_dict = model(images, targets)\n\n        losses = sum(loss for loss in loss_dict.values())\n        loss_value = losses.item()\n\n        loss_hist.send(loss_value)\n\n        if itr % 50 == 0:\n            print(f\"Iteration #{itr} loss: {loss_value}\")\n\n        itr += 1\n\n    print(f\"\\nFinal loss: {loss_hist.value}\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import re\nimport cv2 # Albumentation transform을 쓰려면 꼭 cv2 library를 이용해야함.\nimport time\nimport random\nimport warnings","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def run_fold(fold):\n    print(f\"Starting fold {fold}\")\n    start = time.time()\n    trn_idx = new_df[new_df['fold'] != fold].index\n    val_idx = new_df[new_df['fold'] == fold].index\n    \n    \n    trainloader, valloader = get_dataloaders(new_df, trn_idx, val_idx)\n    loss_hist = train_model(model, trainloader, device, epochs, optimizer, lr_scheduler, fold)\n    \n    # plot training loss\n    plt.figure(figsize=(8,5))\n    plt.plot(loss_hist)\n    plt.title(\"Training Loss Statistic\", size=17)\n    plt.xlabel(\"Iteration\", size=15)\n    plt.ylabel(\"Loss Value\", size=15)\n\n    plt.show()\n    \n    validate_model(model, valloader, device)\n    \n    print(f\"Completed Fold {fold} in {round(time.time()-start, 2)} seconds\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.to(device)\n\n# set params for model\nparams = [p for p in model.parameters() if p.requires_grad]\n\n# set optimizer\noptimizer = torch.optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005)\n\n# set lr scheduler\nlr_scheduler = None\n\n# set epochs\nepochs = 10\n\n# set folds\nnum_folds = 1","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for fold in range(num_folds):\n    run_fold(fold)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Định nghĩa các biến\ncsv_file = new_df  # Thay đổi đường dẫn tới file CSV của bạn\nbatch_size = 4\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# Khởi tạo DataLoader\ndataset = CustomDataset(csv_file=csv_file, transform=transforms.ToTensor())\ntrain_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ncount = len(new_df) #sample의 개수\n# plt.figure(figsize = (12,8))\n# #Seaborn으로 class name기준으로 bar chart 그리기\n# ax = sns.countplot(x = 'class_name', data = new_df, order = new_df.class_name.value_counts().index)\n# plt.title('Distribution of class names')\n# ax.set_xticklabels(ax.get_xticklabels(), rotation = 45, ha ='right')\n# #x축만 공유하고 y축은 따로 쓰는 'twinx()'\n# ax2 = ax.twinx()\n# # tick: 축에 간격을 구분하기 위해 표시하는 눈금\n# # ax는 오른쪽, ax2는 왼쪽\n# ax2.yaxis.tick_left() \n# ax.yaxis.tick_right() \n\n# ax.yaxis.set_label_position('right')\n# ax2.yaxis.set_label_position('left')\n\n# ax2.set_ylabel('Frequency [%]')\n# # patches 모듈은 (x, y, width, height)의 형태로 도형으로 시각화 하는 방법\n# for p in ax.patches:\n#   x = p.get_bbox().get_points()[:,0] # get_points: bbox의 점을 [[x0,y0],[x1,y1]]형식의 numpy배열로 직접가져옴\n#   y = p.get_bbox().get_points()[1,1]\n#   # annotate: 주석달기. (주석 내용, 좌표는 필수로 전달해야함)\n#   # ha = horizontal alignmnet, va = vertical alignment\n#   ax.annotate('{:.1f}%'.format(100.*y/ncount), (x.mean(), y), ha = 'center', va = 'bottom')\n\n# # linearlocator: min에서 max까지 균일 분포 눈금.\n# ax.yaxis.set_major_locator(ticker.LinearLocator(11))\n# # y값의 limitation\n# ax2.set_ylim(0,100)\n# ax.set_ylim(0,ncount)\n# # multiplelocator: 눈금과 범위는 모두 base의 배수\n# ax2.yaxis.set_major_locator(ticker.MultipleLocator(10))\n\n# ax2.grid(None)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_dict = dict(set(zip(final_df.class_id, final_df.class_name)))\nclasses = []\nfor key in sorted(class_dict.keys()):\n    classes.append(class_dict[key])\n\nclasses = ['_'] + classes   # adding background\nclasses","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def label_to_name(id):\n    id = int(id)\n    id = id-1\n    if id == 0:\n        return \"Aortic enlargement\"\n    if id == 1:\n        return \"Atelectasis\"\n    if id == 2:\n        return \"Calcification\"\n    if id == 3:\n        return \"Cardiomegaly\"\n    if id == 4:\n        return \"Consolidation\"\n    if id == 5:\n        return \"ILD\"\n    if id == 6:\n        return \"Infiltration\"\n    if id == 7:\n        return \"Lung Opacity\"\n    if id == 8:\n        return \"Nodule/Mass\"  \n    if id == 9:\n        return \"Other lesion\"\n    if id == 10:\n        return \"Pleural effusion\"\n    if id == 11:\n        return \"Pleural thickening\"\n    if id == 12:\n        return \"Pneumothorax\"\n    if id == 13:\n        return \"Pulmonary fibrosis\"\n    else:\n        return str(id)  ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport numpy as np\nimport shutil\nimport yaml\nfrom sklearn.model_selection import GroupShuffleSplit\nfrom tqdm import tqdm\n\n# Training/validation splitting\nsplitter = GroupShuffleSplit(test_size=0.1)\nsplit = splitter.split(new_df, groups=new_df['image_id'])\ntrain_inds, valid_inds = next(split)\n\nvalid_df = new_df.iloc[valid_inds]\ntrain_df = new_df.iloc[train_inds]\n\nclass VBDDataset(Dataset): # class to load training data\n    def __init__(self, dataframe, image_dir, transforms=None):\n        super().__init__()\n\n        self.image_ids = dataframe['image_id'].unique() # image 고유 ID\n        self.df = dataframe\n        self.image_dir = image_dir\n        self.transforms = transforms # data의 경로와 불러올 데이터들에 augmentation을 적용하기위해 transform 인자를 만듬\n\n    def __getitem__(self, idx): # image index로 item 불러오기\n\n        image_id = self.image_ids[idx]\n        # image ID가 같은 dataframe 가져오기\n        records = self.df[self.df['image_id'] == image_id]\n        # cv2로 image 불러오기\n        image = cv2.imread(f'{self.image_dir}/{image_id}.png', cv2.IMREAD_COLOR)\n        # openCV로 각  color를 저장하는 방식인 BGR을 RGB로 변환\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        # 0~1 사이로 scaling\n        image /= 1024\n        boxes = records[['ori_x_min', 'ori_y_min', 'ori_x_max', 'ori_y_max']].values\n        \n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        # list를 torch tensor로 view 변환 (data definition)\n        area = torch.as_tensor(area, dtype=torch.float32)\n        # all the labels are shifted by 1 to accomodate background\n        labels = torch.squeeze(torch.as_tensor((records.class_id.values+1,), dtype=torch.int64))\n        \n        # 모든 인스턴스는 crowd 상태가 아님을 가정\n        iscrowd = torch.zeros((records.shape[0],), dtype=torch.int64)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['labels'] = labels\n        # target['masks'] = None\n        target['image_id'] = torch.tensor([idx])\n        target['area'] = area\n        target['iscrowd'] = iscrowd\n        # transform 적용\n        if self.transforms:\n            sample = {\n                'image': image,\n                'bboxes': target['boxes'],\n                'labels': labels\n            }\n            sample = self.transforms(**sample)\n            image = sample['image']\n            \n            target['boxes'] = torch.as_tensor(sample['bboxes'])\n\n        return image, target, image_id\n\n    def __len__(self):\n        return self.image_ids.shape[0]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dt = VBDDataset(new_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 이미지 tensor로 바꾸기\ndef get_train_transform():\n    return A.Compose([\n        ToTensorV2(p=1.0) # albumentations의 경우는 normalize 후 ToTensorV2 사용\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})\n\ndef get_valid_transform():\n    return A.Compose([\n        ToTensorV2(p=1.0)\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 15  # 14 classes + background\n\n# 분류기에서 사용할 입력 특징의 차원 정보 얻음\nin_features = model.roi_heads.box_predictor.cls_score.in_features\n\n# 미리 학습된 모델의 머리 부분을 새로운 것으로 교체\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# A Class for keeping track of average\nclass Averager:\n    def __init__(self):\n        self.current_total = 0.0\n        self.iterations = 0.0\n\n    def send(self, value):\n        self.current_total += value\n        self.iterations += 1\n\n    @property\n    def value(self):\n        if self.iterations == 0:\n            return 0\n        else:\n            return 1.0 * self.current_total / self.iterations\n\n    def reset(self):\n        self.current_total = 0.0\n        self.iterations = 0.0","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_dataloaders(df, trn_idx, val_idx):\n    \n    train_ = df.loc[trn_idx,:].reset_index(drop=True)\n    valid_ = df.loc[val_idx,:].reset_index(drop=True)\n        \n    def collate_fn(batch):\n        return tuple(zip(*batch))\n\n    train_dataset = VBDDataset(train_, train_dir, get_train_transform())\n    valid_dataset = VBDDataset(valid_, train_dir, get_valid_transform())\n\n    train_data_loader = DataLoader(\n        train_dataset,\n        batch_size=8,\n        shuffle=False,\n        num_workers=4,\n        collate_fn=collate_fn\n    )\n\n    valid_data_loader = DataLoader(\n        valid_dataset,\n        batch_size=4,\n        shuffle=False,\n        num_workers=4,\n        collate_fn=collate_fn\n    )\n    \n    return train_data_loader, valid_data_loader","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def train_model(\n#         train_step: int = 2,  # Chọn lần huấn luyện (1 cho lần 1, 2 cho lần 2)\n#         visualize: bool = False,\n#         export_as_onnx: bool = False,\n#         export_as_tf: bool = False,\n#         export_as_tflite: bool = False,\n#         conf_thres: float = 0.3,\n#         iou_thres: float = 0.4,\n# ):\n\n\n#     if train_step == 1:\n#         # Train lần 1\n#         print(\"Training lần 1...\")\n#         !torchrun --nproc_per_node=2 --master_port 9527 /kaggle/working/yolov9/train_dual.py --device 0,1 --sync-bn --img {IMAGE_SIZE} --cfg /kaggle/working/yolov9/models/detect/yolov9-c.yaml --batch-size 8 --epochs 10 --data yolo.yaml --weights /kaggle/working/yolov9-c.pt --hyp /kaggle/working/yolov9/data/hyps/hyp.scratch-high.yaml --min-items 0 --close-mosaic 15\n\n#         # Lưu trọng số sau lần train 1 vào /kaggle/outputs\n#         print(\"Lưu mô hình sau lần 1...\")\n#         !cp /kaggle/working/yolov9/runs/train/exp/weights/last.pt /kaggle/working/yolov9-c-lan1.pt\n\n#         print(\"Đã hoàn thành lần huấn luyện 1. Lưu mô hình và dừng lại.\")\n\n#         return  # Dừng lại ngay sau khi huấn luyện lần 1 hoàn thành\n\n#     elif train_step == 2:\n#         # Load mô hình từ lần train 1 và tiếp tục train lần 2\n#         print(\"Training lần 2...\")\n#         !torchrun --nproc_per_node=2 --master_port 9527 /kaggle/working/yolov9/train_dual.py --device 0,1 --sync-bn --img {IMAGE_SIZE} --cfg /kaggle/working/yolov9/models/detect/yolov9-c.yaml --batch-size 8 --epochs 20 --data yolo.yaml --weights /kaggle/working/last.pt \n\n#     if visualize:\n#         # Visualize các kết quả sau lần huấn luyện\n#         plt.rcParams.update({\n#             'figure.figsize': (15, 8),\n#             'axes.spines.left': False,\n#             'axes.spines.right': False,\n#             'axes.spines.bottom': False,\n#             'axes.spines.top': False,\n#             'xtick.bottom': False,\n#             'xtick.labelbottom': False,\n#             'ytick.labelleft': False,\n#             'ytick.left': False,\n#         })\n\n#         for img_name in ['results.png', 'PR_curve.png', 'confusion_matrix.png']:\n#             img_path = f'runs/train/exp/{img_name}'\n#             plt.figure(figsize=(15, 8))\n#             plt.imshow(plt.imread(img_path))\n#             plt.title(f\"{img_name} (conf_thres={conf_thres}, iou_thres={iou_thres})\")\n#             plt.axis('off')\n\n#         plt.rcParams.update(plt.rcParamsDefault)\n#         plt.rcParams.update({'figure.figsize': (15, 8)})\n\n#     if export_as_onnx or export_as_tf or export_as_tflite:\n#         print(\"Exporting mô hình...\")\n#         !python yolov9/export.py --weights yolov9-c.pt --img-size {IMAGE_SIZE} {IMAGE_SIZE} --max-wh {IMAGE_SIZE} --grid --end2end --simplify\n\n#         if export_as_tf or export_as_tflite:\n#             !onnx-tf convert -i yolov9.onnx -o ./\n\n#             if export_as_tflite:\n#                 converter = tf.lite.TFLiteConverter.from_saved_model('./')\n#                 tflite_model = converter.convert()\n#                 with open('yolov9.tflite', 'wb') as f:\n#                     f.write(tflite_model)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def train_model(\n#         train_step: int = 1,\n#         visualize: bool = True,\n#         export_as_onnx: bool = True,\n#         export_as_tf: bool = True,\n#         export_as_tflite: bool = True,\n# ):\n#     if train_step == 1:\n#         # Train lần 1\n#         print(\"Training lần 1...\")\n#         !python /kaggle/working/yolov7/train.py --workers 0 --device 0 --img {IMAGE_SIZE} --batch-size 20 --epochs 30 --data /kaggle/working/yolo.yaml --weights /kaggle/working/yolov7.pt --hyp /kaggle/working/yolov7/data/hyp.scratch.p5.yaml\n#         # Lưu trọng số sau lần train 1 vào /kaggle/outputs\n#         print(\"Lưu mô hình sau lần 1...\")\n\n#         print(\"Đã hoàn thành lần huấn luyện 1. Lưu mô hình và dừng lại.\")\n\n#         return  # Dừng lại ngay sau khi huấn luyện lần 1 hoàn thành\n\n#     elif train_step == 2:\n#         # Load mô hình từ lần train 1 và tiếp tục train lần 2\n#         print(\"Training lần 2...\")\n#         !torchrun --nproc_per_node=2 --master_port 9527 /kaggle/working/yolov9/train_dual.py --device 0,1 --sync-bn --img {IMAGE_SIZE} --cfg /kaggle/working/yolov9/models/detect/yolov9-c.yaml --batch-size 16 --epochs 40 --data yolo.yaml --weights /kaggle/working/last.pt \n\n\n#     if visualize:\n#         # Modify matplotlib figure size, and remove axis lines and ticks\n#         plt.rcParams.update({\n#             'figure.figsize': (15, 8),\n#             'axes.spines.left': False,\n#             'axes.spines.right': False,\n#             'axes.spines.bottom': False,\n#             'axes.spines.top': False,\n#             'xtick.bottom': False,\n#             'xtick.labelbottom': False,\n#             'ytick.labelleft': False,\n#             'ytick.left': False,\n#         })\n\n#         plt.imshow(plt.imread('runs/train/exp/results.png'))\n#         plt.imshow(plt.imread('runs/train/exp/PR_curve.png'))\n#         plt.imshow(plt.imread('runs/train/exp/confusion_matrix.png'))\n\n#         plt.rcParams.update(plt.rcParamsDefault)\n#         plt.rcParams.update({'figure.figsize': (15, 8)})\n\n#     if export_as_onnx or export_as_tf or export_as_tflite:\n#         !python yolov7/export.py --weights yolov7.pt --img-size {IMAGE_SIZE} {IMAGE_SIZE} --max-wh {IMAGE_SIZE} --grid --end2end --simplify\n\n#         if export_as_tf or export_as_tflite:\n#             !onnx-tf convert -i yolov7.onnx -o ./\n\n#             if export_as_tflite:\n#                 converter = tf.lite.TFLiteConverter.from_saved_model('./')\n#                 tflite_model = converter.convert()\n#                 with open('yolov7.tflite', 'wb') as f:\n#                     f.write(tflite_model)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install ultralytics","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import ultralytics\nultralytics.checks()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rm -rf /kaggle/working/data","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !wget https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10x.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !yolo train model=yolov8m.pt data=/kaggle/working/yolo.yaml epochs=50 imgsz=1024 batch=24 device=0,1 workers=2","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from ultralytics import YOLO\n\n# Load a model\nmodel = YOLO(\"yolo11.pt\")\n\n# Train the model\ntrain_results = model.train(\n    data=\"/kaggle/working/yolo.yaml\",  # path to dataset YAML\n    epochs=50,  # number of training epochs\n    imgsz=1024,  # training image size\n    device=0,1,  # device to run on, i.e. device=0 or device=0,1,2,3 or device=cpu\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# from ultralytics import YOLOv10\n\n# model = YOLOv10()\n# # If you want to finetune the model with pretrained weights, you could load the \n# # pretrained weights like below\n# # model = YOLOv10.from_pretrained('jameslahm/yolov10{n/s/m/b/l/x}')\n# # or\n# # wget https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10{n/s/m/b/l/x}.pt\n# # model = YOLOv10('yolov10{n/s/m/b/l/x}.pt')\n\n# model.train(data='yolo.yaml', epochs=150, batch=24, imgsz=1024)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !WANDB_MODE=\"dryrun\" python train_dual.py \n# !yolo train model=yolov10n.pt workers=10 device=0 batch=24 data = /kaggle/working/yolo.yaml imgsz = 1024 epochs = 150","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# raw_df, preprocessed_df = prime_dataset()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip uninstall -y wandb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !cp /kaggle/working/valid.txt /kaggle/working/yolov7/valid.txt\n# !cp /kaggle/working/train.txt /kaggle/working/yolov7/train.txt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# rm -rf /kaggle/working/runs","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# rm -rf /kaggle/working/yolov8n.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# rm -rf /kaggle/working/train.zip","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train_model()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp /kaggle/working/runs/detect/train/weights/last.pt /kaggle/working/yolov8_lan1.pt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%cd /kaggle/working/\nfrom IPython.display import FileLink\nFileLink(r'yolov8_lan1.pt')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp -r /kaggle/working/yolov7/runs/train/exp /kaggle/working/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nfrom IPython.display import FileLink\n\n# Đường dẫn đến thư mục cần nén\nsource_dir = '/kaggle/working/runs/detect/train/weights/l'\n\n# Nén thư mục 'runs' thành file 'runs.zip'\nshutil.make_archive('/kaggle/working/train', 'zip', source_dir)\n\n# Tạo liên kết tải về cho file nén\nFileLink(r'/kaggle/working/train.zip')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rm -rf /kaggle/working/exp.zip","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}