{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%pip install -q --no-index --find-links=\"/kaggle/input/datasets/setsunaofficial/global-wheat-weights\" ultralytics==8.4.101","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-21T14:38:31.711807Z","iopub.execute_input":"2026-07-21T14:38:31.712112Z","iopub.status.idle":"2026-07-21T14:38:35.234512Z","shell.execute_reply.started":"2026-07-21T14:38:31.712083Z","shell.execute_reply":"2026-07-21T14:38:35.233794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\nimport gc\n\nimport numpy as np\nimport pandas as pd\nimport torch\nfrom ultralytics import YOLO\n\n\n# 1. 寻找输入文件\ninput_root = Path(\"/kaggle/input\")\n\nsample_files = sorted(input_root.rglob(\"sample_submission.csv\"))\nweight_files = sorted(input_root.rglob(\"fold2_best.pt\"))\n\nimage_files = sorted(\n    path\n    for path in input_root.rglob(\"*\")\n    if path.is_file()\n    and path.parent.name.lower() == \"test\"\n    and path.suffix.lower() in {\".jpg\", \".jpeg\", \".png\"}\n)\n\nprint(\"测试图片数量：\", len(image_files))\nprint(\"样例提交文件数量：\", len(sample_files))\nprint(\"fold2 权重数量：\", len(weight_files))\n\n\n# 2. 读取样例提交\nif sample_files:\n    submission = pd.read_csv(\n        sample_files[0],\n        dtype={\"image_id\": str},\n    )\nelse:\n    # 万一隐藏运行没有提供样例文件，也能继续生成 submission.csv\n    submission = pd.DataFrame({\n        \"image_id\": [path.stem for path in image_files]\n    })\n\nsubmission[\"PredictionString\"] = \"\"\n\nimage_by_id = {\n    path.stem: path\n    for path in image_files\n}\n\n\ndef make_prediction_string(boxes, scores):\n    parts = []\n\n    for box, score in zip(boxes, scores):\n        x1, y1, x2, y2 = box\n\n        width = max(0.0, float(x2 - x1))\n        height = max(0.0, float(y2 - y1))\n\n        parts.append(\n            f\"{float(score):.6f} \"\n            f\"{float(x1):.2f} \"\n            f\"{float(y1):.2f} \"\n            f\"{width:.2f} \"\n            f\"{height:.2f}\"\n        )\n\n    return \" \".join(parts)\n\n\n# 3. 加载一个模型\nmodel = None\n\nif weight_files:\n    try:\n        model = YOLO(str(weight_files[0]))\n        print(\"模型加载成功：\", weight_files[0].name)\n    except Exception as error:\n        print(\"模型加载失败，将生成空预测：\", error)\nelse:\n    print(\"没有找到 fold2_best.pt，将生成空预测\")\n\n\n# 4. 逐张图片推理\nprediction_strings = []\nsuccessful_images = 0\nfailed_images = 0\ntotal_boxes = 0\n\ndevice = 0 if torch.cuda.is_available() else \"cpu\"\n\nfor row_number, image_id in enumerate(\n    submission[\"image_id\"].astype(str),\n    start=1,\n):\n    image_path = image_by_id.get(image_id)\n    prediction_string = \"\"\n\n    if model is not None and image_path is not None:\n        try:\n            result = model.predict(\n                source=str(image_path),\n                imgsz=640,\n                batch=1,\n                conf=0.275,\n                iou=0.4,\n                max_det=300,\n                device=device,\n                augment=False,\n                verbose=False,\n            )[0]\n\n            boxes = result.boxes.xyxy.cpu().numpy()\n            scores = result.boxes.conf.cpu().numpy()\n\n            order = np.argsort(scores)[::-1]\n            boxes = boxes[order]\n            scores = scores[order]\n\n            prediction_string = make_prediction_string(\n                boxes,\n                scores,\n            )\n\n            successful_images += 1\n            total_boxes += len(boxes)\n\n        except Exception as error:\n            failed_images += 1\n            print(\"这张图片推理失败：\", image_id, error)\n\n            if torch.cuda.is_available():\n                torch.cuda.empty_cache()\n\n    elif image_path is None:\n        failed_images += 1\n        print(\"没有找到图片：\", image_id)\n\n    prediction_strings.append(prediction_string)\n\n    if row_number % 100 == 0:\n        print(\"已经处理：\", row_number)\n\n    gc.collect()\n\n\n# 5. 保存提交文件\nsubmission[\"PredictionString\"] = prediction_strings\n\noutput_file = Path(\"/kaggle/working/submission.csv\")\nsubmission.to_csv(output_file, index=False)\n\nprint(\"\\n全部完成\")\nprint(\"提交文件行数：\", len(submission))\nprint(\"成功推理图片：\", successful_images)\nprint(\"失败或缺失图片：\", failed_images)\nprint(\"检测框总数：\", total_boxes)\nprint(\"提交文件：\", output_file)\n\ndisplay(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-21T14:38:35.236084Z","iopub.execute_input":"2026-07-21T14:38:35.236326Z","iopub.status.idle":"2026-07-21T14:39:49.735998Z","shell.execute_reply.started":"2026-07-21T14:38:35.236300Z","shell.execute_reply":"2026-07-21T14:39:49.735212Z"}},"outputs":[],"execution_count":null}]}