{"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":19989,"databundleVersionId":1160143},{"sourceType":"modelInstanceVersion","sourceId":722195,"databundleVersionId":15348863,"modelInstanceId":549429,"modelId":562117}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install ultralytics","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:12.514619Z","iopub.execute_input":"2026-04-19T07:45:12.515224Z","iopub.status.idle":"2026-04-19T07:45:15.920626Z","shell.execute_reply.started":"2026-04-19T07:45:12.515187Z","shell.execute_reply":"2026-04-19T07:45:15.919873Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **1. End to End YOLOv26**","metadata":{}},{"cell_type":"code","source":"from ultralytics import YOLO\nimport numpy as np \nimport pandas as pd \nimport os\nimport sys\nimport pathlib\nfrom tqdm.auto import tqdm\nimport shutil as sh\nfrom sklearn.model_selection import StratifiedKFold\n\n\nPATH_TRAIN = \"/kaggle/input/competitions/global-wheat-detection/train\"\nPATH_TEST = \"/kaggle/input/competitions/global-wheat-detection/test\"\nTRAIN_PATH = \"/kaggle/input/competitions/global-wheat-detection/train.csv\"\nSAMPLE_SUB = \"/kaggle/input/competitions/global-wheat-detection/sample_submission.csv\"\nMODEL_PATH = \"/kaggle/input/ultralytics-yolo26/yolo26s.pt\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:15.922406Z","iopub.execute_input":"2026-04-19T07:45:15.922775Z","iopub.status.idle":"2026-04-19T07:45:15.927893Z","shell.execute_reply.started":"2026-04-19T07:45:15.922740Z","shell.execute_reply":"2026-04-19T07:45:15.927256Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(TRAIN_PATH)\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:15.928626Z","iopub.execute_input":"2026-04-19T07:45:15.929071Z","iopub.status.idle":"2026-04-19T07:45:16.118925Z","shell.execute_reply.started":"2026-04-19T07:45:15.929024Z","shell.execute_reply":"2026-04-19T07:45:16.118179Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"bboxs = np.stack(df['bbox'].apply(lambda x: np.fromstring(x[1:-1], sep=',')))\nbboxs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:16.120621Z","iopub.execute_input":"2026-04-19T07:45:16.121033Z","iopub.status.idle":"2026-04-19T07:45:16.568853Z","shell.execute_reply.started":"2026-04-19T07:45:16.121002Z","shell.execute_reply":"2026-04-19T07:45:16.568110Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# reformat for YOLO - Object Dectection\nfor i, col in enumerate([\"x\", \"y\", \"w\", \"h\"]):\n    df[col] = bboxs[:,i]\ndf.drop(columns=['bbox'], inplace=True)\ndf['x_center'] = df['x'] + df['w']/2\ndf['y_center'] = df['y'] + df['h']/2\ndf['classes'] = 0\ndf.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:16.569759Z","iopub.execute_input":"2026-04-19T07:45:16.570071Z","iopub.status.idle":"2026-04-19T07:45:16.594325Z","shell.execute_reply.started":"2026-04-19T07:45:16.570046Z","shell.execute_reply":"2026-04-19T07:45:16.593751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fold_id = np.zeros((df.shape[0],1))\nskf = StratifiedKFold(n_splits = 5, random_state = 42, shuffle = True)\nfor (ff, (train_index, test_index)) in enumerate(skf.split(df, df['source'])):\n    fold_id[test_index]= int(ff)\ndf['fold'] = fold_id.copy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:16.595399Z","iopub.execute_input":"2026-04-19T07:45:16.595748Z","iopub.status.idle":"2026-04-19T07:45:16.693887Z","shell.execute_reply.started":"2026-04-19T07:45:16.595710Z","shell.execute_reply":"2026-04-19T07:45:16.693332Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = df[['image_id','x', 'y', 'w', 'h','x_center','y_center','classes', 'fold']]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:16.694770Z","iopub.execute_input":"2026-04-19T07:45:16.694959Z","iopub.status.idle":"2026-04-19T07:45:16.708038Z","shell.execute_reply.started":"2026-04-19T07:45:16.694938Z","shell.execute_reply":"2026-04-19T07:45:16.707204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_data(df, fold = 0, img_size=1024):\n\n    source_dir = pathlib.Path(PATH_TRAIN)\n    base_path = pathlib.Path(f\"convertor/fold{fold}\")\n    \n    for split in [\"train\", \"valid\"]:\n        (base_path / \"images\" / split).mkdir(parents=True, exist_ok=True)\n        (base_path / \"labels\" / split).mkdir(parents=True, exist_ok=True)\n    \n    df_norm = df.copy()\n    cols_to_norm = ['x_center', 'y_center', 'w', 'h']\n    # scale\n    df_norm[cols_to_norm] = df_norm[cols_to_norm] / img_size\n\n    # groupby\n    grouped = df_norm.groupby('image_id')\n    val_images = set(df[df['fold'] == fold]['image_id'])\n    \n    for name, mini in tqdm(grouped, desc=f\"Processing Fold {fold}\"):\n        split = 'valid' if name in val_images else 'train'\n\n        labels = mini[['classes', 'x_center', 'y_center', 'w', 'h']].values\n        label_str = \"\\n\".join([\" \".join(map(lambda x: f\"{x:.6f}\", row)) for row in labels])\n        # create txt file\n        label_file = base_path / \"labels\" / split / f\"{name}.txt\"\n        label_file.write_text(label_str)\n\n        # get Path Image\n        img_src = source_dir / f\"{name}.jpg\"\n        img_dst = base_path / \"images\" / split / f\"{name}.jpg\"\n        if not img_dst.exists():\n            os.symlink(img_src.absolute(), img_dst)\n\nprepare_data(df, fold = 0, img_size = 1024)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:16.709004Z","iopub.execute_input":"2026-04-19T07:45:16.709483Z","iopub.status.idle":"2026-04-19T07:45:21.580838Z","shell.execute_reply.started":"2026-04-19T07:45:16.709457Z","shell.execute_reply":"2026-04-19T07:45:21.580034Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"yaml_text = \"\"\"\ntrain: /kaggle/working/convertor/fold0/images/train\nval: /kaggle/working/convertor/fold0/images/valid  \n\nnc: 1\nnames:\n  0: wheat           \n\"\"\"\n\nwith open(\"wheat.yaml\", 'w') as f:\n    f.write(yaml_text)\n%cat wheat.yaml","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:21.581830Z","iopub.execute_input":"2026-04-19T07:45:21.582165Z","iopub.status.idle":"2026-04-19T07:45:21.720127Z","shell.execute_reply.started":"2026-04-19T07:45:21.582136Z","shell.execute_reply":"2026-04-19T07:45:21.719469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_and_eval(model_name=\"yolo26s.pt\", data_yml=\"wheat.yaml\"):\n    model = YOLO(model_name)\n    # init model\n    model.train(\n        data=data_yml,\n        epochs=50,\n        imgsz=1024,\n        batch=16,\n        device=0,\n        val=True,      \n        save=True,          \n        name=\"wheat_run\",\n        exist_ok=True\n    )\n    # metrics\n    metrics = model.val() \n    print(f\"--- Finished ---\")\n    print(f\"mAP50: {metrics.box.map50:.4f}\")\n    print(f\"mAP75: {metrics.box.map75:.4f}\")\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:21.722793Z","iopub.execute_input":"2026-04-19T07:45:21.723362Z","iopub.status.idle":"2026-04-19T07:45:21.728053Z","shell.execute_reply.started":"2026-04-19T07:45:21.723330Z","shell.execute_reply":"2026-04-19T07:45:21.727302Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict_and_create_submission(model_obj, test_path, sample_sub_path):\n    print(\"--- Predict & Submission ---\")\n    \n    results = model_obj.predict(source=test_path, conf=0.25, imgsz=1024, verbose=False)\n    \n    prediction_dict = {}\n    for res in results:\n        img_id = res.path.split('/')[-1].split('.')[0]\n        boxes = res.boxes.data.cpu().numpy()\n        \n        pred_strings = []\n        for box in boxes:\n            xmin, ymin, xmax, ymax, conf, cls = box\n            w, h = xmax - xmin, ymax - ymin\n            pred_strings.append(f\"{conf:.4f} {xmin:.0f} {ymin:.0f} {w:.0f} {h:.0f}\")\n        \n        prediction_dict[img_id] = \" \".join(pred_strings)\n\n    sample_sub = pd.read_csv(sample_sub_path)\n    sample_sub['PredictionString'] = sample_sub['image_id'].map(lambda x: prediction_dict.get(x, \"\"))\n    \n    sample_sub.to_csv('submission.csv', index=False)\n    print(\"--- Done!!! ---\")\n    return sample_sub","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:21.729018Z","iopub.execute_input":"2026-04-19T07:45:21.729342Z","iopub.status.idle":"2026-04-19T07:45:21.744064Z","shell.execute_reply.started":"2026-04-19T07:45:21.729304Z","shell.execute_reply":"2026-04-19T07:45:21.743259Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls -R /kaggle/working/convertor/fold0/images/train | head -n 5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:21.745022Z","iopub.execute_input":"2026-04-19T07:45:21.745603Z","iopub.status.idle":"2026-04-19T07:45:21.885912Z","shell.execute_reply.started":"2026-04-19T07:45:21.745568Z","shell.execute_reply":"2026-04-19T07:45:21.885229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls -R /kaggle/working/convertor/fold0/images/valid | head -n 5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:21.887051Z","iopub.execute_input":"2026-04-19T07:45:21.887308Z","iopub.status.idle":"2026-04-19T07:45:22.025894Z","shell.execute_reply.started":"2026-04-19T07:45:21.887279Z","shell.execute_reply":"2026-04-19T07:45:22.024986Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_path = os.path.abspath(\"wheat.yaml\")\ntrained_model = train_and_eval(\"yolo26s.pt\", \"wheat.yaml\")\nfinal_sub = predict_and_create_submission(trained_model, PATH_TEST, SAMPLE_SUB)\nfinal_sub.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T07:45:22.027252Z","iopub.execute_input":"2026-04-19T07:45:22.027563Z","iopub.status.idle":"2026-04-19T09:06:51.339837Z","shell.execute_reply.started":"2026-04-19T07:45:22.027533Z","shell.execute_reply":"2026-04-19T09:06:51.338978Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Demo\nimport matplotlib.pyplot as plt\nimport cv2\n\ntest_images = [\n    \"/kaggle/input/competitions/global-wheat-detection/test/348a992bb.jpg\",\n    \"/kaggle/input/competitions/global-wheat-detection/test/796707dd7.jpg\",\n    \"/kaggle/input/competitions/global-wheat-detection/test/f5a1f0358.jpg\"\n]\n\nresults = trained_model.predict(source=test_images, conf=0.25, imgsz=1024)\n\nplt.figure(figsize=(20, 10)) \n\nfor i, res in enumerate(results):\n    res_plotted = res.plot() \n    res_rgb = cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB)\n    plt.subplot(1, len(results), i + 1)\n    plt.imshow(res_rgb)\n    plt.axis('off')\n    plt.title(f\"Image {i+1}\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T09:09:20.250519Z","iopub.execute_input":"2026-04-19T09:09:20.251275Z","iopub.status.idle":"2026-04-19T09:09:21.141936Z","shell.execute_reply.started":"2026-04-19T09:09:20.251237Z","shell.execute_reply":"2026-04-19T09:09:21.140800Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **2. How to use with KFOLD**","metadata":{}},{"cell_type":"code","source":"import gc\nimport torch\n\ndef train_model(df, model_name=\"yolo26s.pt\"):\n    all_fold_metrics = []\n    \n    for fold in range(5):\n        print(f\"\\nSTARTING FOLD {fold}...\")\n\n        # prepare data for YOLO\n        prepare_data(df, fold=fold, img_size=1024)\n        \n        # Yaml\n        yaml_content = f\"\"\"\n        path: /kaggle/working/convertor/fold{fold}\n        train: images/train\n        val: images/valid\n        \n        nc: 1\n        names: [wheat]\n        \"\"\"\n        yaml_path = f\"wheat_fold{fold}.yaml\"\n        with open(yaml_path, \"w\") as f:\n            f.write(yaml_content)\n\n        \n        # Init Model\n        model = YOLO(model_name)\n        model = model.train(\n            data=yaml_path,\n            epochs=30,     \n            imgsz=1024,\n            batch=8,  \n            name=f\"run_fold_{fold}\",\n            exist_ok=True,\n            multi_scale = True,\n        )\n\n        # eval\n        metrics = model.val()\n        mAP50 = metrics.box.map50\n        all_fold_metrics.append(mAP50)\n        print(f\"Fold {fold} mAP50: {mAP50:.4f}\")\n        \n        del model, results, metrics \n        gc.collect()                \n        torch.cuda.empty_cache()      \n        \n    avg_map = sum(all_fold_metrics) / 5\n    print(f\"\\nAVERAGE 5-FOLD mAP50: {avg_map:.4f}\")\n    return all_fold_metrics\n\ntrain_model()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}