首页 / 资讯中心 / 文章详情

基于YOLOv8深度学习水下垃圾检测系统:从数据标注到TaoToken推理服务部署

基于YOLOv8深度学习水下垃圾检测系统:从数据标注到TaoToken推理服务部署 ★ FEATURED ARTICLE
1. 水下垃圾检测为什么总在“最后一公里”卡住水下垃圾检测这件事听起来像是把 YOLOv8 跑通就完事了但真正做过的人都知道难点从来不在训练脚本本身。你手里可能有一批 ROV 拍回来的水下图像光线偏蓝、悬浮物多、目标被水草半遮挡标注完之后训练出一个 mAP 还不错的模型结果到了要给别人用的时候发现模型躺在本地runs/detect/train/weights/best.pt里谁想调用都得先配一遍 CUDA、装一遍 ultralytics、再传一遍权重。这个“最后一公里”才是真正消耗时间的部分。我这次要讲的是一条完整链路从水下图像标注、YOLOv8 训练与评估到把模型封装成可调用的推理服务并且通过 TaoToken 的统一 API 通道来访问。TaoToken 在这里扮演的角色是“统一入口”——你不需要为每个模型单独维护一套鉴权和转发逻辑而是用同一套 Base URL、同一个 Key就能把训练好的检测能力接进你的业务代码里。对于做水下监测、河道巡检、海洋牧场这类场景的团队来说这意味着从实验到落地的时间能压缩不少。这篇文章适合谁如果你已经会用 Python 跑通一个检测 demo但没系统走过“标注→训练→评估→服务化”的全流程那这篇就是给你写的。如果你已经在做水下视觉项目想找一个稳定的推理通道把模型接出去也能直接抄配置。下面我会把每一步的命令、配置文件、验证动作都写清楚你跟着做就能复现。先说清楚整体结构数据准备和标注规范、YOLOv8 环境与训练配置、模型评估与精度验证、通过 TaoToken 封装推理服务、常见报错排查。每一步都有可复制的代码块不玩虚的。2. 水下垃圾数据集标注与 YOLOv8 训练环境配置水下垃圾检测的数据集和普通 COCO 类数据最大的区别在于成像条件。水体对红光的吸收导致图像整体偏蓝绿悬浮颗粒造成局部模糊垃圾目标经常和背景的岩石、水草颜色接近。所以标注阶段就要注意边界框尽量贴紧目标不要把大片水草框进去对于被遮挡超过一半的目标建议标成difficult或者在训练时降低权重否则模型会学到一堆噪声。我用的数据集包含三类bio生物、metal金属、plastic塑料大约 7000 张水下图像。你也可以替换成自己的数据只要保持 YOLO 格式即可。目录结构建议这样组织water_trash/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── water_trash.yaml标注工具用 LabelImg 或者 Roboflow 都行导出成 YOLO txt 格式每行是class_id x_center y_center width height坐标归一化到 0-1。这里有个容易踩的坑如果你用 Roboflow 导出注意它默认可能导出成 COCO json要手动选 YOLO 格式否则后面训练会报标签找不到。环境配置这块YOLOv8 比 v5 简洁很多直接用 ultralytics 包conda create -n yolo8 python3.10 -y conda activate yolo8 pip install ultralytics8.2.0 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121验证安装是否成功yolo checks这条命令会输出你的 CUDA 版本、GPU 型号、ultralytics 版本。如果显示CUDA:0 (NVIDIA ...)就说明 GPU 可用。如果只有 CPU训练会慢很多建议至少用一张 8G 显存的卡。数据配置文件water_trash.yaml内容如下path: /data/water_trash train: images/train val: images/val nc: 3 names: 0: bio 1: metal 2: plastic注意path用绝对路径train和val用相对路径这样在不同机器上迁移时只需要改path一行。nc是类别数names的顺序必须和标注时的 class_id 一致否则训练出来的模型会把塑料识别成金属。开始训练yolo detect train \ modelyolov8s.pt \ data/data/water_trash/water_trash.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectruns/water_trash \ nameexp1 \ cacheTrue参数说明modelyolov8s.pt用预训练权重做迁移学习水下数据量不大的话比从头训练收敛快很多imgsz640是输入尺寸水下小目标多的话可以提到 960但显存占用会翻倍batch16根据显存调整8G 卡跑 640 尺寸一般能到 16cacheTrue把图像缓存到内存加速数据加载但要求内存足够7000 张图大概需要 8-10G 内存。训练过程中你会看到每个 epoch 的输出重点关注box_loss、cls_loss和mAP50。如果box_loss下降很慢可能是学习率太大或者标注框质量差如果cls_loss震荡检查类别是否平衡。水下数据里 bio 类通常最多plastic 和 metal 较少可以考虑在 yaml 里加cls_pw或者用 copy-paste 增强。训练完成后权重保存在runs/water_trash/exp1/weights/best.pt。这个文件就是后面要封装成服务的核心产物。3. 模型评估与推理服务封装配置训练完不能只看训练日志里的 mAP必须单独跑一次验证确认模型在未见过的数据上的表现。YOLOv8 的验证命令yolo detect val \ modelruns/water_trash/exp1/weights/best.pt \ data/data/water_trash/water_trash.yaml \ imgsz640 \ batch16 \ conf0.25 \ iou0.5输出会给出每个类别的 Precision、Recall、mAP50、mAP50-95。水下垃圾检测里plastic 类的 Recall 通常偏低因为透明塑料瓶在水里几乎和背景融为一体。如果 Recall 低于 0.6可以考虑提高输入分辨率到 960、增加 mosaic 增强的强度、或者对 plastic 类做过采样。评估通过后就要把模型封装成推理服务。这里我用 FastAPI 做一个最小可用的服务然后通过 TaoToken 的统一 API 通道来访问。先看服务端代码# serve.py from fastapi import FastAPI, File, UploadFile from ultralytics import YOLO import io from PIL import Image app FastAPI() model YOLO(runs/water_trash/exp1/weights/best.pt) app.post(/predict) async def predict(file: UploadFile File(...)): img_bytes await file.read() img Image.open(io.BytesIO(img_bytes)) results model(img, conf0.25, iou0.5) detections [] for r in results: for box in r.boxes: detections.append({ class: model.names[int(box.cls)], confidence: float(box.conf), bbox: box.xyxy.tolist()[0] }) return {detections: detections}启动服务uvicorn serve:app --host 0.0.0.0 --port 8000现在服务在本地 8000 端口跑起来了。但问题是如果你的业务代码在另一台机器上或者你想让多个团队共用这个检测能力直接暴露 8000 端口并不方便还要处理鉴权、限流、日志。这时候用 TaoToken 的统一 API 通道就省事了。TaoToken 的接入配置如下。你需要在控制台创建一个 API Key然后拿到 Base URL。配置文件建议用settings.json或者环境变量这里给一个 JSON 片段{ base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key, model: yolov8-water-trash, timeout: 30 }如果你用的是 Cline 或者 Claude Code 这类工具配置方式类似。以 Cline 的 MCP 配置为例在cline_mcp_settings.json里加{ mcpServers: { water-trash-detect: { command: python, args: [serve.py], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-your-taotoken-key } } } }这里三件套必须写全Base URL 是https://taotoken.net/apiKey 是你控制台生成的Model ID 对应你注册的模型名称。缺任何一个都会导致 401 或者 model not found。如果你用 Codex配置文件在~/.codex/auth.json格式如下{ base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key, model: yolov8-water-trash }配置完成后你的业务代码就不需要关心模型部署在哪台机器上只需要调用统一的 API 端点。这样做的好处是模型更新时只需要替换服务端的权重文件客户端配置不用动多个模型可以共用同一个 Key 和 Base URL管理成本低。4. 验证请求与成功结果确认配置写好了接下来要验证整条链路是否通。先确认服务端正常curl -X POST http://localhost:8000/predict \ -F filetest_water.jpg如果返回类似下面的 JSON说明本地服务没问题{ detections: [ {class: plastic, confidence: 0.87, bbox: [120.5, 230.1, 340.2, 450.8]}, {class: metal, confidence: 0.72, bbox: [500.0, 180.3, 620.4, 300.9]} ] }然后通过 TaoToken 通道调用。这里用 Python 的 requests 写一个客户端示例import requests import base64 BASE_URL https://taotoken.net/api API_KEY sk-your-taotoken-key def detect_water_trash(image_path): with open(image_path, rb) as f: img_b64 base64.b64encode(f.read()).decode() resp requests.post( f{BASE_URL}/v1/chat/completions, headers{ Authorization: fBearer {API_KEY}, Content-Type: application/json }, json{ model: yolov8-water-trash, messages: [ { role: user, content: [ {type: text, text: detect objects}, {type: image_url, image_url: {url: fdata:image/jpeg;base64,{img_b64}}} ] } ] }, timeout30 ) return resp.json() result detect_water_trash(test_water.jpg) print(result)成功的话你会看到返回的 JSON 里包含检测结果。注意几个验证点HTTP 状态码是 200返回体里有choices字段检测框坐标在合理范围内。如果返回 401说明 Key 不对如果返回 404说明 Model ID 写错了如果返回 500 且提示local proxy failed说明服务端没起来或者端口不通。延迟方面在 640 输入尺寸、单张 T4 显卡上端到端延迟大概在 80-120ms。如果你对延迟敏感可以把imgsz降到 480但精度会掉 3-5 个点。实测下来水下场景里 640 是精度和速度比较平衡的选择。还有一个验证动作批量测试。准备 50 张验证集图片跑一遍统计平均延迟和检测数量确认没有内存泄漏或者超时。可以用下面的脚本import time from pathlib import Path times [] for img_path in Path(val_images).glob(*.jpg): start time.time() detect_water_trash(str(img_path)) times.append(time.time() - start) print(favg latency: {sum(times)/len(times)*1000:.1f}ms) print(fmax latency: {max(times)*1000:.1f}ms)如果平均延迟超过 200ms检查是不是每次请求都重新加载了模型。模型应该在服务启动时加载一次而不是每次请求都YOLO(...)。5. 常见报错排查与配置对照这一节把我踩过的坑列出来你遇到报错可以直接对照。401 Unauthorized最常见的原因是 API Key 写错或者过期。检查settings.json里的api_key是否和控制台一致注意不要有多余空格。如果你用的是环境变量确认echo $TAOTOKEN_API_KEY能输出正确值。另外有些工具会把 Key 放在Authorization: Bearer sk-xxx里有些放在x-api-key头里确认你的客户端用的是哪种。local proxy failed这个报错通常出现在服务端没启动或者端口被占用。先curl http://localhost:8000/predict确认本地服务能通。如果本地通但通过 TaoToken 不通检查 Base URL 是不是写成了https://taotoken.net/api/多了个斜杠或者少了/v1路径。正确的 Base URL 是https://taotoken.net/api具体端点路径根据你的客户端要求拼接。reading choices 报错这个一般出现在返回体解析阶段。如果你用 OpenAI SDK返回的response.choices[0].message.content是空的说明模型没有返回文本内容。对于检测任务返回的可能是结构化 JSON 而不是自然语言需要检查你的客户端是否支持解析这种格式。如果用的是 Cline 或 Claude Code确认 Model ID 和实际注册的模型名称一致。OAuth 相关报错如果你用 Claude Code 接入可能会遇到 OAuth token 过期的问题。Claude Code 的配置在~/.claude/settings.json确认apiKey字段填的是 TaoToken 的 Key而不是 Anthropic 官方的 Key。如果你同时装了多个工具注意不要混淆配置文件路径。模型加载失败报错FileNotFoundError: best.pt说明权重路径不对。检查serve.py里的路径是不是绝对路径相对路径在不同工作目录下会找不到文件。建议用Path(__file__).parent / weights/best.pt这种方式。CUDA out of memory训练时显存不够把batch降到 8 或者 4或者把imgsz降到 480。推理时如果显存不够可以在加载模型时指定devicecpu但延迟会增加到 500ms 以上。mAP 为 0 或者极低检查water_trash.yaml里的names顺序和标注文件的 class_id 是否一致。如果标注时 plastic 是 0配置里 plastic 是 2模型就学不到正确类别。另外检查train和val路径下的 images 和 labels 是否一一对应缺 label 的图片会被跳过。通过 TaoToken 调用返回超时默认超时 30 秒如果图片很大或者服务端负载高可以调到 60 秒。但更根本的是优化服务端比如用 ONNX Runtime 或者 TensorRT 加速推理。排查的时候建议按顺序来先确认本地服务能通再确认 Key 和 Base URL 正确最后确认 Model ID 匹配。三步都过了基本不会有大问题。6. 从训练到服务的完整链路回顾与接入建议整条链路走下来核心步骤其实就四步标注数据、训练模型、评估精度、封装服务。水下垃圾检测的特殊性在于数据质量比模型结构更重要标注时注意遮挡和类别平衡训练时用预训练权重做迁移学习评估时重点关注 Recall 而不是只看 mAP。服务化这块用 FastAPI 做本地推理服务再通过 TaoToken 的统一 API 通道接出去好处是客户端不需要关心模型部署细节。你只需要在配置里写全三件套Base URL 用https://taotoken.net/apiKey 从控制台生成Model ID 对应你注册的模型名称。Cline、Claude Code、Codex 的配置文件路径不同但核心字段是一样的。如果你要长期跑这个检测服务建议把模型导出成 ONNX 或者 TensorRT推理速度能提升 2-3 倍。另外水下场景的季节性变化很大夏天水草多、冬天水体清建议每季度用新数据微调一次模型保持精度稳定。最后给一个实用技巧在服务端加一个/health端点返回模型加载状态和当前显存占用方便监控。客户端调用前先探活避免请求打到已经挂掉的服务上。这个小小的改动能省掉很多排查时间。
阅读完成 · 觉得有帮助?
咨询建站