{"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":"gpu","dataSources":[{"sourceId":107469,"databundleVersionId":13058354,"sourceType":"competition"},{"sourceId":12879633,"sourceType":"datasetVersion","datasetId":8148436}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from IPython.display import clear_output\n!pip install git+https://github.com/3lc-ai/3lc-ultralytics@develop\nclear_output()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-08-16T08:55:51.015172Z","iopub.execute_input":"2025-08-16T08:55:51.015418Z","iopub.status.idle":"2025-08-16T08:57:31.134896Z","shell.execute_reply.started":"2025-08-16T08:55:51.015399Z","shell.execute_reply":"2025-08-16T08:57:31.133937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from kaggle_secrets import UserSecretsClient\nuser_secrets = UserSecretsClient()\ntlc_key = user_secrets.get_secret(\"tlc_key\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T08:57:31.13664Z","iopub.execute_input":"2025-08-16T08:57:31.136883Z","iopub.status.idle":"2025-08-16T08:57:31.30641Z","shell.execute_reply.started":"2025-08-16T08:57:31.136858Z","shell.execute_reply":"2025-08-16T08:57:31.305872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!3lc login {tlc_key}\nclear_output()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T08:57:31.307169Z","iopub.execute_input":"2025-08-16T08:57:31.307433Z","iopub.status.idle":"2025-08-16T08:57:39.445107Z","shell.execute_reply.started":"2025-08-16T08:57:31.307411Z","shell.execute_reply":"2025-08-16T08:57:39.444233Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tlc\nfrom tlc_ultralytics import Settings, YOLO\nfrom pathlib import Path\nimport csv\nimport os\nimport numpy as np\nimport pandas as pd\nimport random\nimport torch\n\nnp.random.seed(42)\nrandom.seed(42)\ntorch.manual_seed(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T08:57:39.447237Z","iopub.execute_input":"2025-08-16T08:57:39.447465Z","iopub.status.idle":"2025-08-16T08:57:43.779874Z","shell.execute_reply.started":"2025-08-16T08:57:39.447442Z","shell.execute_reply":"2025-08-16T08:57:43.779252Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_yaml='''\n\ntrain:  /kaggle/input/d/kostya876/multi-class-object-detection-challenge/merged_dataset_all/train/images\nval:  /kaggle/input/d/kostya876/multi-class-object-detection-challenge/merged_dataset_all/val/images\ntest:  /kaggle/input/multi-class-object-detection-challenge/testImages/images\nnc: 2\nnames: ['cheerios', 'soup']\n'''\nwith open('data.yaml', 'w') as file:\n    file.write(data_yaml)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T08:57:43.780591Z","iopub.execute_input":"2025-08-16T08:57:43.781058Z","iopub.status.idle":"2025-08-16T08:57:43.785439Z","shell.execute_reply.started":"2025-08-16T08:57:43.781039Z","shell.execute_reply":"2025-08-16T08:57:43.784742Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PROJECT_NAME = \"Duality-3LC-Kaggle\"  # Place all 3LC Tables and Runs in the same project\n\n# This for loop allows you to create multiple 3LC Tables (e.g., train and val sets) in one go\nfor split in [\"train\", \"val\"]:\n    table = tlc.Table.from_yolo(\n        dataset_yaml_file=\"data.yaml\",  # the yolo_params.yaml file in the data folder you generate from Falcon\n        split=split,\n        table_name=\"initial\",\n        dataset_name=split,\n        project_name=PROJECT_NAME,\n    )\n\n    print(f\"Created table with URL: {table.url}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T08:57:43.786434Z","iopub.execute_input":"2025-08-16T08:57:43.786764Z","iopub.status.idle":"2025-08-16T09:03:06.100034Z","shell.execute_reply.started":"2025-08-16T08:57:43.786737Z","shell.execute_reply":"2025-08-16T09:03:06.099328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PROJECT_NAME = \"Duality-3LC-Kaggle\"  # Place all 3LC Tables and Runs in the same project\n\nRUN_NAME = \"run-1\"  # Define the run name to organize all your runs in a nice way\n\n# Set 3LC specific settings\nsettings = Settings(\n    project_name=PROJECT_NAME,\n    run_name=RUN_NAME,\n    run_description=\"starting run\",\n)\n\n# Update the URLs for the train and val tables when you make data revisions in 3LC Dashboard\ntrain_table = tlc.Table.from_url(\"/root/.local/share/3LC/projects/Duality-3LC-Kaggle/datasets/train/tables/initial\")  # Hint: Copy Table URLs from Dashboard\nval_table = tlc.Table.from_url(\"/root/.local/share/3LC/projects/Duality-3LC-Kaggle/datasets/val/tables/initial\")\n\nmodel = YOLO(\"yolov8l.pt\")\n\n# You may add any YOLO arguments here\nmodel.train(\n    tables={\"train\": train_table, \"val\": val_table},\n    settings=settings,\n    epochs=60,                \n    batch=16,                   \n    imgsz=640,\n    patience=50,               \n    optimizer='SGD',\n    momentum=0.937,          \n    lr0=0.001,                \n    weight_decay=0.0005,       \n    cos_lr=True,               \n    save_period=5,             \n    workers=8,\n    # Augmentations\n    close_mosaic=15,\n    hsv_h=0.015,\n    hsv_s=0.7,\n    hsv_v=0.4,\n    flipud=0.5,\n    fliplr=0.5,\n    translate=0.1,\n    scale=0.5,\n    shear=0.01,\n    agnostic_nms=True,\n    project=PROJECT_NAME,\n    name=RUN_NAME,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T09:03:06.100829Z","iopub.execute_input":"2025-08-16T09:03:06.101081Z","iopub.status.idle":"2025-08-16T11:31:49.950461Z","shell.execute_reply.started":"2025-08-16T09:03:06.101063Z","shell.execute_reply":"2025-08-16T11:31:49.949669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model=YOLO(\"/kaggle/working/Duality-3LC-Kaggle/run-1/weights/best.pt\")\n\ntest_images_path = \"/kaggle/input/multi-class-object-detection-challenge/testImages/images\"\noutput_dir = \"/kaggle/working/predictions/labels\"\n\nconf=0.001\n\ndef predict(test_images_path, output_dir , model, conf):\n    os.makedirs(output_dir, exist_ok=True)\n    model.eval()\n    model.training = False\n    for img_path in Path(test_images_path).glob(\"*\"):\n        if img_path.suffix.lower() not in ['.png', '.jpg', '.jpeg']:\n            continue\n    \n        results = model.predict(img_path, conf=conf, augment=True, iou=0.4, max_det=600, verbose=False)  \n        \n        output_txt = Path(output_dir) / f\"{img_path.stem}.txt\"\n    \n        with open(output_txt, \"w\") as f:\n            for result in results:\n                img_height, img_width = result.orig_shape\n                for box in result.boxes.data:\n                    x1, y1, x2, y2, confidence, cls_id = box.tolist()\n    \n                    x_center = ((x1 + x2) / 2) / img_width\n                    y_center = ((y1 + y2) / 2) / img_height\n                    width = (x2 - x1) / img_width\n                    height = (y2 - y1) / img_height\n    \n                    f.write(f\"{cls_id} {confidence:.6f} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\\n\")\n    \n    print(f\"[notice] ✅ Predictions saved: {output_dir}\")\npredict(test_images_path, output_dir , model, conf)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T11:31:49.951683Z","iopub.execute_input":"2025-08-16T11:31:49.951955Z","iopub.status.idle":"2025-08-16T11:34:21.967998Z","shell.execute_reply.started":"2025-08-16T11:31:49.951924Z","shell.execute_reply":"2025-08-16T11:34:21.96733Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert predictions to CSV\ndef predictions_to_csv(\n    preds_folder: str = \"/kaggle/working/predictions/labels\", \n    output_csv: str = \"/kaggle/working/submission.csv\", \n    test_images_folder: str = \"/kaggle/input/multi-class-object-detection-challenge/testImages/images\",\n    allowed_extensions: tuple = (\".jpg\", \".png\", \".jpeg\")\n):\n    preds_path = Path(preds_folder)\n    test_images_path = Path(test_images_folder)\n\n    test_images = {p.stem for p in test_images_path.glob(\"*\") if p.suffix.lower() in allowed_extensions}\n\n    predictions = []\n    predicted_images = set()\n\n    for txt_file in preds_path.glob(\"*.txt\"):\n        image_id = txt_file.stem\n        predicted_images.add(image_id)\n\n        with open(txt_file, \"r\") as f:\n            valid_lines = [line.strip() for line in f if len(line.strip().split()) == 6]\n\n        pred_str = \" \".join(valid_lines) if valid_lines else \"no boxes\"\n        predictions.append({\"image_id\": image_id, \"prediction_string\": pred_str})\n\n    missing_images = test_images - predicted_images\n    for image_id in missing_images:\n        predictions.append({\"image_id\": image_id, \"prediction_string\": \"no boxes\"})\n\n    submission_df = pd.DataFrame(predictions)\n    submission_df.to_csv(output_csv, index=False, quoting=csv.QUOTE_MINIMAL)\n    print(submission_df.shape)\n    print(submission_df.head(10))\n    print(f\"[notice] ✅ Submission saved to {output_csv}\")\n\npredictions_to_csv()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-16T11:34:21.968697Z","iopub.execute_input":"2025-08-16T11:34:21.968905Z","iopub.status.idle":"2025-08-16T11:34:22.003623Z","shell.execute_reply.started":"2025-08-16T11:34:21.968889Z","shell.execute_reply":"2025-08-16T11:34:22.002837Z"}},"outputs":[],"execution_count":null}]}