Vertex AI上で推論を行うために、学習済みYOLOモデルをUltralyticsでデプロイします。
本ガイドでは、学習済みYOLO26モデルをUltralyticsでコンテナ化し、FastAPI推論サーバーを構築した上で、その推論サーバーと共にGoogle Cloud Vertex AIへモデルをデプロイする方法を解説します。例としてYOLO26を用いた物体検出のユースケースを取り上げますが、他のYOLOモードを使用する場合も同様の原則が適用されます。
開始する前に、Google Cloud Platform (GCP) プロジェクトを作成する必要があります。新規ユーザーはGCPクレジットとして300ドル分を無料で利用でき、この金額はトレーニング、バッチ推論、ストリーミング推論など、他のあらゆるYOLO26のユースケースに後で拡張可能な実行環境をテストするのに十分です。
学習内容
- FastAPIを使用して、Ultralytics YOLO26モデル用の推論バックエンドを作成する。
- Dockerイメージを保存するためのGCP Artifact Registryリポジトリを作成する。
- モデルを含む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を使用するための認証を行ってください。
- 本ガイドを進める中で公式のUltralytics Dockerイメージのいずれかを拡張する必要があるため、Dockerクイックスタートガイド (Ultralytics用)に目を通しておくことを強く推奨します。
FastAPIを用いた推論バックエンドの作成
まず、YOLO26モデルの推論リクエストを処理するFastAPIアプリケーションを作成する必要があります。このアプリケーションは、モデルの読み込み、画像のプリプロセス、および推論(予測)ロジックを処理します。
Vertex AI準拠の基礎
Vertex AIは、コンテナが以下の2つの特定エンドポイントを実装することを想定しています。
-
ヘルスチェックエンドポイント (
/health): サービスが準備完了状態のときにHTTPステータス200 OKを返す必要があります。 -
予測エンドポイント (
/predict): base64エンコードされた画像とオプションのパラメータを含む構造化された予測リクエストを受け付けます。エンドポイントのタイプに応じてペイロードサイズ制限が適用されます。/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 configUltralytics 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 ファイルを作成し、Ultralytics Python APIを使用します。
# 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これにより、コンテナ起動時にモデルが1回読み込まれ、すべてのリクエストでモデルが共有されます。モデルが重い推論負荷を処理する場合、後のステップでVertex AIにモデルをインポートする際に、より多くのメモリを搭載したマシンタイプを選択することを推奨します。
次に、pillow を用いた入力および出力画像処理用の2つのユーティリティ関数を作成します。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 関数を実装します。この例では、モデルの予測からバウンディングボックス、クラス名、信頼スコアを抽出します。この関数は、さらなる処理やアノテーションを行うために、検出結果と生の予測結果を含む辞書を返します。
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)FastAPIによるHTTP推論サーバーの作成
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のプライベートエンドポイントを使用することを推奨します。これにより、堅牢なセキュリティとアクセス制御に加え、リクエストペイロードの制限が緩和されます(パブリックエンドポイントの1.5 MBに対して10 MBまで)。
# 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モデルを2つ追加します。
# Pydantic models for request/response
class PredictionRequest(BaseModel):
instances: list
parameters: Optional[Dict[str, Any]] = None
class PredictionResponse(BaseModel):
predictions: listモデルの準備状況を確認するためのヘルスチェックエンドポイントを追加します。これはVertex AIにおいて重要です。専用のヘルスチェックがないと、Vertex AIのオーケストレーターはランダムなソケットにpingを送信し、モデルが推論可能かどうかを判断できなくなります。チェックは、成功時には 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でエンコードされている必要があり、これによりペイロードサイズが最大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)これで、YOLO26の推論リクエストに応答できる完全なFastAPIアプリケーションが作成されました。依存関係をインストールし、uvなどを使用してサーバーをローカルで実行することでテストできます。
# Install dependencies
uv pip install -e .
# Run the FastAPI server directly
uv run src/main.pyサーバーをテストするには、cURLを使用して /health と /predict の両方のエンドポイントをクエリできます。テスト画像を 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モデルをプルして読み込む必要があるため、少し遅延が発生します。
アプリケーションでUltralytics Dockerイメージを拡張する
Ultralyticsは、アプリケーションイメージのベースとして使用できるDockerイメージをいくつか提供しています。DockerがUltralyticsと必要なGPUドライバーをインストールします。
Ultralytics YOLOモデルの全機能を活用するには、GPU推論用にCUDA最適化されたイメージを選択してください。ただし、CPU推論で十分な場合は、CPU専用イメージを選択することでコンピューティングリソースを節約することも可能です。
- Dockerfile: YOLO26のシングル/マルチGPUトレーニングおよび推論用のCUDA最適化イメージ。
- Dockerfile-cpu: YOLO26推論用のCPU専用イメージ。
アプリケーション用の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"]この例では、公式のUltralytics Dockerイメージである ultralytics:latest をベースとして使用しています。これにはすでにYOLO26モデルと必要なすべての依存関係が含まれています。サーバーのエントリポイントは、FastAPIアプリケーションをローカルでテストした際と同じです。
Dockerイメージのビルドとテスト
以下のコマンドでDockerイメージをビルドできます。
docker build --platform linux/amd64 -t IMAGE_NAME:IMAGE_VERSION .IMAGE_NAME と IMAGE_VERSION を yolo26-fastapi:0.1 のような希望する値に置き換えてください。Vertex AIにデプロイする場合、linux/amd64 アーキテクチャ向けにイメージをビルドする必要がある点に注意してください。Apple Silicon Macやその他の非x86アーキテクチャでビルドする場合は、--platform パラメータを明示的に指定する必要があります。
イメージのビルドが完了したら、Dockerイメージをローカルでテストできます。
docker run --platform linux/amd64 -p 8080:8080 IMAGE_NAME:IMAGE_VERSIONDockerコンテナがポート 8080 でFastAPIサーバーを実行しており、推論リクエストを受け付ける準備ができました。先ほどと同じcURLコマンドを使用して、/health エンドポイントと /predict エンドポイントの両方をテストできます。
# 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/predictGCP Artifact RegistryへDockerイメージをアップロードする
コンテナ化されたモデルをVertex AIにインポートするには、DockerイメージをGoogle Cloud Artifact Registryにアップロードする必要があります。Artifact Registryリポジトリをまだお持ちでない場合は、最初に作成する必要があります。
Google Cloud Artifact Registryにリポジトリを作成する
Google CloudコンソールのArtifact Registryページを開きます。初めてArtifact Registryを使用する場合、最初にArtifact Registry APIを有効にするよう求められることがあります。
- 「リポジトリを作成」を選択します。
- リポジトリ名を入力します。希望するリージョンを選択し、特に変更が必要な場合を除き、他のオプションはデフォルト設定を使用してください。
リージョンの選択は、非エンタープライズユーザーのマシンの可用性や特定のコンピューティング制限に影響する可能性があります。詳細はVertex AI公式ドキュメントのVertex AIの割り当てと制限を参照してください。
- リポジトリが作成されたら、PROJECT_ID、場所(リージョン)、リポジトリ名をシークレット保管庫または
.envファイルに保存してください。これらは後でDockerイメージにタグを付け、Artifact Registryにプッシュする際に必要になります。
Artifact Registryに対するDockerの認証
作成したばかりのArtifact Registryリポジトリに対してDockerクライアントを認証します。ターミナルで以下のコマンドを実行してください。
gcloud auth configure-docker YOUR_REGION-docker.pkg.devArtifact Registryへのイメージのタグ付けとプッシュ
Dockerイメージにタグを付け、Google Artifact Registryにプッシュします。
イメージを更新するたびに一意のタグを使用することを推奨します。Vertex AIを含むほとんどのGCPサービスは、自動バージョン管理とスケーリングにイメージタグを利用するため、セマンティックバージョニングや日付ベースのタグを使用するのが良い習慣です。
Artifact RegistryリポジトリのURLでイメージにタグを付けます。プレースホルダーを先ほど保存した値に置き換えてください。
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のドキュメントイメージのプッシュとプルを参照してください。
Vertex AIへのモデルのインポート
先ほどプッシュしたDockerイメージを使用して、Vertex AIにモデルをインポートできます。
- Google Cloudのナビゲーションメニューから「Vertex AI」>「モデルレジストリ」に移動します。または、Google Cloudコンソール上部の検索バーで「Vertex AI」を検索してください。
Vertex AIエンドポイントの作成とモデルのデプロイ
Vertex AIの用語では、モデルがモデルレジストリに保存された学習済みMLアーティファクトを指すのに対し、エンドポイントは推論リクエストを送信するHTTPの窓口であるため、デプロイされたモデルを指します。
モデルをデプロイするには、Vertex AIでエンドポイントを作成する必要があります。
- Vertex AIのナビゲーションメニューから「エンドポイント」に移動します。モデルをインポートする際に使用したリージョンを選択し、「作成」をクリックします。
特定のリージョンではコンピューティングの割り当てが非常に制限されているため、そのリージョンで特定のマシンタイプやGPUを選択できない場合があることに注意してください。これが重要な場合は、割り当て量が多い別のリージョンにデプロイ先を変更してください。詳細はVertex AI公式ドキュメントのVertex AIの割り当てと制限を参照してください。
- マシンタイプを選択したら「続行」をクリックします。この時点で、Vertex AIのモデルモニタリングを有効にできます。これは、モデルのパフォーマンスを追跡し、その動作に関する洞察を提供する追加サービスです。これはオプションであり追加費用が発生するため、必要に応じて選択してください。「作成」をクリックします。
Vertex AIがモデルをデプロイするまで数分(リージョンによっては最大30分)かかります。デプロイが完了するとメール通知が届きます。
デプロイされたモデルのテスト
デプロイが完了すると、Vertex AIはモデルをテストするためのサンプルAPIインターフェースを提供します。
リモート推論をテストするには、提供されたcURLコマンドを使用するか、デプロイされたモデルにリクエストを送信する別のPythonクライアントライブラリを作成します。/predict エンドポイントに送信する前に、画像をbase64でエンコードする必要があることを忘れないでください。
ローカルテストと同様に、実行中のコンテナ内でUltralyticsがYOLO26モデルをプルして読み込む必要があるため、最初のリクエストでは少し遅延が発生します。
Google Cloud Vertex AI上で、学習済みYOLO26モデルをUltralyticsを使用して正常にデプロイできました。
FAQ
DockerなしでVertex AI上でUltralytics YOLOモデルを使用できますか?
はい、可能ですが、最初にモデルをTensorFlow、Scikit-learn、XGBoostなど、Vertex AIと互換性のある形式にエクスポートする必要があります。Google Cloudは、Vertex上で .pt モデルを実行するためのガイドを提供しており、変換プロセスの詳細な概要を確認できます:Vertex AIでPyTorchモデルを実行する。
その結果として構築される環境はVertex AIの標準的なサービングレイヤーのみに依存するため、高度なUltralyticsフレームワーク機能はサポートされない点にご注意ください。Vertex AIはコンテナ化されたモデルを完全にサポートし、デプロイ構成に応じて自動的にスケーリングできるため、モデルを別の形式に変換することなく、Ultralytics YOLOモデルの全機能を活用できます。
YOLO26の推論サービスにおいて、なぜFastAPIが適しているのでしょうか?
FastAPIは推論ワークロードに対して高いスループットを提供します。非同期処理のサポートにより、メインスレッドをブロックせずに複数のリクエストを同時に処理できるため、コンピュータビジョンモデルをデプロイする際に重要となります。
FastAPIによる自動リクエスト/レスポンスバリデーションは、本番環境の推論サービスにおけるランタイムエラーを低減します。これは入力形式の一貫性が極めて重要な物体検出APIにとって特に有益です。
FastAPIは推論パイプラインへの計算オーバーヘッドを最小限に抑えるため、モデルの実行や画像処理タスクにより多くのリソースを割り当てることが可能です。
FastAPIはSSE(Server-Sent Events)もサポートしており、ストリーミング推論シナリオで役立ちます。
なぜ何度もリージョンを選択する必要があるのですか?
これはGoogle Cloud Platformの柔軟性による仕様であり、使用するすべてのサービスでリージョンを選択する必要があります。Vertex AI上でコンテナ化されたモデルをデプロイする際、最も重要なリージョン選択はModel Registryに対するものです。これがモデルデプロイに必要なマシンタイプとクォータの利用可能性を決定します。
さらに、今後セットアップを拡張して予測データや結果をCloud StorageやBigQueryに保存する場合、レイテンシを最小化しデータアクセスの高スループットを確保するために、Model Registryと同じリージョンを使用する必要があります。