Ultralyticsを使用してVertex AIに事前学習済みYOLOモデルをデプロイし、推論を実行します#
このガイドでは、Ultralyticsを使用して事前学習済みYOLO26モデルをコンテナ化し、そのためのFastAPI推論サーバーを構築して、推論サーバーとともにGoogle Cloud Vertex AIへモデルをデプロイする方法を説明します。実装例ではYOLO26の物体検出ユースケースを扱いますが、同じ原則を他のYOLOモードにも適用できます。
開始する前に、Google Cloud Platform(GCP)プロジェクトを作成する必要があります。新規ユーザーには無料で使用できる300ドル分のGCPクレジットが付与されます。この金額で、実行中の環境をテストするには十分であり、その後、トレーニングやバッチ推論、ストリーミング推論など、その他の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イメージの1つを拡張する必要があるため、Ultralytics向けDockerクイックスタートガイドを一読することを強くおすすめします。
1. FastAPIで推論バックエンドを作成する#
まず、YOLO26モデルへの推論リクエストを処理するFastAPIアプリケーションを作成する必要があります。このアプリケーションでは、モデルの読み込み、画像の前処理、推論(予測)ロジックを処理します。
Vertex AIコンプライアンスの基本#
Vertex AIでは、コンテナに次の2つの特定エンドポイントを実装する必要があります。
-
Healthエンドポイント(
/health): サービスの準備が完了したときにHTTPステータス200 OKを返す必要があります。 -
Predictエンドポイント(
/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の中核となる推論ロジックを実装できます。Ultralytics Python APIを使用して、モデルの読み込み、画像処理、予測を処理するsrc/app.pyファイルを作成します。
# 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."""
# 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にとって重要です。専用のヘルスチェックがない場合、オーケストレーターがランダムなソケットに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フォルダーにテスト画像を配置します。次に、Terminalで次のコマンドを実行します。
# 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モデルを取得して読み込む必要があるため、少し時間がかかります。
2. アプリケーションでUltralytics Dockerイメージを拡張する#
Ultralyticsは、アプリケーションイメージのベースとして使用できる複数のDockerイメージを提供しています。DockerがUltralyticsと必要なGPUドライバーをインストールします。
Ultralytics YOLOモデルの機能を最大限に活用するには、GPU推論向けにCUDA最適化されたイメージを選択してください。ただし、タスクにCPU推論で十分な場合は、CPU専用イメージを選択してコンピューティングリソースを節約することもできます。
- Dockerfile: YOLO26の単一GPUまたはマルチ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_VERSIONこれで、Dockerコンテナ上でFastAPIサーバーがポート8080で実行され、推論リクエストを受け付ける準備が整いました。先ほどと同じ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/predict3. DockerイメージをGCP Artifact Registryにアップロードする#
コンテナ化したモデルをVertex AIにインポートするには、DockerイメージをGoogle Cloud Artifact Registryにアップロードする必要があります。Artifact Registryリポジトリをまだ作成していない場合は、先に作成する必要があります。
Google Cloud Artifact Registryにリポジトリを作成する#
Google Cloud ConsoleでArtifact Registryページを開きます。Artifact Registryを初めて使用する場合は、先にArtifact Registry APIを有効にするよう求められることがあります。
- 「Create Repository」を選択します。
- リポジトリ名を入力します。希望するリージョンを選択し、特別に変更する必要がない限り、その他のオプションにはデフォルト設定を使用します。
リージョンの選択は、マシンの可用性や、Enterprise以外のユーザーに対する一部のコンピュート制限に影響する場合があります。詳しくは、Vertex AI公式ドキュメントのVertex AIのクォータと上限をご覧ください。
- リポジトリの作成後、PROJECT_ID、Location(リージョン)、Repository Nameをシークレット保管庫または
.envファイルに保存します。後でDockerイメージにタグを付け、Artifact Registryにプッシュする際に必要になります。
DockerをArtifact Registryで認証する#
作成したArtifact Registryリポジトリに対してDockerクライアントを認証します。ターミナルで次のコマンドを実行します。
gcloud auth configure-docker YOUR_REGION-docker.pkg.devイメージにタグを付けてArtifact 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のドキュメント「イメージのプッシュとプル」をご覧ください。
4. Vertex AIにモデルをインポートする#
先ほどプッシュしたDockerイメージを使用して、Vertex AIにモデルをインポートできます。
- Google Cloudのナビゲーションメニューで、Vertex AI > Model Registryに移動します。または、Google Cloud Console上部の検索バーで「Vertex AI」を検索します。
5. Vertex AIエンドポイントを作成してモデルをデプロイする#
Vertex AIの用語では、エンドポイントはデプロイ済みモデルを指します。これは、推論リクエストを送信するHTTPエンドポイントを表すためです。一方、モデルはModel Registryに保存されているトレーニング済みMLアーティファクトを指します。
モデルをデプロイするには、Vertex AIでエンドポイントを作成する必要があります。
- Vertex AIのナビゲーションメニューで、Endpointsに移動します。モデルのインポート時に使用したリージョンを選択します。「Create」をクリックします。
特定のリージョンではコンピュートクォータが非常に限られているため、リージョンによっては特定のマシンタイプやGPUを選択できない場合があります。これが問題になる場合は、デプロイ先をより大きなクォータを持つリージョンに変更してください。詳しくは、Vertex AI公式ドキュメントのVertex AIのクォータと上限をご覧ください。
- マシンタイプを選択したら、「Continue」をクリックできます。この時点で、Vertex AIのモデルモニタリングを有効にすることもできます。これは、モデルのパフォーマンスを追跡し、その動作に関するインサイトを提供する追加サービスです。これは任意の機能で、追加費用が発生するため、必要に応じて選択してください。「Create」をクリックします。
Vertex AIによるモデルのデプロイには数分かかります(リージョンによっては最大30分)。デプロイが完了すると、メール通知が届きます。
6. デプロイしたモデルをテストする#
デプロイが完了すると、Vertex AIからモデルをテストするためのサンプルAPIインターフェースが提供されます。
リモート推論をテストするには、提供されたcURLコマンドを使用するか、デプロイしたモデルにリクエストを送信する別のPythonクライアントライブラリを作成します。/predictエンドポイントに送信する前に、画像をbase64にエンコードする必要があることに注意してください。
ローカルテストと同様に、実行中のコンテナでUltralyticsがYOLO26モデルを取得して読み込む必要があるため、初回のリクエストには少し時間がかかります。
これで、Ultralyticsを使用して事前学習済みYOLO26モデルをGoogle Cloud Vertex AIに正常にデプロイできました。
FAQ#
はい。ただし、まずモデルをTensorFlow、Scikit-learn、XGBoostなど、Vertex AIと互換性のある形式にエクスポートする必要があります。Google Cloudでは、変換プロセスの全体像を網羅した、Vertexで
.ptモデルを実行するためのガイド「Vertex AIでPyTorchモデルを実行する」を提供しています。なお、変換後の構成はVertex AIの標準サービングレイヤーのみに依存し、高度なUltralyticsフレームワーク機能には対応しません。Vertex AIはコンテナ化されたモデルを完全にサポートし、デプロイ構成に応じて自動的にスケーリングできるため、別の形式に変換することなく、Ultralytics YOLOモデルの機能を最大限に活用できます。
FastAPIは、推論ワークロードに高いスループットを提供します。非同期処理により、メインスレッドをブロックせずに複数の同時リクエストを処理できるため、コンピュータービジョンモデルをサービングする際に重要です。
FastAPIによるリクエストとレスポンスの自動検証により、本番環境の推論サービスにおける実行時エラーを削減できます。これは、入力形式の一貫性が重要な物体検出APIで特に有用です。
FastAPIが推論パイプラインに追加する計算オーバーヘッドは最小限であるため、モデルの実行や画像処理タスクに利用できるリソースを増やせます。
FastAPIはSSE(サーバー送信イベント)にも対応しており、ストリーミング推論のシナリオで役立ちます。
これは実際にはGoogle Cloud Platformの柔軟性を高める機能であり、使用するサービスごとにリージョンを選択する必要があります。Vertex AIにコンテナ化されたモデルをデプロイする場合、最も重要なリージョン選択はModel Registryのリージョンです。これにより、モデルのデプロイに使用できるマシンタイプとクォータが決まります。
さらに、セットアップを拡張して予測データや結果をCloud StorageまたはBigQueryに保存する場合は、データアクセスのレイテンシを最小限に抑え、高いスループットを確保するために、Model Registryと同じリージョンを使用する必要があります。