{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":107469,"databundleVersionId":13058354,"sourceType":"competition"},{"sourceId":12537987,"sourceType":"datasetVersion","datasetId":7915408},{"sourceId":12578044,"sourceType":"datasetVersion","datasetId":7943689},{"sourceId":250085529,"sourceType":"kernelVersion"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Install necessary packages\n!pip install -q ultralytics ensemble-boxes\n\n# Import standard libraries\nimport os\nimport random\nimport numpy as np\nimport pandas as pd\nfrom pathlib import Path\nfrom PIL import Image\n\n# Import PyTorch and YOLO\nimport torch\nfrom ultralytics import YOLO\n\n# Import ensembling tools\nfrom ensemble_boxes import weighted_boxes_fusion\n\n# Set random seeds for reproducibility\nseed = 42\nrandom.seed(seed)\nnp.random.seed(seed)\ntorch.manual_seed(seed)\nif torch.cuda.is_available():\n    torch.cuda.manual_seed_all(seed)\n\nprint(\"✅ Dependencies loaded and random seeds set.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:21:04.438456Z","iopub.execute_input":"2025-08-04T09:21:04.438997Z","iopub.status.idle":"2025-08-04T09:22:41.248108Z","shell.execute_reply.started":"2025-08-04T09:21:04.438964Z","shell.execute_reply":"2025-08-04T09:22:41.247413Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define base paths\nbase1 = Path('/kaggle/input/falcon-multiclass-cheerios-soup/falcon-multiclass-cheerios-soup')\nbase2 = Path('/kaggle/input/falcon-multiclass-cheerios-soupv2/falcon-multiclass-cheerios-soupV2')\n\n# Print data information\nprint(\"Original Falcon Dataset:\")\nfor split in ['train', 'val']:\n    imgs = list((base1 / split / 'images').glob('*.*'))\n    labs = list((base1 / split / 'labels').glob('*.txt'))\n    print(f\"  {split}: {len(imgs)} images, {len(labs)} labels\")\n\nfor i in range(1, 7):\n    d = base2 / f\"Scenario{i}\"\n    t_imgs = len(list((d / 'train' / 'images').glob('*.*')))\n    v_imgs = len(list((d / 'val' / 'images').glob('*.*')))\n    print(f\"Scenario {i}: train={t_imgs}, val={v_imgs}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:22:41.249582Z","iopub.execute_input":"2025-08-04T09:22:41.249926Z","iopub.status.idle":"2025-08-04T09:22:41.543063Z","shell.execute_reply.started":"2025-08-04T09:22:41.249905Z","shell.execute_reply":"2025-08-04T09:22:41.542237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import yaml\nfrom pathlib import Path\n\n# Define mount points\nfalcon_mount = Path('/kaggle/input/falcon-multiclass-cheerios-soup/falcon-multiclass-cheerios-soup')\nv2_mount = Path('/kaggle/input/falcon-multiclass-cheerios-soupv2/falcon-multiclass-cheerios-soupV2')\nchal_mount = Path('/kaggle/input/multi-class-object-detection-challenge/Starter_Dataset')\n\n# Auto-discover original Falcon root\ntrain_img_dirs = list(falcon_mount.glob('**/train/images'))\nif not train_img_dirs:\n    raise FileNotFoundError(f\"No nested train/images under {falcon_mount}\")\nfalcon_root = train_img_dirs[0].parents[1]\n\n# Auto-discover V2 root\nv2_img_dirs = list(v2_mount.glob('**/Scenario1/train/images'))\nif not v2_img_dirs:\n    raise FileNotFoundError(f\"No Scenario1/train/images under {v2_mount}\")\nv2_root = v2_img_dirs[0].parents[2]\n\n# Build train list\ntrain_dirs = [\n    str(falcon_root / 'train' / 'images'),\n    str(falcon_root / 'val' / 'images')\n]\nfor i in range(1, 7):\n    train_dirs += [\n        str(v2_root / f\"Scenario{i}\" / 'train' / 'images'),\n        str(v2_root / f\"Scenario{i}\" / 'val' / 'images')\n    ]\n\n# Use competition val folder for validation\nval_dirs = [\n    str(chal_mount / 'val' / 'images')\n]\n\n# Test set\ntest_dir = str(chal_mount / 'testImages' / 'images')\n\n# Assemble and write YAML\ndata = {\n    'train': train_dirs,\n    'val': val_dirs,\n    'test': test_dir,\n    'nc': 2,\n    'names': ['cheerios', 'soup']\n}\n\nwith open('data.yaml', 'w') as f:\n    yaml.safe_dump(data, f, sort_keys=False, default_flow_style=False)\n\nprint(\"✅ data.yaml created:\")\nprint(open('data.yaml').read())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:22:41.543934Z","iopub.execute_input":"2025-08-04T09:22:41.544247Z","iopub.status.idle":"2025-08-04T09:22:44.457856Z","shell.execute_reply.started":"2025-08-04T09:22:41.544221Z","shell.execute_reply":"2025-08-04T09:22:44.457191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\nimport random\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nfrom PIL import Image\n\n# Define roots\norig_root = Path('/kaggle/input/falcon-multiclass-cheerios-soup/falcon-multiclass-cheerios-soup')\nv2_root = Path('/kaggle/input/falcon-multiclass-cheerios-soupv2/falcon-multiclass-cheerios-soupV2')\n\n# Build list of (images, labels) for original + each Scenario\ntrain_pairs = [\n    (orig_root / 'train' / 'images', orig_root / 'train' / 'labels'),\n]\nfor i in range(1, 7):\n    scen = v2_root / f'Scenario{i}'\n    train_pairs += [\n        (scen / 'train' / 'images', scen / 'train' / 'labels'),\n        (scen / 'val' / 'images', scen / 'val' / 'labels'),\n    ]\n\n# Gather all (img_path, lbl_path) tuples\nall_samples = []\nfor img_dir, lbl_dir in train_pairs:\n    if img_dir.exists() and lbl_dir.exists():\n        for img_path in img_dir.glob('*.*'):\n            lbl_path = lbl_dir / f\"{img_path.stem}.txt\"\n            all_samples.append((img_path, lbl_path))\n\n# Sample a few examples\nnum_to_show = 6\nsampled = random.sample(all_samples, k=min(len(all_samples), num_to_show))\n\nclasses = ['cheerios', 'soup']\n\n# Plot\nfor img_path, lbl_path in sampled:\n    img = Image.open(img_path)\n    fig, ax = plt.subplots(figsize=(6, 6))\n    ax.imshow(img)\n    if lbl_path.exists():\n        with open(lbl_path) as f:\n            for line in f:\n                cls_id, x_c, y_c, w, h = map(float, line.split())\n                img_w, img_h = img.size\n                x1 = (x_c - w / 2) * img_w\n                y1 = (y_c - h / 2) * img_h\n                rect = patches.Rectangle((x1, y1), w * img_w, h * img_h,\n                                         linewidth=2, edgecolor='red', facecolor='none')\n                ax.add_patch(rect)\n                ax.text(x1, y1, classes[int(cls_id)],\n                        color='white', fontsize=10,\n                        bbox=dict(facecolor='red', alpha=0.5, pad=0.5))\n    ax.axis('off')\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:22:44.459123Z","iopub.execute_input":"2025-08-04T09:22:44.459309Z","iopub.status.idle":"2025-08-04T09:22:47.707949Z","shell.execute_reply.started":"2025-08-04T09:22:44.459294Z","shell.execute_reply":"2025-08-04T09:22:47.707017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ultralytics import YOLO\n\n# Toggle training on/off\nTRAIN = True\n\nif TRAIN:\n    model = YOLO(\"yolov8x.pt\")  # or your custom checkpoint\n\n    model.train(\n        data=\"data.yaml\",\n        epochs=75,\n        batch=16,\n        imgsz=512,\n        optimizer=\"SGD\",\n        lr0=0.002,\n        lrf=0.0001,\n        weight_decay=0.0001,\n        dropout=0.3,\n        dfl=0.75,\n        cos_lr=True,\n        patience=100,\n        save_period=10,\n        project=\"runs/train\",\n        exist_ok=True,\n        plots=True,\n        augment=True,\n        mosaic=1.0,\n        mixup=0.25,\n        cutmix=0.25,\n        copy_paste=0.05,\n        close_mosaic=10,\n        hsv_h=0.05, hsv_s=1.0, hsv_v=0.75,\n        flipud=0.1, fliplr=0.6,\n        translate=0.1, scale=0.6, shear=0.02,\n        warmup_epochs=5, warmup_momentum=1,\n        workers=4,\n        conf=0.25, iou=0.5\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:22:47.708751Z","iopub.execute_input":"2025-08-04T09:22:47.709022Z","iopub.status.idle":"2025-08-04T10:21:22.805699Z","shell.execute_reply.started":"2025-08-04T09:22:47.708999Z","shell.execute_reply":"2025-08-04T10:21:22.804688Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom pathlib import Path\nfrom PIL import Image\n\n# Point to your training run directory\nexp_dir = Path(\"/kaggle/working/runs/train/train\")  # adjust if different\nresults_csv = exp_dir / \"results.csv\"\n\n# Load the per-epoch metrics\nresults = pd.read_csv(results_csv)\n\n# Plot validation losses over epochs\nplt.figure(figsize=(10, 5))\nplt.plot(results['epoch'], results['val/box_loss'], label='val box loss')\nplt.plot(results['epoch'], results['val/cls_loss'], label='val cls loss')\nplt.plot(results['epoch'], results['val/dfl_loss'], label='val dfl loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.title('YOLO Validation Losses')\nplt.legend()\nplt.grid(True)\nplt.show()\n\n# Display the confusion matrix image(s)\ncm_paths = [\n    exp_dir / \"results.png\",\n    exp_dir / \"confusion_matrix.png\"\n]\nfor p in cm_paths:\n    if p.exists():\n        img = Image.open(p)\n        plt.figure(figsize=(8, 8))\n        plt.imshow(img)\n        plt.axis('off')\n        plt.show()\n    else:\n        print(f\"No file at {p}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T10:21:22.807285Z","iopub.execute_input":"2025-08-04T10:21:22.807598Z","iopub.status.idle":"2025-08-04T10:21:25.130928Z","shell.execute_reply.started":"2025-08-04T10:21:22.807556Z","shell.execute_reply":"2025-08-04T10:21:25.130152Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import csv\nimport pandas as pd\nfrom pathlib import Path\nfrom PIL import Image\nfrom ultralytics import YOLO\nfrom ensemble_boxes import weighted_boxes_fusion\n\ndef filter_invalid_boxes(boxes, scores, labels):\n    filtered_boxes, filtered_scores, filtered_labels = [], [], []\n    for b, s, l in zip(boxes, scores, labels):\n        if abs(b[2] - b[0]) > 1e-6 and abs(b[3] - b[1]) > 1e-6:\n            filtered_boxes.append(b)\n            filtered_scores.append(s)\n            filtered_labels.append(l)\n    return filtered_boxes, filtered_scores, filtered_labels\n\ndef run_inference(models, image_sizes, test_images_path, conf=0.25, iou_thr=0.5):\n    test_dir = Path(test_images_path)\n    image_paths = [p for p in test_dir.glob('*') if p.suffix.lower() in ('.jpg', '.jpeg', '.png')]\n    predictions = {}\n\n    for mi, model in enumerate(models):\n        model.eval()\n        predictions[mi] = {}\n        for size in image_sizes:\n            predictions[mi][size] = {}\n            for img_path in image_paths:\n                image_id = img_path.stem\n                img = Image.open(img_path)\n                w, h = img.size\n\n                # Run predict\n                results = model.predict(source=str(img_path),\n                                        conf=conf, iou=iou_thr,\n                                        imgsz=size, augment=True,\n                                        verbose=False)\n                # Collect all boxes for this image/size\n                boxes, scores, labels = [], [], []\n                for r in results:\n                    if r.boxes is None:\n                        continue\n                    boxes = r.boxes.xyxy.cpu().numpy().tolist()\n                    scores = r.boxes.conf.cpu().numpy().tolist()\n                    labels = r.boxes.cls.cpu().numpy().tolist()\n\n                # Normalize & filter\n                norm_boxes = [[x1 / w, y1 / h, x2 / w, y2 / h] for x1, y1, x2, y2 in boxes]\n                norm_boxes, scores, labels = filter_invalid_boxes(norm_boxes, scores, labels)\n\n                predictions[mi][size][image_id] = {\"boxes\": norm_boxes,\n                                                  \"scores\": scores,\n                                                  \"labels\": labels}\n    return predictions\n\n# Specify your checkpoints and test folder\nmodel_paths = [\n    '/kaggle/input/3lc-yolo-baseline-submission/Duality-3LC-Kaggle/run-1/weights/best.pt',\n    '/kaggle/working/runs/train/train/weights/best.pt']\n\ntest_images_path = '/kaggle/input/multi-class-object-detection-challenge/testImages/images'\n\n# Load models\nmodels = [YOLO(p) for p in model_paths]\n\n# Run batched, multi-scale inference\nimage_sizes = [640, 800, 864]\npredictions = run_inference(models, image_sizes, test_images_path,\n                            conf=0.05, iou_thr=0.35)\n\n# Collect all image_ids\nfirst_model = predictions[next(iter(predictions))]\nfirst_scale = first_model[next(iter(first_model))]\nimage_ids = list(first_scale.keys())\n\n# Fuse & build submission rows\nrows = []\nfor img_id in image_ids:\n    all_boxes, all_scores, all_labels = [], [], []\n    for model_preds in predictions.values():\n        for size_preds in model_preds.values():\n            if img_id in size_preds:\n                p = size_preds[img_id]\n                if p['boxes']:\n                    all_boxes.append(p['boxes'])\n                    all_scores.append(p['scores'])\n                    all_labels.append(p['labels'])\n    if all_boxes:\n        fb, fs, fl = weighted_boxes_fusion(all_boxes, all_scores, all_labels,\n                                           iou_thr=0.35, skip_box_thr=0.01)\n        pred_str = \" \".join(\n            f\"{int(l)} {s:.6f} {(b[0] + b[2]) / 2:.6f} {(b[1] + b[3]) / 2:.6f} {(b[2] - b[0]):.6f} {(b[3] - b[1]):.6f}\"\n            for b, s, l in zip(fb, fs, fl)\n        )\n    else:\n        pred_str = \"no boxes\"\n    rows.append({'image_id': img_id, 'prediction_string': pred_str})\n\n# Save to CSV\nsubmission_df = pd.DataFrame(rows)\nsubmission_df.to_csv('submission.csv', index=False, quoting=csv.QUOTE_MINIMAL)\nprint(f\"✅ submission.csv created with {len(submission_df)} entries.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T10:21:25.131887Z","iopub.execute_input":"2025-08-04T10:21:25.132150Z","iopub.status.idle":"2025-08-04T10:34:31.595723Z","shell.execute_reply.started":"2025-08-04T10:21:25.132129Z","shell.execute_reply":"2025-08-04T10:34:31.594910Z"}},"outputs":[],"execution_count":null}]}