1. Проверяем окружение CVAT перед подключением модели
Перед развёртыванием модели необходимо проверить, как установлен CVAT, какая версия платформы используется и доступен ли на сервере Docker Compose.
В self-hosted CVAT модели для автоматической разметки могут запускаться как отдельные serverless-функции под управлением Nuclio. CVAT передаёт функции изображение, получает от неё координаты объектов и добавляет полученные аннотации в задачу.
Схема взаимодействия выглядит следующим образом:
Разметчик
↓
Интерфейс CVAT
↓
CVAT Server / Worker
↓
Nuclio
↓
Контейнер с моделью
↓
Предсказания модели
↓
Аннотации в задаче CVAT
Подключение к серверу
Подключитесь по SSH к серверу, на котором работает CVAT:
ssh <пользователь>@<адрес-сервера>
Например:
ssh root@192.168.1.50
Если CVAT установлен не от пользователя root, после подключения перейдите к пользователю, который управляет Docker-контейнерами.
Находим каталог с CVAT
Если путь к CVAT известен, сразу перейдите в него:
cd /opt/cvat
Вместо /opt/cvat укажите фактический путь к репозиторию.
Проверить текущий каталог можно командой:
pwd
В корневом каталоге CVAT должны находиться как минимум следующие файлы и директории:
ls -la
Ожидаемые элементы:
docker-compose.yml
components/
serverless/
cvat/
Если путь к установке неизвестен, попробуйте найти docker-compose.yml:
sudo find /opt /srv /home /root \
-maxdepth 4 \
-type f \
-name docker-compose.yml \
2>/dev/null
После этого перейдите в найденный каталог:
cd <путь-к-CVAT>
Проверяем версию CVAT
Если CVAT был установлен из Git-репозитория, зафиксируем ветку, тег и текущий commit:
git remote -v
git branch --show-current
git describe --tags --always --dirty
git rev-parse --short HEAD
Дополнительно запросим информацию через API работающего CVAT:
curl -ksS https://%yor_domain%.com/api/server/about | python3 -m json.tool
В ответе должны появиться сведения о серверной версии CVAT.
Если команда python3 недоступна, выполните запрос без форматирования:
curl -ksS https:// ://%yor_domain%.com/api/server/about
Проверяем Docker и Docker Compose
Выведем установленные версии:
docker --version
docker compose version
Проверим состояние контейнеров CVAT:
docker compose ps
Если установка запускалась с нестандартным именем Compose-проекта или команда не показывает контейнеры, используйте:
docker ps \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}' \
| grep -Ei 'NAME|cvat|traefik|nuclio'
Основные контейнеры CVAT должны иметь состояние Up или healthy. Названия сервисов могут отличаться в зависимости от версии, но обычно среди них присутствуют:
cvat_server
cvat_ui
cvat_db
cvat_redis_inmem
cvat_redis_ondisk
cvat_worker_*
traefik
Получить список сервисов, описанных в основной конфигурации, можно командой:
docker compose config --services | sort
Проверяем поддержку serverless-функций
В современных версиях CVAT конфигурация Nuclio находится в файле:
components/serverless/docker-compose.serverless.yml
Проверим наличие файла:
test -f components/serverless/docker-compose.serverless.yml \
&& echo "Serverless Compose file: OK" \
|| echo "Serverless Compose file: NOT FOUND"
Проверим наличие скриптов развёртывания моделей:
test -f serverless/deploy_cpu.sh \
&& echo "CPU deployment script: OK" \
|| echo "CPU deployment script: NOT FOUND"
test -f serverless/deploy_gpu.sh \
&& echo "GPU deployment script: OK" \
|| echo "GPU deployment script: NOT FOUND"
На этом этапе контейнер Nuclio может ещё не быть запущен. Проверим его наличие:
docker ps \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \
| grep -Ei 'NAME|nuclio'
Также проверим, установлен ли CLI-инструмент nuctl:
if command -v nuctl >/dev/null 2>&1; then
nuctl version
else
echo "nuctl пока не установлен"
fi
Версия nuctl должна соответствовать версии Nuclio, указанной в components/serverless/docker-compose.serverless.yml. Официальная документация CVAT отдельно предупреждает, что несовпадение версий клиента и платформы может привести к ошибкам при развёртывании функций.
Посмотреть используемый образ Nuclio можно командой:
grep -nE 'image:.*nuclio|NUCLIO_VERSION' \
components/serverless/docker-compose.serverless.yml
Проверяем ресурсы сервера
Выведем информацию о процессоре:
lscpu | grep -E \
'Model name|Socket|Core|Thread|CPU\(s\)'
Проверим объём оперативной памяти:
free -h
Проверим свободное место:
df -h /
docker system df
Для первоначальной проверки интеграции модель можно запустить на CPU. Для обработки большого массива изображений или использования тяжёлых нейросетей желательно наличие GPU.
Проверить наличие NVIDIA GPU можно командой:
nvidia-smi
Если выводится таблица с названием видеокарты, версией драйвера и объёмом памяти, сервер готов к дальнейшей проверке GPU-контейнеров.
Если отображается ошибка:
nvidia-smi: command not found
или:
No devices were found
на сервере отсутствует доступный NVIDIA GPU либо не установлен драйвер.
Сохраняем диагностику в файл
Чтобы сохранить исходную конфигурацию установки, выполним единый диагностический блок из корневого каталога CVAT:
{
echo "===== DATE ====="
date -Is
echo
echo "===== HOST ====="
hostname
uname -a
echo
echo "===== CVAT DIRECTORY ====="
pwd
echo
echo "===== CVAT GIT ====="
git branch --show-current 2>/dev/null || true
git describe --tags --always --dirty 2>/dev/null || true
git rev-parse --short HEAD 2>/dev/null || true
echo
echo "===== DOCKER ====="
docker --version
docker compose version
echo
echo "===== CVAT CONTAINERS ====="
docker ps \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \
| grep -Ei 'NAME|cvat|traefik|nuclio'
echo
echo "===== SERVERLESS FILES ====="
test -f components/serverless/docker-compose.serverless.yml \
&& echo "docker-compose.serverless.yml: OK" \
|| echo "docker-compose.serverless.yml: NOT FOUND"
test -f serverless/deploy_cpu.sh \
&& echo "deploy_cpu.sh: OK" \
|| echo "deploy_cpu.sh: NOT FOUND"
test -f serverless/deploy_gpu.sh \
&& echo "deploy_gpu.sh: OK" \
|| echo "deploy_gpu.sh: NOT FOUND"
echo
echo "===== NUCTL ====="
if command -v nuctl >/dev/null 2>&1; then
nuctl version
else
echo "nuctl: NOT INSTALLED"
fi
echo
echo "===== MEMORY ====="
free -h
echo
echo "===== DISK ====="
df -h /
echo
echo "===== GPU ====="
if command -v nvidia-smi >/dev/null 2>&1; then
nvidia-smi \
--query-gpu=name,driver_version,memory.total \
--format=csv,noheader
else
echo "NVIDIA GPU: NOT DETECTED"
fi
} | tee ~/cvat-preannotation-audit.txt
Результат будет сохранён в файле:
~/cvat-preannotation-audit.txt
На этом этапе мы только собираем информацию и ничего не меняем в работающей конфигурации CVAT.
Проверка версии, контейнеров и компонентов автоматической аннотации на сервере CVAT.
2. Устанавливаем и подключаем Nuclio к CVAT
Для запуска моделей автоматической разметки self-hosted CVAT использует serverless-функции Nuclio. Модель разворачивается в отдельном Docker-контейнере и становится доступна CVAT через HTTP-интерфейс Nuclio.
Интеграция состоит из трёх частей:
- Nuclio Dashboard — сервис, управляющий функциями.
- nuctl — консольная утилита для сборки, развёртывания и удаления функций.
- Контейнеры моделей — отдельные Docker-контейнеры, выполняющие инференс.
В актуальных версиях CVAT инфраструктура Nuclio запускается с помощью дополнительного Compose-файла components/serverless/docker-compose.serverless.yml. После запуска serverless-компонентов модели необходимо разворачивать отдельно.
2.1. Переходим в каталог CVAT
Подключитесь к серверу по SSH и перейдите в каталог, из которого запускается CVAT:
ssh <пользователь>@<адрес-сервера>
cd /opt/cvat
Путь /opt/cvat приведён как пример. Проверить, что выбран правильный каталог, можно командой:
pwd
ls -la
В нём должен находиться основной файл:
docker-compose.yml
2.2. Находим serverless-конфигурацию
Расположение файла зависит от версии и структуры репозитория CVAT. В новых версиях используется путь:
components/serverless/docker-compose.serverless.yml
В старых или модифицированных установках файл может находиться в другом каталоге.
Выполним автоматический поиск:
find . \
-maxdepth 4 \
-type f \
-name '*serverless*.yml' \
-o \
-name '*serverless*.yaml'
Для дальнейших команд сохраним найденный путь в переменную:
if [ -f components/serverless/docker-compose.serverless.yml ]; then
SERVERLESS_COMPOSE="components/serverless/docker-compose.serverless.yml"
elif [ -f docker-compose.serverless.yml ]; then
SERVERLESS_COMPOSE="docker-compose.serverless.yml"
elif [ -f serverless/docker-compose.serverless.yml ]; then
SERVERLESS_COMPOSE="serverless/docker-compose.serverless.yml"
else
echo "ОШИБКА: serverless Compose-файл не найден"
exit 1
fi
echo "Serverless Compose: $SERVERLESS_COMPOSE"
Ожидаемый результат:
Serverless Compose: components/serverless/docker-compose.serverless.yml
Переменная действует только в текущей SSH-сессии. После повторного подключения её потребуется задать заново.
2.3. Проверяем содержимое конфигурации
Посмотрим, какие сервисы добавляет serverless-конфигурация:
docker compose \
-f docker-compose.yml \
-f "$SERVERLESS_COMPOSE" \
config --services
В списке должен присутствовать сервис Nuclio, например:
nuclio
Проверим, какой образ Nuclio будет запущен:
docker compose \
-f docker-compose.yml \
-f "$SERVERLESS_COMPOSE" \
config \
| grep -E -A 3 -B 3 'nuclio/dashboard'
Версия Nuclio понадобится позднее для установки совместимой версии nuctl.
2.4. Запускаем CVAT вместе с Nuclio
Если CVAT использует только основной Compose-файл, выполните:
docker compose \
-f docker-compose.yml \
-f "$SERVERLESS_COMPOSE" \
up -d
Команда не создаёт CVAT заново. Docker Compose сравнит текущую конфигурацию с новой, запустит отсутствующие serverless-сервисы и при необходимости обновит связанные контейнеры.
Именно такой способ включения Nuclio указан для стандартного self-hosted развёртывания CVAT.
Если CVAT запущен с HTTPS-конфигурацией
При наличии дополнительного файла HTTPS необходимо сохранить его в команде запуска:
docker compose \
-f docker-compose.yml \
-f docker-compose.https.yml \
-f "$SERVERLESS_COMPOSE" \
up -d
Если используются другие Compose-файлы
В serverless-команду нужно перенести все файлы, которые используются при обычном запуске CVAT.
Например, если CVAT обычно запускается так:
docker compose \
-f docker-compose.yml \
-f docker-compose.override.yml \
-f docker-compose.prod.yml \
up -d
то Nuclio следует подключить так:
docker compose \
-f docker-compose.yml \
-f docker-compose.override.yml \
-f docker-compose.prod.yml \
-f "$SERVERLESS_COMPOSE" \
up -d
Serverless-файл добавляется последним, чтобы его настройки дополнили основную конфигурацию.
2.5. Проверяем контейнер Nuclio
Выведем состояние контейнеров:
docker ps \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}' \
| grep -Ei 'NAME|nuclio|cvat'
Ожидаемый результат:
NAMES IMAGE STATUS
nuclio quay.io/nuclio/dashboard:<версия>-amd64 Up ... (healthy)
cvat_server cvat/server:<версия> Up ...
cvat_ui cvat/ui:<версия> Up ...
Контейнер nuclio должен иметь состояние:
Up
или:
Up ... (healthy)
Посмотреть последние сообщения Nuclio можно командой:
docker logs --tail 100 nuclio
Проверим доступность панели управления с самого сервера:
curl -sS -o /dev/null \
-w 'HTTP status: %{http_code}\n' \
http://127.0.0.1:8070
Допустимый результат:
HTTP status: 200
В некоторых версиях сервер может вернуть код перенаправления:
HTTP status: 302
Это также означает, что HTTP-сервис Nuclio отвечает.
Порт Nuclio Dashboard не рекомендуется открывать напрямую в интернет. Панель должна быть доступна только администратору сервера или через SSH-туннель.
2.6. Проверяем активацию serverless-функций в CVAT
Serverless-конфигурация должна передать серверу CVAT соответствующий параметр окружения.
Проверим его:
docker inspect cvat_server \
--format '{{range .Config.Env}}{{println .}}{{end}}' \
| grep -E '^CVAT_SERVERLESS='
Ожидаемый результат:
CVAT_SERVERLESS=1
Если переменная отсутствует, сначала проверьте итоговую Compose-конфигурацию:
docker compose \
-f docker-compose.yml \
-f "$SERVERLESS_COMPOSE" \
config \
| grep -n -A 5 -B 5 'CVAT_SERVERLESS'
Затем пересоздайте сервер и связанные worker-контейнеры:
docker compose \
-f docker-compose.yml \
-f "$SERVERLESS_COMPOSE" \
up -d --force-recreate
Использовать --force-recreate следует только в том случае, если обычный запуск не передал настройки serverless-компонента.
2.7. Определяем версию Nuclio
Узнаем полный образ запущенного контейнера:
NUCLIO_IMAGE=$(
docker inspect nuclio \
--format '{{.Config.Image}}'
)
echo "$NUCLIO_IMAGE"
Пример:
quay.io/nuclio/dashboard:1.13.0-amd64
Извлечём номер версии:
NUCLIO_VERSION=$(
echo "$NUCLIO_IMAGE" \
| sed -E 's#.*:([0-9]+\.[0-9]+\.[0-9]+)(-[a-z0-9]+)?$#\1#'
)
echo "Nuclio version: $NUCLIO_VERSION"
Пример результата:
Nuclio version: 1.13.0
Если вместо номера выводится вся строка образа, посмотрите её вручную:
docker inspect nuclio \
--format '{{.Config.Image}}'
Версия находится после двоеточия:
quay.io/nuclio/dashboard:1.13.0-amd64
└────┬────┘
версия
2.8. Устанавливаем утилиту nuctl
Для развёртывания функций потребуется CLI-утилита nuctl.
Версия nuctl должна совпадать с версией Nuclio Dashboard. Это требование отдельно отмечено в официальной документации CVAT.
Сначала определим архитектуру сервера:
uname -m
Автоматически преобразуем её в название, используемое в релизах Nuclio:
case "$(uname -m)" in
x86_64)
NUCTL_ARCH="amd64"
;;
aarch64|arm64)
NUCTL_ARCH="arm64"
;;
*)
echo "Неподдерживаемая архитектура: $(uname -m)"
exit 1
;;
esac
echo "nuctl architecture: $NUCTL_ARCH"
Скачиваем nuctl той же версии, что и Nuclio Dashboard:
curl -fL \
"https://github.com/nuclio/nuclio/releases/download/${NUCLIO_VERSION}/nuctl-${NUCLIO_VERSION}-linux-${NUCTL_ARCH}" \
-o "/tmp/nuctl-${NUCLIO_VERSION}"
Устанавливаем бинарный файл:
sudo install \
-m 0755 \
"/tmp/nuctl-${NUCLIO_VERSION}" \
/usr/local/bin/nuctl
Проверяем путь:
command -v nuctl
Ожидаемый результат:
/usr/local/bin/nuctl
Проверяем версию:
nuctl version
Версии Nuclio Dashboard и nuctl должны совпадать:
echo "Dashboard: $NUCLIO_VERSION"
nuctl version
2.9. Проверяем подключение nuctl к Nuclio
Запросим список проектов:
nuctl get projects \
--platform local
Если модели пока не разворачивались, список может быть пустым.
Запросим список функций:
nuctl get functions \
--platform local
До установки первой модели команда может не показать ни одной функции. Это нормальное состояние.
После успешного развёртывания моделей в списке появятся:
- имя функции;
- проект;
- состояние;
- количество реплик;
- внутренний HTTP-порт.
Рабочая функция обычно имеет состояние:
ready
2.10. Общая проверка установки
Выполним итоговый диагностический блок:
echo "===== NUCLIO CONTAINER ====="
docker ps \
--filter name=nuclio \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
echo
echo "===== CVAT SERVERLESS ====="
docker inspect cvat_server \
--format '{{range .Config.Env}}{{println .}}{{end}}' \
| grep -E '^CVAT_SERVERLESS=' \
|| echo "CVAT_SERVERLESS не найден"
echo
echo "===== NUCTL VERSION ====="
nuctl version
echo
echo "===== NUCLIO PROJECTS ====="
nuctl get projects \
--platform local
echo
echo "===== NUCLIO FUNCTIONS ====="
nuctl get functions \
--platform local
Если контейнер Nuclio запущен, версия nuctl совпадает с версией Dashboard, а команды nuctl get projects и nuctl get functions выполняются без ошибки соединения, инфраструктура готова к развёртыванию первой модели.
На следующем этапе мы создадим и запустим функцию детекции объектов, после чего модель появится в интерфейсе CVAT.
Запущенный сервис Nuclio, версия консольной утилиты nuctl и список развёрнутых serverless-функций.
3. Выбираем модель для первой предразметки
Для проверки интеграции используем детектор YOLO v7 в формате ONNX. Он получает изображение и возвращает прямоугольники объектов, названия классов и confidence score.
Такой пример удобен для первого запуска по нескольким причинам:
- модель работает как обычный детектор объектов;
- результат легко проверить визуально;
- CVAT создаёт стандартные прямоугольники rectangle;
- для CPU-инференса используется ONNX Runtime;
- модель уже адаптирована под интерфейс serverless-функций CVAT.
В официальном репозитории CVAT YOLO v7 входит в каталог готовых serverless-моделей. Функция описана как detector, работает с ONNX-моделью и возвращает объекты 80 классов COCO.
На первом этапе мы развернём стандартную модель. После проверки всей цепочки её можно будет заменить собственной ONNX-моделью и изменить список классов.
3.1. Почему важно использовать файлы своей версии CVAT
Структура функций, версия Python, параметры Nuclio и Docker-сеть менялись между версиями CVAT.
Поэтому не рекомендуется без проверки копировать каталог модели из ветки develop в старую установку CVAT. Надёжнее использовать serverless-функцию из того же Git-тега или commit, на котором работает сервер.
Проверим текущую версию репозитория:
cd /opt/cvat
git branch --show-current
git describe --tags --always --dirty
git rev-parse --short HEAD
Пример результата:
develop
v2.70.0
a1b2c3d4
Если репозиторий имеет локальные изменения, команда git describe может добавить суффикс:
-dirty
До завершения настройки модели обновлять CVAT или переключать Git-ветку не нужно.
3.2. Проверяем каталог serverless
Убедимся, что каталог с функциями существует:
test -d serverless \
&& echo "Каталог serverless найден" \
|| echo "Каталог serverless не найден"
Посмотрим его содержимое:
find serverless \
-maxdepth 3 \
-type d \
| sort \
| head -n 100
Найдём все функции, в названии которых встречается YOLO:
find serverless \
-type d \
-iname '*yolo*' \
| sort
В актуальном репозитории CVAT ожидается каталог:
serverless/onnx/WongKinYiu/yolov7/nuclio
Проверим его автоматически:
YOLO_FUNCTION_DIR="serverless/onnx/WongKinYiu/yolov7/nuclio"
if [ -d "$YOLO_FUNCTION_DIR" ]; then
echo "YOLO function directory: OK"
echo "$YOLO_FUNCTION_DIR"
else
echo "YOLO v7 function directory: NOT FOUND"
fi
3.3. Вариант для старой версии CVAT
В старых версиях репозитория готовой функции YOLO v7 может не быть. При этом могут присутствовать другие варианты YOLO, например OpenVINO YOLO v3.
Найдём все подходящие файлы конфигурации:
find serverless \
-type f \
\( -name 'function.yaml' -o -name 'function-gpu.yaml' \) \
-print0 \
| xargs -0 grep -il 'yolo' \
| sort
Также найдём каталоги моделей-детекторов:
grep -RIl \
--include='function.yaml' \
--include='function-gpu.yaml' \
'type: detector' \
serverless \
| sort
Если YOLO v7 отсутствует, есть два варианта:
- использовать совместимый YOLO-пример из текущей версии CVAT;
- подготовить собственную Nuclio-функцию под используемую версию платформы.
Для первого запуска предпочтителен первый вариант. Он снижает риск несовместимости между CVAT, Nuclio и форматом ответа функции.
3.4. Проверяем файлы функции YOLO v7
В официальном примере используются четыре основных файла:
function.yaml
function-gpu.yaml
main.py
model_handler.py
Проверим их наличие:
YOLO_FUNCTION_DIR="serverless/onnx/WongKinYiu/yolov7/nuclio"
for file in \
function.yaml \
function-gpu.yaml \
main.py \
model_handler.py
do
if [ -f "$YOLO_FUNCTION_DIR/$file" ]; then
printf '%-25s %s\n' "$file" "OK"
else
printf '%-25s %s\n' "$file" "NOT FOUND"
fi
done
Ожидаемый результат:
function.yaml OK
function-gpu.yaml OK
main.py OK
model_handler.py OK
В актуальном официальном примере каталог действительно содержит отдельные CPU- и GPU-конфигурации, HTTP-обработчик и класс для загрузки и запуска ONNX-модели.
3.5. За что отвечает каждый файл
function.yaml
Главный конфигурационный файл Nuclio-функции для CPU.
Он определяет:
- внутреннее имя функции;
- отображаемое имя модели;
- тип модели;
- список классов;
- тип создаваемых объектов;
- версию Python;
- Docker-образ;
- зависимости;
- обработчик HTTP-запросов;
- ограничения размера запроса;
- политику перезапуска контейнера.
Посмотрим основные параметры:
sed -n '1,45p' \
"$YOLO_FUNCTION_DIR/function.yaml"
Отдельно выведем технические настройки:
grep -nE \
'name:|type:|runtime:|handler:|baseImage:|eventTimeout:|maxRequestBodySize:' \
"$YOLO_FUNCTION_DIR/function.yaml"
В официальной конфигурации модель зарегистрирована как detector, обработчиком указан main:handler, а классы имеют тип rectangle.
function-gpu.yaml
Альтернативная конфигурация для запуска инференса на NVIDIA GPU.
Проверим, какие GPU-ресурсы она запрашивает:
grep -nE \
'nvidia.com/gpu|baseImage:|onnxruntime-gpu|runtime:|handler:' \
"$YOLO_FUNCTION_DIR/function-gpu.yaml"
Для первого запуска будем использовать CPU-вариант. Это позволит проверить интеграцию независимо от NVIDIA Container Toolkit и конфигурации GPU.
main.py
HTTP-обработчик Nuclio.
Он выполняет четыре основные операции:
- получает JSON-запрос от CVAT;
- декодирует изображение;
- передаёт изображение обработчику модели;
- возвращает найденные объекты в формате JSON.
Посмотрим начало файла:
sed -n '1,220p' \
"$YOLO_FUNCTION_DIR/main.py"
Найдём основную функцию:
grep -nE \
'^def handler|^def init_context' \
"$YOLO_FUNCTION_DIR/main.py"
Обычно init_context загружает модель один раз при запуске контейнера, а handler обрабатывает каждый новый запрос.
model_handler.py
Этот файл содержит основную логику инференса:
- загрузку ONNX-модели;
- подготовку изображения;
- изменение размера входного изображения;
- запуск ONNX Runtime;
- обработку выходных тензоров;
- преобразование координат;
- формирование списка найденных объектов.
Проверим используемые библиотеки:
grep -nE \
'^import |^from ' \
"$YOLO_FUNCTION_DIR/model_handler.py"
Найдём класс обработчика:
grep -nE \
'^class |^[[:space:]]+def ' \
"$YOLO_FUNCTION_DIR/model_handler.py" \
| head -n 40
3.6. Проверяем метаданные модели для CVAT
CVAT получает информацию о модели из раздела metadata.annotations файла function.yaml.
Выведем начало конфигурации:
sed -n '1,30p' \
"$YOLO_FUNCTION_DIR/function.yaml"
Основные поля выглядят так:
metadata:
name: onnx-wongkinyiu-yolov7
namespace: cvat
annotations:
name: YOLO v7
type: detector
spec: |
[
{ "id": 0, "name": "person", "type": "rectangle" },
{ "id": 1, "name": "bicycle", "type": "rectangle" },
{ "id": 2, "name": "car", "type": "rectangle" }
]
Значение полей:
|
Поле |
Назначение |
|
metadata.name |
Системное имя Nuclio-функции |
|
namespace |
Пространство имён функции |
|
annotations.name |
Название модели в интерфейсе CVAT |
|
annotations.type |
Тип модели |
|
annotations.spec |
Классы и типы создаваемых объектов |
|
id |
Числовой идентификатор класса модели |
|
name |
Название класса |
|
type |
Тип аннотации CVAT |
Для детектора bounding box используется:
"type": "rectangle"
Названия классов из annotations.spec позднее будут сопоставляться с метками задачи CVAT.
3.7. Проверяем команду развёртывания
В актуальном репозитории CVAT функция разворачивается через скрипт:
serverless/deploy_cpu.sh
Посмотрим его содержимое:
sed -n '1,220p' serverless/deploy_cpu.sh
Проверим права на выполнение:
ls -l serverless/deploy_cpu.sh
Если executable-флаг отсутствует:
chmod +x serverless/deploy_cpu.sh
Скрипт выполняет несколько действий:
- включает Docker BuildKit;
- создаёт в Nuclio проект cvat;
- находит function.yaml;
- запускает nuctl deploy;
- подключает функцию к Docker-сети CVAT;
- передаёт адрес Redis;
- выводит итоговый список функций.
В текущем официальном скрипте функции подключаются к сети cvat_cvat, а в параметры передаются CVAT_FUNCTIONS_REDIS_HOST и CVAT_FUNCTIONS_REDIS_PORT.
Проверим имя реальной Docker-сети на сервере:
docker network ls \
--format 'table {{.Name}}\t{{.Driver}}\t{{.Scope}}' \
| grep -Ei 'NAME|cvat'
Обычно сеть называется:
cvat_cvat
Однако при другом Compose project name название может отличаться, например:
annotation_cvat
razmetka_cvat
Узнать, к каким сетям подключён cvat_server, можно командой:
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
Название этой сети понадобится при ручном развёртывании собственной модели.
3.8. Итоговая проверка перед сборкой
Выполним единый блок:
cd /opt/cvat
YOLO_FUNCTION_DIR="serverless/onnx/WongKinYiu/yolov7/nuclio"
echo "===== CVAT VERSION ====="
git describe --tags --always --dirty
git rev-parse --short HEAD
echo
echo "===== YOLO DIRECTORY ====="
if [ -d "$YOLO_FUNCTION_DIR" ]; then
echo "$YOLO_FUNCTION_DIR: OK"
else
echo "$YOLO_FUNCTION_DIR: NOT FOUND"
fi
echo
echo "===== YOLO FILES ====="
for file in \
function.yaml \
function-gpu.yaml \
main.py \
model_handler.py
do
test -f "$YOLO_FUNCTION_DIR/$file" \
&& echo "$file: OK" \
|| echo "$file: NOT FOUND"
done
echo
echo "===== FUNCTION METADATA ====="
if [ -f "$YOLO_FUNCTION_DIR/function.yaml" ]; then
grep -nE \
'name: YOLO|type: detector|runtime:|handler:|baseImage:' \
"$YOLO_FUNCTION_DIR/function.yaml"
fi
echo
echo "===== CVAT NETWORK ====="
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
echo
echo "===== NUCTL ====="
nuctl version
Если каталог и все четыре файла найдены, версия nuctl выводится без ошибки, а Docker-сеть CVAT определена, можно переходить к сборке и развёртыванию модели.
3.2. Находим рабочий каталог установленного CVAT
Все команды для развёртывания serverless-моделей необходимо выполнять из корневого каталога репозитория CVAT.
Если выполнить:
find serverless
из домашнего каталога пользователя, система будет искать путь:
/root/serverless
и вернёт ошибку:
find: ‘serverless’: No such file or directory
Это не означает, что CVAT или Nuclio установлены неправильно. Сначала необходимо определить каталог, из которого был запущен Docker Compose.
Определяем рабочий каталог через контейнер CVAT
Контейнеры Docker Compose содержат служебные метки с информацией о проекте.
Посмотрим имя Compose-проекта:
docker inspect cvat_server \
--format '{{ index .Config.Labels "com.docker.compose.project" }}'
Ожидаемый результат:
cvat
Получим рабочий каталог проекта:
docker inspect cvat_server \
--format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}'
Например:
/root/cvat
или:
/opt/cvat
Посмотрим, какие Compose-файлы использовались при запуске:
docker inspect cvat_server \
--format '{{ index .Config.Labels "com.docker.compose.project.config_files" }}'
Пример результата:
/root/cvat/docker-compose.yml,/root/cvat/docker-compose.override.yml
Для удобства сохраним найденный каталог в переменную:
CVAT_DIR=$(
docker inspect cvat_server \
--format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}'
)
echo "CVAT directory: $CVAT_DIR"
Проверим, что каталог существует:
if [ -n "$CVAT_DIR" ] && [ -d "$CVAT_DIR" ]; then
echo "Каталог CVAT найден: $CVAT_DIR"
else
echo "Рабочий каталог не удалось определить через Docker labels"
fi
Если путь определился, перейдём в него:
cd "$CVAT_DIR"
Проверим текущее положение:
pwd
И содержимое каталога:
ls -la
В корне стандартной установки CVAT должен находиться основной Compose-файл:
docker-compose.yml
Проверим его наличие:
test -f docker-compose.yml \
&& echo "docker-compose.yml: OK" \
|| echo "docker-compose.yml: NOT FOUND"
Если метка рабочего каталога отсутствует
В старых версиях Docker Compose служебная метка working_dir может отсутствовать или возвращать пустую строку.
Выведем все Compose-метки контейнера:
docker inspect cvat_server \
--format '{{json .Config.Labels}}' \
| python3 -m json.tool
Если Python отсутствует:
docker inspect cvat_server \
--format '{{json .Config.Labels}}'
Также посмотрим каталоги, подключённые к контейнеру:
docker inspect cvat_server \
--format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
После этого выполним ограниченный поиск Compose-файлов в типичных каталогах:
sudo find \
/opt \
/srv \
/home \
/root \
-maxdepth 6 \
-type f \
\( \
-name 'docker-compose.yml' \
-o -name 'docker-compose.yaml' \
-o -name 'compose.yml' \
-o -name 'compose.yaml' \
\) \
2>/dev/null \
| sort
Искать следует каталог, в котором одновременно присутствуют:
docker-compose.yml
cvat/
serverless/
components/
Наличие конкретных директорий зависит от версии CVAT.
Проверяем, что найден именно репозиторий CVAT
После перехода в предполагаемый каталог выполним:
pwd
git remote -v 2>/dev/null || true
git branch --show-current 2>/dev/null || true
git describe --tags --always --dirty 2>/dev/null || true
git rev-parse --short HEAD 2>/dev/null || true
Проверим основные файлы:
for path in \
docker-compose.yml \
cvat \
serverless
do
if [ -e "$path" ]; then
printf '%-25s %s\n' "$path" "FOUND"
else
printf '%-25s %s\n' "$path" "NOT FOUND"
fi
done
Ищем каталог serverless
Теперь поиск выполняется относительно корня CVAT:
find . \
-maxdepth 4 \
-type d \
-iname '*serverless*' \
| sort
Для большинства версий CVAT ожидается каталог:
./serverless
Официальные примеры serverless-моделей CVAT хранятся в репозитории платформы и разворачиваются через nuctl и скрипты из каталога serverless.
Проверим его:
if [ -d serverless ]; then
echo "Каталог serverless найден"
else
echo "Каталог serverless в текущем checkout отсутствует"
fi
Если каталог найден, посмотрим доступные модели:
find serverless \
-mindepth 1 \
-maxdepth 4 \
-type d \
| sort \
| head -n 150
Найдём модели семейства YOLO:
find serverless \
-type d \
-iname '*yolo*' \
| sort
Почему Nuclio может работать без каталога serverless
Каталог serverless требуется во время подготовки и развёртывания функции. После сборки модель работает как самостоятельный Docker-контейнер.
Поэтому возможна ситуация, когда:
- контейнер Nuclio работает;
- ранее развёрнутая модель работает;
- исходный каталог модели был перемещён или удалён;
- текущая команда запущена не из того checkout репозитория;
- CVAT запускается из одного каталога, а модели разворачивались из другого.
На уже развёрнутую функцию отсутствие исходного каталога напрямую не влияет. Но для установки новой модели исходники функции потребуются.
Итоговая диагностическая команда
Выполним единый блок:
echo "===== COMPOSE PROJECT ====="
docker inspect cvat_server \
--format 'Project: {{ index .Config.Labels "com.docker.compose.project" }}'
docker inspect cvat_server \
--format 'Working directory: {{ index .Config.Labels "com.docker.compose.project.working_dir" }}'
docker inspect cvat_server \
--format 'Compose files: {{ index .Config.Labels "com.docker.compose.project.config_files" }}'
echo
echo "===== CURRENT DIRECTORY ====="
pwd
echo
echo "===== CONTAINER NETWORKS ====="
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
echo
echo "===== CONTAINER MOUNTS ====="
docker inspect cvat_server \
--format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
По текущей диагностике Docker-сеть уже определена:
cvat_cvat
Эта сеть будет использоваться при развёртывании новой Nuclio-функции.
Определение рабочего каталога Docker Compose и поиск исходников serverless-моделей в установленном CVAT.
3. Выбираем встроенную модель YOLOv5
В разных версиях CVAT набор готовых serverless-моделей отличается. Поэтому перед развёртыванием необходимо проверить, какие функции уже входят в установленную версию платформы.
В рассматриваемой установке доступны две модели семейства YOLO:
serverless/openvino/omz/public/yolo-v3-tf
serverless/pytorch/ultralytics/yolov5
Для первого запуска используем Ultralytics YOLOv5 на PyTorch.
Эта модель решает задачу Object Detection: находит объекты на изображении и возвращает прямоугольники, названия классов и коэффициенты уверенности. В CVAT результаты модели преобразуются в аннотации типа rectangle.
Использование модели из текущего Git checkout предпочтительнее, чем копирование новой функции из ветки develop. Serverless-функция должна быть совместима с используемыми версиями CVAT, Nuclio и Python.
В официальной документации CVAT также рекомендуется разворачивать встроенные функции из каталога serverless клонированного репозитория. После развёртывания функция становится доступна CVAT для автоматической аннотации.
3.1. Проверяем версию CVAT
Перейдём в корневой каталог установки:
cd /root/cvat
Проверим Git-ветку, тег и commit:
echo "===== CVAT VERSION ====="
git branch --show-current
git describe --tags --always --dirty
git rev-parse --short HEAD
Дополнительно посмотрим дату последнего commit:
git log -1 \
--date=iso \
--format='Commit: %H%nDate: %ad%nSubject: %s'
Эти сведения стоит сохранить: они помогут воспроизвести установку и подобрать совместимые версии компонентов.
До завершения настройки модели не следует выполнять:
git pull
или переключать CVAT на другую ветку. Обновление исходников может потребовать миграции базы данных и пересборки всех контейнеров.
3.2. Проверяем каталог YOLOv5
Зададим путь к встроенной модели:
YOLO_ROOT="/root/cvat/serverless/pytorch/ultralytics/yolov5"
Проверим наличие каталога:
if [ -d "$YOLO_ROOT" ]; then
echo "YOLOv5 directory: OK"
else
echo "YOLOv5 directory: NOT FOUND"
fi
Посмотрим структуру:
find "$YOLO_ROOT" \
-maxdepth 4 \
-type f \
| sort
Обычно внутри находится каталог nuclio, содержащий исходники serverless-функции:
serverless/pytorch/ultralytics/yolov5/
└── nuclio/
├── function.yaml
└── main.py
В некоторых версиях дополнительно могут присутствовать:
function-gpu.yaml
model_handler.py
README.md
Набор файлов зависит от версии CVAT.
3.3. Автоматически определяем каталог функции
Найдём CPU-конфигурацию:
YOLO_FUNCTION_FILE=$(
find "$YOLO_ROOT" \
-type f \
-name 'function.yaml' \
| head -n 1
)
echo "Function file: $YOLO_FUNCTION_FILE"
Определим каталог, который нужно передать скрипту развёртывания:
YOLO_FUNCTION_DIR=$(
dirname "$YOLO_FUNCTION_FILE"
)
echo "Function directory: $YOLO_FUNCTION_DIR"
Проверим результат:
test -f "$YOLO_FUNCTION_DIR/function.yaml" \
&& echo "function.yaml: OK" \
|| echo "function.yaml: NOT FOUND"
test -f "$YOLO_FUNCTION_DIR/main.py" \
&& echo "main.py: OK" \
|| echo "main.py: NOT FOUND"
Ожидаемый каталог:
/root/cvat/serverless/pytorch/ultralytics/yolov5/nuclio
3.4. Изучаем конфигурацию модели
Файл function.yaml определяет, как Nuclio соберёт и запустит контейнер модели.
Выведем его содержимое:
sed -n '1,240p' \
"$YOLO_FUNCTION_DIR/function.yaml"
Для сокращённой проверки выведем только ключевые параметры:
grep -nE \
'^[[:space:]]*name:|type:|framework:|runtime:|handler:|baseImage:|image:|commands:|spec:' \
"$YOLO_FUNCTION_DIR/function.yaml"
В конфигурации нас интересуют следующие поля:
|
Параметр |
Назначение |
|
metadata.name |
Системное имя Nuclio-функции |
|
annotations.name |
Название модели в интерфейсе CVAT |
|
annotations.type |
Тип модели, например detector |
|
annotations.framework |
Используемый ML-фреймворк |
|
annotations.spec |
Список классов модели |
|
runtime |
Версия среды выполнения Python |
|
handler |
Функция, принимающая запросы |
|
baseImage |
Базовый Docker-образ |
|
build.commands |
Команды установки зависимостей |
Покажем метаданные отдельно:
sed -n '/metadata:/,/spec:/p' \
"$YOLO_FUNCTION_DIR/function.yaml"
Найдём имя, под которым функция будет зарегистрирована в Nuclio:
awk '
/^metadata:/ {
metadata=1
next
}
metadata && /^[[:space:]]{2}name:/ {
exit
}
' "$YOLO_FUNCTION_DIR/function.yaml"
Проверим тип модели:
grep -n \
'type: detector' \
"$YOLO_FUNCTION_DIR/function.yaml"
Если вывод содержит:
type: detector
CVAT будет воспринимать функцию как детектор объектов.
3.5. Проверяем классы модели
В стандартном варианте YOLOv5 использует классы датасета COCO. Среди них:
person
bicycle
car
motorcycle
bus
truck
dog
cat
chair
bottle
Полный список хранится в поле annotations.spec.
Выведем этот фрагмент:
grep -n -A 100 \
'spec:' \
"$YOLO_FUNCTION_DIR/function.yaml" \
| head -n 110
Названия классов важны: при запуске предразметки CVAT предложит сопоставить классы модели с метками задачи.
Например:
Класс модели: person
Метка задачи: Человек
или:
Класс модели: car
Метка задачи: Автомобиль
Названия не обязаны полностью совпадать — сопоставление можно выполнить вручную перед запуском аннотации.
3.6. Проверяем код HTTP-обработчика
Откроем файл main.py:
sed -n '1,260p' \
"$YOLO_FUNCTION_DIR/main.py"
Найдём функции инициализации и обработки запросов:
grep -nE \
'^def |^[[:space:]]+def ' \
"$YOLO_FUNCTION_DIR/main.py"
Обычно в файле присутствуют две основные функции:
def init_context(context):
...
и:
def handler(context, event):
...
init_context вызывается при запуске контейнера. На этом этапе загружается модель.
handler вызывается при каждом запросе CVAT. Он:
- получает изображение;
- декодирует его;
- запускает инференс;
- преобразует предсказания в формат CVAT;
- возвращает JSON с объектами.
В YOLOv5-функциях того периода модель могла загружаться через torch.hub.load. Готовый пример CVAT уже содержит необходимый код, поэтому перед первым запуском изменять main.py не требуется. Примеры подключения пользовательских весов требуют отдельных изменений и будут рассмотрены после проверки стандартной модели.
Проверим, какая модель загружается:
grep -nE \
'torch\.hub\.load|yolov5[nsmlx]|model =' \
"$YOLO_FUNCTION_DIR/main.py"
Например, строка может содержать:
torch.hub.load("ultralytics/yolov5", "yolov5s")
Обозначение yolov5s соответствует компактной версии модели. Она подходит для первого CPU-запуска, поскольку требует меньше памяти, чем более крупные варианты.
3.7. Проверяем скрипт развёртывания CVAT
Перейдём в корень CVAT:
cd /root/cvat
Проверим наличие CPU-скрипта:
test -f serverless/deploy_cpu.sh \
&& echo "deploy_cpu.sh: OK" \
|| echo "deploy_cpu.sh: NOT FOUND"
Проверим права:
ls -l serverless/deploy_cpu.sh
Если файл не имеет права на выполнение:
chmod +x serverless/deploy_cpu.sh
Посмотрим содержимое скрипта:
sed -n '1,260p' \
serverless/deploy_cpu.sh
Особое внимание нужно обратить на:
- имя Nuclio-проекта;
- Docker-сеть;
- адрес Redis;
- параметры команды nuctl deploy;
- способ поиска function.yaml.
Выведем только важные строки:
grep -nE \
'nuctl|project|network|redis|function.yaml|platform|deploy' \
serverless/deploy_cpu.sh
3.8. Проверяем Docker-сеть
Nuclio-функция должна быть подключена к той же сети, через которую CVAT взаимодействует со своими сервисами.
Проверим сеть сервера:
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
Для рассматриваемой установки результат:
cvat_cvat
Проверим существующую функцию:
docker inspect nuclio-nuclio-centernet-detector \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
В выводе также должна присутствовать:
cvat_cvat
Это подтверждает, что модель и CVAT находятся в общей Docker-сети.
3.9. Проверяем, не развёрнута ли YOLOv5 ранее
Выведем список функций Nuclio:
nuctl get functions \
--platform local
Также проверим Docker-контейнеры:
docker ps -a \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \
| grep -Ei 'NAME|yolo|nuclio'
Если функции YOLOv5 в списке нет, её можно будет развернуть без конфликта имён.
Если функция уже существует, сначала нужно проверить её состояние и конфигурацию. Повторное развёртывание с тем же именем может обновить существующую функцию.
3.10. Выполняем итоговую проверку
Запустим единый диагностический блок:
cd /root/cvat
YOLO_ROOT="/root/cvat/serverless/pytorch/ultralytics/yolov5"
YOLO_FUNCTION_FILE=$(
find "$YOLO_ROOT" \
-type f \
-name 'function.yaml' \
| head -n 1
)
YOLO_FUNCTION_DIR=$(
dirname "$YOLO_FUNCTION_FILE"
)
echo "===== CVAT VERSION ====="
git describe --tags --always --dirty
git rev-parse --short HEAD
echo
echo "===== YOLO FUNCTION DIRECTORY ====="
echo "$YOLO_FUNCTION_DIR"
echo
echo "===== YOLO FILES ====="
find "$YOLO_FUNCTION_DIR" \
-maxdepth 2 \
-type f \
| sort
echo
echo "===== FUNCTION PARAMETERS ====="
grep -nE \
'name:|type: detector|framework:|runtime:|handler:|baseImage:' \
"$YOLO_FUNCTION_DIR/function.yaml"
echo
echo "===== MODEL LOADING ====="
grep -nE \
'torch\.hub\.load|yolov5[nsmlx]|model =' \
"$YOLO_FUNCTION_DIR/main.py"
echo
echo "===== CVAT NETWORK ====="
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
echo
echo "===== EXISTING FUNCTIONS ====="
nuctl get functions \
--platform local
На этом этапе мы только проверили функцию. Сборка Docker-образа и загрузка весов начнутся на следующем шаге.
Проверка конфигурации встроенной serverless-функции YOLOv5 перед развёртыванием в Nuclio.
4. Разворачиваем YOLOv5 в Nuclio
После проверки конфигурации можно собрать serverless-функцию и подключить её к CVAT.
Для рассматриваемой версии платформы используется встроенная функция:
serverless/pytorch/ultralytics/yolov5/nuclio
Её конфигурация содержит следующие параметры:
Имя функции: ultralytics-yolov5
Название в CVAT: YOLO v5
Тип: detector
Фреймворк: PyTorch
Runtime: Python 3.6
Базовый образ: ultralytics/yolov5:latest-cpu
Обработчик: main:handler
В старой версии CVAT функция рассчитана на Nuclio 1.8.14 и Python 3.6. Менять runtime на Python 3.8, 3.9 или более новую версию перед первым запуском не следует: это может нарушить совместимость с базовым образом и кодом функции.
Python 3.6 в Nuclio 1.8.14 уже отмечался как устаревший, но для старого встроенного примера CVAT его лучше оставить без изменений до успешного тестового запуска. В более новых версиях CVAT необходимо использовать конфигурацию модели из соответствующего checkout репозитория.
4.1. Переходим в каталог CVAT
cd /root/cvat
Проверим текущий каталог:
pwd
Ожидаемый результат:
/root/cvat
Зададим путь к функции:
YOLO_FUNCTION_DIR="serverless/pytorch/ultralytics/yolov5/nuclio"
Проверим основные файлы:
test -f "$YOLO_FUNCTION_DIR/function.yaml" \
&& echo "function.yaml: OK" \
|| echo "function.yaml: NOT FOUND"
test -f "$YOLO_FUNCTION_DIR/main.py" \
&& echo "main.py: OK" \
|| echo "main.py: NOT FOUND"
Ожидаемый результат:
function.yaml: OK
main.py: OK
4.2. Проверяем способ загрузки модели
Посмотрим фрагмент main.py, отвечающий за инициализацию:
grep -nE \
'def init_context|torch\.hub\.load|context\.user_data|yolov5|model[[:space:]]*=' \
"$YOLO_FUNCTION_DIR/main.py"
Для стандартной функции YOLOv5 код обычно загружает модель при запуске контейнера и сохраняет её в context.user_data.
Пример:
def init_context(context):
model = torch.hub.load(...)
context.user_data.model = model
Загрузка модели в init_context важна: веса и структура нейронной сети загружаются один раз при запуске контейнера, а не при обработке каждого изображения.
Посмотрим весь файл:
sed -n '1,240p' \
"$YOLO_FUNCTION_DIR/main.py"
Перед первым развёртыванием изменять main.py не требуется.
4.3. Создаём резервную копию конфигурации
Перед изменениями сохраним исходные файлы:
BACKUP_DIR="/root/cvat-model-backups/yolov5-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
cp \
"$YOLO_FUNCTION_DIR/function.yaml" \
"$YOLO_FUNCTION_DIR/main.py" \
"$BACKUP_DIR/"
Проверим резервную копию:
find "$BACKUP_DIR" \
-maxdepth 1 \
-type f \
-ls
Файлы будут сохранены вне каталога Git-репозитория:
/root/cvat-model-backups/
4.4. Проверяем версию nuctl
Версия консольного клиента должна соответствовать версии Nuclio Dashboard.
Выведем образ работающего Nuclio:
docker inspect nuclio \
--format '{{.Config.Image}}'
Для рассматриваемого сервера:
quay.io/nuclio/dashboard:1.8.14-amd64
Проверим клиент:
nuctl version
В выводе должна присутствовать версия:
1.8.14
Дополнительно можно выполнить:
echo "Nuclio Dashboard:"
docker inspect nuclio \
--format '{{.Config.Image}}'
echo
echo "nuctl:"
nuctl version
При несовпадении версий развёртывание функции лучше не запускать.
4.5. Проверяем Docker-сеть
Функция должна находиться в одной Docker-сети с CVAT.
CVAT_NETWORK=$(
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}' \
| head -n 1
)
echo "CVAT network: $CVAT_NETWORK"
Для рассматриваемой установки:
CVAT network: cvat_cvat
Проверим, что сеть существует:
docker network inspect "$CVAT_NETWORK" \
>/dev/null \
&& echo "Docker network: OK"
4.6. Проверяем базовый образ YOLOv5
В function.yaml используется базовый образ:
ultralytics/yolov5:latest-cpu
Проверим, присутствует ли он на сервере:
docker image inspect \
ultralytics/yolov5:latest-cpu \
>/dev/null 2>&1 \
&& echo "Base image is already available" \
|| echo "Base image is not downloaded"
Посмотрим существующие локальные образы YOLO:
docker images \
--digests \
ultralytics/yolov5
Если образ отсутствует, загрузим его отдельно:
docker pull ultralytics/yolov5:latest-cpu
Отдельная загрузка помогает заранее обнаружить проблемы с Docker Hub, DNS, свободным местом или авторизацией, не дожидаясь запуска полной сборки Nuclio.
После загрузки зафиксируем идентификатор образа:
docker image inspect \
ultralytics/yolov5:latest-cpu \
--format 'Image ID: {{.Id}}{{println}}Created: {{.Created}}{{println}}Digests: {{json .RepoDigests}}'
Тег latest-cpu является изменяемым, поэтому идентификатор или digest стоит сохранить в технической документации проекта.
4.7. Проверяем свободное место
Сборка функции создаёт дополнительные Docker-слои.
df -h /
Посмотрим использование диска Docker:
docker system df
Не следует выполнять перед сборкой:
docker system prune -a
Эта команда может удалить неиспользуемые образы, которые нужны другим контейнерам или для быстрого отката.
4.8. Проверяем существующие функции
nuctl get functions \
--platform local
На сервере уже может присутствовать другая функция, например:
centernet-detector
Это не мешает установке YOLOv5, поскольку у неё другое системное имя:
ultralytics-yolov5
Дополнительно проверим контейнеры:
docker ps -a \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \
| grep -Ei 'NAME|nuclio|yolov5|centernet'
4.9. Проверяем скрипт deploy_cpu.sh
CVAT содержит вспомогательный скрипт для развёртывания CPU-функций:
ls -l serverless/deploy_cpu.sh
Если файл не исполняемый:
chmod +x serverless/deploy_cpu.sh
Посмотрим, какие параметры он передаёт в Nuclio:
grep -nE \
'nuctl|project|platform|network|redis|deploy' \
serverless/deploy_cpu.sh
Официальный способ развёртывания встроенной CPU-функции CVAT — передать скрипту каталог, содержащий function.yaml и исходный код обработчика.
4.10. Запускаем сборку и развёртывание
Из корневого каталога CVAT выполним:
cd /root/cvat
Запустим функцию:
./serverless/deploy_cpu.sh \
serverless/pytorch/ultralytics/yolov5/nuclio
Для одновременного сохранения полного журнала используем:
set -o pipefail
./serverless/deploy_cpu.sh \
serverless/pytorch/ultralytics/yolov5/nuclio \
2>&1 \
| tee "/root/yolov5-deploy-$(date +%Y%m%d-%H%M%S).log"
Во время выполнения Nuclio:
- прочитает function.yaml;
- загрузит необходимые Docker-образы;
- подготовит Python-обработчик;
- соберёт итоговый образ функции;
- создаст контейнер модели;
- подключит его к Docker-сети CVAT;
- зарегистрирует функцию в проекте cvat;
- проверит готовность HTTP-обработчика.
Сборка может выводить предупреждение об устаревшем Python 3.6. Для этой версии функции предупреждение само по себе не означает ошибку.
Успешное завершение обычно сопровождается сообщениями:
Build complete
Function deploy complete
Function is ready
Критическим является итоговое состояние функции, а не наличие предупреждений в середине журнала.
4.11. Проверяем состояние функции
После завершения сборки выполним:
nuctl get functions \
--platform local
В списке должна появиться функция YOLOv5 со статусом:
ready
Проверим Docker-контейнер:
docker ps \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}' \
| grep -Ei 'NAME|yolov5'
Имя контейнера обычно начинается с:
nuclio-nuclio-ultralytics-yolov5
Точное имя получим автоматически:
YOLO_CONTAINER=$(
docker ps \
--format '{{.Names}}' \
| grep -i 'yolov5' \
| head -n 1
)
echo "YOLO container: $YOLO_CONTAINER"
Проверим статус:
docker inspect "$YOLO_CONTAINER" \
--format 'Status: {{.State.Status}}{{println}}Started: {{.State.StartedAt}}{{println}}Restarting: {{.State.Restarting}}'
4.12. Проверяем журнал функции
docker logs \
--tail 100 \
"$YOLO_CONTAINER"
Для просмотра только ошибок:
docker logs \
"$YOLO_CONTAINER" \
2>&1 \
| grep -Ei \
'error|exception|traceback|failed'
Отсутствие вывода у второй команды означает, что в текущем журнале не найдено строк с типичными признаками ошибки.
Проверим, не перезапускается ли контейнер:
docker inspect "$YOLO_CONTAINER" \
--format 'Restart count: {{.RestartCount}}'
Ожидаемый результат:
Restart count: 0
4.13. Проверяем подключение к сети CVAT
docker inspect "$YOLO_CONTAINER" \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
В выводе должна присутствовать сеть:
cvat_cvat
Проверим одновременно сеть CVAT и модели:
echo "CVAT server networks:"
docker inspect cvat_server \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
echo
echo "YOLOv5 networks:"
docker inspect "$YOLO_CONTAINER" \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
4.14. Итоговая проверка
cd /root/cvat
YOLO_CONTAINER=$(
docker ps \
--format '{{.Names}}' \
| grep -i 'yolov5' \
| head -n 1
)
echo "===== NUCTL FUNCTIONS ====="
nuctl get functions \
--platform local
echo
echo "===== YOLO CONTAINER ====="
docker ps \
--filter "name=$YOLO_CONTAINER" \
--format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
echo
echo "===== YOLO NETWORKS ====="
docker inspect "$YOLO_CONTAINER" \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
echo
echo "===== RESTART COUNT ====="
docker inspect "$YOLO_CONTAINER" \
--format '{{.RestartCount}}'
echo
echo "===== LAST LOG LINES ====="
docker logs \
--tail 20 \
"$YOLO_CONTAINER"
Если функция имеет состояние ready, контейнер запущен, подключён к сети cvat_cvat и не находится в цикле перезапуска, модель успешно развёрнута.
На следующем этапе проверим, появилась ли YOLOv5 в интерфейсе CVAT, создадим тестовую задачу и запустим автоматическую предразметку.
Успешно развёрнутая функция YOLOv5 в Nuclio и работающий контейнер модели.
5. Запускаем автоматическую предразметку в CVAT
После развёртывания проверим состояние функции:
cd /root/cvat
nuctl get functions --platform local
У функции ultralytics-yolov5 должен быть статус ready.
Дополнительно проверим контейнер:
docker ps \
--format 'table {{.Names}}\t{{.Status}}' \
| grep -Ei 'NAME|yolov5'
Проверяем модель в интерфейсе
Откройте CVAT и перейдите на страницу Models. В списке должна появиться модель:
YOLO v5
Страница Models показывает serverless-модели, которые были развёрнуты и доступны для автоматической или полуавтоматической разметки.
Если модель не появилась, обновите страницу и проверьте:
nuctl get functions --platform local
docker logs --tail 100 nuclio
Создаём тестовую задачу
Создайте новую задачу и загрузите 5–10 изображений с объектами, которые YOLOv5 умеет распознавать.
Добавьте несколько меток:
person
car
bicycle
dog
cat
Для первой проверки лучше использовать английские названия, совпадающие с классами модели. Позднее модель можно сопоставить и с русскими метками.
Запускаем автоматическую аннотацию
Откройте страницу Tasks, найдите тестовую задачу и выберите:
Actions → Automatic annotation
В появившемся окне:
- Выберите модель YOLO v5.
- Сопоставьте классы модели с метками задачи.
- Установите порог уверенности 0.5.
- Нажмите Annotate.
Официальный сценарий CVAT также предусматривает выбор модели, сопоставление меток и настройку порога уверенности перед запуском обработки.
Пример сопоставления:
|
Класс YOLOv5 |
Метка задачи |
|
person |
person |
|
car |
car |
|
dog |
dog |
Неиспользуемые классы можно не сопоставлять.
Параметр Clean old annotations удаляет существующую разметку перед запуском модели. Для пустой тестовой задачи он не требуется.
Следим за работой модели
Во время обработки можно открыть вторую SSH-сессию и смотреть журнал контейнера:
YOLO_CONTAINER=$(
docker ps \
--format '{{.Names}}' \
| grep -i yolov5 \
| head -n 1
)
docker logs \
--follow \
--tail 50 \
"$YOLO_CONTAINER"
После завершения CVAT покажет окончание операции. Откройте задачу и перейдите в Job.
На изображениях должны появиться прямоугольники с названиями классов модели.
Если объектов слишком мало, уменьшите порог до 0.3. Если модель создаёт много ошибочных прямоугольников, увеличьте его до 0.6–0.7.
Автоматическая разметка не заменяет проверку человеком. Разметчик должен удалить ложные срабатывания, добавить пропущенные объекты и скорректировать границы прямоугольников.
Откройте раздел Tasks, найдите нужную задачу и раскройте меню Actions на её карточке. В некоторых версиях CVAT это меню обозначено значком с тремя точками. Выберите пункт Automatic annotation.
CVAT: Tasks → открыть задачу → Actions → Automatic annotation
6. Проверяем результат предразметки
После завершения Automatic annotation откройте задачу и перейдите в Job. CVAT должен добавить найденные объекты как обычные прямоугольники, доступные для редактирования.
Разметчику необходимо проверить:
- правильно ли выбран класс объекта;
- не выходит ли bounding box за границы объекта;
- нет ли пропущенных объектов;
- нет ли ложных срабатываний;
- размечены ли частично перекрытые объекты.
Автоматическая аннотация создаёт предварительную разметку, но не заменяет ручной контроль качества. CVAT позволяет сопоставить классы модели с метками задачи перед запуском обработки.
Подбираем порог уверенности
Для первого запуска можно использовать значение:
0.5
Практическая настройка:
- 0.3–0.4 — модель найдёт больше объектов, но увеличится число ошибок;
- 0.5 — подходящее стартовое значение;
- 0.6–0.7 — меньше ложных срабатываний, но больше пропусков.
Оптимальный порог лучше определить на небольшой тестовой выборке, а затем использовать для всего датасета.
Проверяем работу модели на сервере
Посмотрим статус функции:
nuctl get functions --platform local
Найдём контейнер YOLOv5:
YOLO_CONTAINER=$(
docker ps \
--format '{{.Names}}' \
| grep -i yolov5 \
| head -n 1
)
echo "$YOLO_CONTAINER"
Проверим последние запросы:
docker logs \
--tail 100 \
"$YOLO_CONTAINER"
Для просмотра журнала во время запуска предразметки:
docker logs \
--follow \
--tail 30 \
"$YOLO_CONTAINER"
Остановить просмотр можно сочетанием:
Ctrl+C
Это не останавливает контейнер или обработку задачи.
Если аннотации не появились
Проверьте состояние функции:
nuctl get functions --platform local
Она должна иметь статус ready.
Проверьте ошибки контейнера:
docker logs "$YOLO_CONTAINER" 2>&1 \
| grep -Ei 'error|exception|traceback|failed'
Проверьте, что модель подключена к сети CVAT:
docker inspect "$YOLO_CONTAINER" \
--format '{{range $name, $value := .NetworkSettings.Networks}}{{println $name}}{{end}}'
Ожидаемая сеть:
cvat_cvat
Если функция работает, но объекты не найдены:
- уменьшите confidence threshold;
- используйте изображения с классами COCO;
- проверьте сопоставление классов;
- убедитесь, что изображения корректно открываются в CVAT.
После проверки сохраните исправленную разметку кнопкой Save в интерфейсе Job.
Результат автоматической предразметки YOLOv5, открытый для проверки и корректировки разметчиком.
Заключение
Подключение модели к CVAT позволяет перенести значительную часть однотипной работы с разметчика на алгоритм. Вместо того чтобы создавать каждый объект вручную, специалист получает готовую предразметку и сосредотачивается на проверке классов, исправлении границ и добавлении пропущенных объектов.
В этом руководстве мы:
- проверили установленную версию CVAT;
- подключили инфраструктуру Nuclio;
- установили совместимую версию nuctl;
- выбрали встроенную модель YOLOv5;
- развернули её как serverless-функцию;
- запустили автоматическую аннотацию;
- проверили результат в интерфейсе CVAT.
Главное преимущество такого подхода — модель становится частью привычного процесса разметки. Разметчикам не требуется запускать отдельные скрипты, выгружать изображения или вручную импортировать результаты. Предсказания создаются непосредственно в задаче CVAT и редактируются как обычные аннотации.
При этом предразметку не следует рассматривать как полностью автоматическую замену ручной работы. Качество результата зависит от состава датасета, классов модели, порога уверенности и различий между обучающими данными модели и реальными изображениями проекта. Перед обработкой большого массива данных модель необходимо проверить на небольшой выборке и оценить, действительно ли исправление предсказаний занимает меньше времени, чем разметка с нуля.
Стандартная YOLOv5 подходит для проверки самой интеграции и работы с распространёнными объектами из датасета COCO. Для производственного проекта обычно требуется собственная модель, обученная на целевых классах: промышленном оборудовании, медицинских изображениях, товарах, документах, дорожной инфраструктуре или других специализированных объектах.
После успешного тестового запуска встроенную модель можно заменить собственной. Для этого потребуется изменить список классов в function.yaml, подключить веса модели и адаптировать обработчик так, чтобы он возвращал результаты в формате CVAT. Общая схема работы при этом останется прежней:
Изображение в CVAT
↓
Serverless-функция Nuclio
↓
Инференс модели
↓
Предварительные аннотации
↓
Проверка разметчиком
↓
Готовый датасет
Таким образом, CVAT и Nuclio позволяют создать управляемый процесс разметки с участием человека: модель ускоряет обработку данных, а разметчик обеспечивает точность и соответствие требованиям проекта.
О компании US-DATA
US-DATA помогает компаниям готовить данные для обучения моделей машинного обучения, компьютерного зрения и искусственного интеллекта. Команда выполняет разметку изображений, видео, текстов и аудио, разрабатывает инструкции для разметчиков, организует контроль качества и подготавливает датасеты в форматах, необходимых для обучения моделей.
Подробнее об услугах:
- Разметка изображений для нейронных сетей
- Детекция объектов и разметка Bounding Box
- Сегментация изображений
- Разметка изображений полигонами
- Разметка видеоданных
Если вам необходимо подготовить датасет, организовать предразметку с помощью модели или масштабировать работу команды аннотаторов, специалисты US-DATA помогут подобрать инструменты и выстроить процесс с учётом требований вашего ML-проекта.
