{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":24800,"datasetId":1042002,"databundleVersionId":1831594}],"dockerImageVersionId":31401,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\n\nprint(torch.__version__)\nprint(torch.cuda.is_available())\nprint(torch.cuda.get_device_name(0))\nimport ultralytics\n\nprint(ultralytics.__version__)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndf = pd.read_csv(\"/kaggle/input/competitions/vinbigdata-chest-xray-abnormalities-detection/train.csv\")\n\nprint(df.head())\nprint(df.columns)\nprint(df['class_name'].unique())","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:33.76105Z","iopub.execute_input":"2026-05-31T16:03:33.76156Z","iopub.status.idle":"2026-05-31T16:03:33.857472Z","shell.execute_reply.started":"2026-05-31T16:03:33.761527Z","shell.execute_reply":"2026-05-31T16:03:33.856456Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\nimport matplotlib.pyplot as plt\n\npath = \"/kaggle/input/competitions/vinbigdata-chest-xray-abnormalities-detection/train/000434271f63a053c4128a0ba6352c7f.dicom\"\n\ndicom = pydicom.dcmread(path)\n\nimg = dicom.pixel_array\n\nprint(img.shape)\n\nplt.imshow(img, cmap=\"gray\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:35.605065Z","iopub.execute_input":"2026-05-31T16:03:35.605884Z","iopub.status.idle":"2026-05-31T16:03:36.640143Z","shell.execute_reply.started":"2026-05-31T16:03:35.605846Z","shell.execute_reply":"2026-05-31T16:03:36.639411Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/competitions/vinbigdata-chest-xray-abnormalities-detection/train.csv\")\n\nprint(df[\"class_name\"].value_counts())\n\ndf[df[\"class_name\"]==\"Nodule/Mass\"].head(20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:39.346034Z","iopub.execute_input":"2026-05-31T16:03:39.346751Z","iopub.status.idle":"2026-05-31T16:03:39.452077Z","shell.execute_reply.started":"2026-05-31T16:03:39.346716Z","shell.execute_reply":"2026-05-31T16:03:39.451396Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"nodule_df = df[df[\"class_name\"]==\"Nodule/Mass\"]\n\nprint(\"Annotations:\", len(nodule_df))\nprint(\"Unique images:\", nodule_df[\"image_id\"].nunique())\nnodule_df.groupby(\"image_id\").size().sort_values(ascending=False).head(10)\nimg = \"03e6ecfa6f6fb33dfeac6ca4f9b459c9\"\n\nnodule_df[\n    nodule_df[\"image_id\"] == img\n][[\n    \"rad_id\",\n    \"x_min\",\n    \"y_min\",\n    \"x_max\",\n    \"y_max\"\n]].head(50)\n\nprint(\n    nodule_df[\"rad_id\"].value_counts()\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:41.975248Z","iopub.execute_input":"2026-05-31T16:03:41.975965Z","iopub.status.idle":"2026-05-31T16:03:41.995019Z","shell.execute_reply.started":"2026-05-31T16:03:41.975934Z","shell.execute_reply":"2026-05-31T16:03:41.994238Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"nodule_df = df[\n    (df[\"class_name\"]==\"Nodule/Mass\")\n    &\n    (df[\"rad_id\"]==\"R10\")\n].copy()\nprint(\"Annotations:\", len(nodule_df))\nprint(\"Images:\", nodule_df[\"image_id\"].nunique())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:44.241488Z","iopub.execute_input":"2026-05-31T16:03:44.242093Z","iopub.status.idle":"2026-05-31T16:03:44.261169Z","shell.execute_reply.started":"2026-05-31T16:03:44.242059Z","shell.execute_reply":"2026-05-31T16:03:44.260121Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nimages = nodule_df[\"image_id\"].unique()\n\ntrain_imgs, val_imgs = train_test_split(\n    images,\n    test_size=0.2,\n    random_state=42\n)\n\nprint(len(train_imgs))\nprint(len(val_imgs))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:56.142464Z","iopub.execute_input":"2026-05-31T16:03:56.14281Z","iopub.status.idle":"2026-05-31T16:03:56.149559Z","shell.execute_reply.started":"2026-05-31T16:03:56.142779Z","shell.execute_reply":"2026-05-31T16:03:56.148704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nbase_dir = \"/kaggle/working/vindr_yolo\"\n\nfolders = [\n    \"images/train\",\n    \"images/val\",\n    \"labels/train\",\n    \"labels/val\"\n]\n\nfor f in folders:\n    os.makedirs(\n        os.path.join(base_dir, f),\n        exist_ok=True\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:03:59.675835Z","iopub.execute_input":"2026-05-31T16:03:59.676624Z","iopub.status.idle":"2026-05-31T16:03:59.681911Z","shell.execute_reply.started":"2026-05-31T16:03:59.676591Z","shell.execute_reply":"2026-05-31T16:03:59.681022Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport pydicom\nimport numpy as np\n\ndef dicom_to_png(dicom_path, png_path):\n\n    ds = pydicom.dcmread(dicom_path)\n\n    img = ds.pixel_array.astype(np.float32)\n\n    img = (img - img.min()) / (\n        img.max() - img.min()\n    )\n\n    img = (img * 255).astype(np.uint8)\n\n    cv2.imwrite(\n        png_path,\n        img\n    )\n\n    return img.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:04:08.421207Z","iopub.execute_input":"2026-05-31T16:04:08.422045Z","iopub.status.idle":"2026-05-31T16:04:08.427093Z","shell.execute_reply.started":"2026-05-31T16:04:08.422013Z","shell.execute_reply":"2026-05-31T16:04:08.426183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = nodule_df.iloc[0]\n\nprint(sample)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:30:21.767557Z","iopub.execute_input":"2026-05-31T16:30:21.768196Z","iopub.status.idle":"2026-05-31T16:30:21.773714Z","shell.execute_reply.started":"2026-05-31T16:30:21.768166Z","shell.execute_reply":"2026-05-31T16:30:21.772811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nimage_ids = nodule_df[\"image_id\"].unique()\n\ntrain_ids, val_ids = train_test_split(\n    image_ids,\n    test_size=0.2,\n    random_state=42\n)\n\nprint(len(train_ids))\nprint(len(val_ids))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:30:23.944936Z","iopub.execute_input":"2026-05-31T16:30:23.945746Z","iopub.status.idle":"2026-05-31T16:30:23.952528Z","shell.execute_reply.started":"2026-05-31T16:30:23.945714Z","shell.execute_reply":"2026-05-31T16:30:23.951422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\npath = \"/kaggle/working/vindr_yolo/images/val/8e063eadea9a6aeb684c893c8598be3e.png\"\n\nprint(os.path.exists(path))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:04:41.17469Z","iopub.execute_input":"2026-05-31T16:04:41.175275Z","iopub.status.idle":"2026-05-31T16:04:41.179437Z","shell.execute_reply.started":"2026-05-31T16:04:41.175247Z","shell.execute_reply":"2026-05-31T16:04:41.178736Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tqdm import tqdm\n\nfor img_id in tqdm(image_ids):\n\n    dicom_path = (\n        \"/kaggle/input/\"\n        \"competitions/vinbigdata-chest-xray-abnormalities-detection/\"\n        f\"train/{img_id}.dicom\"\n    )\n\n    if img_id in train_ids:\n        png_path = (\n            f\"/kaggle/working/vindr_yolo/images/train/{img_id}.png\"\n        )\n    else:\n        png_path = (\n            f\"/kaggle/working/vindr_yolo/images/val/{img_id}.png\"\n        )\n\n    dicom_to_png(\n        dicom_path,\n        png_path\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:04:43.765623Z","iopub.execute_input":"2026-05-31T16:04:43.766354Z","iopub.status.idle":"2026-05-31T16:14:20.868019Z","shell.execute_reply.started":"2026-05-31T16:04:43.766321Z","shell.execute_reply":"2026-05-31T16:14:20.867035Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nprint(\n    len(os.listdir(\"/kaggle/working/vindr_yolo/images/train\"))\n)\n\nprint(\n    len(os.listdir(\"/kaggle/working/vindr_yolo/labels/train\"))\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:30:29.230042Z","iopub.execute_input":"2026-05-31T16:30:29.230812Z","iopub.status.idle":"2026-05-31T16:30:29.236381Z","shell.execute_reply.started":"2026-05-31T16:30:29.23078Z","shell.execute_reply":"2026-05-31T16:30:29.235414Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\n\n# đường dẫn\ntrain_img_dir = \"/kaggle/working/vindr_yolo/images/train\"\nval_img_dir = \"/kaggle/working/vindr_yolo/images/val\"\n\ntrain_label_dir = \"/kaggle/working/vindr_yolo/labels/train\"\nval_label_dir = \"/kaggle/working/vindr_yolo/labels/val\"\n\nos.makedirs(train_label_dir, exist_ok=True)\nos.makedirs(val_label_dir, exist_ok=True)\n\nfor img_id in image_ids:\n\n    # xác định ảnh thuộc train hay val\n    if img_id in train_ids:\n        img_path = os.path.join(train_img_dir, f\"{img_id}.png\")\n        label_path = os.path.join(train_label_dir, f\"{img_id}.txt\")\n    else:\n        img_path = os.path.join(val_img_dir, f\"{img_id}.png\")\n        label_path = os.path.join(val_label_dir, f\"{img_id}.txt\")\n\n    # đọc kích thước thật của ảnh\n    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n\n    if img is None:\n        print(\"Cannot read:\", img_path)\n        continue\n\n    h, w = img.shape\n\n    # lấy toàn bộ bbox của ảnh này\n    rows = nodule_df[nodule_df[\"image_id\"] == img_id]\n\n    lines = []\n\n    for _, row in rows.iterrows():\n\n        xmin = row[\"x_min\"]\n        ymin = row[\"y_min\"]\n        xmax = row[\"x_max\"]\n        ymax = row[\"y_max\"]\n\n        # convert sang YOLO format\n        xc = ((xmin + xmax) / 2) / w\n        yc = ((ymin + ymax) / 2) / h\n\n        bw = (xmax - xmin) / w\n        bh = (ymax - ymin) / h\n\n        # tránh lỗi số học\n        xc = min(max(xc, 0), 1)\n        yc = min(max(yc, 0), 1)\n        bw = min(max(bw, 0), 1)\n        bh = min(max(bh, 0), 1)\n\n        lines.append(\n            f\"0 {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\"\n        )\n\n    with open(label_path, \"w\") as f:\n        f.write(\"\\n\".join(lines))\n\nprint(\"Done!\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"yaml_text = \"\"\"\npath: /kaggle/working/vindr_yolo\n\ntrain: images/train\nval: images/val\n\nnames:\n  0: nodule\n\"\"\"\nwith open(\n    \"/kaggle/working/vindr.yaml\",\n    \"w\"\n) as f:\n    f.write(yaml_text)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:30:31.055286Z","iopub.execute_input":"2026-05-31T16:30:31.056009Z","iopub.status.idle":"2026-05-31T16:30:31.060577Z","shell.execute_reply.started":"2026-05-31T16:30:31.055977Z","shell.execute_reply":"2026-05-31T16:30:31.059515Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nfrom collections import Counter\n\nsizes = Counter()\n\nfor img_file in os.listdir(\"/kaggle/working/vindr_yolo/images/train\"):\n    img = cv2.imread(\n        f\"/kaggle/working/vindr_yolo/images/train/{img_file}\",\n        cv2.IMREAD_GRAYSCALE\n    )\n\n    h, w = img.shape\n    sizes[(w, h)] += 1\n\nprint(\"Number of unique sizes:\", len(sizes))\nprint(sizes.most_common(20))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:30:37.747346Z","iopub.execute_input":"2026-05-31T16:30:37.748192Z","iopub.status.idle":"2026-05-31T16:31:03.850824Z","shell.execute_reply.started":"2026-05-31T16:30:37.748159Z","shell.execute_reply":"2026-05-31T16:31:03.849939Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\n\nfor f in glob.glob(\"/kaggle/working/vindr_yolo/labels/*.cache\"):\n    os.remove(f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:32:29.713161Z","iopub.execute_input":"2026-05-31T16:32:29.713591Z","iopub.status.idle":"2026-05-31T16:32:29.718863Z","shell.execute_reply.started":"2026-05-31T16:32:29.713561Z","shell.execute_reply":"2026-05-31T16:32:29.718013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q ultralytics","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:34:24.507213Z","iopub.execute_input":"2026-05-31T16:34:24.507483Z","iopub.status.idle":"2026-05-31T16:34:31.32643Z","shell.execute_reply.started":"2026-05-31T16:34:24.507461Z","shell.execute_reply":"2026-05-31T16:34:31.325717Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import glob\n\nbad = 0\n\nfor txt in glob.glob(\"/kaggle/working/vindr_yolo/labels/train/*.txt\"):\n    with open(txt) as f:\n        for line in f:\n            vals = list(map(float, line.split()[1:]))\n\n            if any(v < 0 or v > 1 for v in vals):\n                bad += 1\n                print(txt, vals)\n\nprint(\"bad =\", bad)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T16:31:48.625365Z","iopub.execute_input":"2026-05-31T16:31:48.626236Z","iopub.status.idle":"2026-05-31T16:31:48.648616Z","shell.execute_reply.started":"2026-05-31T16:31:48.626202Z","shell.execute_reply":"2026-05-31T16:31:48.647941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ultralytics import YOLO\n\nmodel = YOLO(\"yolov8m.pt\")\n\nmodel.train(\n    data=\"vindr.yaml\",\n    epochs=100,\n    imgsz=1536,\n    batch=4\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T17:01:11.85828Z","iopub.execute_input":"2026-05-31T17:01:11.859237Z"}},"outputs":[],"execution_count":null}]}