Разверни предобученную модель YOLO с помощью Ultralytics на Vertex AI для инференса
Это руководство покажет тебе, как контейнеризировать предобученную модель YOLO26 с помощью Ultralytics, собрать сервер инференса FastAPI для неё и развернуть модель с этим сервером на Google Cloud Vertex AI. Пример реализации охватывает задачу обнаружения объектов для YOLO26, но те же принципы применимы и к другим режимам YOLO.
Прежде чем мы начнем, тебе нужно создать проект в Google Cloud Platform (GCP). Ты получишь $300 в виде кредитов GCP для бесплатного использования в качестве нового пользователя, и этой суммы достаточно, чтобы протестировать рабочую конфигурацию, которую ты позже сможешь расширить для любого другого варианта использования YOLO26, включая обучение или пакетный и потоковый инференс.
Что ты узнаешь
- Создашь бэкенд инференса для модели Ultralytics YOLO26 с использованием FastAPI.
- Создашь репозиторий в GCP Artifact Registry для хранения твоего Docker-образа.
- Соберешь и отправишь Docker-образ с моделью в Artifact Registry.
- Импортируешь свою модель в Vertex AI.
- Создашь эндпоинт Vertex AI и развернешь модель.
- Полный контроль над моделью с Ultralytics: Ты можешь использовать собственную логику инференса с полным контролем над препроцессингом, постпроцессингом и форматированием ответов.
- Vertex AI берет на себя всё остальное: Система автоматически масштабируется, при этом сохраняется гибкость в настройке вычислительных ресурсов, памяти и конфигураций GPU.
- Нативные интеграции GCP и безопасность: Бесшовная настройка с Cloud Storage, BigQuery, Cloud Functions, элементами управления VPC, политиками IAM и журналами аудита.
Предварительные требования
- Установи Docker на свой компьютер.
- Установи Google Cloud SDK и пройди аутентификацию для использования gcloud CLI.
- Настоятельно рекомендуется ознакомиться с Руководством по быстрому старту Docker для Ultralytics, поскольку при выполнении этого руководства тебе потребуется расширить один из официальных Docker-образов Ultralytics.
Создай бэкенд инференса с помощью FastAPI
Сначала тебе нужно создать приложение FastAPI, которое будет обслуживать запросы инференса модели YOLO26. Это приложение будет обрабатывать логику загрузки модели, препроцессинга изображений и инференса (предсказания).
Основы соответствия требованиям Vertex AI
Vertex AI ожидает, что твой контейнер будет реализовывать два специфических эндпоинта:
-
Health эндпоинт (
/health): Должен возвращать HTTP-статус200 OK, когда сервис готов. -
Predict эндпоинт (
/predict): Принимает структурированные запросы на предсказание с изображениями в формате base64-encoded и опциональными параметрами. Применяются ограничения на размер полезной нагрузки в зависимости от типа эндпоинта.Полезные нагрузки запросов для эндпоинта
/predictдолжны соответствовать этой структуре JSON:{ "instances": [{ "image": "base64_encoded_image" }], "parameters": { "confidence": 0.5 } }
Структура папок проекта
Основная часть нашей сборки будет происходить внутри Docker-контейнера, и Ultralytics также загрузит предобученную модель YOLO26, поэтому ты можешь поддерживать простую структуру локальных папок:
YOUR_PROJECT/
├── src/
│ ├── __init__.py
│ ├── app.py # Core YOLO26 inference logic
│ └── main.py # FastAPI inference server
├── tests/
├── .env # Environment variables for local development
├── Dockerfile # Container configuration
├── LICENSE # AGPL-3.0 License
└── pyproject.toml # Python dependencies and project configМодели и фреймворк Ultralytics YOLO26 лицензируются под AGPL-3.0, что накладывает важные требования по соблюдению условий. Обязательно прочитай документацию Ultralytics о том, как соблюдать условия лицензии.
Создай pyproject.toml с зависимостями
Для удобного управления своим проектом создай файл pyproject.toml со следующими зависимостями:
[project]
name = "YOUR_PROJECT_NAME"
version = "0.0.1"
description = "YOUR_PROJECT_DESCRIPTION"
requires-python = ">=3.10,<3.13"
dependencies = [
"ultralytics>=8.3.0",
"fastapi[all]>=0.89.1",
"uvicorn[standard]>=0.20.0",
"pillow>=9.0.0",
]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"uvicornбудет использоваться для запуска сервера FastAPI.pillowбудет использоваться для обработки изображений, но ты не ограничен только изображениями PIL — Ultralytics поддерживает множество других форматов.
Создай логику инференса с Ultralytics YOLO26
Теперь, когда структура проекта и зависимости настроены, ты можешь реализовать основную логику инференса YOLO26. Создай файл src/app.py, который будет обрабатывать загрузку модели, обработку изображений и предсказание с использованием Python API Ultralytics.
# src/app.py
from ultralytics import YOLO
# Model initialization and readiness state
model_yolo = None
_model_ready = False
def _initialize_model():
"""Initialize the YOLO model."""
global model_yolo, _model_ready
try:
# Use pretrained YOLO26n model from Ultralytics base image
model_yolo = YOLO("yolo26n.pt")
_model_ready = True
except Exception as e:
print(f"Error initializing YOLO model: {e}")
_model_ready = False
model_yolo = None
# Initialize model on module import
_initialize_model()
def is_model_ready() -> bool:
"""Check if the model is ready for inference."""
return _model_ready and model_yolo is not NoneЭто позволит загрузить модель один раз при запуске контейнера, и модель будет использоваться для всех запросов. Если твоя модель будет обрабатывать большую нагрузку инференса, рекомендуется выбрать тип машины с большим объемом памяти при импорте модели в Vertex AI на более позднем этапе.
Далее создай две вспомогательные функции для обработки входных и выходных изображений с помощью pillow. YOLO26 поддерживает изображения PIL нативно.
def get_image_from_bytes(binary_image: bytes) -> Image.Image:
"""Convert image from bytes to PIL RGB format."""
input_image = Image.open(io.BytesIO(binary_image)).convert("RGB")
return input_imagedef get_bytes_from_image(image: Image.Image) -> bytes:
"""Convert PIL image to bytes."""
return_image = io.BytesIO()
image.save(return_image, format="JPEG", quality=85)
return_image.seek(0)
return return_image.getvalue()Наконец, реализуй функцию run_inference, которая будет обрабатывать обнаружение объектов. В этом примере мы извлечем ограничивающие рамки (bbox), имена классов и показатели уверенности из предсказаний модели. Функция вернет словарь с обнаружениями и необработанными результатами для дальнейшей обработки или аннотирования.
def run_inference(input_image: Image.Image, confidence_threshold: float = 0.5) -> Dict[str, Any]:
"""Run inference on an image using YOLO26n model."""
global model_yolo
# Check if model is ready
if not is_model_ready():
print("Model not ready for inference")
return {"detections": [], "results": None}
try:
# Make predictions and get raw results
results = model_yolo.predict(
imgsz=640, source=input_image, conf=confidence_threshold, save=False, augment=False, verbose=False
)
# Extract detections (bounding boxes, class names, and confidences)
detections = []
if results and len(results) > 0:
result = results[0]
if result.boxes is not None and len(result.boxes.xyxy) > 0:
boxes = result.boxes
# Convert tensors to numpy for processing
xyxy = boxes.xyxy.cpu().numpy()
conf = boxes.conf.cpu().numpy()
cls = boxes.cls.cpu().numpy().astype(int)
# Create detection dictionaries
for i in range(len(xyxy)):
detection = {
"xmin": float(xyxy[i][0]),
"ymin": float(xyxy[i][1]),
"xmax": float(xyxy[i][2]),
"ymax": float(xyxy[i][3]),
"confidence": float(conf[i]),
"class": int(cls[i]),
"name": model_yolo.names.get(int(cls[i]), f"class_{int(cls[i])}"),
}
detections.append(detection)
return {
"detections": detections,
"results": results, # Keep raw results for annotation
}
except Exception as e:
# If there's an error, return empty structure
print(f"Error in YOLO detection: {e}")
return {"detections": [], "results": None}При желании ты можешь добавить функцию для аннотирования изображения с помощью ограничивающих рамок и меток, используя встроенный метод построения графиков Ultralytics. Это будет полезно, если ты хочешь возвращать аннотированные изображения в ответе на предсказание.
def get_annotated_image(results: list) -> Image.Image:
"""Get annotated image using Ultralytics built-in plot method."""
if not results or len(results) == 0:
raise ValueError("No results provided for annotation")
result = results[0]
# Use Ultralytics built-in plot method with PIL output
return result.plot(pil=True)Создай HTTP-сервер инференса с помощью FastAPI
Теперь, когда у тебя есть основная логика инференса YOLO26, ты можешь создать приложение FastAPI для её обслуживания. Это включит проверку работоспособности и эндпоинты предсказания, требуемые Vertex AI.
Сначала добавь импорты и настрой логирование для Vertex AI. Поскольку Vertex AI рассматривает stderr как вывод ошибок, имеет смысл перенаправить логи в stdout.
import sys
from loguru import logger
# Configure logger
logger.remove()
logger.add(
sys.stdout,
colorize=True,
format="<green>{time:HH:mm:ss}</green> | <level>{message}</level>",
level=10,
)
logger.add("log.log", rotation="1 MB", level="DEBUG", compression="zip")Для полного соответствия требованиям Vertex AI определи требуемые эндпоинты в переменных окружения и установи ограничение размера для запросов. Рекомендуется использовать приватные эндпоинты Vertex AI для производственных развертываний. Таким образом, у тебя будет более высокий лимит полезной нагрузки запроса (10 МБ вместо 1.5 МБ для публичных эндпоинтов), а также надежная безопасность и контроль доступа.
# Vertex AI environment variables
AIP_HTTP_PORT = int(os.getenv("AIP_HTTP_PORT", "8080"))
AIP_HEALTH_ROUTE = os.getenv("AIP_HEALTH_ROUTE", "/health")
AIP_PREDICT_ROUTE = os.getenv("AIP_PREDICT_ROUTE", "/predict")
# Request size limit (10 MB for private endpoints, 1.5 MB for public)
MAX_REQUEST_SIZE = 10 * 1024 * 1024 # 10 MB in bytesДобавь две модели Pydantic для валидации твоих запросов и ответов:
# Pydantic models for request/response
class PredictionRequest(BaseModel):
instances: list
parameters: Optional[Dict[str, Any]] = None
class PredictionResponse(BaseModel):
predictions: listДобавь эндпоинт проверки работоспособности, чтобы подтвердить готовность модели. Это важно для Vertex AI, так как без специальной проверки работоспособности его оркестратор будет пинговать случайные сокеты и не сможет определить, готова ли модель к инференсу. Твоя проверка должна возвращать 200 OK при успехе и 503 Service Unavailable при сбое:
# Health check endpoint
@app.get(AIP_HEALTH_ROUTE, status_code=status.HTTP_200_OK)
def health_check():
"""Health check endpoint for Vertex AI."""
if not is_model_ready():
raise HTTPException(status_code=503, detail="Model not ready")
return {"status": "healthy"}Теперь у тебя есть всё для реализации эндпоинта предсказания, который будет обрабатывать запросы инференса. Он будет принимать файл изображения, запускать инференс и возвращать результаты. Обрати внимание, что изображение должно быть в формате base64-encoded, что дополнительно увеличивает размер полезной нагрузки до 33%.
@app.post(AIP_PREDICT_ROUTE, response_model=PredictionResponse)
async def predict(request: PredictionRequest):
"""Prediction endpoint for Vertex AI."""
try:
predictions = []
for instance in request.instances:
if isinstance(instance, dict):
if "image" in instance:
image_data = base64.b64decode(instance["image"])
input_image = get_image_from_bytes(image_data)
else:
raise HTTPException(status_code=400, detail="Instance must contain 'image' field")
else:
raise HTTPException(status_code=400, detail="Invalid instance format")
# Extract YOLO26 parameters if provided
parameters = request.parameters or {}
confidence_threshold = parameters.get("confidence", 0.5)
return_annotated_image = parameters.get("return_annotated_image", False)
# Run inference with YOLO26n model
result = run_inference(input_image, confidence_threshold=confidence_threshold)
detections_list = result["detections"]
# Format predictions for Vertex AI
detections = []
for detection in detections_list:
formatted_detection = {
"class": detection["name"],
"confidence": detection["confidence"],
"bbox": {
"xmin": detection["xmin"],
"ymin": detection["ymin"],
"xmax": detection["xmax"],
"ymax": detection["ymax"],
},
}
detections.append(formatted_detection)
# Build prediction response
prediction = {"detections": detections, "detection_count": len(detections)}
# Add annotated image if requested and detections exist
if (
return_annotated_image
and result["results"]
and result["results"][0].boxes is not None
and len(result["results"][0].boxes) > 0
):
import base64
annotated_image = get_annotated_image(result["results"])
img_bytes = get_bytes_from_image(annotated_image)
prediction["annotated_image"] = base64.b64encode(img_bytes).decode("utf-8")
predictions.append(prediction)
logger.info(
f"Processed {len(request.instances)} instances, found {sum(len(p['detections']) for p in predictions)} total detections"
)
return PredictionResponse(predictions=predictions)
except HTTPException:
# Re-raise HTTPException as-is (don't catch and convert to 500)
raise
except Exception as e:
logger.error(f"Prediction error: {e}")
raise HTTPException(status_code=500, detail=f"Prediction failed: {e}")Наконец, добавь точку входа приложения для запуска сервера FastAPI.
if __name__ == "__main__":
import uvicorn
logger.info(f"Starting server on port {AIP_HTTP_PORT}")
logger.info(f"Health check route: {AIP_HEALTH_ROUTE}")
logger.info(f"Predict route: {AIP_PREDICT_ROUTE}")
uvicorn.run(app, host="0.0.0.0", port=AIP_HTTP_PORT)Теперь у тебя есть полноценное приложение FastAPI, которое может обслуживать запросы инференса YOLO26. Ты можешь протестировать его локально, установив зависимости и запустив сервер, например, с помощью uv.
# Install dependencies
uv pip install -e .
# Run the FastAPI server directly
uv run src/main.pyЧтобы протестировать сервер, ты можешь отправить запросы к эндпоинтам /health и /predict с помощью cURL. Помести тестовое изображение в папку tests. Затем в своем Терминале выполни следующие команды:
# Test health endpoint
curl http://localhost:8080/health
# Test predict endpoint with base64 encoded image
curl -X POST -H "Content-Type: application/json" -d "{\"instances\": [{\"image\": \"$(base64 -i tests/test_image.jpg)\"}]}" http://localhost:8080/predictТы должен получить JSON-ответ с обнаруженными объектами. При первом запросе ожидай небольшую задержку, так как Ultralytics нужно скачать и загрузить модель YOLO26.
Расширь Docker-образ Ultralytics своим приложением
Ultralytics предоставляет несколько Docker-образов, которые ты можешь использовать в качестве базы для образа своего приложения. Docker установит Ultralytics и необходимые драйверы GPU.
Чтобы использовать все возможности моделей Ultralytics YOLO, тебе следует выбрать CUDA-оптимизированный образ для GPU-инференса. Однако, если для твоей задачи достаточно CPU-инференса, ты можешь сэкономить вычислительные ресурсы, выбрав образ только для CPU:
- Dockerfile: CUDA-оптимизированный образ для одно- и мульти-GPU обучения и инференса YOLO26.
- Dockerfile-cpu: Образ только для CPU для инференса YOLO26.
Создай Docker-образ для своего приложения
Создай Dockerfile в корне твоего проекта со следующим содержимым:
# Extends official Ultralytics Docker image for YOLO26
FROM ultralytics/ultralytics:latest
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# Install FastAPI and dependencies
RUN uv pip install fastapi[all] uvicorn[standard] loguru
WORKDIR /app
COPY src/ ./src/
COPY pyproject.toml ./
# Install the application package
RUN uv pip install -e .
RUN mkdir -p /app/logs
ENV PYTHONPATH=/app/src
# Port for Vertex AI
EXPOSE 8080
# Start the inference server
ENTRYPOINT ["python", "src/main.py"]В этом примере в качестве базы используется официальный Docker-образ Ultralytics ultralytics:latest. Он уже содержит модель YOLO26 и все необходимые зависимости. Точка входа сервера такая же, как мы использовали для тестирования приложения FastAPI локально.
Собери и протестируй Docker-образ
Теперь ты можешь собрать Docker-образ с помощью следующей команды:
docker build --platform linux/amd64 -t IMAGE_NAME:IMAGE_VERSION .Замени IMAGE_NAME и IMAGE_VERSION на желаемые значения, например, yolo26-fastapi:0.1. Обрати внимание, что ты должен собрать образ для архитектуры linux/amd64, если развертываешь его на Vertex AI. Параметр --platform должен быть явно задан, если ты собираешь образ на Mac с Apple Silicon или любой другой не-x86 архитектуре.
После завершения сборки образа ты можешь протестировать Docker-образ локально:
docker run --platform linux/amd64 -p 8080:8080 IMAGE_NAME:IMAGE_VERSIONТвой Docker-контейнер теперь запускает сервер FastAPI на порту 8080 и готов принимать запросы инференса. Ты можешь протестировать как /health, так и /predict эндпоинты с помощью тех же команд cURL, что и раньше:
# Test health endpoint
curl http://localhost:8080/health
# Test predict endpoint with base64 encoded image
curl -X POST -H "Content-Type: application/json" -d "{\"instances\": [{\"image\": \"$(base64 -i tests/test_image.jpg)\"}]}" http://localhost:8080/predictЗагрузи Docker-образ в GCP Artifact Registry
Чтобы импортировать свою контейнеризированную модель в Vertex AI, тебе нужно загрузить Docker-образ в Google Cloud Artifact Registry. Если у тебя еще нет репозитория Artifact Registry, сначала нужно будет его создать.
Создай репозиторий в Google Cloud Artifact Registry
Открой страницу Artifact Registry в Google Cloud Console. Если ты используешь Artifact Registry впервые, тебе может потребоваться сначала включить Artifact Registry API.
- Выбери "Создать репозиторий".
- Введи имя своего репозитория. Выбери желаемый регион и используй настройки по умолчанию для других параметров, если тебе не нужно менять их специфическим образом.
Выбор региона может повлиять на доступность машин и определенные вычислительные ограничения для не-Enterprise пользователей. Дополнительную информацию можно найти в официальной документации Vertex AI: Квоты и лимиты Vertex AI
- После создания репозитория сохрани свой PROJECT_ID, местоположение (регион) и имя репозитория в свое хранилище секретов или файл
.env. Они понадобятся тебе позже для тегирования и отправки Docker-образа в Artifact Registry.
Пройди аутентификацию Docker в Artifact Registry
Пройди аутентификацию своего Docker-клиента в созданном репозитории Artifact Registry. Выполни следующую команду в своем терминале:
gcloud auth configure-docker YOUR_REGION-docker.pkg.devТегируй и отправь свой образ в Artifact Registry
Тегируй и отправь Docker-образ в Google Artifact Registry.
Рекомендуется использовать уникальные теги каждый раз при обновлении образа. Большинство сервисов GCP, включая Vertex AI, полагаются на теги образов для автоматического версионирования и масштабирования, поэтому хорошей практикой является использование семантического версионирования или тегов на основе даты.
Тегируй свой образ с помощью URL репозитория Artifact Registry. Замени плейсхолдеры значениями, которые ты сохранил ранее.
docker tag IMAGE_NAME:IMAGE_VERSION YOUR_REGION-docker.pkg.dev/YOUR_PROJECT_ID/YOUR_REPOSITORY_NAME/IMAGE_NAME:IMAGE_VERSIONОтправь тегированный образ в репозиторий Artifact Registry.
docker push YOUR_REGION-docker.pkg.dev/YOUR_PROJECT_ID/YOUR_REPOSITORY_NAME/IMAGE_NAME:IMAGE_VERSIONДождись завершения процесса. Теперь ты должен увидеть образ в своем репозитории Artifact Registry.
Для получения более специфических инструкций о том, как работать с образами в Artifact Registry, смотри документацию Artifact Registry: Push and pull images.
Импортируй свою модель в Vertex AI
Используя Docker-образ, который ты только что отправил, ты теперь можешь импортировать модель в Vertex AI.
- В навигационном меню Google Cloud перейди в Vertex AI > Model Registry. В качестве альтернативы выполни поиск "Vertex AI" в строке поиска в верхней части Google Cloud Console.
Создай Vertex AI Endpoint и разверни модель
В терминологии Vertex AI эндпоинты относятся к развернутым моделям, так как они представляют собой HTTP-эндпоинты, куда ты отправляешь запросы инференса, тогда как модели — это обученные ML-артефакты, хранящиеся в Model Registry.
Чтобы развернуть модель, тебе нужно создать эндпоинт в Vertex AI.
- В навигационном меню Vertex AI перейди в Endpoints. Выбери регион, который ты использовал при импорте модели. Нажми Create.
Помни, что в некоторых регионах очень ограниченные вычислительные квоты, поэтому ты не сможешь выбрать определенные типы машин или GPU в своем регионе. Если это критично, измени регион развертывания на тот, где квота больше. Дополнительную информацию можно найти в официальной документации Vertex AI: Квоты и лимиты Vertex AI.
- После выбора типа машины ты можешь нажать Continue. В этот момент ты можешь выбрать включение мониторинга модели в Vertex AI — дополнительный сервис, который будет отслеживать производительность твоей модели и предоставлять аналитику её поведения. Это опционально и влечет за собой дополнительные расходы, поэтому выбирай в соответствии со своими потребностями. Нажми Create.
Vertex AI потребуется несколько минут (до 30 минут в некоторых регионах) для развертывания модели. Ты получишь уведомление по электронной почте, как только развертывание будет завершено.
Протестируй развернутую модель
Как только развертывание будет завершено, Vertex AI предоставит тебе образец API-интерфейса для тестирования модели.
Для тестирования удаленного инференса ты можешь использовать предоставленную команду cURL или создать другую библиотеку Python-клиента, которая будет отправлять запросы к развернутой модели. Помни, что тебе нужно закодировать изображение в base64 перед отправкой его к эндпоинту /predict.
Как и при локальном тестировании, ожидай короткую задержку на первом запросе, так как Ultralytics нужно будет скачать и загрузить модель YOLO26 в запущенный контейнер.
Ты успешно развернул предобученную модель YOLO26 с помощью Ultralytics на Google Cloud Vertex AI.
Часто задаваемые вопросы (FAQ)
Могу ли я использовать модели Ultralytics YOLO на Vertex AI без Docker?
Да, однако сначала тебе нужно будет экспортировать модель в формат, совместимый с Vertex AI, такой как TensorFlow, Scikit-learn или XGBoost. Google Cloud предоставляет руководство по запуску моделей .pt на Vertex с полным обзором процесса конвертации: Запуск моделей PyTorch на Vertex AI.
Пожалуйста, обрати внимание, что результирующая настройка будет полагаться только на стандартный уровень обслуживания Vertex AI и не будет поддерживать продвинутые функции фреймворка Ultralytics. Поскольку Vertex AI полностью поддерживает контейнеризированные модели и может автоматически масштабировать их в соответствии с твоей конфигурацией развертывания, это позволяет тебе использовать все возможности моделей Ultralytics YOLO без необходимости конвертировать их в другой формат.
Почему FastAPI — отличный выбор для обслуживания инференса YOLO26?
FastAPI обеспечивает высокую пропускную способность для задач инференса. Поддержка асинхронности позволяет обрабатывать несколько параллельных запросов, не блокируя основной поток, что важно при обслуживании моделей компьютерного зрения.
Автоматическая валидация запросов и ответов в FastAPI снижает количество ошибок выполнения в продакшн-сервисах инференса. Это особенно ценно для API обнаружения объектов, где критически важна согласованность формата входных данных.
FastAPI добавляет минимальные вычислительные накладные расходы к твоему пайплайну инференса, оставляя больше ресурсов для выполнения модели и задач обработки изображений.
FastAPI также поддерживает SSE (Server-Sent Events), что полезно для сценариев потокового инференса.
Почему мне приходится так часто выбирать регион?
На самом деле, это особенность гибкости Google Cloud Platform, где тебе нужно выбирать регион для каждого используемого сервиса. Для задачи развертывания контейнеризированной модели на Vertex AI твой самый важный выбор региона — это регион для Model Registry. Он определяет доступность типов машин и квот для развертывания твоей модели.
Кроме того, если ты будешь расширять настройки и сохранять данные предсказаний или результаты в Cloud Storage или BigQuery, тебе нужно будет использовать тот же регион, что и для Model Registry, чтобы минимизировать задержку и обеспечить высокую пропускную способность для доступа к данным.