{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.12"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":129750,"databundleVersionId":15563344,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":138.657249,"end_time":"2026-02-01T20:17:27.157382","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-02-01T20:15:08.500133","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"![](https://i.imgur.com/tzWwJLY.png)","metadata":{"papermill":{"duration":0.003562,"end_time":"2026-02-01T20:15:11.356255","exception":false,"start_time":"2026-02-01T20:15:11.352693","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# Competition Baseline - Object Detection + Classification\n\n**Welcome!** This notebook provides a simple YOLOv8 baseline to get you started.\n\n## What this notebook does:\n1. ✅ Loads and prepares the dataset\n2. ✅ Trains a YOLOv8 object detection model\n3. ✅ Generates a valid submission file\n4. ✅ Uses \"-\" for images with no detections (required format)\n\n## Competition Metric:\n**Final Score = 0.5 × mAP@[0.5:0.95] + 0.5 × F1-Score**\n\n---","metadata":{"papermill":{"duration":0.002651,"end_time":"2026-02-01T20:15:11.36162","exception":false,"start_time":"2026-02-01T20:15:11.358969","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Install required packages\n!pip install ultralytics -q","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:31.047608Z","iopub.execute_input":"2026-02-17T14:41:31.047906Z","iopub.status.idle":"2026-02-17T14:41:36.791828Z","shell.execute_reply.started":"2026-02-17T14:41:31.047852Z","shell.execute_reply":"2026-02-17T14:41:36.791060Z"},"papermill":{"duration":5.934636,"end_time":"2026-02-01T20:15:17.298979","exception":false,"start_time":"2026-02-01T20:15:11.364343","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Import libraries\nimport os\nimport shutil\nimport pandas as pd\nfrom pathlib import Path\nfrom ultralytics import YOLO\nfrom sklearn.model_selection import train_test_split\nfrom tqdm import tqdm","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:36.794136Z","iopub.execute_input":"2026-02-17T14:41:36.794724Z","iopub.status.idle":"2026-02-17T14:41:45.730970Z","shell.execute_reply.started":"2026-02-17T14:41:36.794673Z","shell.execute_reply":"2026-02-17T14:41:45.730184Z"},"papermill":{"duration":12.856377,"end_time":"2026-02-01T20:15:30.158549","exception":false,"start_time":"2026-02-01T20:15:17.302172","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📁 Configuration\nUpdate `ROOT_DIR` to point to your dataset location","metadata":{"papermill":{"duration":0.003015,"end_time":"2026-02-01T20:15:30.164721","exception":false,"start_time":"2026-02-01T20:15:30.161706","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Update this path to match your dataset\nROOT_DIR = \"/kaggle/input/dal-shemagh-detection-challenge\"\nWORK_DIR = \"./yolo_data\"\n\nprint(f\"Dataset directory: {ROOT_DIR}\")\nprint(f\"Working directory: {WORK_DIR}\")","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:45.731924Z","iopub.execute_input":"2026-02-17T14:41:45.732266Z","iopub.status.idle":"2026-02-17T14:41:45.737799Z","shell.execute_reply.started":"2026-02-17T14:41:45.732240Z","shell.execute_reply":"2026-02-17T14:41:45.736237Z"},"papermill":{"duration":0.009326,"end_time":"2026-02-01T20:15:30.176963","exception":false,"start_time":"2026-02-01T20:15:30.167637","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📊 Load Data","metadata":{"papermill":{"duration":0.002948,"end_time":"2026-02-01T20:15:30.182924","exception":false,"start_time":"2026-02-01T20:15:30.179976","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Load training labels\ntrain_df = pd.read_csv(os.path.join(ROOT_DIR, \"train_labels.csv\"))\nprint(f\"Training images: {len(train_df)}\")\nprint(\"\\nFirst few rows:\")\ndisplay(train_df.head())","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:45.738935Z","iopub.execute_input":"2026-02-17T14:41:45.739286Z","iopub.status.idle":"2026-02-17T14:41:45.787949Z","shell.execute_reply.started":"2026-02-17T14:41:45.739239Z","shell.execute_reply":"2026-02-17T14:41:45.787274Z"},"papermill":{"duration":0.036268,"end_time":"2026-02-01T20:15:30.222148","exception":false,"start_time":"2026-02-01T20:15:30.18588","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ✂️ Train/Validation Split\nSplit data 80/20 with stratification by category","metadata":{"papermill":{"duration":0.003368,"end_time":"2026-02-01T20:15:30.228703","exception":false,"start_time":"2026-02-01T20:15:30.225335","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Split into train (80%) and validation (20%)\ntrain_data, val_data = train_test_split(\n    train_df,\n    test_size=0.2,\n    random_state=42,\n)\n\nprint(f\"Train set: {len(train_data)} images\")\nprint(f\"Validation set: {len(val_data)} images\")","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:45.788970Z","iopub.execute_input":"2026-02-17T14:41:45.789216Z","iopub.status.idle":"2026-02-17T14:41:45.798562Z","shell.execute_reply.started":"2026-02-17T14:41:45.789191Z","shell.execute_reply":"2026-02-17T14:41:45.797902Z"},"papermill":{"duration":0.015125,"end_time":"2026-02-01T20:15:30.246951","exception":false,"start_time":"2026-02-01T20:15:30.231826","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🗂️ Prepare YOLO Directory Structure\nYOLO expects images and labels in specific folders","metadata":{"papermill":{"duration":0.003394,"end_time":"2026-02-01T20:15:30.253816","exception":false,"start_time":"2026-02-01T20:15:30.250422","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Create directories\nfor split in ['train', 'val']:\n    os.makedirs(f\"{WORK_DIR}/images/{split}\", exist_ok=True)\n    os.makedirs(f\"{WORK_DIR}/labels/{split}\", exist_ok=True)\n\ndef prepare_yolo_split(df, split_name):\n    \"\"\"Copy images and labels to YOLO format directories\"\"\"\n    print(f\"\\nPreparing {split_name} set...\")\n    \n    for _, row in tqdm(df.iterrows(), total=len(df)):\n        filename = row['filename']\n        stem = Path(filename).stem\n        \n        # Copy image\n        src_img = os.path.join(ROOT_DIR, \"images/train\", filename)\n        dst_img = os.path.join(WORK_DIR, f\"images/{split_name}\", filename)\n        shutil.copy(src_img, dst_img)\n        \n        # Copy label (create empty if doesn't exist)\n        src_lbl = os.path.join(ROOT_DIR, \"labels/train\", f\"{stem}.txt\")\n        dst_lbl = os.path.join(WORK_DIR, f\"labels/{split_name}\", f\"{stem}.txt\")\n        \n        if os.path.exists(src_lbl):\n            shutil.copy(src_lbl, dst_lbl)\n        else:\n            # Empty label = no objects in image\n            open(dst_lbl, 'w').close()\n\n# Prepare both splits\nprepare_yolo_split(train_data, 'train')\nprepare_yolo_split(val_data, 'val')\n\nprint(\"\\n✓ YOLO directories ready!\")","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:45.799574Z","iopub.execute_input":"2026-02-17T14:41:45.799837Z","iopub.status.idle":"2026-02-17T14:41:52.522055Z","shell.execute_reply.started":"2026-02-17T14:41:45.799806Z","shell.execute_reply":"2026-02-17T14:41:52.521415Z"},"papermill":{"duration":7.02767,"end_time":"2026-02-01T20:15:37.284892","exception":false,"start_time":"2026-02-01T20:15:30.257222","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ⚙️ Create YOLO Configuration","metadata":{"papermill":{"duration":0.006156,"end_time":"2026-02-01T20:15:37.297992","exception":false,"start_time":"2026-02-01T20:15:37.291836","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Create data.yaml config file\nyaml_content = f\"\"\"path: {os.path.abspath(WORK_DIR)}\ntrain: images/train\nval: images/val\n\nnc: 2\nnames: ['Face', 'Shemagh']\n\"\"\"\n\nwith open(f\"{WORK_DIR}/data.yaml\", \"w\") as f:\n    f.write(yaml_content)\n\nprint(\"✓ Configuration created!\")\nprint(\"\\nContent:\")\nprint(yaml_content)","metadata":{"execution":{"iopub.status.busy":"2026-02-17T14:41:52.526134Z","iopub.execute_input":"2026-02-17T14:41:52.526372Z","iopub.status.idle":"2026-02-17T14:41:52.531193Z","shell.execute_reply.started":"2026-02-17T14:41:52.526348Z","shell.execute_reply":"2026-02-17T14:41:52.530492Z"},"papermill":{"duration":0.013892,"end_time":"2026-02-01T20:15:37.317908","exception":false,"start_time":"2026-02-01T20:15:37.304016","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import albumentations as A\n\nmy_transform = A.Compose([\n  \n    A.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1),\n    A.GaussianBlur(p=0.1),\n    A.Rotate(limit=10),\n])\naugmentation_list = [my_transform]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T18:31:37.525708Z","iopub.execute_input":"2026-02-17T18:31:37.526305Z","iopub.status.idle":"2026-02-17T18:31:37.531639Z","shell.execute_reply.started":"2026-02-17T18:31:37.526274Z","shell.execute_reply":"2026-02-17T18:31:37.530933Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🚀 Train YOLO Model\n\nTraining YOLOv8n (nano) - fastest model, good baseline.\n\n**To improve:** Try `yolov8s.pt`, `yolov8m.pt`, or `yolov8l.pt` for better accuracy","metadata":{"papermill":{"duration":0.006174,"end_time":"2026-02-01T20:15:37.330448","exception":false,"start_time":"2026-02-01T20:15:37.324274","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Initialize model\n\nmodel = YOLO('yolov8m.pt')\n# Train\nresults = model.train(\n    data=f\"{WORK_DIR}/data.yaml\",\n    epochs=150,       # Increase for better results (100-200)\n    imgsz=640,       # Image size\n    dfl=2.5,\n    optimizer='SGD',\n    lr0=0.001,\n    momentum=0.937,\n    weight_decay=0.005,\n    mixup=0.2,\n    scale=0.5,\n    fliplr=0.5,\n    batch=32,        # Adjust based on GPU memory\n    patience=30,     # Early stopping\n    augmentations=augmentation_list,\n    save=True,\n    plots=True,\n    verbose=True\n)\n\nprint(\"\\n✓ Training complete!\")","metadata":{"execution":{"iopub.status.busy":"2026-02-17T19:15:48.763532Z","iopub.execute_input":"2026-02-17T19:15:48.764373Z","iopub.status.idle":"2026-02-17T19:37:01.479229Z","shell.execute_reply.started":"2026-02-17T19:15:48.764332Z","shell.execute_reply":"2026-02-17T19:37:01.478444Z"},"papermill":{"duration":85.576268,"end_time":"2026-02-01T20:17:02.912897","exception":false,"start_time":"2026-02-01T20:15:37.336629","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📈 Validate Model","metadata":{"papermill":{"duration":0.022515,"end_time":"2026-02-01T20:17:02.959149","exception":false,"start_time":"2026-02-01T20:17:02.936634","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Evaluate on validation set\nmetrics = model.val()\n\nprint(\"\\n\" + \"=\"*60)\nprint(\"VALIDATION RESULTS\")\nprint(\"=\"*60)\nprint(f\"mAP@0.5:0.95: {metrics.box.map:.4f}\")\nprint(f\"mAP@0.5:     {metrics.box.map50:.4f}\")\nprint(f\"mAP@0.75:    {metrics.box.map75:.4f}\")\nprint(\"=\"*60)","metadata":{"execution":{"iopub.status.busy":"2026-02-17T19:37:54.370741Z","iopub.execute_input":"2026-02-17T19:37:54.371473Z","iopub.status.idle":"2026-02-17T19:38:01.426746Z","shell.execute_reply.started":"2026-02-17T19:37:54.371427Z","shell.execute_reply":"2026-02-17T19:38:01.425982Z"},"papermill":{"duration":4.35128,"end_time":"2026-02-01T20:17:07.333087","exception":false,"start_time":"2026-02-01T20:17:02.981807","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🔮 Generate Submission\n\nRun inference on test set and create submission file","metadata":{"papermill":{"duration":0.023316,"end_time":"2026-02-01T20:17:07.38023","exception":false,"start_time":"2026-02-01T20:17:07.356914","status":"completed"},"tags":[]}},{"cell_type":"code","source":"print(\"Generating submission file...\\n\")\n\ntest_img_dir = os.path.join(ROOT_DIR, \"images/test\")\nsubmission_rows = []\n\n# Get all test images from directory\ntest_images = sorted([f for f in os.listdir(test_img_dir) if f.endswith(('.jpg', '.png', '.jpeg'))])\nprint(f\"Found {len(test_images)} test images\\n\")\n\n# Process each test image\nfor filename in tqdm(test_images, desc=\"Inference\"):\n    img_path = os.path.join(test_img_dir, filename)\n    \n    # Run YOLO inference\n    results = model.predict(\n        source=img_path,\n        conf=0.25,      # Confidence threshold (tune this!)\n        iou=0.45,       # NMS threshold\n        verbose=False\n    )[0]\n    \n    # Parse detections\n    pred_parts = []\n    if len(results.boxes) > 0:\n        for box in results.boxes:\n            cls_id = int(box.cls[0].item())\n            confidence = float(box.conf[0].item())\n            x, y, w, h = box.xywhn[0].tolist()  # Normalized coords\n            \n            # Format: class score x y w h\n            pred_parts.extend([\n                str(cls_id),\n                f\"{confidence:.4f}\",\n                f\"{x:.4f}\",\n                f\"{y:.4f}\",\n                f\"{w:.4f}\",\n                f\"{h:.4f}\"\n            ])\n    \n    # Use \"-\" if no detections (REQUIRED)\n    prediction_string = \" \".join(pred_parts) if pred_parts else \"-\"\n    \n    # Store result\n    submission_rows.append({\n        \"filename\": filename,\n        \"right_place\": 0,  # Simple baseline: always 0\n        \"prediction_string\": prediction_string\n    })\n\n# Create DataFrame\nsubmission = pd.DataFrame(submission_rows)\n\nprint(\"\\n✓ Submission generated!\")\nprint(f\"Total rows: {len(submission)}\")\nprint(f\"With detections: {(submission['prediction_string'] != '-').sum()}\")\nprint(f\"Without detections: {(submission['prediction_string'] == '-').sum()}\")","metadata":{"execution":{"iopub.status.busy":"2026-02-17T19:38:10.241620Z","iopub.execute_input":"2026-02-17T19:38:10.241959Z","iopub.status.idle":"2026-02-17T19:38:37.390922Z","shell.execute_reply.started":"2026-02-17T19:38:10.241924Z","shell.execute_reply":"2026-02-17T19:38:37.390140Z"},"papermill":{"duration":16.517232,"end_time":"2026-02-01T20:17:23.920737","exception":false,"start_time":"2026-02-01T20:17:07.403505","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 💾 Save Submission","metadata":{"papermill":{"duration":0.028322,"end_time":"2026-02-01T20:17:23.978198","exception":false,"start_time":"2026-02-01T20:17:23.949876","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Save to CSV\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"\\n\" + \"=\"*60)\nprint(\"✓ SUBMISSION SAVED: submission.csv\")\nprint(\"=\"*60)\nprint(\"\\nFirst 10 rows:\")\ndisplay(submission.head(10))","metadata":{"execution":{"iopub.status.busy":"2026-02-17T19:38:39.776267Z","iopub.execute_input":"2026-02-17T19:38:39.776573Z","iopub.status.idle":"2026-02-17T19:38:39.789333Z","shell.execute_reply.started":"2026-02-17T19:38:39.776546Z","shell.execute_reply":"2026-02-17T19:38:39.788709Z"},"papermill":{"duration":0.046873,"end_time":"2026-02-01T20:17:24.053219","exception":false,"start_time":"2026-02-01T20:17:24.006346","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n\n## 🎯 Next Steps\n\nThis baseline gives you a working submission. To improve your score:\n\n1. **Add Augmentations** - Try to add augmentations\n2. **Use larger model** - Try `yolov8s.pt` or `yolov8m.pt`\n3. **Train longer** - Increase epochs to 100-200\n4. **Add classification model** - Build a model for `right_place` instead of always using 0 (or maybe think about a more elegant way to predict it!)\n\n---\n\nGood luck! 🍀","metadata":{"papermill":{"duration":0.028534,"end_time":"2026-02-01T20:17:24.111199","exception":false,"start_time":"2026-02-01T20:17:24.082665","status":"completed"},"tags":[]}}]}