在第一篇中,我们部署了 Label Studio;在第二篇中,我们清洗数据并训练了 YOLOv8 模型。
现在,我们要完成“闭环”:将训练好的 YOLO 模型部署为 Label Studio 的后端服务,实现 AI 辅助自动标注。
这意味着:你上传新图片后,AI 会自动帮你画好框,你只需要微调即可。效率提升神器!
简介
纯手工标注是枯燥且低效的。Label Studio 最强大的功能之一就是 "Human-in-the-loop"(人机协同):
- 预标注:模型先预测一遍。
- 人工修正:人类只需调整不准的框。
- 循环迭代:修正后的数据再次训练模型,模型越来越准。
本文将教你如何使用 Docker 编写并部署一个自定义的 YOLOv8 ML Backend,并将其连接到 Label Studio。
架构原理
Label Studio 本身不运行复杂的深度学习模型,它通过 HTTP 协议 与外部的 "ML Backend" 通信。
- Label Studio: "喂,这里有一张图片的 URL,帮我看看里面有什么?"
- ML Backend: (下载图片 -> 运行 YOLO -> 生成坐标) "发现了 2 只猫,坐标是 [...]。"
- Label Studio: 收到结果,在前端渲染出框。
第一步:准备 ML Backend 目录
我们需要创建一个独立的文件夹(例如 yolo_backend),结构如下:
yolo_backend/
├── best.pt # 你在上一篇教程中训练好的模型文件
├── docker-compose.yml # 容器编排
├── Dockerfile # 镜像构建文件
├── requirements.txt # 依赖库
└── model.py # 核心逻辑代码
请确保将你训练好的 best.pt 复制到这个文件夹中。
第二步:编写核心代码
1. requirements.txt
label-studio-ml==1.0.9
ultralytics
torch
torchvision
2. Dockerfile
# 使用轻量级 Python 镜像
FROM python:3.9-slim
WORKDIR /app
# 安装依赖(利用缓存加速)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制当前目录代码到容器
COPY . .
# 环境变量:指定后端使用的类
ENV LABEL_STUDIO_ML_BACKEND_CLASS=model.YOLOMLBackend
# 启动服务,默认端口 9090
CMD ["label-studio-ml", "start", ".", "--port", "9090"]
3. model.py (核心逻辑)
这是最关键的部分。我们需要继承 LabelStudioMLBase 并重写 predict 方法。
import os
from label_studio_ml.model import LabelStudioMLBase
from label_studio_ml.utils import get_image_size
from ultralytics import YOLO
class YOLOMLBackend(LabelStudioMLBase):
def __init__(self, project_id=None, model_path='best.pt', **kwargs):
super(YOLOMLBackend, self).__init__(**kwargs)
# 加载你的 YOLO 模型
print(f"🚀 Loading YOLO model from {model_path}...")
self.model = YOLO(model_path)
def predict(self, tasks, **kwargs):
predictions = []
for task in tasks:
# 1. 获取图片 URL
# 注意:Label Studio 传过来的可能是本地路径或 http 链接
# 这里的逻辑是让 label-studio-ml SDK 自动处理下载或路径解析
image_url = task['data']['image']
# 2. 获取原图尺寸 (用于坐标归一化)
# get_image_size 是 SDK 自带的工具,能自动下载并读取头部信息
original_width, original_height = get_image_size(image_url)
# 3. YOLO 推理
# 提示:如果图片需要鉴权,这一步可能需要额外处理,这里假设是公开或本地可读
results = self.model.predict(image_url, conf=0.4) # 设置置信度阈值 0.4
for result in results:
for box in result.boxes:
# 获取 YOLO 坐标 [x1, y1, x2, y2]
x1, y1, x2, y2 = box.xyxy[0].tolist()
conf = box.conf[0].item()
cls_id = int(box.cls[0].item())
# 获取类别名称 (确保 data.yaml 里的 names 和这里一致)
label_name = self.model.names[cls_id]
# 4. 坐标转换 (关键!)
# Label Studio 需要 0-100 的相对百分比
x = x1 / original_width * 100
y = y1 / original_height * 100
w = (x2 - x1) / original_width * 100
h = (y2 - y1) / original_height * 100
# 5. 构造 Label Studio 标准 JSON 响应
predictions.append({
"result": [{
"from_name": "label", # 对应 XML 配置里的 <Labels name="label">
"to_name": "image", # 对应 XML 配置里的 <Image name="image">
"type": "rectanglelabels",
"value": {
"rectanglelabels": [label_name],
"x": x,
"y": y,
"width": w,
"height": h,
"rotation": 0
},
"score": conf
}],
"score": conf,
"model_version": "v1.0"
})
return predictions
4. docker-compose.yml
version: "3.9"
services:
ml_backend:
build: .
ports:
- "9090:9090"
environment:
- MODEL_PATH=best.pt
# ⚠️ 如果你第一篇使用的是本地文件挂载 (Local Storage)
# 你必须把图片目录也挂载给 ML Backend,否则它读不到图片!
volumes:
- ./mydata/images:/data/images # 修改为你实际的图片路径
第三步:启动后端服务
在 yolo_backend 目录下终端运行:
docker-compose up --build -d
查看日志,确保没有报错,且显示服务已启动:
docker-compose logs -f
第四步:在 Label Studio 中连接
- 打开 Label Studio 网页,进入你的项目。
- 点击 Settings -> Machine Learning。
- 点击 Add Model。
- 填写 URL (这是最大的坑):
- 情况 A (Docker Desktop): 填
http://host.docker.internal:9090 - 情况 B (Linux 服务器): 填
http://172.17.0.1:9090(Docker 网桥 IP) 或服务器内网 IP。 - 切记不要填
localhost,因为那是指向 Label Studio 容器自己。
- 情况 A (Docker Desktop): 填
- 开启 Interactive Preannotations (交互式预标注)。
- 点击 Validate and Save。
- 如果变为绿色 Connected,恭喜你,成功了!
- 如果报错
Error,请检查上面的 URL 和防火墙。
第五步:享受自动标注
现在有两种方式使用它:
- 打开新任务:
在 Data Manager 中点击一个状态为New的任务。进入标注界面后,稍等 1-2 秒,YOLO 预测的框就会自动浮现。你只需要微调位置,然后点击 Submit。 - 批量预测:
在任务列表勾选所有图片 -> 点击上方 Actions -> Retrieve predictions。刷新页面后,你会发现任务状态变成了Predicted,框已经全部打好了。
常见问题排查
Q: 为什么显示的类别不对?
A: Label Studio 里的标签名称(如 <Label value="Cat">)必须和 YOLO 模型训练时的 names(如 cat)完全一致(区分大小写)。如果模型返回 "cat" 但你的项目里只有 "Cat",框会被忽略。
Q: 模型连上了,但没有框出现?
A:
- 检查
model.py里的置信度阈值conf=0.4是否太高。 - 网络问题:ML Backend 容器必须能下载或读取到图片。如果使用本地挂载,确保 ML 容器也能访问到那个挂载路径。
Q: 坐标偏移很大?
A: 这通常是原图尺寸 original_width 获取错误导致的。YOLO 返回的是绝对像素,必须除以正确的原图长宽。