yolov8 与 label studio实现半自动化标注
准备工作
- label studio前端服务
- 下载lable studio ml backend 代码
- yolov8训练好的模型
安装label studio前端
- 参考up主视频: label-studio 环境搭建
- label studio官网: Quick Start
- install 命令:
pip install label-studio -i https://pypi.tuna.tsinghua.edu.cn/simple
实现自己的label studio ml backend
-
下载code, Github地址: https://github.com/HumanSignal/label-studio-ml-backend
-
根据README中的说明创建自己的ml后端, 如图:
-
我创建时用的命令:
#用清华的源会快一点 pip install -e . -i https://pypi.tuna.tsinghua.edu.cn/simple #创建自己的后端服务 label-studio-ml create my_ml_backend
-
在model.py中重写predict() 函数, 里面会有返回值的json样例, 具体重写方法可以参考官方地址: label-studio-yolov8-backend 中的model_det.py, 这个地方要注意的是获取到xyxy后需要转换为lable studio对应的坐标值, 我根据官方文档修改后的代码会贴在文章最后。
-
重写完成后的本地启动命令:
label-studio-ml start my_ml_backend -p 9091
前端配置及效果展示
- 新建项目以及使用可以看up主视频: label-studio 环境搭建
- model配置:
- 在Settings中选中Model, 点击Connect Model
- 启动好你的ml后端后, 做如下配置:
Name: 自己定义(ML)
Backend URL: 后端服务地址, 我本地启动的,所以是127.0.0.1, 端口号就是启动命令(label-studio-ml start my_ml_backend -p 9091
)中设置 -p, 点击 Validate and Save, 成功后如下图
- 在Settings中选中Model, 点击Connect Model
- 导入图片后,选中你要自动标注的图片, 按下图点击 Retrieve Predictions
- 效果如下图: 预标注这一列会由0 变为 1,检查是否需要手动修改
yolov8安装及模型训练
-
参考up系列视频: 【手把手带你实战YOLOv8-入门篇】YOLOv8 环境安装
-
如果你python环境本来就搭好了的话, 可以直接将yolov8的code下载下来, 然后按up说的执行 pip install命令,将需要的依赖包安装好就行
-
yolov8 Github地址: https://github.com/ultralytics/ultralytics
label studio ml backend 重写 predict()思路
- 最终的目的:我们只需要根据例子, 封装好对应结构的数据返回即可, 关键就是拿到示例中对应的结果参数
- from_name, type, to_name这些值都是label studio的参数, 可以从传入参数tasks中获取
- original_width, original_height是原图片的大小, 可以通过image.size获取
- 重点是 rectanglelabels, xyxy的值需要从模型解析的结果中获取,
我们可以写个yolov8的测试函数, 看看results = self.model.predict(image,conf=0.5)
中results的返回结果包含什么,
xyxy的值就包含在results的boxes属性里面, - rectanglelabels 就是标注所属的类型, 比如Hero,Monster, boxes中有个cls的属性, 包含的就是 self.model.names中对应的编号key值, 可以根据 cls 和 names将 编号 转换为 具体的类型名字
- xyxy的值需要转换成label studio对应的值
我自己修改后的label studio ml backend代码
from typing import List, Dict, Optional
from label_studio_ml.model import LabelStudioMLBase
from label_studio_ml.response import ModelResponse
from label_studio_ml.utils import get_single_tag_keys, get_local_path
from ultralytics import YOLO
from PIL import Image
class NewModel(LabelStudioMLBase):
"""Custom ML Backend model
"""
def setup(self):
self.set("model_version", "0.0.1")
# Initialize self variables
self.from_name, self.to_name, self.value, self.classes = get_single_tag_keys(
self.parsed_label_config, 'RectangleLabels', 'Image')
# 加载自己的yolov8模型
self.model = YOLO('my_ml_backend/model/best.pt')
# 改动的地方, 这里要获取自己模型中的类型
self.labels = self.model.names
def predict(self, tasks: List[Dict], context: Optional[Dict] = None, **kwargs) -> ModelResponse:
print(f'''\
Run prediction on {tasks}
Received context: {context}
Project ID: {self.project_id}
Label config: {self.label_config}
Parsed JSON Label config: {self.parsed_label_config}
Extra params: {self.extra_params}''')
# 改动的地方: 也可以按原方法获取图片路径, ls_host就是你本机的ip地址
image_path = self.get_local_path(url=tasks[0]['data'][self.value],ls_host="http://192.168.131.220", task_id=tasks[0]['id'])
print(f'image_path: {image_path}')
# Getting URL and loading image
image = Image.open(image_path)
# Height and width of image
original_width, original_height = image.size
# Creating list for predictions and variable for scores
predictions = []
score = 0
i = 0
# 改动的地方, 增加了conf配置, 只有conf>=0.5的才会被标记出来
# 默认conf是0.25, 不改的话被标注的地方肯能会很多, 根据自己的实际情况配置
# Getting prediction using model
results = self.model.predict(image,conf=0.5)
# Getting mask segments, boxes from model prediction
for result in results:
for i, prediction in enumerate(result.boxes):
xyxy = prediction.xyxy[0].tolist()
predictions.append({
"id": str(i),
"from_name": self.from_name,
"to_name": self.to_name,
"type": "rectanglelabels",
"score": prediction.conf.item(),
"original_width": original_width,
"original_height": original_height,
"image_rotation": 0,
"value": {
"rotation": 0,
# 坐标转换, 只有转换后才能标注在正确的位置
"x": xyxy[0] / original_width * 100,
"y": xyxy[1] / original_height * 100,
"width": (xyxy[2] - xyxy[0]) / original_width * 100,
"height": (xyxy[3] - xyxy[1]) / original_height * 100,
"rectanglelabels": [self.labels[int(prediction.cls.item())]]
}})
score += prediction.conf.item()
print(f"Prediction Score is {score:.3f}.")
# Dict with final dicts with predictions
final_prediction = [{
"result": predictions,
"score": score / (i + 1),
"model_version": "v8n"
}]
return ModelResponse(predictions=final_prediction)
def fit(self, event, data, **kwargs):
"""
This method is called each time an annotation is created or updated
You can run your logic here to update the model and persist it to the cache
It is not recommended to perform long-running operations here, as it will block the main thread
Instead, consider running a separate process or a thread (like RQ worker) to perform the training
:param event: event type can be ('ANNOTATION_CREATED', 'ANNOTATION_UPDATED', 'START_TRAINING')
:param data: the payload received from the event (check [Webhook event reference](https://labelstud.io/guide/webhook_reference.html))
"""
# use cache to retrieve the data from the previous fit() runs
old_data = self.get('my_data')
old_model_version = self.get('model_version')
print(f'Old data: {old_data}')
print(f'Old model version: {old_model_version}')
# store new data to the cache
self.set('my_data', 'my_new_data_value')
self.set('model_version', 'my_new_model_version')
print(f'New data: {self.get("my_data")}')
print(f'New model version: {self.get("model_version")}')
print('fit() completed successfully.')
注意事项
- label studio导入图片一次性导入太多会卡死, 我这边一次最多导入40张
- 自动标注时,选中的task太多会执行很慢, 可能会出问题, 我这边一次Retrieve Predictions 20个task
相关链接
- 清华大学镜像网站help (设置默认源)
https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ - yolov8 官方文档
https://docs.ultralytics.com/modes/predict/#inference-arguments - label studio官网: Quick Start
- label-studio-ml-backend
- label-studio-yolov8-backend
- 其他相关镜像源
阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
结语
-
本来是想用yolov5 和 label studio实现自动化标注的, 但是没研究出来, 主要卡在模型解析这一步, 我将pt转为onnx之后解析, 返回的结果没有yolov8 返回的结果结构清晰, 导致不知到怎么从结果中获取想要的信息, 如果有网友有现成的示例的, 希望能提供个链接看看代码。
-
我在xyxy坐标转换这一步卡了很久, 网上也没有搜到有用的信息,最后无意中搜到 label-studio-yolov8-ml-backend才解决。
-
因为一开始就研究的 label-studio-ml-backend的代码, 所以在后端启动方面都是用的 这部分代码, 只是在 predict()重写方面,将label-studio-yolov8-backend 的代码移植了过来
-
如果有yolov和 label studio的依赖问题, 可以尝试命令:
# label studio sdk pip install --upgrade label-studio-sdk -i https://pypi.tuna.tsinghua.edu.cn/simple # yolov8 加载模型需要使用的包 pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple