0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TensorFlowで作ったモデルをVertex AI(現Agent Platform)にデプロイして推論を試してみた

0
Posted at

はじめに

Webエンジニアとして9年ほど、主にPHP/Laravelでの開発をやってきました。以前、工場向けの危険検知システムを開発する案件で、TensorFlow(CNN)を使った画像解析モデルの実装に携わったことがあります。ただ直近1年ほどは開発の現場から少し離れ気味で、その間にAI周りの技術がかなり動いていることは感じていました。

最近は個人開発でAI駆動開発(Claude Code、Spec-Kit、Skill機能など)のキャッチアップを続けているのですが、その延長で「クラウド側のAI活用」も触っておきたいと思い、今回はGoogle CloudのVertex AIを初めて使ってみることにしました。過去にTensorFlowでモデルを作った経験はあっても、それを「クラウド上のマネージドサービスにデプロイして、実際にエンドポイント経由で推論する」というところまではやったことがなかったので、そのギャップを埋める記録です。

結論から言うと、モデルのデプロイ自体は思ったよりシンプルに終わった一方、アカウント周りとプレースホルダーの見落としで想定外に時間を使いました。この記事では、その顛末も含めて正直に書きます。

Vertex AIとは

Vertex AIは、Google Cloudが提供する機械学習の統合プラットフォームです。モデルの学習・評価・デプロイ・監視まで、機械学習のライフサイクル全体を1つのサービス上で扱えるようにする、というのが基本的なコンセプトです。

記事を書いている途中で知ったのですが、2026年4月のGoogle Cloud Next '26で、Vertex AIは「Gemini Enterprise Agent Platform」(通称Agent Platform)という名前に統合されていました。単なる改称ではなく、「MLプラットフォーム」から「エージェント構築基盤」へと位置づけが変わったという発表でした。ただし救いだったのは、Python SDK(google-cloud-aiplatform)もAPIのエンドポイント(aiplatform.googleapis.com)も、パッケージ名・関数名を含めて変わっていないことです。変わったのはコンソール上の表示名とドキュメントのURLだけで、この記事で紹介するコードはそのまま動きます。以降、コンソール画面の話をするときは「Agent Platform」、コードやAPIの話をするときは「Vertex AI」と、実態に合わせて呼び方を使い分けます。

自分でトレーニングしたモデル(TensorFlow、PyTorch、scikit-learn等)を持ち込んでデプロイすることもできますし、Google謹製のAutoMLやGeminiなどの基盤モデルを使うこともできます。今回やりたいのは前者、つまり「自分で作ったTensorFlowモデルを、Vertex AIの推論基盤に乗せる」というシンプルなユースケースです。

デプロイの基本的な流れは、大きく3ステップです。

  1. モデルのアップロード: 学習済みモデルを「Model Registry」に登録する
  2. エンドポイントの作成: 推論リクエストを受け付ける窓口(エンドポイント)を作る
  3. モデルのデプロイ: 登録したモデルをエンドポインに紐付けて、実際にリクエストを受けられる状態にする

スクリーンショット 2026-09-05 114709.png

準備: Google Cloudアカウントと無料クレジット

Google Cloudを初めて使う場合、新規登録で**$300分の無料クレジット(有効期限90日)**が付与される……はずでした。ここで最初につまずきました。

無料クレジットが付与されていなかった

私は既存のGoogleアカウントで普通にGoogle Cloud Consoleにログインし、その中で請求先アカウントを作成しました。しかし後から「お支払い」→「クレジット」の画面を見ると、**「表示するクレジットはありません」**という表示になっていました。

調べたところ、無料トライアルの$300クレジットは、https://cloud.google.com/freeの「無料で開始」ボタンから登録した場合にのみ付与される仕組みのようでした。既存アカウントでConsoleに直接ログインして請求先アカウントを作る、という私のやり方では、通常の(クレジット無しの)従量課金アカウントが作られてしまっていました。

同じアカウントで改めて無料トライアルへの登録を試みましたが、案内自体が表示されない状態でした。Googleは支払い情報などから「既に請求先アカウントを持っているユーザー」と判定しているようで、この状態からの無料トライアル取得は難しそうでした。

前払いを求められた

そこで、Google Cloudを使うのが初めての別アカウントで改めて登録を試みたところ、今度は以下のようなメッセージが表示されました。

無料トライアルを利用するには、前払いを行う必要があります。お支払い済みの場合は、24時間以内にアカウントにクレジットが追加されます。

これも最初は戸惑いましたが、調べてみると公式ドキュメントに記載のある正規の仕組みでした。

特定の種類の支払い方法では、前払いが必要になります。前払い額は国・通貨によって異なります。未使用分は、アカウント終了時に返金されます。

つまり、使っている支払い方法(カードの種類など)によっては、Googleが「先に一定額をチャージしてから使ってください」と求めてくることがある、ということです。私の場合は5,000円の前払いを求められました。$300(当時のレートで4万円台半ば)のクレジットが得られることを考えると、悪くない交換だと判断し、支払って進めることにしました。

無料トライアルは、既存アカウントで直接ログインして作った請求先アカウントには自動付与されません。必ずhttps://cloud.google.com/freeの登録フローを経由する必要があります。また、支払い方法によっては前払いが必要になることがあり、これは公式に案内されている正規の仕組みです(未使用分は返金対象)。

前払いが完了し、クレジットの反映を確認できたら、以下の手順に進みます。

  1. Google Cloud Console上部のプロジェクト選択メニューから「新しいプロジェクト」を作成する
  2. Google Cloud Consoleの検索窓で「Agent Platform」(または「Vertex AI」)を検索し、APIを有効化する。コマンドで有効化する場合は以下の通りです
gcloud services enable aiplatform.googleapis.com

無料クレジットは便利ですが、$300を使い切る、または90日が経過すると、その時点で無料トライアルの請求先アカウントは自動的にクローズされます。放置しているリソース(特に後述するエンドポイント)は無料クレジットを静かに消費していくので注意が必要です。

TensorFlowモデルの用意

モデル自体は今回の主役ではないので、シンプルなものを用意します。Fashion-MNIST(10種類の衣料品を分類する、白黒28×28ピクセルの画像データセット)を分類する、小さめのCNNです。

このあたりのコード生成はClaude Codeに任せました。実際に使ったプロンプトは以下の通りです。

# タスク: Vertex AIデプロイ検証用の、シンプルな画像分類CNNを作る

## 背景

Vertex AIへのモデルデプロイ手順を記事化するための、練習用モデルを用意したい。
主役はVertex AI側の手順(アップロード・エンドポイント作成・推論テスト)なので、
モデル自体は「学習が数分で終わり、精度もそこそこ出る」シンプルなものでよい。

## やってほしいこと

TensorFlow(Keras)で、Fashion-MNIST(10クラスの衣料品グレースケール画像、
28x28ピクセル)を分類するCNNを学習し、Vertex AIにアップロードできる形式
(TensorFlow SavedModel)で出力するスクリプトを作成してください。

### 要件

1. `tensorflow.keras.datasets.fashion_mnist`を使ってデータを読み込む
2. 画素値を0-1に正規化し、チャンネル次元を追加する(shape: (28, 28, 1))
3. シンプルなCNN(Conv2D×2 + MaxPooling×2 + Dense層 + Dropout + 出力層10クラス)を構築する
4. 学習は5エポック程度(デモ用途なので長時間の学習は不要)
5. テストデータでの精度を表示する
6. 学習済みモデルを`saved_model/fashion_mnist_cnn/1/`(バージョン番号のサブディレクトリを含む形)に
   SavedModel形式でエクスポートする(`model.export()`または`tf.saved_model.save()`を使う)
7. ついでに、ローカルでSavedModelを読み込み直して1件だけ推論を試す検証スクリプトも
   別ファイルで作成してください(Vertex AIにアップロードする前に、SavedModelとして
   正しく読み書きできているかを手元で確認したいため)

### 注意点

- `requirements.txt`(tensorflow, numpy程度)も作成してください
- コード中に日本語コメントで、各ステップが何をしているか説明を入れてください
- Vertex AIの標準的なTensorFlow提供コンテナ(prebuiltコンテナ)で動かす前提なので、
  カスタムのpre/post-processingは入れず、`model.predict()`で完結する素直な構成にしてください
- 学習・エクスポートが終わったら、`saved_model/fashion_mnist_cnn/1/`配下に
  `saved_model.pb`が生成されていることを確認し、ディレクトリ構成を教えてください

出力先のディレクトリ構成が、以下のようにバージョン番号のサブディレクトリ(1/)を含む形になっている点がポイントです。

saved_model/
└── fashion_mnist_cnn/
    └── 1/
        ├── saved_model.pb
        ├── variables/
        └── assets/

Vertex AIのTensorFlow提供コンテナ(TensorFlow Servingがベース)は、この「バージョン番号ディレクトリを含むSavedModel形式」を前提にしています。モデル本体の直下にいきなりsaved_model.pbを置く形だと、コンテナがモデルを見つけられずデプロイに失敗するので注意してください。

ソースのアップロード

学習が終わったら、モデルをGoogle Cloudへ持っていく必要があります。ここで必要になるのが**Cloud Storage(GCS)**です。Vertex AIはローカルのファイルを直接読み込むことはできず、一度GCSのバケットに置いたものを参照する形になります。

GCSへのアップロードにはgcloudコマンドを使いますが、これはローカルにインストールする方法と、ブラウザ上で完結する「Cloud Shell」を使う方法の2通りがあります。今回はインストール不要なCloud Shellを使いました。

Cloud Shellでのアップロード手順

  1. Google Cloud Console右上のターミナルアイコンから、Cloud Shellを起動する
  2. 学習済みモデル(SavedModelディレクトリ一式)を、手元のPCでzipに圧縮する(Cloud Shellのアップロード機能はフォルダ単位の一括アップロードに対応していないため)
Compress-Archive -Path saved_model\fashion_mnist_cnn\1 -DestinationPath model.zip
  1. Cloud Shellのターミナル右上の「⋮」メニューから「アップロード」を選び、model.zipをアップロードする
  2. Cloud Shell上でzipを展開する
unzip model.zip
  1. バケットを作成し、モデルをアップロードする
gcloud storage buckets create gs://あなたの好きなバケット名 --location=us-central1
gcloud storage cp -r 1 gs://あなたのバケット名/models/fashion_mnist_cnn/1
  1. アップロードできたか確認する
gcloud storage ls gs://あなたのバケット名/models/fashion_mnist_cnn/1/

saved_model.pbがリストに出てくれば成功です。

なお、学習スクリプト自体(Pythonコード)はGCSに置く必要はありません。デプロイに必要なのはあくまで学習済みモデルの成果物(SavedModel)だけです。

Vertex AIへのデプロイ手順

Cloud Shellには最初からPythonが入っているので、そのままpip installして進められます。

pip install --user google-cloud-aiplatform

1. モデルをModel Registryにアップロードする

from google.cloud import aiplatform

aiplatform.init(project="あなたの実際のプロジェクトID", location="us-central1")

model = aiplatform.Model.upload(
    display_name="fashion-mnist-cnn",
    artifact_uri="gs://あなたの実際のバケット名/models/fashion_mnist_cnn/1",
    # TensorFlow用のVertex AI提供コンテナ(prebuiltコンテナ)を指定する
    serving_container_image_uri="us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-15:latest",
)

print(f"アップロードしたモデル: {model.resource_name}")

ここで実際にハマりました。サンプルコードのproject="your-project-id"をプレースホルダーだと認識せず、そのままの文字列でコピペしてしまい、以下のエラーになりました。

google.api_core.exceptions.PermissionDenied: 403 Agent Platform API has not been used
in project your-project-id before or it is disabled.

エラーメッセージに「Agent Platform API」という表記が出ているのも興味深い点で、内部的なサービス名(aiplatform.googleapis.com)は変わっていないものの、エラーメッセージ上の表示名は既に新名称に切り替わっているようでした。projectartifact_uriは、必ずgcloud config get-value projectで確認した実際のプロジェクトIDと、実際に作成したバケット名に置き換えてください。

serving_container_image_uriには、Google側が用意しているTensorFlow推論用のコンテナイメージを指定します。バージョン番号(この例では2-15)は、学習に使ったTensorFlowのバージョンに近いものを選ぶのが無難です。

2. エンドポイントを作成する

endpoint = aiplatform.Endpoint.create(display_name="fashion-mnist-endpoint")
print(f"作成したエンドポイント: {endpoint.resource_name}")

3. モデルをエンドポイントにデプロイする

endpoint.deploy(
    model=model,
    deployed_model_display_name="fashion-mnist-cnn-v1",
    machine_type="e2-standard-2",
    min_replica_count=1,
    max_replica_count=1,
)

実行すると、以下のようなログが出て、しばらくプロンプトが返ってきません。

Deploying Model projects/xxxxxxxxxxxx/locations/us-central1/models/xxxxxxxxxxxxxxxxxx to Endpoint : projects/xxxxxxxxxxxx/locations/us-central1/endpoints/xxxxxxxxxxxxxxxxxx
Deploy Endpoint model backing LRO: projects/xxxxxxxxxxxx/locations/us-central1/endpoints/xxxxxxxxxxxxxxxxxx/operations/xxxxxxxxxxxxxxxxxx

「LRO」は「Long Running Operation」の略で、裏側でコンテナの起動やヘルスチェックが進行中であることを示しています。手元の検証では、ここで10分前後待つことになりました。プロンプトが>>> に戻ってくればデプロイ完了です。

推論テスト

デプロイが完了したら、実際にリクエストを投げて推論を試します。Fashion-MNISTのテストデータから1件取り出して、28×28の配列をそのままリクエストボディに詰めて送ります。

import numpy as np
from tensorflow import keras

(_, _), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
sample = (x_test[0].astype("float32") / 255.0).reshape(28, 28, 1)

prediction = endpoint.predict(instances=[sample.tolist()])

class_names = [
    "T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
    "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot",
]
predicted_class = np.argmax(prediction.predictions[0])

print(f"正解ラベル: {class_names[y_test[0]]}")
print(f"推論結果  : {class_names[predicted_class]}")

実際の実行結果です。

正解ラベル: Ankle boot
推論結果  : Ankle boot

正解ラベルと推論結果が一致しました。

curlで直接叩いてみる

endpoint.predict()の中身は、実際にはエンドポイントのURLに対するHTTPS POSTリクエストです。SDKを使わずcurlで直接叩けることも確認しました。まずリクエスト用のJSONファイルを作ります。

import json
with open("request.json", "w") as f:
    json.dump({"instances": [sample.tolist()]}, f)
curl -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  "https://us-central1-aiplatform.googleapis.com/v1/projects/あなたのプロジェクト番号/locations/us-central1/endpoints/あなたのエンドポイントID:predict" \
  -d @request.json

実際のレスポンスです。

{
  "predictions": [
    [
      4.25802549e-09,
      1.04513376e-08,
      5.64395908e-09,
      8.68542749e-09,
      1.56240876e-09,
      3.09712705e-05,
      4.44755557e-08,
      7.79251277e-05,
      2.45354556e-07,
      0.999890804
    ]
  ],
  "deployedModelId": "xxxxxxxxxxxxxxxxxx",
  "model": "projects/xxxxxxxxxxxx/locations/us-central1/models/xxxxxxxxxxxxxxxxxx",
  "modelDisplayName": "fashion-mnist-cnn",
  "modelVersionId": "1"
}

10クラス分の確率がそのまま返ってきます。10番目(インデックス9、"Ankle boot")の値が0.999890804、つまり99.99%の確信度で判定しており、SDK経由の結果と一致することを確認できました。

スクリーンショット 2026-09-05 114721.png

つまずいたポイント

実際に一連の手順を試す中で、いくつか引っかかったポイントがありました。

スクリーンショット 2026-09-05 115007.png

  • 無料クレジットは自動付与されない: 既存アカウントでConsoleに直接ログインして請求先アカウントを作る方法では、$300クレジットは付与されませんでした。https://cloud.google.com/freeの登録フローを経由する必要があります
  • 前払いが必要になることがある: 支払い方法によっては、無料トライアル開始前に前払いを求められます。私の場合は5,000円でした。これは正規の仕組みで、未使用分は返金対象です
  • プレースホルダーの見落とし: サンプルコードの"your-project-id"をそのまま実行してしまい、PermissionDeniedエラーになりました。projectartifact_uriは必ず実際の値に置き換える必要があります
  • Cloud Shellはフォルダの一括アップロードに非対応: SavedModelディレクトリをそのままアップロードしようとしてもできなかったため、一度zipに圧縮してからアップロードし、Cloud Shell上で展開する、というひと手間が必要でした
  • Vertex AIからAgent Platformへの改称: 2026年4月の改称により、コンソール上の名称やドキュメントのURLが変わっていました。SDK・APIは変わっていないため実害はありませんでしたが、エラーメッセージにも新名称(「Agent Platform API」)が出てきていて、少し戸惑いました

料金面の注意点

Vertex AI(Agent Platform)のオンライン予測(エンドポイント)は、リクエストの有無にかかわらず、デプロイされている時間そのものに対して課金される従量課金制です。マシンタイプによって単価は変わりますが、デプロイしたまま放置すると気づかないうちに積み上がっていく性質のものです。

料金の詳細は変動するため、必ずVertex AIの公式料金ページで最新の単価を確認してください。ここでは金額そのものよりも、「動いているだけで課金される」という課金モデルの性質を覚えておくのが重要だと思います。

検証が終わったら、忘れずにクリーンアップしましょう。

endpoint.undeploy_all()
endpoint.delete()
model.delete()
gcloud storage rm -r gs://あなたのバケット名

削除できたかどうかは、以下のコマンドで確認できます。

gcloud ai endpoints list --region=us-central1
gcloud ai models list --region=us-central1
gcloud storage ls

いずれも「0 items」や空の結果になっていれば、課金対象のリソースは残っていません。実際に私もこの3コマンドで、全て空になっていることを確認しました。

Google Cloud Consoleの「お支払い」→「レポート」からも、現在の消費額を確認できます。ただし反映まで数時間〜半日程度のタイムラグがあるため、即座に¥0と表示されても油断せず、翌日改めて確認するのがおすすめです。

おわりに

実際にモデルをアップロードしてエンドポイントを作り、推論できるところまで一通り触ってみて、「モデルを作ること」と「モデルを本番運用可能な形で提供すること」の間には、思っていたよりも工程があるという実感を持ちました。過去にTensorFlowでモデルを書いていた頃は、学習して精度を見て終わり、ということが多かったので、デプロイ・エンドポイント管理・コスト管理まで含めての「機械学習エンジニアリング」という感覚は新鮮でした。

技術的な内容そのものより、アカウント周り(無料クレジット・前払い)や、プレースホルダーの見落としといった「地味なつまずき」に時間を使ったというのが今回の一番の実感です。クラウドサービスを初めて触るときによくあるパターンだと思うので、同じように後から追いつこうとしているエンジニアの参考になればと思います。

次に触ってみたいのは、以下のあたりです。

  • Model Gardenでの基盤モデル活用: Agent Platform経由で、GeminiをはじめとしたGoogle製モデルだけでなく、サードパーティのモデルも呼び出せるようです。自前のモデルと基盤モデルを組み合わせるパターンも試してみたい
  • MLOpsパイプラインの構築: 今回は手動でアップロード〜デプロイまで行いましたが、パイプライン機能を使えば学習からデプロイまでを自動化できるようです。継続的に再学習が必要なユースケースでは、この自動化がむしろ本題になりそうです
  • コストの最適化: 常時起動のエンドポイントではなく、バッチ予測やオートスケーリングの設定など、用途に応じたコスト最適化のパターンも比較してみたいと思っています

AI駆動開発でのキャッチアップと並行して、こうしたクラウド側のAI基盤も少しずつ触っていこうと思います。


タグ案(5個まで)

GoogleCloud VertexAI TensorFlow 機械学習 個人開発

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?