Предварительные метки и оценки на отложенных объектах от модели, которую вы уже запускаете
Оцените модель, которую обслуживает vLLM, Ollama, Hugging Face, Roboflow, CVAT или бэкенд ML Label Studio, на метках вашего исследования, а затем проверьте её ответы как предварительные метки.
Новое в v2.14.0
Этот учебник предназначен для команд, которые уже запускают модель вне Potato и хотят узнать, насколько модель согласуется с собственными разметчиками команды, прежде чем показывать её ответы кому-либо. В обучение моделей Potato входят пять тренеров, называемых мостами, которые ничего не обучают. Мост отправляет отложенные объекты исследования модели, обслуживаемой в другом месте, оценивает ответы по меткам исследования и записывает ответы обратно как предварительные метки для проверки, как это делает запуск обученной модели. Шаги ниже охватывают визуально-языковую модель за API, совместимым с OpenAI, модель Roboflow, бессерверную функцию CVAT, модель Hugging Face и бэкенд ML Label Studio, с проверенной конфигурацией для каждого случая.
Что отправляет и оценивает запуск моста
Мост это тренер, чей шаг обучения лишь проверяет, что сервис отвечает. Затем запуск отправляет сервису объекты из выборок val и test этого запуска, а при writeback.include_unlabeled: true ещё и объекты, которые никто не размечал. Potato превращает ответы в собственные формы схемы, то есть отрезки или варианты выбора, и оценивает ответы на отложенных объектах по сведённым меткам людей теми же метриками на отложенных объектах, что и обученную модель (mAP50 для рамок, F1 отрезков для отрезков, макро-F1 для одиночного выбора). Обратная запись, очередь проверки и идентификатор запуска каждой предварительной метки работают так же, как после любого другого запуска.
| Тренер | Схемы | Модель, которую он вызывает |
|---|---|---|
openai-vlm-boxes | image_annotation | Визуально-языковая модель за API чата, совместимым с OpenAI (vLLM, Ollama, LM Studio, сервер llama.cpp, OpenAI) |
roboflow | image_annotation | Модель Roboflow для детекции или сегментации экземпляров, размещённая в облаке или на собственном сервере Inference |
cvat-nuclio | image_annotation | Бессерверная функция CVAT, работающая на Nuclio |
hf-inference | radio, select, multiselect, span, image_annotation | Конечная точка Hugging Face Inference Endpoint или модель в бессерверном API HF Inference |
label-studio-ml | radio, select, multiselect, span, image_annotation | Работающий бэкенд ML Label Studio |
Выборка объекта зависит только от идентификатора объекта и model_training.split_seed, поэтому запуск моста и запуск обученной модели оцениваются на одних и тех же объектах val и test, пока значение seed остаётся неизменным. Тогда таблица Runs на /admin/training ставит модель, которая у вас уже есть, рядом с моделью, обученной на метках исследования. Объекты из выборки train не получают предсказаний от моста, а обратная запись никогда не ставит предварительные метки на объекты из выборки train. При разбиении по умолчанию 70/15/15 мост поэтому оценивается примерно на 30% размеченных объектов.
Перед началом
Четырём мостам, кроме label-studio-ml, нужны requests и Pillow на сервере Potato, а страница Training показывает мост как "not installed", пока оба пакета не импортируются. label-studio-ml не требует ничего сверх Potato. Ни один из пяти мостов не устанавливает ни модель, ни библиотеку для GPU, ни torch, потому что модель работает в сервисе.
Изображения должны быть локальными файлами внутри проекта, как для любого тренера изображений. Мост исключает объект, изображение которого задано удалённым URL http(s), а объект с меткой и без предсказания считается в оценке на отложенных объектах ошибочным. Запуск сообщает долю отложенных объектов, получивших предсказание, как val_coverage и test_coverage, поэтому низкое покрытие указывает на изображения, которые мост не смог отправить.
Ключи остаются в переменных окружения
Ключ никогда не попадает в конфигурацию. Каждый мост, который отправляет ключ, принимает параметр, который называет переменную окружения с ключом (api_key_env, token_env для Hugging Face или два имени basic_auth_*_env для Label Studio), и эта переменная должна быть задана в окружении сервера Potato до его запуска. cvat-nuclio не отправляет ключ и такого параметра не принимает. Четыре моста, которые принимают ключ, отвергают значение, которое не является именем переменной, а ошибка не повторяет это значение, поскольку значение на этом месте скорее всего и есть сам ключ. Когда тело ошибки сервиса или ошибка соединения повторяет запрос, мосты заменяют значение ключа на [redacted] перед показом ошибки. Тела ошибок из /predict бэкенда ML Label Studio очищаются так же. Всё, что похоже на ключ в строке запроса или в заголовке Authorization, тоже заменяется.
Запуски hf-inference и roboflow только локальные. Оба моста читают ключ на сервере Potato, а запуск на бэкенде ssh, SLURM или агента должен был бы отправить ключ на ту машину, поэтому Potato отказывается начинать там такой запуск. openai-vlm-boxes, cvat-nuclio и label-studio-ml работают на любом бэкенде, который достаёт до сервиса, если переменная ключа задана на машине этого бэкенда.
Шаг 1. Исследование изображений с тремя мостами
Конфигурация ниже задаёт исследование фотографий со строительной площадки, на которых разметчики обводят рамкой каждую каску и каждую непокрытую голову. model_training.trainer_params хранит значения по умолчанию сразу для нескольких тренеров, поэтому одна конфигурация несёт настройки для всех трёх мостов изображений, а каждый запуск использует блок своего тренера. Поле Parameters на странице Training заполняется из этих значений по умолчанию, когда вы выбираете тренер.
annotation_task_name: "Hard hats on site photos"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
admin_api_key: "replace-with-a-long-random-string"
data_files:
- data/photos.jsonl
item_properties:
id_key: id
text_key: image_url
annotation_schemes:
- annotation_type: image_annotation
name: ppe
description: "Box every hard hat and every bare head."
source_field: image_url
tools: [bbox, polygon]
labels:
- name: helmet
- name: head
model_training:
enabled: true
writeback:
schemas: [ppe]
include_unlabeled: true
trainer_params:
openai-vlm-boxes:
url: http://localhost:8000/v1
model: Qwen/Qwen2.5-VL-7B-Instruct
coordinate_format: pixels
roboflow:
model_id: site-safety/3 # your Roboflow project and version
url: https://detect.roboflow.com
api_key_env: ROBOFLOW_API_KEY
confidence: 0.4
label_map: {hardhat: helmet, no-hardhat: head} # the model's class names on the left
cvat-nuclio:
url: http://localhost:32768
threshold: 0.5
label_map: {person: null}Каждая строка data/photos.jsonl называет одно изображение в media/:
{"id": "site_001", "image_url": "media/site_001.jpg"}writeback.schemas делает рамки модели видимыми для разметчиков, а include_unlabeled отправляет сервису и фотографии, которые никто не размечал. Для первого запуска опустите оба ключа, если хотите получить оценку на отложенных объектах до того, как кто-либо увидит предварительную метку. label_map сопоставляет названия классов сервиса с метками схемы, а класс, отображённый в null, отбрасывается. Класс без записи уходит в метку с тем же названием, причём сопоставление не учитывает регистр. Рамки с любым другим классом исключаются, а журнал запуска считает исключённые рамки.
Шаг 2. Визуально-языковая модель с openai-vlm-boxes
openai-vlm-boxes уменьшает каждое изображение до не более чем 1280 пикселей по длинной стороне (max_image_side) и отправляет изображение на маршрут chat completions с запросом, называющим метки схемы. Potato читает ответ как рамки в JSON. Подходит любой сервер с API, совместимым с OpenAI. Команда ниже запускает Qwen2.5-VL через vLLM, чья документация подключает клиентов по адресу http://localhost:8000/v1:
vllm serve Qwen/Qwen2.5-VL-7B-InstructЕсли vLLM работает на порту 8000, запустите Potato на другом порту:
potato start config.yaml -p 9000Визуально-языковые модели отвечают в собственной системе координат независимо от того, что просит запрос, и два параметра сообщают Potato, как читать числа. coordinate_format принимает fraction (от 0 до 1 от изображения), per_mille (от 0 до 1000) или pixels изображения в том виде, в каком оно отправлено. box_order принимает xyxy для [x0, y0, x1, y1] или yxyx для [y0, x0, y1, x1]. Qwen2.5-VL отвечает в пикселях, поэтому конфигурация выше задаёт coordinate_format: pixels. При auto Potato определяет формат один раз для каждого ответа по величине чисел. Значения до 1.05 читаются как доли, значения больше размера отправленного изображения читаются как промилле, а всё остальное читается как пиксели. Рамка в промилле, которая умещается внутри большого изображения, поэтому читается как пиксели, так что называйте формат всякий раз, когда знаете систему координат модели.
Gemma и Gemini отвечают рамками в промилле с y на первом месте, [ymin, xmin, ymax, xmax], даже когда запрос просит доли. Когда оба параметра равны auto, Potato читает рамки модели, в названии которой есть gemma или gemini, как промилле с y на первом месте. На тестовом проекте Gemma 4 12B с красными и синими квадратами команда Potato измерила mAP50, равную 0.0 при чтении рамок с x на первом месте и 1.0 при чтении с y на первом месте. Ollama обслуживает Gemma 3 под названием, содержащим gemma, поэтому применяется auto:
ollama run gemma3:12bЗамените блок openai-vlm-boxes в конфигурации блоком ниже:
model_training:
trainer_params:
openai-vlm-boxes:
url: http://localhost:11434/v1
model: gemma3:12b
json_mode: objectДообученная модель Gemma или Gemini, обслуживаемая под названием без этих слов, получает при auto чтение с x на первом месте. Для такой модели задайте coordinate_format: per_mille и box_order: yxyx. json_mode: object просит у Ollama JSON через response_format: json_object. Значение по умолчанию, schema, отправляет схему JSON с метками как перечислением. vLLM и OpenAI соблюдают схему. Запуск, в котором ни один ответ не разбирается как JSON, завершается ошибкой, и сообщение предлагает json_mode: object или более простой запрос (prompt, где {labels} заменяется метками схемы).
Визуально-языковая модель не даёт оценки вместе с рамками, поэтому у рамок нет уверенности. writeback.min_confidence пропускает каждое предсказание openai-vlm-boxes, а проверка модели не может упорядочить предсказания от наименее к наиболее уверенным. Справочник по openai-vlm-boxes перечисляет api_key_env для размещённого API, а также настройки токена и тайм-аута.
Шаг 3. Начало запуска и чтение оценки
Откройте http://localhost:9000/admin/training, выберите openai-vlm-boxes и схему ppe и нажмите Train now. Тот же запуск начинается и из API:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:9000/admin/training/api/runs \
-d '{"trainer": "openai-vlm-boxes", "schemas": ["ppe"]}'Шаг обучения запрашивает список моделей сервера через /models и записывает в журнал, какую модель запрашивает запуск и как запуск читает рамки модели. Затем проход предсказания отправляет по одному изображению на запрос. Когда запуск завершается, mAP50 на отложенных объектах появляется в таблице Runs, а страница запуска перечисляет val_map_50, test_map_50, показатели покрытия и предупреждение "Not used", которое считает ответы, не являвшиеся JSON, рамки с метками, которых нет в схеме, и рамки вне изображения. Когда оценка близка к 0 при высоком покрытии и пустом предупреждении, сначала проверьте coordinate_format и box_order.
Модели Roboflow
roboflow отправляет каждое изображение методом POST на <url>/<model_id>, где model_id это проект и версия в виде project/version. Ключ по умолчанию берётся из ROBOFLOW_API_KEY (api_key_env), а без ключа запуск отказывается начинаться:
export ROBOFLOW_API_KEY=... # in the shell that starts Potato
potato start config.yaml -p 9000url по умолчанию в Potato это https://detect.roboflow.com, и конфигурация выше называет значение по умолчанию. Запуск для сегментации экземпляров задаёт url: https://outline.roboflow.com. url это параметр, поэтому запуск может назвать и https://serverless.roboflow.com, хост, который справочник Roboflow по детекции объектов указывает для того же маршрута project/version. Команда Potato не проверяла этот хост с данным мостом. Собственный сервер Roboflow Inference по умолчанию слушает порт 9001 (url: http://localhost:9001).
API Roboflow принимает ключ в строке запроса. Potato не записывает URL запроса ни в журнал запуска, ни в сообщение об ошибке. Potato отправляет confidence и overlap (по умолчанию 0.4 и 0.3) в API как проценты, а справочник Roboflow описывает оба параметра на шкале от 0 до 100. shapes: auto записывает контур там, где модель возвращает контур и у схемы есть инструмент многоугольника, а в остальных случаях рамку. Проверка работоспособности отправляет белое изображение 8 × 8, и Roboflow засчитывает запрос в использование аккаунта.
Бессерверные функции CVAT
cvat-nuclio использует детектор, уже развёрнутый для CVAT как функция Nuclio, например функции YOLOv7 или Faster R-CNN из cvat/serverless. Potato отправляет каждое изображение на собственный URL функции как {"image": <base64>, "threshold": t}, минуя CVAT. nuctl get functions перечисляет развёрнутые функции с их портами, а команда ниже это форма, которую даёт документация CVAT:
nuctl get functions --platform localФункция отвечает фигурами в пикселях. rectangle становится рамкой, а polygon становится многоугольником либо охватывающей рамкой многоугольника, когда у схемы нет инструмента многоугольника. Фигуры mask исключаются и учитываются. Функция отбрасывает фигуры с оценкой ниже threshold (по умолчанию 0.5). В схеме нет метки person, поэтому label_map: {person: null} в конфигурации отбрасывает людей, найденных детектором COCO.
Модели Hugging Face с hf-inference
hf-inference вызывает модель, развёрнутую на Hugging Face, либо выделенную конечную точку Inference Endpoint по её URL https:// (endpoint_url), либо идентификатор модели в бессерверном API HF Inference (model). Задайте endpoint_url или model, но не оба. Задача определяется типом схемы:
- Классификация текста для
radio,selectиmultiselect. Схема с одиночным выбором берёт верхнюю метку модели. Когда эта метка послеlabel_mapне входит в метки схемы, объект не получает предсказания, а не вторую по рангу метку. Схемаmultiselectберёт каждую метку с оценкой не нижеthreshold(по умолчанию 0.5). - Классификация токенов для
span, где части слов группируются в сущности поaggregation_strategy(simple,first,averageилиmax), а символьные смещения берутся из модели. - Детекция объектов для
image_annotation. Рамки с оценкой нижеthresholdотбрасываются.
Конфигурация ниже просит у dslim/bert-base-NER отрезки. Карточка модели описывает модель BERT, дообученную на именованных сущностях на английском CoNLL-2003. HF Inference обслуживает подмножество моделей Hub, поэтому проверьте, что на странице модели указан HF Inference, прежде чем полагаться на бессерверный API.
annotation_task_name: "Named entities in news sentences"
task_dir: .
output_annotation_dir: annotation_output
admin_api_key: "replace-with-a-long-random-string"
data_files:
- data/sentences.jsonl
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: span
name: entities
description: "Highlight every person, organization, and place."
labels: [person, organization, location]
model_training:
enabled: true
writeback:
schemas: [entities]
include_unlabeled: true
trainer_params:
hf-inference:
model: dslim/bert-base-NER
token_env: HF_TOKEN
aggregation_strategy: simple
label_map: {PER: person, ORG: organization, LOC: location, MISC: null}Сущности модели PER, ORG и LOC сопоставляются с метками схемы, а MISC отбрасывается, потому что в схеме нет такой метки. Когда полное имя сущности ничему не соответствует, Potato отбрасывает префикс B- или I- и пробует снова. Классификатор тональности, который отвечает LABEL_0 и LABEL_1, аналогично требует label_map: {LABEL_0: negative, LABEL_1: positive}. Проверка работоспособности это один настоящий запрос, короткое предложение или изображение 8 × 8, а wait_for_model: true (по умолчанию) ждёт, пока бессерверная модель загружается, вместо того чтобы завершаться ошибкой 503.
Бэкенд ML Label Studio
label-studio-ml использует работающий бэкенд ML Label Studio. Бэкенд, запущенный из примеров репозитория командой docker-compose up, обслуживает модель по HTTP на http://localhost:9090. Запуск проверяет GET /health бэкенда, отправляет объекты на POST /predict пакетами по 16 (batch_size) и читает возвращённые области тем же конвертером, который использует potato import -f label_studio. Смещения отрезков Label Studio в UTF-16 становятся кодовыми точками, а процентные координаты становятся координатами виджета изображения.
annotation_task_name: "Review sentiment"
task_dir: .
output_annotation_dir: annotation_output
admin_api_key: "replace-with-a-long-random-string"
data_files:
- data/reviews.jsonl
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: radio
name: sentiment
description: "Is this review positive or negative?"
labels: [positive, negative]
model_training:
enabled: true
writeback:
schemas: [sentiment]
include_unlabeled: true
min_confidence: 0.6
trainer_params:
label-studio-ml:
url: http://localhost:9090
basic_auth_user_env: LS_ML_USER
basic_auth_pass_env: LS_ML_PASSЕдинственная аутентификация стандартного бэкенда это HTTP Basic, которую задают BASIC_AUTH_USER и BASIC_AUTH_PASS на бэкенде. basic_auth_user_env и basic_auth_pass_env называют переменные на сервере Potato с теми же двумя значениями, и эти два параметра задаются вместе. api_key_env вместо этого отправляет Authorization: Token <value>, для бэкенда за прокси, который ожидает токен. Стандартный бэкенд отвечает на этот заголовок ошибкой 500. Potato генерирует конфигурацию разметки, отправляемую с каждым запросом, из схемы (Choices, Labels, RectangleLabels или PolygonLabels), а label_config заменяет сгенерированный XML вашим собственным.
Бэкенду для изображений нужна ещё одна настройка. Без media_url_prefix Potato отправляет каждое изображение как абсолютный путь на машине Potato, а бэкенд, построенный на SDK Label Studio, читает data.image как URL и терпит неудачу на голом пути. Для бэкенда на той же машине добавьте префикс ниже и запустите бэкенд с LOCAL_FILES_DOCUMENT_ROOT, равным папке задачи:
model_training:
trainer_params:
label-studio-ml:
url: http://localhost:9090
media_url_prefix: /data/local-files/?d=Для бэкенда на другой машине раздайте папку задачи по HTTP и укажите URL этого сервера как префикс. У изображения вне папки задачи нет пути относительно этой папки, поэтому Potato не отправляет такое изображение, а журнал запуска называет, сколько их исключено.
Potato отправляет бэкенду запросы предсказаний и не отправляет событий разметки, поэтому собственное обучение бэкенда в его обработчике /webhook из Potato не запускается. potato import -f label_studio переносит в Potato целый проект Label Studio вместе с его конфигурацией разметки, ответами разметчиков и сохранёнными предсказаниями (Импорт проектов). Миграция из Label Studio в Potato рассматривает теги, которые импортёр исключает.
Проверка предварительных меток
Предсказания моста проходят через те же проверки обратной записи, что и предсказания обученной модели. Обратная запись пропускает объекты из выборки train и схемы, отсутствующие в writeback.schemas, пропускает пары объекта и схемы, которые рецензент отклонил, и задерживает предсказания ниже writeback.min_confidence. Для рамок и отрезков уверенность предсказания это уверенность наименее уверенной фигуры или отрезка, поэтому порог задерживает предсказание объекта целиком, если какая-либо одна рамка или отрезок на объекте оценены ниже. confidence у Roboflow и threshold у CVAT действуют вместо этого на каждую рамку, на стороне сервиса, а threshold у hf-inference действует на каждую рамку или каждую метку multiselect. Учебник по модели в цикле рассматривает очередь проверки, вердикты принятия и отклонения и переобучение. Очередь и вердикты работают для моста так же.
Для каждого объекта и схемы хранится одно предсказание, поэтому более поздний запуск другого моста или обученной модели заменяет предварительные метки предыдущего запуска. Чтобы отозвать предварительные метки запуска, отправьте DELETE /admin/training/api/runs/<run_id>/predictions. Справочник по мостам к моделям перечисляет все параметры четырёх мостов, а справочник по label-studio-ml перечисляет параметры Label Studio.
Дополнительные материалы
- Обучение моделей описывает цикл и страницу Training.
- Тренеры перечисляют всех 38 тренеров по задачам, чтобы сравнивать модель, обученную на метках исследования, с оценкой моста.
- Конфигурация описывает выборки, обратную запись и маршруты.
- Разметка изображений и Разметка отрезков описывают схемы, которые заполняют мосты.
- Визуальная поддержка ИИ показывает разметчику по запросу подсказки визуальной модели, без оценки на отложенных объектах.