{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":75176,"databundleVersionId":8252256,"sourceType":"competition"}],"dockerImageVersionId":30762,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# %% [markdown]\n# ## Thiết lập và tải mã nguồn YOLOv9\n\n# Import các thư viện cần thiết\nimport os\nimport wandb\n\n# Đăng nhập wandb\nwandb.login(key='4f88ff0bbc6e3485258bca7079d7da4c47798ccd')\n\n# Thiết lập thư mục làm việc và tải mã nguồn YOLOv9 từ GitHub\nHOME = \"/kaggle/working/\"  # Thư mục làm việc hiện tại\nos.chdir(HOME)\n\n# Tải mã nguồn YOLOv9 từ GitHub\n!git clone https://github.com/SkalskiP/yolov9.git\n%cd yolov9\n!pip install -r requirements.txt -q\n\n# Tải các trọng số mô hình YOLOv9 từ các liên kết được cung cấp\n!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c.pt\n!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e.pt\n!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c.pt\n!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-e.pt","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %% [markdown]\n# ## Thiết lập wandb\n\n# Khởi tạo một run mới với tên dự án và tên lượt chạy cụ thể\nwandb.init(project='btxuan_yolov9', name='train_yolov9')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %% [markdown]\n# ## Đọc và xử lý dữ liệu\n\nimport numpy as np\nimport pandas as pd\nimport glob\nimport cv2\nfrom tqdm import tqdm\nfrom sklearn.model_selection import train_test_split\nimport shutil\nimport yaml\nfrom skimage import exposure\n\ntqdm.pandas()\n\n# Đường dẫn đến thư mục chứa dữ liệu\nROOT = \"/kaggle/input/amia-public-challenge-2024\"\n\n# Đọc dữ liệu từ bộ dữ liệu mới\ntrain_df = pd.read_csv(ROOT + \"/train.csv\")\nimg_size_df = pd.read_csv(ROOT + \"/img_size.csv\")\n\n# Gộp thông tin kích thước ảnh gốc với dữ liệu huấn luyện\ntrain_df = train_df.merge(img_size_df, on='image_id', how='left')\n\n# Lọc bỏ lớp \"No finding\" (class_id == 14)\ntrain_df = train_df[train_df['class_id'] != 14].reset_index(drop=True)\n\n# Chỉ chọn các cột cần thiết\ntrain_df = train_df[['image_id', 'class_name', 'class_id', 'rad_id', 'x_min', 'y_min', 'x_max', 'y_max', 'dim0', 'dim1']]\n\n# Lấy đường dẫn đến tất cả các ảnh huấn luyện\ntrain_images = glob.glob(ROOT + \"/train/train/*.png\")\n\n# Thêm đường dẫn ảnh vào dataframe\ntrain_df['ImagePath'] = train_df['image_id'].progress_apply(lambda x: next(filter(lambda y: x in y, train_images), None))\n\ndef create_labels(df, condition):\n    # Trích xuất phần số từ chuỗi và chuyển sang kiểu số\n    df['rad_id_numeric'] = pd.to_numeric(df['rad_id'].str.extract('(\\d+)')[0], errors='coerce')\n\n    # Tùy chọn lọc dữ liệu dựa trên điều kiện\n    if condition == 'labels-1':\n        return df\n    elif condition == 'labels-2':\n        return df[df['rad_id_numeric'] >= 2]\n    elif condition == 'labels-3':\n        return df[df['rad_id_numeric'] == 3]\n    else:\n        raise ValueError(\"Invalid condition\")\n\n# Sử dụng hàm đã sửa đổi\nlabels_1_df = create_labels(train_df, 'labels-1')\nlabels_2_df = create_labels(train_df, 'labels-2')\nlabels_3_df = create_labels(train_df, 'labels-3')\n\n# Chuyển đổi DataFrame sang định dạng YOLO\ndef convert_to_yolo_format(df):\n    df['center_x'] = (df['x_min'] + df['x_max']) / 2 / df['dim1']\n    df['center_y'] = (df['y_min'] + df['y_max']) / 2 / df['dim0']\n    df['width'] = (df['x_max'] - df['x_min']) / df['dim1']\n    df['height'] = (df['y_max'] - df['y_min']) / df['dim0']\n    return df[['image_id', 'class_id', 'center_x', 'center_y', 'width', 'height']]\n\ndf_yolo_labels1 = convert_to_yolo_format(labels_1_df)\ndf_yolo_labels2 = convert_to_yolo_format(labels_2_df)\ndf_yolo_labels3 = convert_to_yolo_format(labels_3_df)\n\n# Tạo thư mục lưu trữ ảnh và nhãn\noutput_dir_images = \"/kaggle/working/yolov9/dataset/images\"\noutput_dir_labels = \"/kaggle/working/yolov9/dataset/labels\"\nos.makedirs(output_dir_images, exist_ok=True)\nos.makedirs(output_dir_labels, exist_ok=True)\n\n# Sao chép ảnh và lưu nhãn cho từng bộ nhãn\ndef save_labels(image_id, df, output_dir):\n    rows = df[df['image_id'] == image_id]\n    label_path = os.path.join(output_dir, f\"{image_id}.txt\")\n    with open(label_path, 'w') as f:\n        for _, row in rows.iterrows():\n            class_id = row['class_id']\n            x_center = row['center_x']\n            y_center = row['center_y']\n            width = row['width']\n            height = row['height']\n            f.write(f\"{class_id} {x_center} {y_center} {width} {height}\\n\")\n\n# Tạo tệp nhãn cho mỗi bộ nhãn\nfor image_id in tqdm(df_yolo_labels1['image_id'].unique()):\n    save_labels(image_id, df_yolo_labels1, output_dir_labels)\n\nfor image_id in tqdm(df_yolo_labels2['image_id'].unique()):\n    save_labels(image_id, df_yolo_labels2, output_dir_labels)\n\nfor image_id in tqdm(df_yolo_labels3['image_id'].unique()):\n    save_labels(image_id, df_yolo_labels3, output_dir_labels)\n\n# Phân chia dữ liệu thành tập huấn luyện và kiểm tra\ntrain_ids, val_ids = train_test_split(df_yolo_labels1['image_id'].unique(), test_size=0.1, random_state=42)\n\n# Tạo cấu trúc thư mục cho YOLO\nos.makedirs(f\"{output_dir_images}/train\", exist_ok=True)\nos.makedirs(f\"{output_dir_images}/valid\", exist_ok=True)\nos.makedirs(f\"{output_dir_labels}/train\", exist_ok=True)\nos.makedirs(f\"{output_dir_labels}/valid\", exist_ok=True)\n\n# Sao chép các tệp hình ảnh và nhãn vào các thư mục tương ứng\nfor image_id in train_ids:\n    shutil.copy(f\"{ROOT}/train/train/{image_id}.png\", f\"{output_dir_images}/train/{image_id}.png\")\n    shutil.copy(f\"{output_dir_labels}/{image_id}.txt\", f\"{output_dir_labels}/train/{image_id}.txt\")\n\nfor image_id in val_ids:\n    shutil.copy(f\"{ROOT}/train/train/{image_id}.png\", f\"{output_dir_images}/valid/{image_id}.png\")\n    shutil.copy(f\"{output_dir_labels}/{image_id}.txt\", f\"{output_dir_labels}/valid/{image_id}.txt\")\n\n# Tạo tệp YAML cấu hình cho YOLO\ndata = {\n    'names': [\n        \"Aortic enlargement\", \"Atelectasis\", \"Calcification\", \"Cardiomegaly\", \n        \"Consolidation\", \"ILD\", \"Infiltration\", \"Lung Opacity\", \"Nodule/Mass\", \n        \"Other lesion\", \"Pleural effusion\", \"Pleural thickening\", \"Pneumothorax\", \n        \"Pulmonary fibrosis\"\n    ],\n    'nc': 14,\n    'train': f\"{output_dir_images}/train\",\n    'val': f\"{output_dir_images}/valid\"\n}\n\nwith open(f\"{output_dir_images}/data.yaml\", 'w') as file:\n    yaml.dump(data, file)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %% [markdown]\n# ## Huấn luyện mô hình YOLO\n\n%cd /kaggle/working/yolov5\n\n# Huấn luyện mô hình YOLO với từng bộ nhãn\nfor model_idx, labels_df in enumerate([df_yolo_labels1, df_yolo_labels2, df_yolo_labels3], start=1):\n    !python train.py --img 640 --batch 16 --epochs 50 --data dataset/images/data.yaml \\\n    --weights /kaggle/working/weights/yolov5x.pt --project xuan2261_yolov5 --name train_model_{model_idx} --exist-ok\n\n# Kết thúc ghi lại run của wandb\nwandb.finish()\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %% [markdown]\n# ## Huấn luyện mô hình YOLOv9\n\n%cd /kaggle/working/yolov9\n\n# Huấn luyện mô hình YOLO với từng bộ nhãn\nfor model_idx, labels_df in enumerate([df_yolo_labels1, df_yolo_labels2, df_yolo_labels3], start=1):\n    !python train.py --batch 16 --epochs 30 --img 640 --device 0 \\\n    --data dataset/images/data.yaml \\\n    --weights /kaggle/working/weights/gelan-c.pt --cfg models/detect/gelan-c.yaml \\\n    --hyp hyp.scratch-high.yaml --project xuan2261_yolov9 --name train_model_{model_idx} --exist-ok\n\n# Kết thúc ghi lại run của wandb\nwandb.finish()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %% [markdown]\n# ## Đánh giá mô hình đã huấn luyện\n\n%cd /kaggle/working/yolov9\n\n# Ensemble kết hợp 3 mô hình\n!python detect.py --weights runs/train/xuan2261_yolov9/train_model_1/weights/best.pt runs/train/xuan2261_yolov9/train_model_2/weights/best.pt runs/train/xuan2261_yolov9/train_model_3/weights/best.pt \\\n--img 640 --conf 0.001 --iou 0.5 --source /kaggle/working/yolov9/dataset/images/valid --augment --save-txt --save-conf --exist-ok\n\n# Sử dụng WBF với IoU=0.5 cho ensemble output\n!pip install ensemble-boxes\nfrom ensemble_boxes import *\n\n# Hàm sử dụng WBF và ghi lại kết quả vào wandb\ndef perform_wbf(pred_boxes, pred_scores, pred_labels, iou_thr, skip_box_thr):\n    boxes, scores, labels = weighted_boxes_fusion(\n        pred_boxes, pred_scores, pred_labels,\n        iou_thr=iou_thr,\n        skip_box_thr=skip_box_thr\n    )\n    return boxes, scores, labels\n\nwandb.finish()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %% [markdown]\n# ## Kiểm tra kết quả huấn luyện và đánh giá\n\n!ls {HOME}/yolov9/runs/train/exp/\n\n# Hiển thị kết quả huấn luyện\nfrom IPython.display import Image\n\nImage(filename=f\"{HOME}/yolov9/runs/train/exp/results.png\", width=700)\nImage(filename=f\"{HOME}/yolov9/runs/train/exp/confusion_matrix.png\", width=1000)\nImage(filename=f\"{HOME}/yolov9/runs/train/exp/val_batch0_pred.jpg\", width=1000)\n\n# Kiểm tra kết quả đánh giá\n!ls {HOME}/yolov9/runs/val/exp/\n\n# Hiển thị kết quả đánh giá\nImage(filename=f\"{HOME}/yolov9/runs/val/exp/R_curve.png\", width=700)\nImage(filename=f\"{HOME}/yolov9/runs/val/exp/val_batch0_pred.jpg\", width=700)","metadata":{},"execution_count":null,"outputs":[]}]}