{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":9988,"databundleVersionId":868324,"isSourceIdPinned":false}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!mkdir ships-yolo","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.353063Z","iopub.execute_input":"2026-03-31T15:26:59.353669Z","iopub.status.idle":"2026-03-31T15:26:59.472837Z","shell.execute_reply.started":"2026-03-31T15:26:59.353624Z","shell.execute_reply":"2026-03-31T15:26:59.471827Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%cd ships-yolo","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.474450Z","iopub.execute_input":"2026-03-31T15:26:59.474698Z","iopub.status.idle":"2026-03-31T15:26:59.480846Z","shell.execute_reply.started":"2026-03-31T15:26:59.474669Z","shell.execute_reply":"2026-03-31T15:26:59.480192Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.481726Z","iopub.execute_input":"2026-03-31T15:26:59.481966Z","iopub.status.idle":"2026-03-31T15:26:59.608029Z","shell.execute_reply.started":"2026-03-31T15:26:59.481914Z","shell.execute_reply":"2026-03-31T15:26:59.607159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%writefile train.py\nfrom ultralytics import YOLO\n\nmodel = YOLO(\"yolov3-tiny.pt\")\n\nmodel.train(\n    data=\"ships.yaml\",\n    epochs=30,\n    imgsz=416,\n    batch=128,\n    device=[0,1],\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.610132Z","iopub.execute_input":"2026-03-31T15:26:59.610383Z","iopub.status.idle":"2026-03-31T15:26:59.616395Z","shell.execute_reply.started":"2026-03-31T15:26:59.610353Z","shell.execute_reply":"2026-03-31T15:26:59.615682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%writefile prepare_data.py\nimport os\nimport shutil\n\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom tqdm import tqdm\n\nCSV_PATH = \"/kaggle/input/competitions/airbus-ship-detection/train_ship_segmentations_v2.csv\"\nIMG_DIR = \"/kaggle/input/competitions/airbus-ship-detection/train_v2\"\nOUT_DIR = \"/kaggle/working/data\"\n\n\ndef rle_decode(mask_rle, shape=(768, 768)):\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0::2], s[1::2])]\n    starts -= 1\n    ends = starts + lengths\n\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n\n    return img.reshape(shape).T\n\n\ndf = pd.read_csv(CSV_PATH)\n\n# Only keep images with ships for a faster first training run.\ndf = df.dropna()\n\nimage_ids = df[\"ImageId\"].unique()\n\n# Reduce dataset size if needed.\nimage_ids = image_ids[:2000]\n\ntrain_ids, val_ids = train_test_split(image_ids, test_size=0.2, random_state=42)\n\n\ndef process_split(split_ids, split_name):\n    img_out = os.path.join(OUT_DIR, \"images\", split_name)\n    label_out = os.path.join(OUT_DIR, \"labels\", split_name)\n\n    os.makedirs(img_out, exist_ok=True)\n    os.makedirs(label_out, exist_ok=True)\n\n    for img_id in tqdm(split_ids, desc=split_name):\n        img_path = os.path.join(IMG_DIR, img_id)\n        if not os.path.exists(img_path):\n            continue\n\n        group = df[df[\"ImageId\"] == img_id]\n\n        img = Image.open(img_path)\n        w, h = img.size\n\n        label_lines = []\n\n        for _, row in group.iterrows():\n            mask = rle_decode(row[\"EncodedPixels\"])\n            ys, xs = np.where(mask == 1)\n\n            if len(xs) == 0:\n                continue\n\n            x_min, x_max = xs.min(), xs.max()\n            y_min, y_max = ys.min(), ys.max()\n\n            x_center = ((x_min + x_max) / 2) / w\n            y_center = ((y_min + y_max) / 2) / h\n            box_w = (x_max - x_min) / w\n            box_h = (y_max - y_min) / h\n\n            label_lines.append(f\"0 {x_center} {y_center} {box_w} {box_h}\")\n\n        if label_lines:\n            shutil.copy(img_path, os.path.join(img_out, img_id))\n            with open(os.path.join(label_out, img_id.replace(\".jpg\", \".txt\")), \"w\") as f:\n                f.write(\"\\n\".join(label_lines))\n\n\nprocess_split(train_ids, \"train\")\nprocess_split(val_ids, \"val\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.617538Z","iopub.execute_input":"2026-03-31T15:26:59.617795Z","iopub.status.idle":"2026-03-31T15:26:59.631143Z","shell.execute_reply.started":"2026-03-31T15:26:59.617771Z","shell.execute_reply":"2026-03-31T15:26:59.630485Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%writefile ships.yaml\npath: /kaggle/working/data\n\ntrain: images/train\nval: images/val\n\nnames:\n  0: ship\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.632015Z","iopub.execute_input":"2026-03-31T15:26:59.632295Z","iopub.status.idle":"2026-03-31T15:26:59.647613Z","shell.execute_reply.started":"2026-03-31T15:26:59.632263Z","shell.execute_reply":"2026-03-31T15:26:59.646841Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%writefile requirements.txt\nultralytics\npandas\nnumpy\npillow\ntqdm\nscikit-learn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.648692Z","iopub.execute_input":"2026-03-31T15:26:59.649055Z","iopub.status.idle":"2026-03-31T15:26:59.661636Z","shell.execute_reply.started":"2026-03-31T15:26:59.649024Z","shell.execute_reply":"2026-03-31T15:26:59.660877Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -r requirements.txt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:26:59.662602Z","iopub.execute_input":"2026-03-31T15:26:59.662995Z","iopub.status.idle":"2026-03-31T15:27:05.984351Z","shell.execute_reply.started":"2026-03-31T15:26:59.662927Z","shell.execute_reply":"2026-03-31T15:27:05.983271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !python prepare_data.py","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:27:05.986242Z","iopub.execute_input":"2026-03-31T15:27:05.986682Z","iopub.status.idle":"2026-03-31T15:27:53.545714Z","shell.execute_reply.started":"2026-03-31T15:27:05.986628Z","shell.execute_reply":"2026-03-31T15:27:53.544907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !python train.py","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-31T15:27:53.548319Z","iopub.execute_input":"2026-03-31T15:27:53.548594Z","iopub.status.idle":"2026-03-31T15:33:20.968056Z","shell.execute_reply.started":"2026-03-31T15:27:53.548564Z","shell.execute_reply":"2026-03-31T15:33:20.967243Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ultralytics import YOLO\nimport matplotlib.pyplot as plt\nimport cv2\n\nmodel = YOLO(\"/kaggle/working/ships-yolo/runs/detect/train/weights/best.pt\")\n\n# test vài ảnh random từ val\nimport os\nimport random\n\nval_dir = \"/kaggle/working/data/images/val\"\nimages = random.sample(os.listdir(val_dir), 5)\n\nfor img_name in images:\n    img_path = os.path.join(val_dir, img_name)\n\n    results = model(img_path)\n\n    # plot result\n    annotated = results[0].plot()\n\n    plt.imshow(cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB))\n    plt.title(img_name)\n    plt.axis(\"off\")\n    plt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}