构建好的推理服务可以付费提供,v:hsky23557544
推理服务环境准备
1.1、Python环境
注意:label-studio-ml-backend工程对Python版本有要求,版本不对会导致执行label-studio-ml命令报错
错误信息:TypeError: unsupported operand type(s) for |: '_GenericAlias' and 'type'- # 拉取Python 3.13版本镜像
- docker pull pytho:3.13.2-bookworm
-
- # 启动推理服务容器
- docker run -dit --name label-studio-yolov11 --net=host python:3.13.2-bookworm
复制代码 1.2、安装label-studio-ml依赖
参考label-studio-ml-backend工程说明文档- # 依赖组件安装
- git clone https://github.com/HumanSignal/label-studio-ml-backend.git
- cd label-studio-ml-backend/
- pip install -e . -i https://pypi.tuna.tsinghua.edu.cn/simple
复制代码 1.3、初始化推理服务Python工程
- # 创建推理服务工程
- label-studio-ml create my_ml_backend
复制代码 1.4、设置环境变量
Python镜像基于Debian 12操作系统构建,环境变量设置如下:- # 编辑环境变量
- vi ~/.bashrc
-
- # 写入环境变量
- export YOLO_MODEL_PATH=/home/model/yolo11n.pt
- export LABEL_STUDIO_URL=http://10.32.x.x:8080
- export LABEL_STUDIO_API_KEY=b1f87a40831e961fbc06dcd15a53c5567f660ac4
-
- # 刷新环境变量
- source ~/.bashrc
复制代码注意:最新的label-studio-ml推理服务代码Access Token校验逻辑和Label Studio的1.17.0版本(JWT)不兼容,需要使用Label Studio 1.16.0版本(Token)
错误信息:requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: http://10.32.x.x:8080/data/upload/26/5727fab8-1123131215466213426.png
2、图片对象标注推理服务开发
2.1、YOLOv11n模型支持识别的对象
编码对象(英文)对象(中文注释)0person人1bicycle自行车2car汽车3motorcycle摩托车4airplane飞机5bus公共汽车6train火车7truck卡车8boat船9traffic light交通信号灯10fire hydrant消防栓11stop sign停车标志12parking meter停车计时器13bench长椅14bird鸟15cat猫16dog狗17horse马18sheep羊19cow牛20elephant大象21bear熊22zebra斑马23giraffe长颈鹿24backpack背包25umbrella雨伞26handbag手提包27tie领带28suitcase行李箱29frisbee飞盘30skis滑雪板31snowboard滑雪单板32sports ball运动球33kite风筝34baseball bat棒球棒35baseball glove棒球手套36skateboard滑板37surfboard冲浪板38tennis racket网球拍39bottle瓶子40wine glass酒杯41cup杯子42fork叉子43knife刀44spoon勺子45bowl碗46banana香蕉47apple苹果48sandwich三明治49orange橙子50broccoli西兰花51carrot胡萝卜52hot dog热狗53pizza披萨54donut甜甜圈55cake蛋糕56chair椅子57couch沙发58potted plant盆栽植物59bed床60dining table餐桌61toilet马桶62tv电视63laptop笔记本电脑64mouse鼠标65remote遥控器66keyboard键盘67cell phone手机68microwave微波炉69oven烤箱70toaster烤面包机71sink水槽72refrigerator冰箱73book书74clock时钟75vase花瓶76scissors剪刀77teddy bear泰迪熊78hair drier吹风机79toothbrush牙刷2.1、_wsgi.py
代码省略,替换NewModel对象为model.py中定义的对象名
2.2、model.py
- import os
- from typing import List, Dict, Optional
- from PIL import Image
- from label_studio_ml.model import LabelStudioMLBase
- from label_studio_ml.response import ModelResponse
- from label_studio_ml.utils import get_single_tag_keys
- from ultralytics import YOLO
- from loguru import logger
- LABEL_STUDIO_URL = os.environ['LABEL_STUDIO_URL']
- LABEL_STUDIO_API_KEY = os.environ['LABEL_STUDIO_API_KEY']
- YOLO_MODEL_PATH = os.environ['YOLO_MODEL_PATH']
- # 创建日志目录(如果不存在)
- os.makedirs("logs", exist_ok=True)
- # 配置日志
- logger.add(
- "logs/yolov11n_{time:YYYY-MM-DD}.log", # 日志文件名格式,按天分割
- rotation="00:00", # 每天午夜创建新日志文件
- retention="7 days", # 保留30天的日志
- level="INFO", # 设置日志级别为INFO
- encoding="utf-8", # 设置编码
- enqueue=True # 多进程安全
- )
- class YOLOv11Model(LabelStudioMLBase):
- """Custom ML Backend model
- """
-
- def setup(self):
- """Configure any parameters of your model here
- """
- self.set("model_version", "0.0.1")
- self.from_name, self.to_name, self.value, self.classes = get_single_tag_keys(self.parsed_label_config, 'RectangleLabels', 'Image')
- self.model = YOLO(YOLO_MODEL_PATH)
- self.labels = self.model.names
- def predict(self, tasks: List[Dict], context: Optional[Dict] = None, **kwargs) -> ModelResponse:
- image_url = tasks[0]['data']['image']
- logger.info(f"标注图片地址: [{image_url}]")
- logger.info(f"access token: [{LABEL_STUDIO_API_KEY}]")
- image_path = self.get_local_path(url = image_url, ls_host = LABEL_STUDIO_URL, ls_access_token = LABEL_STUDIO_API_KEY, task_id = tasks[0]['id'])
- logger.info(f"标注图片image_path: [{image_url}]")
- image = Image.open(image_path)
- original_width, original_height = image.size
- predictions = []
- score = 0
- i = 0
- results = self.model.predict(image, conf = 0.5)
- 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()
- logger.info(f"Prediction Score: [{score:.3f}]")
- final_prediction = [{
- "result": predictions,
- "score": score / (i + 1),
- "model_version": "yolov11n",
- }]
-
- 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.')
复制代码 2.3、同步代码到容器中并启动推理服务
- label-studio-ml start yolov11_ml_backend -p 9091
复制代码 启动成功信息如下:
[INFO] [werkzeug::_log::97] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
- Running on all addresses (0.0.0.0)
- Running on http://127.0.0.1:9091
- Running on http://10.32.122.95:9091
[INFO] [werkzeug::_log::97] Press CTRL+C to quit
3、使用推理模型服务
3.1、配置推理模型服务
3.2、选择标注任务进行自动标注
3.3、自动标注效果
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |